public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo) { this.preAssertInitStateIndex = currentScope.methodScope().recordInitializationStates(flowInfo); Constant cst = this.assertExpression.optimizedBooleanConstant(); if ((this.assertExpression.implicitConversion & TypeIds.UNBOXING) != 0) { this.assertExpression.checkNPE(currentScope, flowContext, flowInfo); } boolean isOptimizedTrueAssertion = cst != Constant.NotAConstant && cst.booleanValue() == true; boolean isOptimizedFalseAssertion = cst != Constant.NotAConstant && cst.booleanValue() == false; flowContext.tagBits |= FlowContext.HIDE_NULL_COMPARISON_WARNING; FlowInfo conditionFlowInfo = this.assertExpression.analyseCode(currentScope, flowContext, flowInfo.copy()); flowContext.extendTimeToLiveForNullCheckedField(1); // survive this assert as a Statement flowContext.tagBits &= ~FlowContext.HIDE_NULL_COMPARISON_WARNING; UnconditionalFlowInfo assertWhenTrueInfo = conditionFlowInfo.initsWhenTrue().unconditionalInits(); FlowInfo assertInfo = conditionFlowInfo.initsWhenFalse(); if (isOptimizedTrueAssertion) { assertInfo.setReachMode(FlowInfo.UNREACHABLE_OR_DEAD); } if (this.exceptionArgument != null) { // only gets evaluated when escaping - results are not taken into account FlowInfo exceptionInfo = this.exceptionArgument.analyseCode(currentScope, flowContext, assertInfo.copy()); if (isOptimizedTrueAssertion) { currentScope.problemReporter().fakeReachable(this.exceptionArgument); } else { flowContext.checkExceptionHandlers( currentScope.getJavaLangAssertionError(), this, exceptionInfo, currentScope); } } if (!isOptimizedTrueAssertion) { // add the assert support in the clinit manageSyntheticAccessIfNecessary(currentScope, flowInfo); } // account for potential AssertionError: flowContext.recordAbruptExit(); if (isOptimizedFalseAssertion) { return flowInfo; // if assertions are enabled, the following code will be unreachable // change this if we need to carry null analysis results of the assert // expression downstream } else { CompilerOptions compilerOptions = currentScope.compilerOptions(); if (!compilerOptions.includeNullInfoFromAsserts) { // keep just the initializations info, don't include assert's null info // merge initialization info's and then add back the null info from flowInfo to // make sure that the empty null info of assertInfo doesnt change flowInfo's null info. return ((flowInfo.nullInfoLessUnconditionalCopy()) .mergedWith(assertInfo.nullInfoLessUnconditionalCopy())) .addNullInfoFrom(flowInfo); } return flowInfo .mergedWith(assertInfo.nullInfoLessUnconditionalCopy()) .addInitializationsFrom(assertWhenTrueInfo.discardInitializationInfo()); // keep the merge from the initial code for the definite assignment // analysis, tweak the null part to influence nulls downstream } }
public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo) { // check captured variables are initialized in current context (26134) checkCapturedLocalInitializationIfNecessary( (ReferenceBinding) this.binding.declaringClass.erasure(), currentScope, flowInfo); // process arguments if (this.arguments != null) { boolean analyseResources = currentScope.compilerOptions().analyseResourceLeaks; boolean hasResourceWrapperType = analyseResources && this.resolvedType instanceof ReferenceBinding && ((ReferenceBinding) this.resolvedType).hasTypeBit(TypeIds.BitWrapperCloseable); for (int i = 0, count = this.arguments.length; i < count; i++) { flowInfo = this.arguments[i].analyseCode(currentScope, flowContext, flowInfo).unconditionalInits(); // if argument is an AutoCloseable insert info that it *may* be closed (by the target // method, i.e.) if (analyseResources && !hasResourceWrapperType) { // allocation of wrapped closeables is analyzed specially flowInfo = FakedTrackingVariable.markPassedToOutside( currentScope, this.arguments[i], flowInfo, flowContext, false); } this.arguments[i].checkNPEbyUnboxing(currentScope, flowContext, flowInfo); } analyseArguments(currentScope, flowContext, flowInfo, this.binding, this.arguments); } // record some dependency information for exception types ReferenceBinding[] thrownExceptions; if (((thrownExceptions = this.binding.thrownExceptions).length) != 0) { if ((this.bits & ASTNode.Unchecked) != 0 && this.genericTypeArguments == null) { // https://bugs.eclipse.org/bugs/show_bug.cgi?id=277643, align with javac on JLS 15.12.2.6 thrownExceptions = currentScope.environment().convertToRawTypes(this.binding.thrownExceptions, true, true); } // check exception handling flowContext.checkExceptionHandlers( thrownExceptions, this, flowInfo.unconditionalCopy(), currentScope); } // after having analysed exceptions above start tracking newly allocated resource: if (currentScope.compilerOptions().analyseResourceLeaks && FakedTrackingVariable.isAnyCloseable(this.resolvedType)) FakedTrackingVariable.analyseCloseableAllocation(currentScope, flowInfo, this); if (this.binding.declaringClass.isMemberType() && !this.binding.declaringClass.isStatic()) { // allocating a non-static member type without an enclosing instance of parent type // https://bugs.eclipse.org/bugs/show_bug.cgi?id=335845 currentScope.resetDeclaringClassMethodStaticFlag(this.binding.declaringClass.enclosingType()); // Reviewed for https://bugs.eclipse.org/bugs/show_bug.cgi?id=378674 : // The corresponding problem (when called from static) is not produced until during code // generation } manageEnclosingInstanceAccessIfNecessary(currentScope, flowInfo); manageSyntheticAccessIfNecessary(currentScope, flowInfo); // account for possible exceptions thrown by the constructor flowContext.recordAbruptExit(); // TODO whitelist of ctors that cannot throw any exc.?? return flowInfo; }