protected int resolveLevel(MessageSend messageSend) {
    MethodBinding method = messageSend.binding;
    if (method == null) {
      return INACCURATE_MATCH;
    }
    if (messageSend.resolvedType == null) {
      // Closest match may have different argument numbers when ProblemReason is NotFound
      // see MessageSend#resolveType(BlockScope)
      // see bug https://bugs.eclipse.org/bugs/show_bug.cgi?id=97322
      int argLength = messageSend.arguments == null ? 0 : messageSend.arguments.length;
      if (this.pattern.parameterSimpleNames == null
          || argLength == this.pattern.parameterSimpleNames.length) {
        return INACCURATE_MATCH;
      }
      return IMPOSSIBLE_MATCH;
    }

    int methodLevel = matchMethod(method, false);
    if (methodLevel == IMPOSSIBLE_MATCH) {
      if (method != method.original()) methodLevel = matchMethod(method.original(), false);
      if (methodLevel == IMPOSSIBLE_MATCH) return IMPOSSIBLE_MATCH;
      method = method.original();
    }

    // receiver type
    char[] qualifiedPattern =
        qualifiedPattern(this.pattern.declaringSimpleName, this.pattern.declaringQualification);
    if (qualifiedPattern == null) return methodLevel; // since any declaring class will do

    int declaringLevel;
    if (isVirtualInvoke(method, messageSend)
        && (messageSend.actualReceiverType instanceof ReferenceBinding)) {
      ReferenceBinding methodReceiverType = (ReferenceBinding) messageSend.actualReceiverType;
      declaringLevel =
          resolveLevelAsSubtype(qualifiedPattern, methodReceiverType, method.parameters);
      if (declaringLevel == IMPOSSIBLE_MATCH) {
        if (method.declaringClass == null || this.allSuperDeclaringTypeNames == null) {
          declaringLevel = INACCURATE_MATCH;
        } else {
          if (resolveLevelAsSuperInvocation(methodReceiverType, method.parameters, true)) {
            declaringLevel =
                methodLevel // since this is an ACCURATE_MATCH so return the possibly weaker match
                    | SUPER_INVOCATION_FLAVOR; // this is an overridden method => add flavor to
                                               // returned level
          }
        }
      }
      if ((declaringLevel & FLAVORS_MASK) != 0) {
        // level got some flavors => return it
        return declaringLevel;
      }
    } else {
      declaringLevel = resolveLevelForType(qualifiedPattern, method.declaringClass);
    }
    return methodLevel > declaringLevel ? declaringLevel : methodLevel; // return the weaker match
  }
  public int resolveLevel(Binding binding) {
    if (binding == null) return INACCURATE_MATCH;
    if (!(binding instanceof MethodBinding)) return IMPOSSIBLE_MATCH;

    MethodBinding method = (MethodBinding) binding;
    boolean skipVerif = this.pattern.findDeclarations && this.mayBeGeneric;
    int methodLevel = matchMethod(method, skipVerif);
    if (methodLevel == IMPOSSIBLE_MATCH) {
      if (method != method.original()) methodLevel = matchMethod(method.original(), skipVerif);
      if (methodLevel == IMPOSSIBLE_MATCH) {
        return IMPOSSIBLE_MATCH;
      } else {
        method = method.original();
      }
    }

    // declaring type
    char[] qualifiedPattern =
        qualifiedPattern(this.pattern.declaringSimpleName, this.pattern.declaringQualification);
    if (qualifiedPattern == null) return methodLevel; // since any declaring class will do

    boolean subType = !method.isStatic() && !method.isPrivate();
    if (subType
        && this.pattern.declaringQualification != null
        && method.declaringClass != null
        && method.declaringClass.fPackage != null) {
      subType =
          CharOperation.compareWith(
                  this.pattern.declaringQualification,
                  method.declaringClass.fPackage.shortReadableName())
              == 0;
    }
    int declaringLevel =
        subType
            ? resolveLevelAsSubtype(qualifiedPattern, method.declaringClass, null)
            : resolveLevelForType(qualifiedPattern, method.declaringClass);
    return methodLevel > declaringLevel ? declaringLevel : methodLevel; // return the weaker match
  }
Example #3
0
  /* Answer true if the method use is considered deprecated.
   * An access in the same compilation unit is allowed.
   */
  public final boolean isMethodUseDeprecated(
      MethodBinding method, Scope scope, boolean isExplicitUse) {
    // ignore references insing Javadoc comments
    if ((this.bits & ASTNode.InsideJavadoc) == 0
        && method.isOrEnclosedByPrivateType()
        && !scope.isDefinedInMethod(method)) {
      // ignore cases where method is used from inside itself (e.g. direct recursions)
      method.original().modifiers |= ExtraCompilerModifiers.AccLocallyUsed;
    }

    // TODO (maxime) consider separating concerns between deprecation and access restriction.
    // 				 Caveat: this was not the case when access restriction funtion was added.
    if (isExplicitUse && (method.modifiers & ExtraCompilerModifiers.AccRestrictedAccess) != 0) {
      // note: explicit constructors calls warnings are kept despite the 'new C1()' case (two
      //       warnings, one on type, the other on constructor), because of the 'super()' case.
      AccessRestriction restriction =
          scope.environment().getAccessRestriction(method.declaringClass.erasure());
      if (restriction != null) {
        scope
            .problemReporter()
            .forbiddenReference(
                method,
                this,
                restriction.classpathEntryType,
                restriction.classpathEntryName,
                restriction.getProblemId());
      }
    }

    if (!method.isViewedAsDeprecated()) return false;

    // inside same unit - no report
    if (scope.isDefinedInSameUnit(method.declaringClass)) return false;

    // non explicit use and non explicitly deprecated - no report
    if (!isExplicitUse && (method.modifiers & ClassFileConstants.AccDeprecated) == 0) {
      return false;
    }

    // if context is deprecated, may avoid reporting
    if (!scope.compilerOptions().reportDeprecationInsideDeprecatedCode
        && scope.isInsideDeprecatedCode()) return false;
    return true;
  }
  protected void reportDeclaration(
      MethodBinding methodBinding, MatchLocator locator, SimpleSet knownMethods)
      throws CoreException {
    ReferenceBinding declaringClass = methodBinding.declaringClass;
    IType type = locator.lookupType(declaringClass);
    if (type == null) return; // case of a secondary type

    // Report match for binary
    if (type.isBinary()) {
      IMethod method = null;
      TypeBinding[] parameters = methodBinding.original().parameters;
      int parameterLength = parameters.length;
      char[][] parameterTypes = new char[parameterLength][];
      for (int i = 0; i < parameterLength; i++) {
        char[] typeName = parameters[i].qualifiedSourceName();
        for (int j = 0, dim = parameters[i].dimensions(); j < dim; j++) {
          typeName = CharOperation.concat(typeName, new char[] {'[', ']'});
        }
        parameterTypes[i] = typeName;
      }
      method = locator.createBinaryMethodHandle(type, methodBinding.selector, parameterTypes);
      if (method == null || knownMethods.addIfNotIncluded(method) == null) return;

      IResource resource = type.getResource();
      if (resource == null) resource = type.getJavaProject().getProject();
      IBinaryType info =
          locator.getBinaryInfo(
              (org.eclipse.jdt.internal.core.ClassFile) type.getClassFile(), resource);
      locator.reportBinaryMemberDeclaration(
          resource, method, methodBinding, info, SearchMatch.A_ACCURATE);
      return;
    }

    // When source is available, report match if method is found in the declaring type
    IResource resource = type.getResource();
    if (declaringClass instanceof ParameterizedTypeBinding)
      declaringClass = ((ParameterizedTypeBinding) declaringClass).genericType();
    ClassScope scope = ((SourceTypeBinding) declaringClass).scope;
    if (scope != null) {
      TypeDeclaration typeDecl = scope.referenceContext;
      AbstractMethodDeclaration methodDecl = typeDecl.declarationOf(methodBinding.original());
      if (methodDecl != null) {
        // Create method handle from method declaration
        String methodName = new String(methodBinding.selector);
        Argument[] arguments = methodDecl.arguments;
        int length = arguments == null ? 0 : arguments.length;
        String[] parameterTypes = new String[length];
        for (int i = 0; i < length; i++) {
          char[][] typeName = arguments[i].type.getParameterizedTypeName();
          parameterTypes[i] =
              Signature.createTypeSignature(CharOperation.concatWith(typeName, '.'), false);
        }
        IMethod method = type.getMethod(methodName, parameterTypes);
        if (method == null || knownMethods.addIfNotIncluded(method) == null) return;

        // Create and report corresponding match
        int offset = methodDecl.sourceStart;
        this.match =
            new MethodDeclarationMatch(
                method,
                SearchMatch.A_ACCURATE,
                offset,
                methodDecl.sourceEnd - offset + 1,
                locator.getParticipant(),
                resource);
        locator.report(this.match);
      }
    }
  }
  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;
  }
Example #6
0
  public static boolean checkInvocationArguments(
      BlockScope scope,
      Expression receiver,
      TypeBinding receiverType,
      MethodBinding method,
      Expression[] arguments,
      TypeBinding[] argumentTypes,
      boolean argsContainCast,
      InvocationSite invocationSite) {
    TypeBinding[] params = method.parameters;
    int paramLength = params.length;
    boolean isRawMemberInvocation =
        !method.isStatic()
            && !receiverType.isUnboundWildcard()
            && method.declaringClass.isRawType()
            && method.hasSubstitutedParameters();

    boolean uncheckedBoundCheck =
        (method.tagBits & TagBits.HasUncheckedTypeArgumentForBoundCheck) != 0;
    MethodBinding rawOriginalGenericMethod = null;
    if (!isRawMemberInvocation) {
      if (method instanceof ParameterizedGenericMethodBinding) {
        ParameterizedGenericMethodBinding paramMethod = (ParameterizedGenericMethodBinding) method;
        if (paramMethod.isRaw && method.hasSubstitutedParameters()) {
          rawOriginalGenericMethod = method.original();
        }
      }
    }
    int invocationStatus = INVOCATION_ARGUMENT_OK;
    if (arguments == null) {
      if (method.isVarargs()) {
        TypeBinding parameterType =
            ((ArrayBinding) params[paramLength - 1])
                .elementsType(); // no element was supplied for vararg parameter
        if (!parameterType.isReifiable()) {
          scope
              .problemReporter()
              .unsafeGenericArrayForVarargs(parameterType, (ASTNode) invocationSite);
        }
      }
    } else {
      if (method.isVarargs()) {
        // 4 possibilities exist for a call to the vararg method foo(int i, long ... value) :
        // foo(1), foo(1, 2), foo(1, 2, 3, 4) & foo(1, new long[] {1, 2})
        int lastIndex = paramLength - 1;
        for (int i = 0; i < lastIndex; i++) {
          TypeBinding originalRawParam =
              rawOriginalGenericMethod == null ? null : rawOriginalGenericMethod.parameters[i];
          invocationStatus |=
              checkInvocationArgument(
                  scope, arguments[i], params[i], argumentTypes[i], originalRawParam);
        }
        int argLength = arguments.length;
        if (lastIndex < argLength) { // vararg argument was provided
          TypeBinding parameterType = params[lastIndex];
          TypeBinding originalRawParam = null;

          if (paramLength != argLength
              || parameterType.dimensions() != argumentTypes[lastIndex].dimensions()) {
            parameterType =
                ((ArrayBinding) parameterType)
                    .elementsType(); // single element was provided for vararg parameter
            if (!parameterType.isReifiable()) {
              scope
                  .problemReporter()
                  .unsafeGenericArrayForVarargs(parameterType, (ASTNode) invocationSite);
            }
            originalRawParam =
                rawOriginalGenericMethod == null
                    ? null
                    : ((ArrayBinding) rawOriginalGenericMethod.parameters[lastIndex])
                        .elementsType();
          }
          for (int i = lastIndex; i < argLength; i++) {
            invocationStatus |=
                checkInvocationArgument(
                    scope, arguments[i], parameterType, argumentTypes[i], originalRawParam);
          }
        }
        if (paramLength == argLength) { // 70056
          int varargsIndex = paramLength - 1;
          ArrayBinding varargsType = (ArrayBinding) params[varargsIndex];
          TypeBinding lastArgType = argumentTypes[varargsIndex];
          int dimensions;
          if (lastArgType == TypeBinding.NULL) {
            if (!(varargsType.leafComponentType().isBaseType() && varargsType.dimensions() == 1))
              scope.problemReporter().varargsArgumentNeedCast(method, lastArgType, invocationSite);
          } else if (varargsType.dimensions <= (dimensions = lastArgType.dimensions())) {
            if (lastArgType.leafComponentType().isBaseType()) {
              dimensions--;
            }
            if (varargsType.dimensions < dimensions) {
              scope.problemReporter().varargsArgumentNeedCast(method, lastArgType, invocationSite);
            } else if (varargsType.dimensions == dimensions
                && lastArgType != varargsType
                && lastArgType.leafComponentType().erasure()
                    != varargsType.leafComponentType.erasure()
                && lastArgType.isCompatibleWith(varargsType.elementsType())
                && lastArgType.isCompatibleWith(varargsType)) {
              scope.problemReporter().varargsArgumentNeedCast(method, lastArgType, invocationSite);
            }
          }
        }
      } else {
        for (int i = 0; i < paramLength; i++) {
          TypeBinding originalRawParam =
              rawOriginalGenericMethod == null ? null : rawOriginalGenericMethod.parameters[i];
          invocationStatus |=
              checkInvocationArgument(
                  scope, arguments[i], params[i], argumentTypes[i], originalRawParam);
        }
      }
      if (argsContainCast) {
        CastExpression.checkNeedForArgumentCasts(
            scope, receiver, receiverType, method, arguments, argumentTypes, invocationSite);
      }
    }
    if ((invocationStatus & INVOCATION_ARGUMENT_WILDCARD) != 0) {
      scope
          .problemReporter()
          .wildcardInvocation((ASTNode) invocationSite, receiverType, method, argumentTypes);
    } else if (!method.isStatic()
        && !receiverType.isUnboundWildcard()
        && method.declaringClass.isRawType()
        && method.hasSubstitutedParameters()) {
      scope.problemReporter().unsafeRawInvocation((ASTNode) invocationSite, method);
    } else if (rawOriginalGenericMethod != null
        || uncheckedBoundCheck
        || ((invocationStatus & INVOCATION_ARGUMENT_UNCHECKED) != 0
            && method instanceof ParameterizedGenericMethodBinding
        /*&& method.returnType != scope.environment().convertToRawType(method.returnType.erasure(), true)*/ )) {
      scope
          .problemReporter()
          .unsafeRawGenericMethodInvocation((ASTNode) invocationSite, method, argumentTypes);
      return true;
    }
    return false;
  }
  public TypeBinding resolveType(BlockScope scope) {
    // Propagate the type checking to the arguments, and check if the constructor is defined.
    this.constant = Constant.NotAConstant;
    if (this.type == null) {
      // initialization of an enum constant
      this.resolvedType = scope.enclosingReceiverType();
    } else {
      this.resolvedType = this.type.resolveType(scope, true /* check bounds*/);
      checkParameterizedAllocation:
      {
        if (this.type
            instanceof ParameterizedQualifiedTypeReference) { // disallow new X<String>.Y<Integer>()
          ReferenceBinding currentType = (ReferenceBinding) this.resolvedType;
          if (currentType == null) return currentType;
          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, this.resolvedType);
              break;
            }
          }
        }
      }
    }
    // will check for null after args are resolved

    final boolean isDiamond = this.type != null && (this.type.bits & ASTNode.IsDiamond) != 0;
    // resolve type arguments (for generic constructor call)
    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;
      }
    }

    // buffering the arguments' types
    boolean argsContainCast = false;
    TypeBinding[] argumentTypes = Binding.NO_PARAMETERS;
    if (this.arguments != null) {
      boolean argHasError = false;
      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] = argument.resolveType(scope)) == null) {
          argHasError = true;
        }
      }
      if (argHasError) {
        /* 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 (this.resolvedType instanceof ReferenceBinding) {
          // record a best guess, for clients who need hint about possible constructor match
          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(
                  (ReferenceBinding) this.resolvedType, 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;
              }
            }
          }
        }
        return this.resolvedType;
      }
    }
    if (this.resolvedType == null || !this.resolvedType.isValidBinding()) {
      return null;
    }

    // null type denotes fake allocation for enum constant inits
    if (this.type != null && !this.resolvedType.canBeInstantiated()) {
      scope.problemReporter().cannotInstantiate(this.type, this.resolvedType);
      return this.resolvedType;
    }
    if (isDiamond) {
      TypeBinding[] inferredTypes =
          inferElidedTypes(
              ((ParameterizedTypeBinding) this.resolvedType).genericType(),
              null,
              argumentTypes,
              scope);
      if (inferredTypes == null) {
        scope.problemReporter().cannotInferElidedTypes(this);
        return this.resolvedType = null;
      }
      this.resolvedType =
          this.type.resolvedType =
              scope
                  .environment()
                  .createParameterizedType(
                      ((ParameterizedTypeBinding) this.resolvedType).genericType(),
                      inferredTypes,
                      ((ParameterizedTypeBinding) this.resolvedType).enclosingType());
    }
    ReferenceBinding allocationType = (ReferenceBinding) this.resolvedType;
    if (!(this.binding = scope.getConstructor(allocationType, argumentTypes, this))
        .isValidBinding()) {
      if (this.binding.declaringClass == null) {
        this.binding.declaringClass = allocationType;
      }
      if (this.type != null && !this.type.resolvedType.isValidBinding()) {
        return null;
      }
      scope.problemReporter().invalidConstructor(this, this.binding);
      return this.resolvedType;
    }
    if ((this.binding.tagBits & TagBits.HasMissingType) != 0) {
      scope.problemReporter().missingTypeInConstructor(this, this.binding);
    }
    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);
    }
    if (!isDiamond && this.resolvedType.isParameterizedTypeWithActualArguments()) {
      checkTypeArgumentRedundancy(
          (ParameterizedTypeBinding) this.resolvedType, null, argumentTypes, scope);
    }
    final CompilerOptions compilerOptions = scope.compilerOptions();
    if (compilerOptions.isAnnotationBasedNullAnalysisEnabled
        && (this.binding.tagBits & TagBits.IsNullnessKnown) == 0) {
      new ImplicitNullAnnotationVerifier(
              scope.environment(), compilerOptions.inheritNullAnnotations)
          .checkImplicitNullAnnotations(this.binding, null /*srcMethod*/, false, scope);
    }
    return allocationType;
  }
Example #8
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 |= ASTNode.DisableUnnecessaryCastCheck; // will check later on
      receiverCast = true;
    }
    this.actualReceiverType = this.receiver.resolveType(scope);
    boolean receiverIsType =
        this.receiver instanceof NameReference
            && (((NameReference) this.receiver).bits & Binding.TYPE) != 0;
    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 =
          scope.compilerOptions().sourceLevel
              < ClassFileConstants.JDK1_5; // typeChecks all arguments
      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 (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) {
      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 |= ASTNode.DisableUnnecessaryCastCheck; // will check later on
          argsContainCast = true;
        }
        if ((argumentTypes[i] = argument.resolveType(scope)) == null) {
          argHasError = true;
        }
      }
      if (argHasError) {
        if (this.actualReceiverType instanceof ReferenceBinding) {
          //  record a best guess, for clients who need hint about possible method match
          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 =
              this.receiver.isImplicitThis()
                  ? scope.getImplicitMethod(this.selector, pseudoArgs, this)
                  : scope.findMethod(
                      (ReferenceBinding) this.actualReceiverType, this.selector, 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;
              }
            }
          }
        }
        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.declaringClass == null) {
        if (this.actualReceiverType instanceof ReferenceBinding) {
          this.binding.declaringClass = (ReferenceBinding) this.actualReceiverType;
        } else {
          scope.problemReporter().errorNoMethodFor(this, this.actualReceiverType, argumentTypes);
          return null;
        }
      }
      // https://bugs.eclipse.org/bugs/show_bug.cgi?id=245007 avoid secondary errors in case of
      // missing super type for anonymous classes ...
      ReferenceBinding declaringClass = this.binding.declaringClass;
      boolean avoidSecondary =
          declaringClass != null
              && declaringClass.isAnonymousType()
              && declaringClass.superclass() instanceof MissingTypeBinding;
      if (!avoidSecondary) scope.problemReporter().invalidMethod(this, this.binding);
      MethodBinding closestMatch = ((ProblemMethodBinding) this.binding).closestMatch;
      switch (this.binding.problemId()) {
        case ProblemReasons.Ambiguous:
          break; // no resilience on ambiguous
        case ProblemReasons.NotVisible:
        case ProblemReasons.NonStaticReferenceInConstructorInvocation:
        case ProblemReasons.NonStaticReferenceInStaticContext:
        case ProblemReasons.ReceiverTypeNotVisible:
        case ProblemReasons.ParameterBoundMismatch:
          // only steal returnType in cases listed above
          if (closestMatch != null) this.resolvedType = closestMatch.returnType;
          break;
      }
      // record the closest match, for clients who may still need hint about possible method match
      if (closestMatch != 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;
        }
      }
      return (this.resolvedType != null
              && (this.resolvedType.tagBits & TagBits.HasMissingType) == 0)
          ? this.resolvedType
          : null;
    }
    final CompilerOptions compilerOptions = scope.compilerOptions();
    if (compilerOptions.complianceLevel <= ClassFileConstants.JDK1_6
        && this.binding.isPolymorphic()) {
      scope.problemReporter().polymorphicMethodNotBelow17(this);
      return null;
    }

    if (((this.bits & ASTNode.InsideExpressionStatement) != 0) && this.binding.isPolymorphic()) {
      // we only set the return type to be void if this method invocation is used inside an
      // expression statement
      this.binding =
          scope
              .environment()
              .updatePolymorphicMethodReturnType(
                  (PolymorphicMethodBinding) this.binding, TypeBinding.VOID);
    }
    if ((this.binding.tagBits & TagBits.HasMissingType) != 0) {
      scope.problemReporter().missingTypeInMethod(this, this.binding);
    }
    if (!this.binding.isStatic()) {
      // the "receiver" must not be a type
      if (receiverIsType) {
        scope.problemReporter().mustUseAStaticMethod(this, this.binding);
        if (this.actualReceiverType.isRawType()
            && (this.receiver.bits & ASTNode.IgnoreRawTypeCheck) == 0
            && compilerOptions.getSeverity(CompilerOptions.RawTypeReference)
                != ProblemSeverities.Ignore) {
          scope.problemReporter().rawTypeReference(this.receiver, this.actualReceiverType);
        }
      } 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;
        }
      }
    } else {
      // static message invoked through receiver? legal but unoptimal (optional warning).
      if (!(this.receiver.isImplicitThis() || this.receiver.isSuper() || receiverIsType)) {
        scope.problemReporter().nonStaticAccessToStaticMethod(this, this.binding);
      }
      if (!this.receiver.isImplicitThis()
          && this.binding.declaringClass != this.actualReceiverType) {
        scope.problemReporter().indirectAccessToStaticMethod(this, this.binding);
      }
    }
    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 source level on, array#clone() returns the array type (but binding still shows
    // Object)
    if (this.binding == scope.environment().arrayClone
        && compilerOptions.sourceLevel >= ClassFileConstants.JDK1_5) {
      this.resolvedType = this.actualReceiverType;
    } else {
      TypeBinding returnType;
      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
        returnType = this.binding.returnType;
        if (returnType != null) {
          returnType = scope.environment().convertToRawType(returnType.erasure(), true);
        }
      } else {
        returnType = this.binding.returnType;
        if (returnType != null) {
          returnType = returnType.capture(scope, this.sourceEnd);
        }
      }
      this.resolvedType = returnType;
    }
    if (this.receiver.isSuper()
        && compilerOptions.getSeverity(CompilerOptions.OverridingMethodWithoutSuperInvocation)
            != ProblemSeverities.Ignore) {
      final ReferenceContext referenceContext = scope.methodScope().referenceContext;
      if (referenceContext instanceof AbstractMethodDeclaration) {
        final AbstractMethodDeclaration abstractMethodDeclaration =
            (AbstractMethodDeclaration) referenceContext;
        MethodBinding enclosingMethodBinding = abstractMethodDeclaration.binding;
        if (enclosingMethodBinding.isOverriding()
            && CharOperation.equals(this.binding.selector, enclosingMethodBinding.selector)
            && this.binding.areParametersEqual(enclosingMethodBinding)) {
          abstractMethodDeclaration.bits |= ASTNode.OverridingMethodWithSupercall;
        }
      }
    }
    if (this.typeArguments != null
        && this.binding.original().typeVariables == Binding.NO_TYPE_VARIABLES) {
      scope
          .problemReporter()
          .unnecessaryTypeArgumentsForMethodInvocation(
              this.binding, this.genericTypeArguments, this.typeArguments);
    }
    return (this.resolvedType.tagBits & TagBits.HasMissingType) == 0 ? this.resolvedType : null;
  }