Пример #1
0
  public FlowInfo analyseAssignment(
      BlockScope currentScope,
      FlowContext flowContext,
      FlowInfo flowInfo,
      Assignment assignment,
      boolean isCompound) {
    boolean isReachable = (flowInfo.tagBits & FlowInfo.UNREACHABLE) == 0;
    // compound assignment extra work
    if (isCompound) { // check the variable part is initialized if blank final
      switch (this.bits & ASTNode.RestrictiveFlagMASK) {
        case Binding.FIELD: // reading a field
          FieldBinding fieldBinding = (FieldBinding) this.binding;
          if (fieldBinding.isBlankFinal()
              && currentScope.needBlankFinalFieldInitializationCheck(fieldBinding)) {
            FlowInfo fieldInits =
                flowContext.getInitsForFinalBlankInitializationCheck(
                    fieldBinding.declaringClass.original(), flowInfo);
            if (!fieldInits.isDefinitelyAssigned(fieldBinding)) {
              currentScope.problemReporter().uninitializedBlankFinalField(fieldBinding, this);
            }
          }
          if (!fieldBinding.isStatic()) {
            // https://bugs.eclipse.org/bugs/show_bug.cgi?id=318682
            currentScope.resetEnclosingMethodStaticFlag();
          }
          manageSyntheticAccessIfNecessary(currentScope, flowInfo, true /*read-access*/);
          break;
        case Binding.LOCAL: // reading a local variable
          // check if assigning a final blank field
          LocalVariableBinding localBinding;
          if (!flowInfo.isDefinitelyAssigned(localBinding = (LocalVariableBinding) this.binding)) {
            currentScope.problemReporter().uninitializedLocalVariable(localBinding, this);
            // we could improve error msg here telling "cannot use compound assignment on final
            // local variable"
          }
          if (localBinding.useFlag != LocalVariableBinding.USED) {
            // https://bugs.eclipse.org/bugs/show_bug.cgi?id=185682
            // access from compound assignment does not prevent "unused" warning, unless unboxing is
            // involved:
            if (isReachable && (this.implicitConversion & TypeIds.UNBOXING) != 0) {
              localBinding.useFlag = LocalVariableBinding.USED;
            } else {
              // use values < 0 to count the number of compound uses:
              if (localBinding.useFlag <= LocalVariableBinding.UNUSED) localBinding.useFlag--;
            }
          }
      }
    }
    if (assignment.expression != null) {
      flowInfo =
          assignment
              .expression
              .analyseCode(currentScope, flowContext, flowInfo)
              .unconditionalInits();
    }
    switch (this.bits & ASTNode.RestrictiveFlagMASK) {
      case Binding.FIELD: // assigning to a field
        manageSyntheticAccessIfNecessary(currentScope, flowInfo, false /*write-access*/);

        // check if assigning a final field
        FieldBinding fieldBinding = (FieldBinding) this.binding;
        if (fieldBinding.isFinal()) {
          // inside a context where allowed
          if (!isCompound
              && fieldBinding.isBlankFinal()
              && currentScope.allowBlankFinalFieldAssignment(fieldBinding)) {
            if (flowInfo.isPotentiallyAssigned(fieldBinding)) {
              currentScope
                  .problemReporter()
                  .duplicateInitializationOfBlankFinalField(fieldBinding, this);
            } else {
              flowContext.recordSettingFinal(fieldBinding, this, flowInfo);
            }
            flowInfo.markAsDefinitelyAssigned(fieldBinding);
          } else {
            currentScope.problemReporter().cannotAssignToFinalField(fieldBinding, this);
          }
        }
        if (!fieldBinding.isStatic()) {
          // https://bugs.eclipse.org/bugs/show_bug.cgi?id=318682
          currentScope.resetEnclosingMethodStaticFlag();
        }
        break;
      case Binding.LOCAL: // assigning to a local variable
        LocalVariableBinding localBinding = (LocalVariableBinding) this.binding;
        if (!flowInfo.isDefinitelyAssigned(localBinding)) { // for local variable debug attributes
          this.bits |= ASTNode.FirstAssignmentToLocal;
        } else {
          this.bits &= ~ASTNode.FirstAssignmentToLocal;
        }
        if (localBinding.isFinal()) {
          if ((this.bits & ASTNode.DepthMASK) == 0) {
            // tolerate assignment to final local in unreachable code (45674)
            if ((isReachable && isCompound) || !localBinding.isBlankFinal()) {
              currentScope.problemReporter().cannotAssignToFinalLocal(localBinding, this);
            } else if (flowInfo.isPotentiallyAssigned(localBinding)) {
              currentScope
                  .problemReporter()
                  .duplicateInitializationOfFinalLocal(localBinding, this);
            } else {
              flowContext.recordSettingFinal(localBinding, this, flowInfo);
            }
          } else {
            currentScope.problemReporter().cannotAssignToFinalOuterLocal(localBinding, this);
          }
        } else /* avoid double diagnostic */ if ((localBinding.tagBits & TagBits.IsArgument) != 0) {
          currentScope.problemReporter().parameterAssignment(localBinding, this);
        }
        flowInfo.markAsDefinitelyAssigned(localBinding);
    }
    manageEnclosingInstanceAccessIfNecessary(currentScope, flowInfo);
    return flowInfo;
  }