public void resolveMethodSpecs(
      RoleModel role, ReferenceBinding baseType, boolean resolveBaseMethods) {
    super.resolveMethodSpecs(role, baseType, resolveBaseMethods);
    if (this.roleMethodSpec.isValid() && this.roleMethodSpec.isStatic())
      if (this.predicate != null) makeMethodStatic(this.predicate);

    if (!resolveBaseMethods) return;

    MethodBinding[] baseMethods = new MethodBinding[this.baseMethodSpecs.length];
    for (int i = 0; i < this.baseMethodSpecs.length; i++) {
      if (this.baseMethodSpecs[i].resolvedMethod != null) {
        baseMethods[i] = this.baseMethodSpecs[i].resolvedMethod;
        if (isDangerousMethod(baseMethods[i]))
          this.scope.problemReporter().dangerousCallinBinding(this.baseMethodSpecs[i]);
      } else {
        MethodSpec spec = this.baseMethodSpecs[i];
        baseMethods[i] = new ProblemMethodBinding(spec.selector, null, baseType, 0);
      }
    }
    for (MethodBinding aBaseMethod : baseMethods) {
      if (aBaseMethod.isValidBinding() && aBaseMethod.returnType != TypeBinding.VOID) {
        if (this.callinModifier == TerminalTokens.TokenNameafter
            && this.roleMethodSpec.isValid()
            && this.roleMethodSpec.resolvedType() != TypeBinding.VOID)
          this.scope.problemReporter().ignoringRoleMethodReturn(this.roleMethodSpec);
        break;
      }
    }
    this.binding._baseMethods = baseMethods;
  }
 public TypeBinding resolveType(BlockScope scope) {
   TypeBinding type = super.resolveType(scope);
   if (type instanceof PolyTypeBinding) return type;
   MethodBinding method = getMethodBinding();
   if (method != null && method.isValidBinding() && !method.isSynthetic())
     throw new SelectionNodeFound(this.actualMethodBinding);
   throw new SelectionNodeFound();
 }
 public TypeBinding[] inferElidedTypes(
     ReferenceBinding allocationType,
     ReferenceBinding enclosingType,
     TypeBinding[] argumentTypes,
     final BlockScope scope) {
   /* Given the allocation type and the arguments to the constructor, see if we can synthesize a generic static factory
     method that would, given the argument types and the invocation site, manufacture a parameterized object of type allocationType.
     If we are successful then by design and construction, the parameterization of the return type of the factory method is identical
     to the types elided in the <>.
   */
   MethodBinding factory =
       scope.getStaticFactory(allocationType, enclosingType, argumentTypes, this);
   if (factory instanceof ParameterizedGenericMethodBinding && factory.isValidBinding()) {
     ParameterizedGenericMethodBinding genericFactory =
         (ParameterizedGenericMethodBinding) factory;
     this.inferredReturnType = genericFactory.inferredReturnType;
     return ((ParameterizedTypeBinding) factory.returnType).arguments;
   }
   return null;
 }
  protected int matchMethod(MethodBinding method, boolean skipImpossibleArg) {
    if (!matchesName(this.pattern.selector, method.selector)) return IMPOSSIBLE_MATCH;

    int level = ACCURATE_MATCH;
    // look at return type only if declaring type is not specified
    if (this.pattern.declaringSimpleName == null) {
      // TODO (frederic) use this call to refine accuracy on return type
      // int newLevel = resolveLevelForType(this.pattern.returnSimpleName,
      // this.pattern.returnQualification, this.pattern.returnTypeArguments, 0, method.returnType);
      int newLevel =
          resolveLevelForType(
              this.pattern.returnSimpleName, this.pattern.returnQualification, method.returnType);
      if (level > newLevel) {
        if (newLevel == IMPOSSIBLE_MATCH) return IMPOSSIBLE_MATCH;
        level = newLevel; // can only be downgraded
      }
    }

    // parameter types
    int parameterCount =
        this.pattern.parameterSimpleNames == null ? -1 : this.pattern.parameterSimpleNames.length;
    if (parameterCount > -1) {
      // global verification
      if (method.parameters == null) return INACCURATE_MATCH;
      if (parameterCount != method.parameters.length) return IMPOSSIBLE_MATCH;
      if (!method.isValidBinding()
          && ((ProblemMethodBinding) method).problemId() == ProblemReasons.Ambiguous) {
        // return inaccurate match for ambiguous call (bug 80890)
        return INACCURATE_MATCH;
      }

      // verify each parameter
      for (int i = 0; i < parameterCount; i++) {
        TypeBinding argType = method.parameters[i];
        int newLevel = IMPOSSIBLE_MATCH;
        if (argType.isMemberType()) {
          // only compare source name for member type (bug 41018)
          newLevel =
              CharOperation.match(
                      this.pattern.parameterSimpleNames[i],
                      argType.sourceName(),
                      this.isCaseSensitive)
                  ? ACCURATE_MATCH
                  : IMPOSSIBLE_MATCH;
        } else {
          // TODO (frederic) use this call to refine accuracy on parameter types
          //				 newLevel = resolveLevelForType(this.pattern.parameterSimpleNames[i],
          // this.pattern.parameterQualifications[i], this.pattern.parametersTypeArguments[i], 0,
          // argType);
          newLevel =
              resolveLevelForType(
                  this.pattern.parameterSimpleNames[i],
                  this.pattern.parameterQualifications[i],
                  argType);
        }
        if (level > newLevel) {
          if (newLevel == IMPOSSIBLE_MATCH) {
            if (skipImpossibleArg) {
              // Do not consider match as impossible while finding declarations and source level >=
              // 1.5
              // (see  bugs https://bugs.eclipse.org/bugs/show_bug.cgi?id=79990, 96761, 96763)
              newLevel = level;
            } else {
              return IMPOSSIBLE_MATCH;
            }
          }
          level = newLevel; // can only be downgraded
        }
      }
    }

    return level;
  }
  public TypeBinding resolveType(BlockScope scope) {
    // added for code assist...cannot occur with 'normal' code
    if (this.anonymousType == null && this.enclosingInstance == null) {
      return super.resolveType(scope);
    }

    // Propagate the type checking to the arguments, and checks if the constructor is defined.
    // ClassInstanceCreationExpression ::= Primary '.' 'new' SimpleName '(' ArgumentListopt ')'
    // ClassBodyopt
    // ClassInstanceCreationExpression ::= Name '.' 'new' SimpleName '(' ArgumentListopt ')'
    // ClassBodyopt

    this.constant = Constant.NotAConstant;
    TypeBinding enclosingInstanceType = null;
    ReferenceBinding enclosingInstanceReference = null;
    TypeBinding receiverType = null;
    boolean hasError = false;
    boolean enclosingInstanceContainsCast = false;
    boolean argsContainCast = false;

    if (this.enclosingInstance != null) {
      if (this.enclosingInstance instanceof CastExpression) {
        this.enclosingInstance.bits |= ASTNode.DisableUnnecessaryCastCheck; // will check later on
        enclosingInstanceContainsCast = true;
      }
      if ((enclosingInstanceType = this.enclosingInstance.resolveType(scope)) == null) {
        hasError = true;
      } else if (enclosingInstanceType.isBaseType() || enclosingInstanceType.isArrayType()) {
        scope
            .problemReporter()
            .illegalPrimitiveOrArrayTypeForEnclosingInstance(
                enclosingInstanceType, this.enclosingInstance);
        hasError = true;
      } else if (this.type instanceof QualifiedTypeReference) {
        scope
            .problemReporter()
            .illegalUsageOfQualifiedTypeReference((QualifiedTypeReference) this.type);
        hasError = true;
      } else if (!(enclosingInstanceReference = (ReferenceBinding) enclosingInstanceType)
          .canBeSeenBy(scope)) {
        // https://bugs.eclipse.org/bugs/show_bug.cgi?id=317212
        enclosingInstanceType =
            new ProblemReferenceBinding(
                enclosingInstanceReference.compoundName,
                enclosingInstanceReference,
                ProblemReasons.NotVisible);
        scope.problemReporter().invalidType(this.enclosingInstance, enclosingInstanceType);
        hasError = true;
      } else {
        receiverType =
            ((SingleTypeReference) this.type)
                .resolveTypeEnclosing(scope, (ReferenceBinding) enclosingInstanceType);
        if (receiverType != null && enclosingInstanceContainsCast) {
          CastExpression.checkNeedForEnclosingInstanceCast(
              scope, this.enclosingInstance, enclosingInstanceType, receiverType);
        }
      }
    } else {
      if (this.type == null) {
        // initialization of an enum constant
        receiverType = scope.enclosingSourceType();
      } else {
        receiverType = this.type.resolveType(scope, true /* check bounds*/);
        checkParameterizedAllocation:
        {
          if (receiverType == null || !receiverType.isValidBinding())
            break checkParameterizedAllocation;
          if (this.type
              instanceof
              ParameterizedQualifiedTypeReference) { // disallow new X<String>.Y<Integer>()
            ReferenceBinding currentType = (ReferenceBinding) receiverType;
            do {
              // isStatic() is answering true for toplevel types
              if ((currentType.modifiers & ClassFileConstants.AccStatic) != 0)
                break checkParameterizedAllocation;
              if (currentType.isRawType()) break checkParameterizedAllocation;
            } while ((currentType = currentType.enclosingType()) != null);
            ParameterizedQualifiedTypeReference qRef =
                (ParameterizedQualifiedTypeReference) this.type;
            for (int i = qRef.typeArguments.length - 2; i >= 0; i--) {
              if (qRef.typeArguments[i] != null) {
                scope
                    .problemReporter()
                    .illegalQualifiedParameterizedTypeAllocation(this.type, receiverType);
                break;
              }
            }
          }
        }
      }
    }
    if (receiverType == null || !receiverType.isValidBinding()) {
      hasError = true;
    }

    // resolve type arguments (for generic constructor call)
    final boolean isDiamond = this.type != null && (this.type.bits & ASTNode.IsDiamond) != 0;
    if (this.typeArguments != null) {
      int length = this.typeArguments.length;
      boolean argHasError = scope.compilerOptions().sourceLevel < ClassFileConstants.JDK1_5;
      this.genericTypeArguments = new TypeBinding[length];
      for (int i = 0; i < length; i++) {
        TypeReference typeReference = this.typeArguments[i];
        if ((this.genericTypeArguments[i] =
                typeReference.resolveType(scope, true /* check bounds*/))
            == null) {
          argHasError = true;
        }
        if (argHasError && typeReference instanceof Wildcard) {
          scope.problemReporter().illegalUsageOfWildcard(typeReference);
        }
      }
      if (isDiamond) {
        scope.problemReporter().diamondNotWithExplicitTypeArguments(this.typeArguments);
        return null;
      }
      if (argHasError) {
        if (this.arguments != null) { // still attempt to resolve arguments
          for (int i = 0, max = this.arguments.length; i < max; i++) {
            this.arguments[i].resolveType(scope);
          }
        }
        return null;
      }
    }

    // will check for null after args are resolved
    TypeBinding[] argumentTypes = Binding.NO_PARAMETERS;
    if (this.arguments != null) {
      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 |= ASTNode.DisableUnnecessaryCastCheck; // will check later on
          argsContainCast = true;
        }
        if ((argumentTypes[i] = argument.resolveType(scope)) == null) {
          hasError = true;
        }
      }
    }

    // limit of fault-tolerance
    if (hasError) {
      /* https://bugs.eclipse.org/bugs/show_bug.cgi?id=345359, if arguments have errors, completely bail out in the <> case.
        No meaningful type resolution is possible since inference of the elided types is fully tied to argument types. Do
        not return the partially resolved type.
      */
      if (isDiamond) {
        return null; // not the partially cooked this.resolvedType
      }
      if (receiverType instanceof ReferenceBinding) {
        ReferenceBinding referenceReceiver = (ReferenceBinding) receiverType;
        if (receiverType.isValidBinding()) {
          // record a best guess, for clients who need hint about possible contructor match
          int length = this.arguments == null ? 0 : this.arguments.length;
          TypeBinding[] pseudoArgs = new TypeBinding[length];
          for (int i = length; --i >= 0; ) {
            pseudoArgs[i] =
                argumentTypes[i] == null
                    ? TypeBinding.NULL
                    : argumentTypes[i]; // replace args with errors with null type
          }
          this.binding = scope.findMethod(referenceReceiver, TypeConstants.INIT, pseudoArgs, this);
          if (this.binding != null && !this.binding.isValidBinding()) {
            MethodBinding closestMatch = ((ProblemMethodBinding) this.binding).closestMatch;
            // record the closest match, for clients who may still need hint about possible method
            // match
            if (closestMatch != null) {
              if (closestMatch.original().typeVariables
                  != Binding.NO_TYPE_VARIABLES) { // generic method
                // shouldn't return generic method outside its context, rather convert it to raw
                // method (175409)
                closestMatch =
                    scope
                        .environment()
                        .createParameterizedGenericMethod(
                            closestMatch.original(), (RawTypeBinding) null);
              }
              this.binding = closestMatch;
              MethodBinding closestMatchOriginal = closestMatch.original();
              if (closestMatchOriginal.isOrEnclosedByPrivateType()
                  && !scope.isDefinedInMethod(closestMatchOriginal)) {
                // ignore cases where method is used from within inside itself (e.g. direct
                // recursions)
                closestMatchOriginal.modifiers |= ExtraCompilerModifiers.AccLocallyUsed;
              }
            }
          }
        }
        if (this.anonymousType != null) {
          // insert anonymous type in scope (see
          // https://bugs.eclipse.org/bugs/show_bug.cgi?id=210070)
          scope.addAnonymousType(this.anonymousType, referenceReceiver);
          this.anonymousType.resolve(scope);
          return this.resolvedType = this.anonymousType.binding;
        }
      }
      return this.resolvedType = receiverType;
    }
    if (this.anonymousType == null) {
      // qualified allocation with no anonymous type
      if (!receiverType.canBeInstantiated()) {
        scope.problemReporter().cannotInstantiate(this.type, receiverType);
        return this.resolvedType = receiverType;
      }
      if (isDiamond) {
        TypeBinding[] inferredTypes =
            inferElidedTypes(
                ((ParameterizedTypeBinding) receiverType).genericType(),
                receiverType.enclosingType(),
                argumentTypes,
                scope);
        if (inferredTypes == null) {
          scope.problemReporter().cannotInferElidedTypes(this);
          return this.resolvedType = null;
        }
        receiverType =
            this.type.resolvedType =
                scope
                    .environment()
                    .createParameterizedType(
                        ((ParameterizedTypeBinding) receiverType).genericType(),
                        inferredTypes,
                        ((ParameterizedTypeBinding) receiverType).enclosingType());
      }
      ReferenceBinding allocationType = (ReferenceBinding) receiverType;
      if ((this.binding = scope.getConstructor(allocationType, argumentTypes, this))
          .isValidBinding()) {
        if (isMethodUseDeprecated(this.binding, scope, true)) {
          scope.problemReporter().deprecatedMethod(this.binding, this);
        }
        if (checkInvocationArguments(
            scope,
            null,
            allocationType,
            this.binding,
            this.arguments,
            argumentTypes,
            argsContainCast,
            this)) {
          this.bits |= ASTNode.Unchecked;
        }
        if (this.typeArguments != null
            && this.binding.original().typeVariables == Binding.NO_TYPE_VARIABLES) {
          scope
              .problemReporter()
              .unnecessaryTypeArgumentsForMethodInvocation(
                  this.binding, this.genericTypeArguments, this.typeArguments);
        }
      } else {
        if (this.binding.declaringClass == null) {
          this.binding.declaringClass = allocationType;
        }
        if (this.type != null && !this.type.resolvedType.isValidBinding()) {
          // problem already got signaled on type reference, do not report secondary problem
          return null;
        }
        scope.problemReporter().invalidConstructor(this, this.binding);
        return this.resolvedType = receiverType;
      }
      if ((this.binding.tagBits & TagBits.HasMissingType) != 0) {
        scope.problemReporter().missingTypeInConstructor(this, this.binding);
      }
      if (!isDiamond && receiverType.isParameterizedTypeWithActualArguments()) {
        checkTypeArgumentRedundancy(
            (ParameterizedTypeBinding) receiverType,
            receiverType.enclosingType(),
            argumentTypes,
            scope);
      }
      // The enclosing instance must be compatible with the innermost enclosing type
      ReferenceBinding expectedType = this.binding.declaringClass.enclosingType();
      if (expectedType
          != enclosingInstanceType) // must call before computeConversion() and typeMismatchError()
      scope.compilationUnitScope().recordTypeConversion(expectedType, enclosingInstanceType);
      if (enclosingInstanceType.isCompatibleWith(expectedType)
          || scope.isBoxingCompatibleWith(enclosingInstanceType, expectedType)) {
        this.enclosingInstance.computeConversion(scope, expectedType, enclosingInstanceType);
        return this.resolvedType = receiverType;
      }
      scope
          .problemReporter()
          .typeMismatchError(enclosingInstanceType, expectedType, this.enclosingInstance, null);
      return this.resolvedType = receiverType;
    } else {
      if (isDiamond) {
        scope.problemReporter().diamondNotWithAnoymousClasses(this.type);
        return null;
      }
    }
    ReferenceBinding superType = (ReferenceBinding) receiverType;
    if (superType.isTypeVariable()) {
      superType =
          new ProblemReferenceBinding(
              new char[][] {superType.sourceName()},
              superType,
              ProblemReasons.IllegalSuperTypeVariable);
      scope.problemReporter().invalidType(this, superType);
      return null;
    } else if (this.type != null && superType.isEnum()) { // tolerate enum constant body
      scope.problemReporter().cannotInstantiate(this.type, superType);
      return this.resolvedType = superType;
    }
    // anonymous type scenario
    // an anonymous class inherits from java.lang.Object when declared "after" an interface
    ReferenceBinding anonymousSuperclass =
        superType.isInterface() ? scope.getJavaLangObject() : superType;
    // insert anonymous type in scope
    scope.addAnonymousType(this.anonymousType, superType);
    this.anonymousType.resolve(scope);

    // find anonymous super constructor
    this.resolvedType = this.anonymousType.binding; // 1.2 change
    if ((this.resolvedType.tagBits & TagBits.HierarchyHasProblems) != 0) {
      return null; // stop secondary errors
    }
    MethodBinding inheritedBinding = scope.getConstructor(anonymousSuperclass, argumentTypes, this);
    if (!inheritedBinding.isValidBinding()) {
      if (inheritedBinding.declaringClass == null) {
        inheritedBinding.declaringClass = anonymousSuperclass;
      }
      if (this.type != null && !this.type.resolvedType.isValidBinding()) {
        // problem already got signaled on type reference, do not report secondary problem
        return null;
      }
      scope.problemReporter().invalidConstructor(this, inheritedBinding);
      return this.resolvedType;
    }
    if ((inheritedBinding.tagBits & TagBits.HasMissingType) != 0) {
      scope.problemReporter().missingTypeInConstructor(this, inheritedBinding);
    }
    if (this.enclosingInstance != null) {
      ReferenceBinding targetEnclosing = inheritedBinding.declaringClass.enclosingType();
      if (targetEnclosing == null) {
        scope
            .problemReporter()
            .unnecessaryEnclosingInstanceSpecification(this.enclosingInstance, superType);
        return this.resolvedType;
      } else if (!enclosingInstanceType.isCompatibleWith(targetEnclosing)
          && !scope.isBoxingCompatibleWith(enclosingInstanceType, targetEnclosing)) {
        scope
            .problemReporter()
            .typeMismatchError(
                enclosingInstanceType, targetEnclosing, this.enclosingInstance, null);
        return this.resolvedType;
      }
      this.enclosingInstance.computeConversion(scope, targetEnclosing, enclosingInstanceType);
    }
    if (this.arguments != null) {
      if (checkInvocationArguments(
          scope,
          null,
          anonymousSuperclass,
          inheritedBinding,
          this.arguments,
          argumentTypes,
          argsContainCast,
          this)) {
        this.bits |= ASTNode.Unchecked;
      }
    }
    if (this.typeArguments != null
        && inheritedBinding.original().typeVariables == Binding.NO_TYPE_VARIABLES) {
      scope
          .problemReporter()
          .unnecessaryTypeArgumentsForMethodInvocation(
              inheritedBinding, this.genericTypeArguments, this.typeArguments);
    }
    // Update the anonymous inner class : superclass, interface
    this.binding =
        this.anonymousType.createDefaultConstructorWithBinding(
            inheritedBinding,
            (this.bits & ASTNode.Unchecked) != 0 && this.genericTypeArguments == null);
    return this.resolvedType;
  }
예제 #6
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;
  }
예제 #7
0
  /**
   * Resolve the method or field (see FieldAccessSpec).
   *
   * @param receiverType receiver of the method call.
   * @param scope
   * @param callinExpected whether this method spec is the LHS of a replace callin.
   * @param isBaseSide whether this method spec is the RHS (any binding kind)
   * @param allowEnclosing whether a method may be found in an enclosing type of receiverType
   * @return the resolved method (may be problem method) or null
   */
  public MethodBinding resolveFeature(
      ReferenceBinding receiverType,
      BlockScope scope,
      boolean callinExpected,
      boolean isBaseSide,
      boolean allowEnclosing) {
    // getRealClass() is used, because decapsulation needs to find private methods,
    // which for roles are found only in the class part.
    ReferenceBinding receiverClass = receiverType.getRealClass();
    boolean isConstructorSpec = CharOperation.equals(this.selector, receiverClass.sourceName());
    char[] realSelector = isConstructorSpec ? TypeConstants.INIT : this.selector;
    if (this.hasSignature) {
      TypeBinding[] enhancedParameters = this.parameters;
      // first chance: try enhanced:
      enhancedParameters = MethodSignatureEnhancer.enhanceParameters(scope, this.parameters);
      CompilationResult compilationResult = scope.referenceContext().compilationResult();
      CheckPoint cp = compilationResult.getCheckPoint(scope.referenceContext());

      this.resolvedMethod =
          TypeAnalyzer.findMethod(
              scope,
              receiverClass,
              realSelector,
              enhancedParameters,
              isBaseSide,
              isBaseSide ? this : null);
      if (!this.resolvedMethod.isValidBinding()
          && this.resolvedMethod.problemId() == ProblemReasons.NotFound) {
        // second+ chance: try plain:
        while (receiverClass != null) {
          compilationResult.rollBack(cp);
          MethodBinding plainMethod =
              TypeAnalyzer.findMethod(
                  scope,
                  receiverClass,
                  realSelector,
                  this.parameters,
                  isBaseSide,
                  isBaseSide ? this : null);
          if (!callinExpected) {
            this.resolvedMethod = plainMethod;
          } else {
            if (plainMethod != null && plainMethod.isValidBinding())
              scope.problemReporter().replaceMappingToNonCallin(this, plainMethod);
            // mark the ProblemMethodBinding consistently to what we have been looking for last:
            this.resolvedMethod.modifiers |=
                ExtraCompilerModifiers.AccCallin | ClassFileConstants.AccStatic;
          }
          if (plainMethod != null && plainMethod.isValidBinding()) break;
          if (allowEnclosing) receiverClass = receiverClass.enclosingType();
          else receiverClass = null;
        }
      }
    } else {
      CompilationResult compilationResult = scope.referenceContext().compilationResult();
      CheckPoint cp = compilationResult.getCheckPoint(scope.referenceContext());
      while (receiverClass != null) {
        this.resolvedMethod = receiverClass.getMethod(scope, realSelector);
        if (this.resolvedMethod != null && this.resolvedMethod.isValidBinding()) break; // good
        if (!allowEnclosing) break; // bad
        compilationResult.rollBack(cp);
        receiverClass = receiverClass.enclosingType();
      }
    }
    if (this.resolvedMethod != null) {
      if (this.resolvedMethod.isValidBinding()) {
        // check visibility of role-side in callin:
        if (!isBaseSide
            && scope.referenceContext() instanceof CallinMappingDeclaration
            && !this.resolvedMethod.canBeSeenBy(this, scope)) {
          scope.problemReporter().invisibleMethod(this, this.resolvedMethod);
          this.resolvedMethod =
              new ProblemMethodBinding(
                  this.resolvedMethod, this.selector, this.parameters, ProblemReasons.NotVisible);
        }
      }
      if (!this.resolvedMethod.isValidBinding() && this.resolvedMethod.declaringClass == null)
        this.resolvedMethod.declaringClass = receiverClass; // needed for computeUniqueKey (via
      // CallinCalloutBinding.computeUniqueKey)
    }
    return this.resolvedMethod;
  }