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;
  }
Example #3
0
  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;
  }