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; }
public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo) { // analyse the enclosing instance if (this.enclosingInstance != null) { flowInfo = this.enclosingInstance.analyseCode(currentScope, flowContext, flowInfo); } else { if (this.binding != null && this.binding.declaringClass != null) { ReferenceBinding superclass = this.binding.declaringClass.superclass(); if (superclass != null && superclass.isMemberType() && !superclass.isStatic()) { // creating an anonymous type of a non-static member type without an enclosing instance of // parent type currentScope.resetDeclaringClassMethodStaticFlag(superclass.enclosingType()); } } } // check captured variables are initialized in current context (26134) checkCapturedLocalInitializationIfNecessary( (ReferenceBinding) (this.anonymousType == null ? this.binding.declaringClass.erasure() : this.binding.declaringClass.superclass().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); if (analyseResources && !hasResourceWrapperType) { // allocation of wrapped closeables is analyzed specially // if argument is an AutoCloseable insert info that it *may* be closed (by the target // method, i.e.) flowInfo = FakedTrackingVariable.markPassedToOutside( currentScope, this.arguments[i], flowInfo, flowContext, false); } if ((this.arguments[i].implicitConversion & TypeIds.UNBOXING) != 0) { this.arguments[i].checkNPE(currentScope, flowContext, flowInfo); } } analyseArguments(currentScope, flowContext, flowInfo, this.binding, this.arguments); } // analyse the anonymous nested type if (this.anonymousType != null) { flowInfo = this.anonymousType.analyseCode(currentScope, flowContext, flowInfo); } // 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); } manageEnclosingInstanceAccessIfNecessary(currentScope, flowInfo); manageSyntheticAccessIfNecessary(currentScope, flowInfo); // account for possible exceptions thrown by constructor execution: flowContext.recordAbruptExit(); return flowInfo; }
public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo) { boolean nonStatic = !this.binding.isStatic(); boolean wasInsideAssert = ((flowContext.tagBits & FlowContext.HIDE_NULL_COMPARISON_WARNING) != 0); flowInfo = this.receiver .analyseCode(currentScope, flowContext, flowInfo, nonStatic) .unconditionalInits(); // recording the closing of AutoCloseable resources: boolean analyseResources = currentScope.compilerOptions().analyseResourceLeaks; if (analyseResources && CharOperation.equals(TypeConstants.CLOSE, this.selector)) { FakedTrackingVariable trackingVariable = FakedTrackingVariable.getCloseTrackingVariable(this.receiver); if (trackingVariable != null) { // null happens if receiver is not a local variable or not an AutoCloseable if (trackingVariable.methodScope == currentScope.methodScope()) { trackingVariable.markClose(flowInfo, flowContext); } else { trackingVariable.markClosedInNestedMethod(); } } } if (nonStatic) { this.receiver.checkNPE(currentScope, flowContext, flowInfo); // https://bugs.eclipse.org/bugs/show_bug.cgi?id=318682 if (this.receiver.isThis()) { // accessing non-static method without an object currentScope.resetDeclaringClassMethodStaticFlag(this.binding.declaringClass); } } else if (this.receiver.isThis()) { if ((this.receiver.bits & ASTNode.IsImplicitThis) == 0) { // explicit this receiver, not allowed in static context currentScope.resetEnclosingMethodStaticFlag(); } } FlowInfo conditionFlowInfo; if (this.arguments != null) { int length = this.arguments.length; for (int i = 0; i < length; i++) { Expression argument = this.arguments[i]; if ((argument.implicitConversion & TypeIds.UNBOXING) != 0) { argument.checkNPE(currentScope, flowContext, flowInfo); } if (this.receiver.resolvedType != null && this.receiver.resolvedType.id == TypeIds.T_OrgEclipseCoreRuntimeAssert && argument.resolvedType != null && argument.resolvedType.id == TypeIds.T_boolean) { Constant cst = argument.optimizedBooleanConstant(); boolean isOptimizedTrueAssertion = cst != Constant.NotAConstant && cst.booleanValue() == true; boolean isOptimizedFalseAssertion = cst != Constant.NotAConstant && cst.booleanValue() == false; flowContext.tagBits |= FlowContext.HIDE_NULL_COMPARISON_WARNING; conditionFlowInfo = argument.analyseCode(currentScope, flowContext, flowInfo.copy()); if (!wasInsideAssert) { 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 (!isOptimizedFalseAssertion) { // if assertion is not false for sure, only then it makes sense to carry the flow info // ahead. // if the code does reach ahead, it means the assert didn't cause an exit, and so // the expression inside it shouldn't change the prior flowinfo // viz. org.eclipse.core.runtime.Assert.isLegal(false && o != null) // keep the merge from the initial code for the definite assignment // analysis, tweak the null part to influence nulls downstream flowInfo = flowInfo .mergedWith(assertInfo.nullInfoLessUnconditionalCopy()) .addInitializationsFrom(assertWhenTrueInfo.discardInitializationInfo()); } } else { flowInfo = argument.analyseCode(currentScope, flowContext, flowInfo).unconditionalInits(); } if (analyseResources) { // if argument is an AutoCloseable insert info that it *may* be closed (by the target // method, i.e.) flowInfo = FakedTrackingVariable.markPassedToOutside(currentScope, argument, flowInfo, false); } } analyseArguments(currentScope, flowContext, flowInfo, this.binding, this.arguments); } ReferenceBinding[] thrownExceptions; if ((thrownExceptions = this.binding.thrownExceptions) != Binding.NO_EXCEPTIONS) { 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); } // must verify that exceptions potentially thrown by this expression are caught in the method flowContext.checkExceptionHandlers(thrownExceptions, this, flowInfo.copy(), currentScope); // TODO (maxime) the copy above is needed because of a side effect into // checkExceptionHandlers; consider protecting there instead of here; // NullReferenceTest#test0510 } manageSyntheticAccessIfNecessary(currentScope, flowInfo); return flowInfo; }