예제 #1
0
  void checkAgainstInheritedMethods(
      MethodBinding currentMethod,
      MethodBinding[] methods,
      int length,
      MethodBinding[] allInheritedMethods) {
    CompilerOptions options = type.scope.compilerOptions();
    // need to find the overridden methods to avoid blaming this type for issues which are already
    // reported against a supertype
    // but cannot ignore an overridden inherited method completely when it comes to checking for
    // bridge methods
    int[] overriddenInheritedMethods =
        length > 1 ? findOverriddenInheritedMethods(methods, length) : null;
    nextMethod:
    for (int i = length; --i >= 0; ) {
      MethodBinding inheritedMethod = methods[i];
      if (overriddenInheritedMethods == null || overriddenInheritedMethods[i] == 0) {
        if (currentMethod.isStatic()
            != inheritedMethod
                .isStatic()) { // Cannot override a static method or hide an instance method
          problemReporter(currentMethod).staticAndInstanceConflict(currentMethod, inheritedMethod);
          continue nextMethod;
        }

        // want to tag currentMethod even if return types are not equal
        if (inheritedMethod.isAbstract()) {
          currentMethod.modifiers |=
              ExtraCompilerModifiers.AccImplementing | ExtraCompilerModifiers.AccOverriding;

          //			with the above change an abstract method is tagged as implementing the inherited
          // abstract method
          //			if (!currentMethod.isAbstract() && inheritedMethod.isAbstract()) {
          //				if ((currentMethod.modifiers & CompilerModifiers.AccOverriding) == 0)
          //					currentMethod.modifiers |= CompilerModifiers.AccImplementing;
        } else {
          currentMethod.modifiers |= ExtraCompilerModifiers.AccOverriding;
        }

        if (!areReturnTypesCompatible(currentMethod, inheritedMethod)) {
          if (!(currentMethod.returnType != null
              && currentMethod.returnType.isObjectLiteralType()
              && inheritedMethod.returnType != null
              && inheritedMethod.returnType.isObjectLiteralType()))
            if (reportIncompatibleReturnTypeError(currentMethod, inheritedMethod))
              continue nextMethod;
        }

        if (!isAsVisible(currentMethod, inheritedMethod))
          problemReporter(currentMethod).visibilityConflict(currentMethod, inheritedMethod);
        if (options.reportDeprecationWhenOverridingDeprecatedMethod
            && inheritedMethod.isViewedAsDeprecated()) {
          if (!currentMethod.isViewedAsDeprecated()
              || options.reportDeprecationInsideDeprecatedCode) {
            problemReporter(currentMethod)
                .overridesDeprecatedMethod(currentMethod, inheritedMethod);
          }
        }
      }
      checkForBridgeMethod(currentMethod, inheritedMethod, allInheritedMethods);
    }
  }
예제 #2
0
  void checkAgainstInheritedMethods(
      MethodBinding currentMethod, MethodBinding[] methods, int length) {
    nextMethod:
    for (int i = length; --i >= 0; ) {
      MethodBinding inheritedMethod = methods[i];
      if (currentMethod.isStatic()
          != inheritedMethod
              .isStatic()) { // Cannot override a static method or hide an instance method
        this.problemReporter(currentMethod)
            .staticAndInstanceConflict(currentMethod, inheritedMethod);
        continue nextMethod;
      }

      if (!currentMethod.isAbstract() && inheritedMethod.isAbstract()) {
        if ((currentMethod.modifiers & CompilerModifiers.AccOverriding) == 0)
          currentMethod.modifiers |= CompilerModifiers.AccImplementing;
      } else {
        currentMethod.modifiers |= CompilerModifiers.AccOverriding;
      }

      if (!areReturnTypesEqual(currentMethod, inheritedMethod)) {
        this.problemReporter(currentMethod).incompatibleReturnType(currentMethod, inheritedMethod);
      } else {
        if (currentMethod.thrownExceptions != NoExceptions)
          this.checkExceptions(currentMethod, inheritedMethod);
        if (inheritedMethod.isFinal())
          this.problemReporter(currentMethod)
              .finalMethodCannotBeOverridden(currentMethod, inheritedMethod);
        if (!this.isAsVisible(currentMethod, inheritedMethod))
          this.problemReporter(currentMethod).visibilityConflict(currentMethod, inheritedMethod);
        if (environment.options.reportDeprecationWhenOverridingDeprecatedMethod
            && inheritedMethod.isViewedAsDeprecated()) {
          if (!currentMethod.isViewedAsDeprecated()
              || environment.options.reportDeprecationInsideDeprecatedCode) {
            // check against the other inherited methods to see if they hide this inheritedMethod
            ReferenceBinding declaringClass = inheritedMethod.declaringClass;
            if (declaringClass.isInterface())
              for (int j = length; --j >= 0; )
                if (i != j && methods[j].declaringClass.implementsInterface(declaringClass, false))
                  continue nextMethod;

            this.problemReporter(currentMethod)
                .overridesDeprecatedMethod(currentMethod, inheritedMethod);
          }
        }
      }
    }
  }
  // helper method for findSingleStaticImport()
  private MethodBinding findStaticMethod(ReferenceBinding currentType, char[] selector) {
    if (!currentType.canBeSeenBy(this)) return null;

    do {
      currentType.initializeForStaticImports();
      MethodBinding[] methods = currentType.getMethods(selector);
      if (methods != Binding.NO_METHODS) {
        for (int i = methods.length; --i >= 0; ) {
          MethodBinding method = methods[i];
          if (method.isStatic() && method.canBeSeenBy(this.fPackage)) return method;
        }
      }
    } while ((currentType = currentType.superclass()) != null);
    return null;
  }
예제 #4
0
 void checkConcreteInheritedMethod(MethodBinding concreteMethod, MethodBinding[] abstractMethods) {
   // Remember that interfaces can only define public instance methods
   if (concreteMethod.isStatic())
     // Cannot inherit a static method which is specified as an instance method by an interface
     problemReporter().staticInheritedMethodConflicts(type, concreteMethod, abstractMethods);
   if (!concreteMethod.isPublic()) {
     int index = 0, length = abstractMethods.length;
     if (concreteMethod.isProtected()) {
       for (; index < length; index++) if (abstractMethods[index].isPublic()) break;
     } else if (concreteMethod.isDefault()) {
       for (; index < length; index++) if (!abstractMethods[index].isDefault()) break;
     }
     if (index < length)
       problemReporter().inheritedMethodReducesVisibility(type, concreteMethod, abstractMethods);
   }
 }
 /**
  * Create raw generic method for raw type (double substitution from type vars with raw type
  * arguments, and erasure of method variables) Only invoked for non-static generic methods of raw
  * type
  */
 public ParameterizedGenericMethodBinding(
     MethodBinding originalMethod, RawTypeBinding rawType, LookupEnvironment environment) {
   TypeVariableBinding[] originalVariables = originalMethod.typeVariables;
   int length = originalVariables.length;
   TypeBinding[] rawArguments = new TypeBinding[length];
   for (int i = 0; i < length; i++) {
     rawArguments[i] =
         environment.convertToRawType(
             originalVariables[i].erasure(), false /*do not force conversion of enclosing types*/);
   }
   this.isRaw = true;
   this.tagBits = originalMethod.tagBits;
   this.environment = environment;
   this.modifiers = originalMethod.modifiers;
   this.selector = originalMethod.selector;
   this.declaringClass = rawType == null ? originalMethod.declaringClass : rawType;
   this.typeVariables = Binding.NO_TYPE_VARIABLES;
   this.typeArguments = rawArguments;
   this.originalMethod = originalMethod;
   boolean ignoreRawTypeSubstitution = rawType == null || originalMethod.isStatic();
   this.parameters =
       Scope.substitute(
           this,
           ignoreRawTypeSubstitution
               ? originalMethod.parameters // no substitution if original was static
               : Scope.substitute(rawType, originalMethod.parameters));
   this.thrownExceptions =
       Scope.substitute(
           this,
           ignoreRawTypeSubstitution
               ? originalMethod.thrownExceptions // no substitution if original was static
               : Scope.substitute(rawType, originalMethod.thrownExceptions));
   // error case where exception type variable would have been substituted by a non-reference type
   // (207573)
   if (this.thrownExceptions == null) this.thrownExceptions = Binding.NO_EXCEPTIONS;
   this.returnType =
       Scope.substitute(
           this,
           ignoreRawTypeSubstitution
               ? originalMethod.returnType // no substitution if original was static
               : Scope.substitute(rawType, originalMethod.returnType));
   this.wasInferred = false; // not resulting from method invocation inferrence
   this.parameterNonNullness = originalMethod.parameterNonNullness;
 }
 /* collect matching methods from one supertype. */
 private void collectOverriddenMethods(
     MethodBinding original,
     char[] selector,
     int suggestedParameterLength,
     ReferenceBinding superType,
     Set ifcsSeen,
     List result) {
   MethodBinding[] ifcMethods = superType.getMethods(selector, suggestedParameterLength);
   int length = ifcMethods.length;
   boolean added = false;
   for (int i = 0; i < length; i++) {
     MethodBinding currentMethod = ifcMethods[i];
     if (currentMethod.isStatic()) continue;
     if (MethodVerifier.doesMethodOverride(original, currentMethod, this.environment)) {
       result.add(currentMethod);
       added =
           true; // when overriding one or more methods from superType don't traverse to transitive
                 // superTypes
     }
   }
   if (!added)
     findAllOverriddenMethods(
         original, selector, suggestedParameterLength, superType, ifcsSeen, result);
 }
예제 #7
0
파일: ASTNode.java 프로젝트: beefeather/ohl
  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;
  }
예제 #8
0
  void checkInheritedMethods(MethodBinding[] methods, int length) {
    MethodBinding first = methods[0];
    int index = length;
    while (--index > 0 && areReturnTypesEqual(first, methods[index])) {
      /*empty*/
    }
    if (index > 0) { // All inherited methods do NOT have the same vmSignature
      this.problemReporter()
          .inheritedMethodsHaveIncompatibleReturnTypes(this.type, methods, length);
      return;
    }

    MethodBinding concreteMethod = null;
    if (!type.isInterface()) { // ignore concrete methods for interfaces
      for (int i = length;
          --i >= 0; ) { // Remember that only one of the methods can be non-abstract
        if (!methods[i].isAbstract()) {
          concreteMethod = methods[i];
          break;
        }
      }
    }
    if (concreteMethod == null) {
      if (this.type.isClass() && !this.type.isAbstract()) {
        for (int i = length; --i >= 0; ) {
          if (mustImplementAbstractMethod(methods[i])) {
            TypeDeclaration typeDeclaration = this.type.scope.referenceContext;
            if (typeDeclaration != null) {
              MethodDeclaration missingAbstractMethod =
                  typeDeclaration.addMissingAbstractMethodFor(methods[0]);
              missingAbstractMethod
                  .scope
                  .problemReporter()
                  .abstractMethodMustBeImplemented(this.type, methods[0]);
            } else {
              this.problemReporter().abstractMethodMustBeImplemented(this.type, methods[0]);
            }
            return;
          }
        }
      }
      return;
    }

    MethodBinding[] abstractMethods = new MethodBinding[length - 1];
    index = 0;
    for (int i = length; --i >= 0; )
      if (methods[i] != concreteMethod) abstractMethods[index++] = methods[i];

    // Remember that interfaces can only define public instance methods
    if (concreteMethod.isStatic())
      // Cannot inherit a static method which is specified as an instance method by an interface
      this.problemReporter().staticInheritedMethodConflicts(type, concreteMethod, abstractMethods);
    if (!concreteMethod.isPublic())
      // Cannot reduce visibility of a public method specified by an interface
      this.problemReporter()
          .inheritedMethodReducesVisibility(type, concreteMethod, abstractMethods);
    if (concreteMethod.thrownExceptions != NoExceptions)
      for (int i = abstractMethods.length; --i >= 0; )
        this.checkExceptions(concreteMethod, abstractMethods[i]);
  }
  /**
   * Check and fill in implicit annotations from overridden methods and from default. Precondition:
   * caller has checked whether annotation-based null analysis is enabled.
   */
  public void checkImplicitNullAnnotations(
      MethodBinding currentMethod,
      AbstractMethodDeclaration srcMethod,
      boolean complain,
      Scope scope) {
    // check inherited nullness from superclass and superInterfaces
    try {
      ReferenceBinding currentType = currentMethod.declaringClass;
      if (currentType.id == TypeIds.T_JavaLangObject) {
        return;
      }
      boolean usesTypeAnnotations = scope.environment().usesNullTypeAnnotations();
      boolean needToApplyReturnNonNullDefault =
          currentMethod.hasNonNullDefaultFor(
              Binding.DefaultLocationReturnType, usesTypeAnnotations);
      boolean needToApplyParameterNonNullDefault =
          currentMethod.hasNonNullDefaultFor(Binding.DefaultLocationParameter, usesTypeAnnotations);
      boolean needToApplyNonNullDefault =
          needToApplyReturnNonNullDefault | needToApplyParameterNonNullDefault;
      // compatibility & inheritance do not consider constructors / static methods:
      boolean isInstanceMethod = !currentMethod.isConstructor() && !currentMethod.isStatic();
      complain &= isInstanceMethod;
      if (!needToApplyNonNullDefault
          && !complain
          && !(this.inheritNullAnnotations && isInstanceMethod)) {
        return; // short cut, no work to be done
      }

      if (isInstanceMethod) {
        List superMethodList = new ArrayList();

        // need super types connected:
        if (currentType instanceof SourceTypeBinding
            && !currentType.isHierarchyConnected()
            && !currentType.isAnonymousType()) {
          ((SourceTypeBinding) currentType).scope.connectTypeHierarchy();
        }

        int paramLen = currentMethod.parameters.length;
        findAllOverriddenMethods(
            currentMethod.original(),
            currentMethod.selector,
            paramLen,
            currentType,
            new HashSet(),
            superMethodList);

        // prepare interim storage for nullness info so we don't pollute currentMethod before we
        // know its conflict-free:
        InheritedNonNullnessInfo[] inheritedNonNullnessInfos =
            new InheritedNonNullnessInfo[paramLen + 1]; // index 0 is for the return type
        for (int i = 0; i < paramLen + 1; i++)
          inheritedNonNullnessInfos[i] = new InheritedNonNullnessInfo();

        int length = superMethodList.size();
        for (int i = length; --i >= 0; ) {
          MethodBinding currentSuper = (MethodBinding) superMethodList.get(i);
          if ((currentSuper.tagBits & TagBits.IsNullnessKnown) == 0) {
            // recurse to prepare currentSuper
            checkImplicitNullAnnotations(
                currentSuper,
                null,
                false,
                scope); // TODO (stephan) complain=true if currentSuper is source method??
          }
          checkNullSpecInheritance(
              currentMethod,
              srcMethod,
              needToApplyReturnNonNullDefault,
              needToApplyParameterNonNullDefault,
              complain,
              currentSuper,
              null,
              scope,
              inheritedNonNullnessInfos);
          needToApplyNonNullDefault = false;
        }

        // transfer collected information into currentMethod:
        InheritedNonNullnessInfo info = inheritedNonNullnessInfos[0];
        if (!info.complained) {
          long tagBits = 0;
          if (info.inheritedNonNullness == Boolean.TRUE) {
            tagBits = TagBits.AnnotationNonNull;
          } else if (info.inheritedNonNullness == Boolean.FALSE) {
            tagBits = TagBits.AnnotationNullable;
          }
          if (tagBits != 0) {
            if (!usesTypeAnnotations) {
              currentMethod.tagBits |= tagBits;
            } else {
              if (!currentMethod.returnType.isBaseType()) {
                LookupEnvironment env = scope.environment();
                currentMethod.returnType =
                    env.createAnnotatedType(
                        currentMethod.returnType, env.nullAnnotationsFromTagBits(tagBits));
              }
            }
          }
        }
        for (int i = 0; i < paramLen; i++) {
          info = inheritedNonNullnessInfos[i + 1];
          if (!info.complained && info.inheritedNonNullness != null) {
            Argument currentArg = srcMethod == null ? null : srcMethod.arguments[i];
            if (!usesTypeAnnotations)
              recordArgNonNullness(
                  currentMethod, paramLen, i, currentArg, info.inheritedNonNullness);
            else
              recordArgNonNullness18(
                  currentMethod, i, currentArg, info.inheritedNonNullness, scope.environment());
          }
        }
      }
      if (needToApplyNonNullDefault) {
        if (!usesTypeAnnotations) currentMethod.fillInDefaultNonNullness(srcMethod);
        else currentMethod.fillInDefaultNonNullness18(srcMethod, scope.environment());
      }
    } finally {
      currentMethod.tagBits |= TagBits.IsNullnessKnown;
    }
  }