/** Normal field binding did not work, try to bind to a field of the delegate receiver. */
 public TypeBinding reportError(BlockScope scope) {
   if (this.binding instanceof ProblemFieldBinding) {
     scope.problemReporter().invalidField(this, (FieldBinding) this.binding);
   } else if (this.binding instanceof ProblemReferenceBinding) {
     scope.problemReporter().invalidType(this, (TypeBinding) this.binding);
   } else {
     scope.problemReporter().unresolvableReference(this, this.binding);
   }
   return null;
 }
  public FlowInfo analyseCode(
      BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo, boolean valueRequired) {
    // determine the rank until which we now we do not need any actual value for the field access
    int otherBindingsCount = this.otherBindings == null ? 0 : this.otherBindings.length;

    boolean needValue = otherBindingsCount == 0 ? valueRequired : !this.otherBindings[0].isStatic();
    boolean complyTo14 =
        currentScope.compilerOptions().complianceLevel >= ClassFileConstants.JDK1_4;
    switch (this.bits & ASTNode.RestrictiveFlagMASK) {
      case Binding.FIELD: // reading a field
        break;
      case Binding.LOCAL: // reading a local variable
        LocalVariableBinding localBinding;
        if (!flowInfo.isDefinitelyAssigned(localBinding = (LocalVariableBinding) this.binding)) {
          if (localBinding.declaringScope instanceof CompilationUnitScope)
            currentScope.problemReporter().uninitializedGlobalVariable(localBinding, this);
          else currentScope.problemReporter().uninitializedLocalVariable(localBinding, this);
        }
        if ((flowInfo.tagBits & FlowInfo.UNREACHABLE) == 0) {
          localBinding.useFlag = LocalVariableBinding.USED;
        } else if (localBinding.useFlag == LocalVariableBinding.UNUSED) {
          localBinding.useFlag = LocalVariableBinding.FAKE_USED;
        }
        checkNPE(currentScope, flowContext, flowInfo, true);
    }
    if (needValue) {
      manageEnclosingInstanceAccessIfNecessary(currentScope, flowInfo);
      // only for first binding (if value needed only)
    }
    if (this.otherBindings != null) {
      for (int i = 0; i < otherBindingsCount; i++) {
        needValue =
            i < otherBindingsCount - 1 ? !this.otherBindings[i + 1].isStatic() : valueRequired;
        if (needValue || complyTo14) {
          TypeBinding lastReceiverType = getGenericCast(i);
          if (lastReceiverType == null) {
            if (i == 0) {
              lastReceiverType = ((VariableBinding) this.binding).type;
            } else {
              lastReceiverType = this.otherBindings[i - 1].type;
            }
          }
        }
      }
    }
    return flowInfo;
  }
  public TypeBinding resolveType(BlockScope scope) {
    // field and/or local are done before type lookups
    // the only available value for the restrictiveFlag BEFORE
    // the TC is Flag_Type Flag_LocalField and Flag_TypeLocalField
    this.actualReceiverType = scope.enclosingReceiverType();
    this.constant = Constant.NotAConstant;
    if ((
        /*this.codegenBinding =*/ this.binding =
            scope.getBinding(
                this.tokens, this.bits & ASTNode.RestrictiveFlagMASK, this, true /*resolve*/))
        .isValidBinding()) {
      switch (this.bits & ASTNode.RestrictiveFlagMASK) {
        case Binding.VARIABLE: // ============only variable===========
        case Binding.TYPE | Binding.VARIABLE:
          if (this.binding instanceof LocalVariableBinding) {
            this.bits &= ~ASTNode.RestrictiveFlagMASK; // clear bits
            this.bits |= Binding.LOCAL;
            return this.resolvedType = getOtherFieldBindings(scope);
          }
          if (this.binding instanceof FieldBinding) {
            FieldBinding fieldBinding = (FieldBinding) this.binding;
            MethodScope methodScope = scope.methodScope();
            // check for forward references
            if (this.indexOfFirstFieldBinding == 1
                && methodScope.enclosingSourceType() == fieldBinding.original().declaringClass
                && methodScope.lastVisibleFieldID >= 0
                && fieldBinding.id >= methodScope.lastVisibleFieldID
                && (!fieldBinding.isStatic() || methodScope.isStatic)) {
              scope.problemReporter().forwardReference(this, 0, methodScope.enclosingSourceType());
            }
            this.bits &= ~ASTNode.RestrictiveFlagMASK; // clear bits
            this.bits |= Binding.FIELD;

            //						// check for deprecated receiver type
            //						// deprecation check for receiver type if not first token
            //						if (indexOfFirstFieldBinding > 1) {
            //							if (isTypeUseDeprecated(this.actualReceiverType, scope))
            //								scope.problemReporter().deprecatedType(this.actualReceiverType, this);
            //						}

            return this.resolvedType = getOtherFieldBindings(scope);
          }
          // thus it was a type
          this.bits &= ~ASTNode.RestrictiveFlagMASK; // clear bits
          this.bits |= Binding.TYPE;
        case Binding.TYPE: // =============only type ==============
          TypeBinding type = (TypeBinding) this.binding;
          //					if (isTypeUseDeprecated(type, scope))
          //						scope.problemReporter().deprecatedType(type, this);
          return this.resolvedType = type;
      }
    }
    // ========error cases===============
    return this.resolvedType = this.reportError(scope);
  }
예제 #4
0
  public void resolve(BlockScope scope) {
    MethodScope methodScope = scope.methodScope();

    if (methodScope == null) {
      /* return statement outside of a method */
      scope.problemReporter().cannotReturnOutsideFunction(this);
      return;
    }

    MethodBinding methodBinding = null;
    TypeBinding methodType =
        (methodScope.referenceContext instanceof AbstractMethodDeclaration)
            ? ((methodBinding = ((AbstractMethodDeclaration) methodScope.referenceContext).binding)
                    == null
                ? null
                : methodBinding.returnType)
            : TypeBinding.ANY;
    TypeBinding expressionType;
    if (this.expression == null) {
      if (methodType != null && !methodType.isAnyType())
        scope.problemReporter().shouldReturn(methodType, this);
      return;
    }
    this.expression.setExpectedType(methodType); // needed in case of generic method invocation
    if ((expressionType = this.expression.resolveType(scope)) == null) return;
    if (methodType == null) return;

    if (methodType
        != expressionType) // must call before computeConversion() and typeMismatchError()
    scope.compilationUnitScope().recordTypeConversion(methodType, expressionType);
    if (this.expression.isConstantValueOfTypeAssignableToType(expressionType, methodType)
        || expressionType.isCompatibleWith(methodType)) {

      return;
    }
    if (methodBinding != null && !methodBinding.isConstructor())
      scope.problemReporter().typeMismatchError(expressionType, methodType, this.expression);
  }
 /** Check and/or redirect the field access to the delegate receiver if any */
 public TypeBinding checkFieldAccess(BlockScope scope) {
   FieldBinding fieldBinding = (FieldBinding) this.binding;
   MethodScope methodScope = scope.methodScope();
   // check for forward references
   if (this.indexOfFirstFieldBinding == 1
       && methodScope.enclosingSourceType() == fieldBinding.original().declaringClass
       && methodScope.lastVisibleFieldID >= 0
       && fieldBinding.id >= methodScope.lastVisibleFieldID
       && (!fieldBinding.isStatic() || methodScope.isStatic)) {
     scope.problemReporter().forwardReference(this, 0, methodScope.enclosingSourceType());
   }
   this.bits &= ~ASTNode.RestrictiveFlagMASK; // clear bits
   this.bits |= Binding.FIELD;
   return getOtherFieldBindings(scope);
 }
  public TypeBinding resolveType(BlockScope scope) {
    // Propagate the type checking to the arguments, and check if the constructor is defined.
    constant = Constant.NotAConstant;
    if (this.member != null) {
      this.resolvedType = this.member.resolveForAllocation(scope, this);
      if (this.resolvedType != null && !this.resolvedType.isValidBinding()) {
        scope.problemReporter().invalidType(this, this.resolvedType);
      }
    } else if (this.type == null) {
      // initialization of an enum constant
      this.resolvedType = scope.enclosingReceiverType();
    } else {
      this.resolvedType = this.type.resolveType(scope, true /* check bounds*/);
    }
    // will check for null after args are resolved
    // buffering the arguments' types
    boolean argsContainCast = false;
    TypeBinding[] argumentTypes = Binding.NO_PARAMETERS;
    if (arguments != null) {
      boolean argHasError = false;
      int length = arguments.length;
      argumentTypes = new TypeBinding[length];
      for (int i = 0; i < length; i++) {
        Expression argument = this.arguments[i];
        if ((argumentTypes[i] = argument.resolveType(scope)) == null) {
          argHasError = true;
          argumentTypes[i] = TypeBinding.UNKNOWN;
        }
      }
      if (argHasError) {
        //			if (this.resolvedType instanceof ReferenceBinding) {
        //				// record a best guess, for clients who need hint about possible contructor match
        //				TypeBinding[] pseudoArgs = new TypeBinding[length];
        //				for (int i = length; --i >= 0;)
        //					pseudoArgs[i] = argumentTypes[i] == null ? this.resolvedType : argumentTypes[i]; //
        // replace args with errors with receiver
        //				this.binding = scope.findMethod((ReferenceBinding) this.resolvedType,
        // TypeConstants.INIT, pseudoArgs, this);
        //			}
        //			return this.resolvedType;
      }
    }
    if (this.resolvedType == null
        || this.resolvedType.isAnyType()
        || this.resolvedType instanceof ProblemReferenceBinding) {
      this.binding =
          new ProblemMethodBinding(
              TypeConstants.INIT, Binding.NO_PARAMETERS, ProblemReasons.NotFound);
      this.resolvedType = TypeBinding.UNKNOWN;
      return this.resolvedType;
    }

    if (!this.resolvedType.isValidBinding()) return null;
    if (this.resolvedType instanceof ReferenceBinding) {
      ReferenceBinding allocationType = (ReferenceBinding) this.resolvedType;
      if (!(binding = scope.getConstructor(allocationType, argumentTypes, this)).isValidBinding()) {
        if (binding.declaringClass == null) binding.declaringClass = allocationType;
        scope.problemReporter().invalidConstructor(this, binding);
        return this.resolvedType;
      }
      if (argumentTypes.length != binding.parameters.length)
        scope.problemReporter().wrongNumberOfArguments(this, binding);
      if (isMethodUseDeprecated(binding, scope, true))
        scope.problemReporter().deprecatedMethod(binding, this);
      checkInvocationArguments(
          scope,
          null,
          allocationType,
          this.binding,
          this.arguments,
          argumentTypes,
          argsContainCast,
          this);
    }

    return this.resolvedType;
  }
  public FlowInfo analyseAssignment(
      BlockScope currentScope,
      FlowContext flowContext,
      FlowInfo flowInfo,
      Assignment assignment,
      boolean isCompound) {
    // determine the rank until which we now we do not need any actual value for the field access
    int otherBindingsCount = this.otherBindings == null ? 0 : this.otherBindings.length;
    boolean needValue = otherBindingsCount == 0 || !this.otherBindings[0].isStatic();
    boolean complyTo14 =
        currentScope.compilerOptions().complianceLevel >= ClassFileConstants.JDK1_4;
    FieldBinding lastFieldBinding = null;
    switch (this.bits & ASTNode.RestrictiveFlagMASK) {
      case Binding.FIELD: // reading a field
        lastFieldBinding = (FieldBinding) this.binding;
        break;
      case Binding.LOCAL:
        // first binding is a local variable
        LocalVariableBinding localBinding;
        if (!flowInfo.isDefinitelyAssigned(localBinding = (LocalVariableBinding) this.binding)) {
          currentScope.problemReporter().uninitializedLocalVariable(localBinding, this);
        }
        if ((flowInfo.tagBits & FlowInfo.UNREACHABLE) == 0) {
          localBinding.useFlag = LocalVariableBinding.USED;
        } else if (localBinding.useFlag == LocalVariableBinding.UNUSED) {
          localBinding.useFlag = LocalVariableBinding.FAKE_USED;
        }
        checkNPE(currentScope, flowContext, flowInfo, true);
    }

    if (needValue) {
      manageEnclosingInstanceAccessIfNecessary(currentScope, flowInfo);
      // only for first binding
    }
    // all intermediate field accesses are read accesses
    if (this.otherBindings != null) {
      for (int i = 0; i < otherBindingsCount - 1; i++) {
        lastFieldBinding = this.otherBindings[i];
        needValue = !this.otherBindings[i + 1].isStatic();
      }
      lastFieldBinding = this.otherBindings[otherBindingsCount - 1];
    }

    if (isCompound) {
      TypeBinding lastReceiverType;
      switch (otherBindingsCount) {
        case 0:
          lastReceiverType = this.actualReceiverType;
          break;
        case 1:
          lastReceiverType = ((VariableBinding) this.binding).type;
          break;
        default:
          lastReceiverType = this.otherBindings[otherBindingsCount - 2].type;
          break;
      }
    }

    if (assignment.expression != null) {
      flowInfo =
          assignment
              .expression
              .analyseCode(currentScope, flowContext, flowInfo)
              .unconditionalInits();
    }

    // equivalent to valuesRequired[maxOtherBindings]
    TypeBinding lastReceiverType;
    switch (otherBindingsCount) {
      case 0:
        lastReceiverType = this.actualReceiverType;
        break;
      case 1:
        lastReceiverType = ((VariableBinding) this.binding).type;
        break;
      default:
        lastReceiverType = this.otherBindings[otherBindingsCount - 2].type;
        break;
    }

    return flowInfo;
  }
  public TypeBinding getOtherFieldBindings(BlockScope scope) {
    // At this point restrictiveFlag may ONLY have two potential value : FIELD LOCAL (i.e cast
    // <<(VariableBinding) binding>> is valid)
    int length = this.tokens.length;
    FieldBinding field;
    if ((this.bits & Binding.FIELD) != 0) {
      field = (FieldBinding) this.binding;
      if (!field.isStatic()) {
        // must check for the static status....
        if (this.indexOfFirstFieldBinding
                > 1 // accessing to a field using a type as "receiver" is allowed only with static
                    // field
            || scope.methodScope()
                .isStatic) { // the field is the first token of the qualified reference....
          scope.problemReporter().staticFieldAccessToNonStaticVariable(this, field);
          return null;
        }
      } else {
        // indirect static reference ?
        if (this.indexOfFirstFieldBinding > 1
            && field.declaringClass != this.actualReceiverType
            && field.declaringClass.canBeSeenBy(scope)) {
          scope.problemReporter().indirectAccessToStaticField(this, field);
        }
      }
      // only last field is actually a write access if any
      if (isFieldUseDeprecated(
          field,
          scope,
          (this.bits & ASTNode.IsStrictlyAssigned) != 0 && this.indexOfFirstFieldBinding == length))
        scope.problemReporter().deprecatedField(field, this);
    } else {
      field = null;
    }
    TypeBinding type = ((VariableBinding) this.binding).type;
    int index = this.indexOfFirstFieldBinding;
    if (index == length) { // 	restrictiveFlag == FIELD
      // perform capture conversion if read access
      return type;
    }
    // allocation of the fieldBindings array	and its respective constants
    int otherBindingsLength = length - index;
    this.otherCodegenBindings = this.otherBindings = new FieldBinding[otherBindingsLength];
    this.otherDepths = new int[otherBindingsLength];

    // save first depth, since will be updated by visibility checks of other bindings
    int firstDepth = (this.bits & ASTNode.DepthMASK) >> ASTNode.DepthSHIFT;
    // iteration on each field
    while (index < length) {
      char[] token = this.tokens[index];
      if (type == null) return null; // could not resolve type prior to this point

      this.bits &= ~ASTNode.DepthMASK; // flush previous depth if any
      FieldBinding previousField = field;
      field = scope.getField(type, token, this);
      int place = index - this.indexOfFirstFieldBinding;
      this.otherBindings[place] = field;
      this.otherDepths[place] = (this.bits & ASTNode.DepthMASK) >> ASTNode.DepthSHIFT;
      if (field.isValidBinding()) {
        // set generic cast of for previous field (if any)
        if (previousField != null) {
          TypeBinding fieldReceiverType = type;
          TypeBinding receiverErasure = type;
          if (receiverErasure instanceof ReferenceBinding) {
            if (receiverErasure.findSuperTypeWithSameErasure(field.declaringClass) == null) {
              fieldReceiverType =
                  field.declaringClass; // handle indirect inheritance thru variable secondary bound
            }
          }
          FieldBinding originalBinding = previousField.original();
        }
        // only last field is actually a write access if any
        if (isFieldUseDeprecated(
            field, scope, (this.bits & ASTNode.IsStrictlyAssigned) != 0 && index + 1 == length)) {
          scope.problemReporter().deprecatedField(field, this);
        }

        if (field.isStatic()) {
          // static field accessed through receiver? legal but unoptimal (optional warning)
          scope.problemReporter().nonStaticAccessToStaticField(this, field);
          // indirect static reference ?
          if (field.declaringClass != type) {
            scope.problemReporter().indirectAccessToStaticField(this, field);
          }
        }
        type = field.type;
        index++;
      } else {
        this.constant = Constant.NotAConstant; // don't fill other constants slots...
        scope.problemReporter().invalidField(this, field, index, type);
        setDepth(firstDepth);
        return null;
      }
    }
    setDepth(firstDepth);
    type = (this.otherBindings[otherBindingsLength - 1]).type;
    // perform capture conversion if read access
    return type;
  }
예제 #9
0
  public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo) {
    if (this.expression != null) {
      flowInfo = this.expression.analyseCode(currentScope, flowContext, flowInfo);
    }

    // compute the return sequence (running the finally blocks)
    FlowContext traversedContext = flowContext;
    int subCount = 0;
    boolean saveValueNeeded = false;
    boolean hasValueToSave =
        this.expression != null
            && this.expression.constant == Constant.NotAConstant
            && !(this.expression instanceof NullLiteral);
    do {
      SubRoutineStatement sub;
      if ((sub = traversedContext.subroutine()) != null) {
        if (this.subroutines == null) {
          this.subroutines = new SubRoutineStatement[5];
        }
        if (subCount == this.subroutines.length) {
          System.arraycopy(
              this.subroutines,
              0,
              (this.subroutines = new SubRoutineStatement[subCount * 2]),
              0,
              subCount); // grow
        }
        this.subroutines[subCount++] = sub;
        if (sub.isSubRoutineEscaping()) {
          saveValueNeeded = false;
          this.bits |= ASTNode.IsAnySubRoutineEscaping;
          break;
        }
      }
      traversedContext.recordReturnFrom(flowInfo.unconditionalInits());

      if (traversedContext instanceof InsideSubRoutineFlowContext) {
        ASTNode node = traversedContext.associatedNode;
        if (node instanceof TryStatement) {
          TryStatement tryStatement = (TryStatement) node;
          flowInfo.addInitializationsFrom(tryStatement.subRoutineInits); // collect inits
          if (hasValueToSave) {
            if (this.saveValueVariable == null) { // closest subroutine secret variable is used
              prepareSaveValueLocation(tryStatement);
            }
            saveValueNeeded = true;
          }
        }
      } else if (traversedContext instanceof InitializationFlowContext) {
        currentScope.problemReporter().cannotReturnOutsideFunction(this);
        return FlowInfo.DEAD_END;
      }
    } while ((traversedContext = traversedContext.parent) != null);

    // resize subroutines
    if ((this.subroutines != null) && (subCount != this.subroutines.length)) {
      System.arraycopy(
          this.subroutines, 0, (this.subroutines = new SubRoutineStatement[subCount]), 0, subCount);
    }

    // secret local variable for return value (note that this can only occur in a real method)
    if (saveValueNeeded) {
      if (this.saveValueVariable != null) {
        this.saveValueVariable.useFlag = LocalVariableBinding.USED;
      }
    } else {
      this.saveValueVariable = null;
      if (this.expression != null && this.expression.resolvedType == TypeBinding.BOOLEAN) {
        this.expression.bits |= ASTNode.IsReturnedValue;
      }
    }
    return FlowInfo.DEAD_END;
  }