Esempio n. 1
0
  public TypeBinding resolveType(BlockScope scope) {
    // Answer the signature return type
    // Base type promotion

    this.constant = Constant.NotAConstant;
    boolean receiverCast = false, argsContainCast = false;
    if (this.receiver instanceof CastExpression) {
      this.receiver.bits |= DisableUnnecessaryCastCheck; // will check later on
      receiverCast = true;
    }
    this.actualReceiverType = this.receiver.resolveType(scope);
    if (receiverCast && this.actualReceiverType != null) {
      // due to change of declaring class with receiver type, only identity cast should be notified
      if (((CastExpression) this.receiver).expression.resolvedType == this.actualReceiverType) {
        scope.problemReporter().unnecessaryCast((CastExpression) this.receiver);
      }
    }
    // resolve type arguments (for generic constructor call)
    if (this.typeArguments != null) {
      int length = this.typeArguments.length;
      boolean argHasError = false; // typeChecks all arguments
      this.genericTypeArguments = new TypeBinding[length];
      for (int i = 0; i < length; i++) {
        if ((this.genericTypeArguments[i] =
                this.typeArguments[i].resolveType(scope, true /* check bounds*/))
            == null) {
          argHasError = true;
        }
      }
      if (argHasError) {
        return null;
      }
    }
    // will check for null after args are resolved
    TypeBinding[] argumentTypes = Binding.NO_PARAMETERS;
    if (this.arguments != null) {
      boolean argHasError = false; // typeChecks all arguments
      int length = this.arguments.length;
      argumentTypes = new TypeBinding[length];
      for (int i = 0; i < length; i++) {
        Expression argument = this.arguments[i];
        if (argument instanceof CastExpression) {
          argument.bits |= DisableUnnecessaryCastCheck; // will check later on
          argsContainCast = true;
        }
        if ((argumentTypes[i] = this.arguments[i].resolveType(scope)) == null) argHasError = true;
      }
      if (argHasError) {
        if (this.actualReceiverType instanceof ReferenceBinding) {
          // record any selector match, for clients who may still need hint about possible method
          // match
          this.binding =
              scope.findMethod(
                  (ReferenceBinding) this.actualReceiverType,
                  this.selector,
                  new TypeBinding[] {},
                  this);
        }
        return null;
      }
    }
    if (this.actualReceiverType == null) {
      return null;
    }
    // base type cannot receive any message
    if (this.actualReceiverType.isBaseType()) {
      scope.problemReporter().errorNoMethodFor(this, this.actualReceiverType, argumentTypes);
      return null;
    }

    this.binding =
        this.receiver.isImplicitThis()
            ? scope.getImplicitMethod(this.selector, argumentTypes, this)
            : scope.getMethod(this.actualReceiverType, this.selector, argumentTypes, this);
    if (!this.binding.isValidBinding()) {
      if (this.binding instanceof ProblemMethodBinding
          && ((ProblemMethodBinding) this.binding).problemId() == ProblemReasons.NotVisible) {
        if (this.evaluationContext.declaringTypeName != null) {
          this.delegateThis =
              scope.getField(scope.enclosingSourceType(), EvaluationConstants.DELEGATE_THIS, this);
          if (this.delegateThis
              == null) { // if not found then internal error, field should have been found
            this.constant = Constant.NotAConstant;
            scope.problemReporter().invalidMethod(this, this.binding);
            return null;
          }
        } else {
          this.constant = Constant.NotAConstant;
          scope.problemReporter().invalidMethod(this, this.binding);
          return null;
        }
        CodeSnippetScope localScope = new CodeSnippetScope(scope);
        MethodBinding privateBinding =
            this.receiver instanceof CodeSnippetThisReference
                    && ((CodeSnippetThisReference) this.receiver).isImplicit
                ? localScope.getImplicitMethod(
                    (ReferenceBinding) this.delegateThis.type, this.selector, argumentTypes, this)
                : localScope.getMethod(this.delegateThis.type, this.selector, argumentTypes, this);
        if (!privateBinding.isValidBinding()) {
          if (this.binding.declaringClass == null) {
            if (this.actualReceiverType instanceof ReferenceBinding) {
              this.binding.declaringClass = (ReferenceBinding) this.actualReceiverType;
            } else { // really bad error ....
              scope
                  .problemReporter()
                  .errorNoMethodFor(this, this.actualReceiverType, argumentTypes);
              return null;
            }
          }
          scope.problemReporter().invalidMethod(this, this.binding);
          return null;
        } else {
          this.binding = privateBinding;
        }
      } else {
        if (this.binding.declaringClass == null) {
          if (this.actualReceiverType instanceof ReferenceBinding) {
            this.binding.declaringClass = (ReferenceBinding) this.actualReceiverType;
          } else { // really bad error ....
            scope.problemReporter().errorNoMethodFor(this, this.actualReceiverType, argumentTypes);
            return null;
          }
        }
        scope.problemReporter().invalidMethod(this, this.binding);
        return null;
      }
    }
    if (!this.binding.isStatic()) {
      // the "receiver" must not be a type, in other words, a NameReference that the TC has bound to
      // a Type
      if (this.receiver instanceof NameReference
          && (((NameReference) this.receiver).bits & Binding.TYPE) != 0) {
        scope.problemReporter().mustUseAStaticMethod(this, this.binding);
      } else {
        // handle indirect inheritance thru variable secondary bound
        // receiver may receive generic cast, as part of implicit conversion
        TypeBinding oldReceiverType = this.actualReceiverType;
        this.actualReceiverType =
            this.actualReceiverType.getErasureCompatibleType(this.binding.declaringClass);
        this.receiver.computeConversion(scope, this.actualReceiverType, this.actualReceiverType);
        if (this.actualReceiverType != oldReceiverType
            && this.receiver.postConversionType(scope)
                != this
                    .actualReceiverType) { // record need for explicit cast at codegen since
                                           // receiver could not handle it
          this.bits |= NeedReceiverGenericCast;
        }
      }
    }
    if (checkInvocationArguments(
        scope,
        this.receiver,
        this.actualReceiverType,
        this.binding,
        this.arguments,
        argumentTypes,
        argsContainCast,
        this)) {
      this.bits |= ASTNode.Unchecked;
    }

    // -------message send that are known to fail at compile time-----------
    if (this.binding.isAbstract()) {
      if (this.receiver.isSuper()) {
        scope.problemReporter().cannotDireclyInvokeAbstractMethod(this, this.binding);
      }
      // abstract private methods cannot occur nor abstract static............
    }
    if (isMethodUseDeprecated(this.binding, scope, true))
      scope.problemReporter().deprecatedMethod(this.binding, this);

    // from 1.5 compliance on, array#clone() returns the array type (but binding still shows Object)
    if (this.actualReceiverType.isArrayType()
        && this.binding.parameters == Binding.NO_PARAMETERS
        && scope.compilerOptions().complianceLevel >= ClassFileConstants.JDK1_5
        && CharOperation.equals(this.binding.selector, CLONE)) {
      this.resolvedType = this.actualReceiverType;
    } else {
      TypeBinding returnType = this.binding.returnType;

      if (returnType != null) {
        if ((this.bits & ASTNode.Unchecked) != 0 && this.genericTypeArguments == null) {
          returnType = scope.environment().convertToRawType(returnType.erasure(), true);
        }
        returnType = returnType.capture(scope, this.sourceEnd);
      }
      this.resolvedType = returnType;
    }
    return this.resolvedType;
  }