public FlowInfo analyseCode( BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo, boolean valueRequired) { boolean nonStatic = !this.binding.isStatic(); this.receiver.analyseCode(currentScope, flowContext, flowInfo, nonStatic); if (nonStatic) { this.receiver.checkNPE(currentScope, flowContext, flowInfo); // https://bugs.eclipse.org/bugs/show_bug.cgi?id=318682 if (this.receiver.isThis()) { currentScope.resetEnclosingMethodStaticFlag(); } } else if (this.receiver.isThis()) { if ((this.receiver.bits & ASTNode.IsImplicitThis) == 0) { // explicit this receiver, not allowed in static context // https://bugs.eclipse.org/bugs/show_bug.cgi?id=318682 currentScope.resetEnclosingMethodStaticFlag(); } } if (valueRequired || currentScope.compilerOptions().complianceLevel >= ClassFileConstants.JDK1_4) { manageSyntheticAccessIfNecessary(currentScope, flowInfo, true /*read-access*/); } return flowInfo; }
public FlowInfo analyseCode( BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo, boolean valueRequired) { currentScope.resetEnclosingMethodStaticFlag(); return analyseCode(currentScope, flowContext, 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; }
public FlowInfo analyseAssignment( BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo, Assignment assignment, boolean isCompound) { // compound assignment extra work if (isCompound) { // check the variable part is initialized if blank final if (this.binding.isBlankFinal() && this.receiver.isThis() && currentScope.needBlankFinalFieldInitializationCheck(this.binding)) { FlowInfo fieldInits = flowContext.getInitsForFinalBlankInitializationCheck( this.binding.declaringClass.original(), flowInfo); if (!fieldInits.isDefinitelyAssigned(this.binding)) { currentScope.problemReporter().uninitializedBlankFinalField(this.binding, this); // we could improve error msg here telling "cannot use compound assignment on final blank // field" } } manageSyntheticAccessIfNecessary(currentScope, flowInfo, true /*read-access*/); } flowInfo = this.receiver .analyseCode(currentScope, flowContext, flowInfo, !this.binding.isStatic()) .unconditionalInits(); if (assignment.expression != null) { flowInfo = assignment .expression .analyseCode(currentScope, flowContext, flowInfo) .unconditionalInits(); } manageSyntheticAccessIfNecessary(currentScope, flowInfo, false /*write-access*/); // check if assigning a final field if (this.binding.isFinal()) { // in a context where it can be assigned? if (this.binding.isBlankFinal() && !isCompound && this.receiver.isThis() && !(this.receiver instanceof QualifiedThisReference) && ((this.receiver.bits & ASTNode.ParenthesizedMASK) == 0) // (this).x is forbidden && currentScope.allowBlankFinalFieldAssignment(this.binding)) { if (flowInfo.isPotentiallyAssigned(this.binding)) { currentScope .problemReporter() .duplicateInitializationOfBlankFinalField(this.binding, this); } else { flowContext.recordSettingFinal(this.binding, this, flowInfo); } flowInfo.markAsDefinitelyAssigned(this.binding); } else { // assigning a final field outside an initializer or constructor or wrong reference currentScope.problemReporter().cannotAssignToFinalField(this.binding, this); } } // https://bugs.eclipse.org/bugs/show_bug.cgi?id=318682 if (!this.binding.isStatic()) { if (this.receiver.isThis()) { currentScope.resetEnclosingMethodStaticFlag(); } } else if (this.receiver.isThis()) { if ((this.receiver.bits & ASTNode.IsImplicitThis) == 0) { // explicit this, not allowed in static context currentScope.resetEnclosingMethodStaticFlag(); } } return flowInfo; }