예제 #1
0
  void checkPackagePrivateAbstractMethod(MethodBinding abstractMethod) {
    // check that the inherited abstract method (package private visibility) is implemented within
    // the same package
    PackageBinding necessaryPackage = abstractMethod.declaringClass.fPackage;
    if (necessaryPackage == this.type.fPackage) return; // not a problem

    ReferenceBinding superType = this.type.superclass();
    char[] selector = abstractMethod.selector;
    do {
      if (!superType.isValidBinding()) return;
      if (!superType.isAbstract()) return; // closer non abstract super type will be flagged instead

      if (necessaryPackage == superType.fPackage) {
        MethodBinding[] methods = superType.getMethods(selector);
        nextMethod:
        for (int m = methods.length; --m >= 0; ) {
          MethodBinding method = methods[m];
          if (method.isPrivate() || method.isConstructor() || method.isDefaultAbstract())
            continue nextMethod;
          if (doesMethodOverride(method, abstractMethod))
            return; // found concrete implementation of abstract method in same package
        }
      }
    } while ((superType = superType.superclass()) != abstractMethod.declaringClass);

    // non visible abstract methods cannot be overridden so the type must be defined abstract
    this.problemReporter().abstractMethodCannotBeOverridden(this.type, abstractMethod);
  }
예제 #2
0
 void computeMethods() {
   MethodBinding[] methods = type.methods();
   int size = methods.length;
   this.currentMethods =
       new HashtableOfObject(
           size == 0
               ? 1
               : size); // maps method selectors to an array of methods... must search to match
   // paramaters & return type
   for (int m = size; --m >= 0; ) {
     MethodBinding method = methods[m];
     if (!(method.isConstructor()
         || method
             .isDefaultAbstract())) { // keep all methods which are NOT constructors or default
       // abstract
       MethodBinding[] existingMethods =
           (MethodBinding[]) this.currentMethods.get(method.selector);
       if (existingMethods == null) existingMethods = new MethodBinding[1];
       else
         System.arraycopy(
             existingMethods,
             0,
             (existingMethods = new MethodBinding[existingMethods.length + 1]),
             0,
             existingMethods.length - 1);
       existingMethods[existingMethods.length - 1] = method;
       this.currentMethods.put(method.selector, existingMethods);
     }
   }
 }
예제 #3
0
 ProblemReporter problemReporter(MethodBinding currentMethod) {
   ProblemReporter reporter = problemReporter();
   if (currentMethod.declaringClass == type
       && currentMethod.sourceMethod()
           != null) // only report against the currentMethod if its implemented by the type
   reporter.referenceContext = currentMethod.sourceMethod();
   return reporter;
 }
 void applyReturnNullBits(MethodBinding method, long nullnessBits) {
   if (this.environment.usesNullTypeAnnotations()) {
     if (!method.returnType.isBaseType()) {
       method.returnType =
           this.environment.createAnnotatedType(
               method.returnType, this.environment.nullAnnotationsFromTagBits(nullnessBits));
     }
   } else {
     method.tagBits |= nullnessBits;
   }
 }
예제 #5
0
  boolean isAsVisible(MethodBinding newMethod, MethodBinding inheritedMethod) {
    if (inheritedMethod.modifiers == newMethod.modifiers) return true;

    if (newMethod.isPublic()) return true; // Covers everything
    if (inheritedMethod.isPublic()) return false;

    if (newMethod.isProtected()) return true;
    if (inheritedMethod.isProtected()) return false;

    return !newMethod
        .isPrivate(); // The inheritedMethod cannot be private since it would not be visible
  }
예제 #6
0
  public boolean isSuper(String currentClassName) {
    if (!isSpecial) return false;

    if (methodBinding.isConstructor()) {
      if (!(getExpression() instanceof ThisExpression)) return false;
    }

    String name = methodBinding.getDeclaringClass().getClassName();
    if (currentClassName.equals(name)) return false;

    return true;
  }
예제 #7
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);
    }
  }
  // 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;
  }
예제 #9
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);
          }
        }
      }
    }
  }
예제 #10
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);
   }
 }
예제 #11
0
파일: ASTNode.java 프로젝트: beefeather/ohl
  /* 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;
  }
 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;
 }
 // version for invocation from LambdaExpression:
 static void createArgumentBindings(
     Argument[] arguments, MethodBinding binding, MethodScope scope) {
   boolean useTypeAnnotations = scope.environment().usesNullTypeAnnotations();
   if (arguments != null && binding != null) {
     for (int i = 0, length = arguments.length; i < length; i++) {
       Argument argument = arguments[i];
       binding.parameters[i] = argument.createBinding(scope, binding.parameters[i]);
       if (useTypeAnnotations) continue; // no business with SE7 null annotations in the 1.8 case.
       // createBinding() has resolved annotations, now transfer nullness info from the argument to
       // the method:
       long argTypeTagBits = (argument.binding.tagBits & TagBits.AnnotationNullMASK);
       if (argTypeTagBits != 0) {
         if (binding.parameterNonNullness == null) {
           binding.parameterNonNullness = new Boolean[arguments.length];
           binding.tagBits |= TagBits.IsNullnessKnown;
         }
         binding.parameterNonNullness[i] =
             Boolean.valueOf(argTypeTagBits == TagBits.AnnotationNonNull);
       }
     }
   }
 }
 /* record declared nullness of a parameter into the method and into the argument (if present). */
 void recordArgNonNullness(
     MethodBinding method,
     int paramCount,
     int paramIdx,
     Argument currentArgument,
     Boolean nonNullNess) {
   if (method.parameterNonNullness == null) method.parameterNonNullness = new Boolean[paramCount];
   method.parameterNonNullness[paramIdx] = nonNullNess;
   if (currentArgument != null) {
     currentArgument.binding.tagBits |=
         nonNullNess.booleanValue() ? TagBits.AnnotationNonNull : TagBits.AnnotationNullable;
   }
 }
  public void manageSyntheticAccessIfNecessary(BlockScope currentScope, FlowInfo flowInfo) {
    if ((flowInfo.tagBits & FlowInfo.UNREACHABLE_OR_DEAD) != 0) return;
    // if constructor from parameterized type got found, use the original constructor at codegen
    // time
    MethodBinding codegenBinding = this.binding.original();

    ReferenceBinding declaringClass;
    if (codegenBinding.isPrivate()
        && currentScope.enclosingSourceType() != (declaringClass = codegenBinding.declaringClass)) {

      // from 1.4 on, local type constructor can lose their private flag to ease emulation
      if ((declaringClass.tagBits & TagBits.IsLocalType) != 0
          && currentScope.compilerOptions().complianceLevel >= ClassFileConstants.JDK1_4) {
        // constructor will not be dumped as private, no emulation required thus
        codegenBinding.tagBits |= TagBits.ClearPrivateModifier;
      } else {
        this.syntheticAccessor =
            ((SourceTypeBinding) declaringClass)
                .addSyntheticMethod(codegenBinding, isSuperAccess());
        currentScope.problemReporter().needToEmulateMethodAccess(codegenBinding, this);
      }
    }
  }
 /* 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);
 }
 /**
  * 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 argument type mapping, handling varargs */
  private static ParameterizedGenericMethodBinding inferFromArgumentTypes(
      Scope scope,
      MethodBinding originalMethod,
      TypeBinding[] arguments,
      TypeBinding[] parameters,
      InferenceContext inferenceContext) {
    if (originalMethod.isVarargs()) {
      int paramLength = parameters.length;
      int minArgLength = paramLength - 1;
      int argLength = arguments.length;
      // process mandatory arguments
      for (int i = 0; i < minArgLength; i++) {
        parameters[i].collectSubstitutes(
            scope, arguments[i], inferenceContext, TypeConstants.CONSTRAINT_EXTENDS);
        if (inferenceContext.status == InferenceContext.FAILED)
          return null; // impossible substitution
      }
      // process optional arguments
      if (minArgLength < argLength) {
        TypeBinding varargType = parameters[minArgLength]; // last arg type - as is ?
        TypeBinding lastArgument = arguments[minArgLength];
        checkVarargDimension:
        {
          if (paramLength == argLength) {
            if (lastArgument == TypeBinding.NULL) break checkVarargDimension;
            switch (lastArgument.dimensions()) {
              case 0:
                break; // will remove one dim
              case 1:
                if (!lastArgument.leafComponentType().isBaseType()) break checkVarargDimension;
                break; // will remove one dim
              default:
                break checkVarargDimension;
            }
          }
          // eliminate one array dimension
          varargType = ((ArrayBinding) varargType).elementsType();
        }
        for (int i = minArgLength; i < argLength; i++) {
          varargType.collectSubstitutes(
              scope, arguments[i], inferenceContext, TypeConstants.CONSTRAINT_EXTENDS);
          if (inferenceContext.status == InferenceContext.FAILED)
            return null; // impossible substitution
        }
      }
    } else {
      int paramLength = parameters.length;
      for (int i = 0; i < paramLength; i++) {
        parameters[i].collectSubstitutes(
            scope, arguments[i], inferenceContext, TypeConstants.CONSTRAINT_EXTENDS);
        if (inferenceContext.status == InferenceContext.FAILED)
          return null; // impossible substitution
      }
    }
    TypeVariableBinding[] originalVariables = originalMethod.typeVariables;
    if (!resolveSubstituteConstraints(
        scope, originalVariables, inferenceContext, false /*ignore Ti<:Uk*/))
      return null; // impossible substitution

    // apply inferred variable substitutions - replacing unresolved variable with original ones in
    // param method
    TypeBinding[] inferredSustitutes = inferenceContext.substitutes;
    TypeBinding[] actualSubstitutes = inferredSustitutes;
    for (int i = 0, varLength = originalVariables.length; i < varLength; i++) {
      if (inferredSustitutes[i] == null) {
        if (actualSubstitutes == inferredSustitutes) {
          System.arraycopy(
              inferredSustitutes,
              0,
              actualSubstitutes = new TypeBinding[varLength],
              0,
              i); // clone to replace null with original variable in param method
        }
        actualSubstitutes[i] = originalVariables[i];
      } else if (actualSubstitutes != inferredSustitutes) {
        actualSubstitutes[i] = inferredSustitutes[i];
      }
    }
    ParameterizedGenericMethodBinding paramMethod =
        scope.environment().createParameterizedGenericMethod(originalMethod, actualSubstitutes);
    return paramMethod;
  }
  private Object reduceSubType(Scope scope, TypeBinding subCandidate, TypeBinding superCandidate) {
    // 18.2.3 Subtyping Constraints
    if (subCandidate.isProperType(true) && superCandidate.isProperType(true)) {
      if (subCandidate.isCompatibleWith(superCandidate, scope)) return TRUE;
      return FALSE;
    }
    if (subCandidate.id == TypeIds.T_null) return TRUE;
    if (superCandidate.id == TypeIds.T_null) return FALSE;
    if (subCandidate instanceof InferenceVariable)
      return new TypeBound((InferenceVariable) subCandidate, superCandidate, SUBTYPE, this.isSoft);
    if (superCandidate instanceof InferenceVariable)
      return new TypeBound(
          (InferenceVariable) superCandidate,
          subCandidate,
          SUPERTYPE,
          this.isSoft); // normalize to have variable on LHS
    switch (superCandidate.kind()) {
      case Binding.GENERIC_TYPE:
      case Binding.TYPE:
      case Binding.RAW_TYPE:
        {
          if (subCandidate.isSubtypeOf(superCandidate)) return TRUE;
          return FALSE;
        }
      case Binding.PARAMETERIZED_TYPE:
        {
          List<ConstraintFormula> constraints = new ArrayList<>();
          while (superCandidate != null
              && superCandidate.kind() == Binding.PARAMETERIZED_TYPE
              && subCandidate != null) {
            if (!addConstraintsFromTypeParameters(
                subCandidate, (ParameterizedTypeBinding) superCandidate, constraints)) return FALSE;
            // travel to enclosing types to check if they have type parameters, too:
            superCandidate = superCandidate.enclosingType();
            subCandidate = subCandidate.enclosingType();
          }
          switch (constraints.size()) {
            case 0:
              return TRUE;
            case 1:
              return constraints.get(0);
            default:
              return constraints.toArray(new ConstraintFormula[constraints.size()]);
          }
        }
      case Binding.ARRAY_TYPE:
        TypeBinding tPrime = ((ArrayBinding) superCandidate).elementsType();
        // let S'[] be the most specific array type that is a supertype of S (or S itself)
        ArrayBinding sPrimeArray = null;
        switch (subCandidate.kind()) {
          case Binding.INTERSECTION_TYPE:
            {
              WildcardBinding intersection = (WildcardBinding) subCandidate;
              sPrimeArray =
                  findMostSpecificSuperArray(
                      intersection.bound, intersection.otherBounds, intersection);
              break;
            }
          case Binding.ARRAY_TYPE:
            sPrimeArray = (ArrayBinding) subCandidate;
            break;
          case Binding.TYPE_PARAMETER:
            {
              TypeVariableBinding subTVB = (TypeVariableBinding) subCandidate;
              sPrimeArray =
                  findMostSpecificSuperArray(subTVB.firstBound, subTVB.otherUpperBounds(), subTVB);
              break;
            }
          default:
            return FALSE;
        }
        if (sPrimeArray == null) return FALSE;
        TypeBinding sPrime = sPrimeArray.elementsType();
        if (!tPrime.isPrimitiveType() && !sPrime.isPrimitiveType()) {
          return ConstraintTypeFormula.create(sPrime, tPrime, SUBTYPE, this.isSoft);
        }
        return TypeBinding.equalsEquals(tPrime, sPrime) ? TRUE : FALSE; // same primitive type?

        // "type variable" has two implementations in JDT:
      case Binding.WILDCARD_TYPE:
        if (subCandidate.kind() == Binding.INTERSECTION_TYPE) {
          ReferenceBinding[] intersectingTypes = subCandidate.getIntersectingTypes();
          if (intersectingTypes != null)
            for (int i = 0; i < intersectingTypes.length; i++)
              if (TypeBinding.equalsEquals(intersectingTypes[i], superCandidate)) return true;
        }
        WildcardBinding variable = (WildcardBinding) superCandidate;
        if (variable.boundKind == Wildcard.SUPER)
          return ConstraintTypeFormula.create(subCandidate, variable.bound, SUBTYPE, this.isSoft);
        return FALSE;
      case Binding.TYPE_PARAMETER:
        // similar to wildcard, but different queries for lower bound
        if (subCandidate.kind() == Binding.INTERSECTION_TYPE) {
          ReferenceBinding[] intersectingTypes = subCandidate.getIntersectingTypes();
          if (intersectingTypes != null)
            for (int i = 0; i < intersectingTypes.length; i++)
              if (TypeBinding.equalsEquals(intersectingTypes[i], superCandidate)) return true;
        }
        if (superCandidate instanceof CaptureBinding) {
          CaptureBinding capture = (CaptureBinding) superCandidate;
          if (capture.lowerBound != null
              && (capture.firstBound == null || capture.firstBound.id == TypeIds.T_JavaLangObject))
            return ConstraintTypeFormula.create(
                subCandidate, capture.lowerBound, SUBTYPE, this.isSoft);
        }
        return FALSE;
      case Binding.INTERSECTION_TYPE:
        superCandidate = ((WildcardBinding) superCandidate).allBounds();
        // $FALL-THROUGH$
      case Binding.INTERSECTION_TYPE18:
        TypeBinding[] intersectingTypes =
            ((IntersectionTypeBinding18) superCandidate).intersectingTypes;
        ConstraintFormula[] result = new ConstraintFormula[intersectingTypes.length];
        for (int i = 0; i < intersectingTypes.length; i++) {
          result[i] =
              ConstraintTypeFormula.create(
                  subCandidate, intersectingTypes[i], SUBTYPE, this.isSoft);
        }
        return result;
      case Binding.POLY_TYPE:
        PolyTypeBinding poly = (PolyTypeBinding) superCandidate;
        Invocation invocation = (Invocation) poly.expression;
        MethodBinding binding = invocation.binding();
        if (binding == null || !binding.isValidBinding()) return FALSE;
        TypeBinding returnType =
            binding.isConstructor() ? binding.declaringClass : binding.returnType;
        return reduceSubType(
            scope,
            subCandidate,
            returnType.capture(scope, invocation.sourceStart(), invocation.sourceEnd()));
    }
    throw new IllegalStateException("Unexpected RHS " + superCandidate); // $NON-NLS-1$
  }
  /**
   * 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;
    }
  }
예제 #21
0
 public Type getTypeBinding() {
   if (methodBinding == null) return super.getTypeBinding();
   return methodBinding.getReturnType();
 }
예제 #22
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]);
  }
예제 #23
0
파일: ASTNode.java 프로젝트: beefeather/ohl
 /** Figures if @Deprecated annotation is specified, do not resolve entire annotations. */
 public static void resolveDeprecatedAnnotations(
     BlockScope scope, Annotation[] annotations, Binding recipient) {
   if (recipient != null) {
     int kind = recipient.kind();
     if (annotations != null) {
       int length;
       if ((length = annotations.length) >= 0) {
         switch (kind) {
           case Binding.PACKAGE:
             PackageBinding packageBinding = (PackageBinding) recipient;
             if ((packageBinding.tagBits & TagBits.DeprecatedAnnotationResolved) != 0) return;
             break;
           case Binding.TYPE:
           case Binding.GENERIC_TYPE:
             ReferenceBinding type = (ReferenceBinding) recipient;
             if ((type.tagBits & TagBits.DeprecatedAnnotationResolved) != 0) return;
             break;
           case Binding.METHOD:
             MethodBinding method = (MethodBinding) recipient;
             if ((method.tagBits & TagBits.DeprecatedAnnotationResolved) != 0) return;
             break;
           case Binding.FIELD:
             FieldBinding field = (FieldBinding) recipient;
             if ((field.tagBits & TagBits.DeprecatedAnnotationResolved) != 0) return;
             break;
           case Binding.LOCAL:
             LocalVariableBinding local = (LocalVariableBinding) recipient;
             if ((local.tagBits & TagBits.DeprecatedAnnotationResolved) != 0) return;
             break;
           default:
             return;
         }
         for (int i = 0; i < length; i++) {
           TypeReference annotationTypeRef = annotations[i].type;
           // only resolve type name if 'Deprecated' last token
           if (!CharOperation.equals(
               TypeConstants.JAVA_LANG_DEPRECATED[2], annotationTypeRef.getLastToken())) return;
           TypeBinding annotationType = annotations[i].type.resolveType(scope);
           if (annotationType != null
               && annotationType.isValidBinding()
               && annotationType.id == TypeIds.T_JavaLangDeprecated) {
             switch (kind) {
               case Binding.PACKAGE:
                 PackageBinding packageBinding = (PackageBinding) recipient;
                 packageBinding.tagBits |=
                     (TagBits.AnnotationDeprecated | TagBits.DeprecatedAnnotationResolved);
                 return;
               case Binding.TYPE:
               case Binding.GENERIC_TYPE:
               case Binding.TYPE_PARAMETER:
                 ReferenceBinding type = (ReferenceBinding) recipient;
                 type.tagBits |=
                     (TagBits.AnnotationDeprecated | TagBits.DeprecatedAnnotationResolved);
                 return;
               case Binding.METHOD:
                 MethodBinding method = (MethodBinding) recipient;
                 method.tagBits |=
                     (TagBits.AnnotationDeprecated | TagBits.DeprecatedAnnotationResolved);
                 return;
               case Binding.FIELD:
                 FieldBinding field = (FieldBinding) recipient;
                 field.tagBits |=
                     (TagBits.AnnotationDeprecated | TagBits.DeprecatedAnnotationResolved);
                 return;
               case Binding.LOCAL:
                 LocalVariableBinding local = (LocalVariableBinding) recipient;
                 local.tagBits |=
                     (TagBits.AnnotationDeprecated | TagBits.DeprecatedAnnotationResolved);
                 return;
               default:
                 return;
             }
           }
         }
       }
     }
     switch (kind) {
       case Binding.PACKAGE:
         PackageBinding packageBinding = (PackageBinding) recipient;
         packageBinding.tagBits |= TagBits.DeprecatedAnnotationResolved;
         return;
       case Binding.TYPE:
       case Binding.GENERIC_TYPE:
       case Binding.TYPE_PARAMETER:
         ReferenceBinding type = (ReferenceBinding) recipient;
         type.tagBits |= TagBits.DeprecatedAnnotationResolved;
         return;
       case Binding.METHOD:
         MethodBinding method = (MethodBinding) recipient;
         method.tagBits |= TagBits.DeprecatedAnnotationResolved;
         return;
       case Binding.FIELD:
         FieldBinding field = (FieldBinding) recipient;
         field.tagBits |= TagBits.DeprecatedAnnotationResolved;
         return;
       case Binding.LOCAL:
         LocalVariableBinding local = (LocalVariableBinding) recipient;
         local.tagBits |= TagBits.DeprecatedAnnotationResolved;
         return;
       default:
         return;
     }
   }
 }
예제 #24
0
파일: ASTNode.java 프로젝트: beefeather/ohl
 /**
  * Resolve annotations, and check duplicates, answers combined tagBits for recognized standard
  * annotations
  */
 public static void resolveAnnotations(
     BlockScope scope, Annotation[] sourceAnnotations, Binding recipient) {
   AnnotationBinding[] annotations = null;
   int length = sourceAnnotations == null ? 0 : sourceAnnotations.length;
   if (recipient != null) {
     switch (recipient.kind()) {
       case Binding.PACKAGE:
         PackageBinding packageBinding = (PackageBinding) recipient;
         if ((packageBinding.tagBits & TagBits.AnnotationResolved) != 0) return;
         packageBinding.tagBits |=
             (TagBits.AnnotationResolved | TagBits.DeprecatedAnnotationResolved);
         break;
       case Binding.TYPE:
       case Binding.GENERIC_TYPE:
         ReferenceBinding type = (ReferenceBinding) recipient;
         if ((type.tagBits & TagBits.AnnotationResolved) != 0) return;
         type.tagBits |= (TagBits.AnnotationResolved | TagBits.DeprecatedAnnotationResolved);
         if (length > 0) {
           annotations = new AnnotationBinding[length];
           type.setAnnotations(annotations);
         }
         break;
       case Binding.METHOD:
         MethodBinding method = (MethodBinding) recipient;
         if ((method.tagBits & TagBits.AnnotationResolved) != 0) return;
         method.tagBits |= (TagBits.AnnotationResolved | TagBits.DeprecatedAnnotationResolved);
         if (length > 0) {
           annotations = new AnnotationBinding[length];
           method.setAnnotations(annotations);
         }
         break;
       case Binding.FIELD:
         FieldBinding field = (FieldBinding) recipient;
         if ((field.tagBits & TagBits.AnnotationResolved) != 0) return;
         field.tagBits |= (TagBits.AnnotationResolved | TagBits.DeprecatedAnnotationResolved);
         if (length > 0) {
           annotations = new AnnotationBinding[length];
           field.setAnnotations(annotations);
         }
         break;
       case Binding.LOCAL:
         LocalVariableBinding local = (LocalVariableBinding) recipient;
         if ((local.tagBits & TagBits.AnnotationResolved) != 0) return;
         local.tagBits |= (TagBits.AnnotationResolved | TagBits.DeprecatedAnnotationResolved);
         if (length > 0) {
           annotations = new AnnotationBinding[length];
           local.setAnnotations(annotations);
         }
         break;
       default:
         return;
     }
   }
   if (sourceAnnotations == null) return;
   for (int i = 0; i < length; i++) {
     Annotation annotation = sourceAnnotations[i];
     final Binding annotationRecipient = annotation.recipient;
     if (annotationRecipient != null && recipient != null) {
       // only local and field can share annnotations
       switch (recipient.kind()) {
         case Binding.FIELD:
           FieldBinding field = (FieldBinding) recipient;
           field.tagBits = ((FieldBinding) annotationRecipient).tagBits;
           break;
         case Binding.LOCAL:
           LocalVariableBinding local = (LocalVariableBinding) recipient;
           local.tagBits = ((LocalVariableBinding) annotationRecipient).tagBits;
           break;
       }
       if (annotations != null) {
         // need to fill the instances array
         annotations[0] = annotation.getCompilerAnnotation();
         for (int j = 1; j < length; j++) {
           Annotation annot = sourceAnnotations[j];
           annotations[j] = annot.getCompilerAnnotation();
         }
       }
       return;
     } else {
       annotation.recipient = recipient;
       annotation.resolveType(scope);
       // null if receiver is a package binding
       if (annotations != null) {
         annotations[i] = annotation.getCompilerAnnotation();
       }
     }
   }
   // check duplicate annotations
   if (annotations != null) {
     AnnotationBinding[] distinctAnnotations =
         annotations; // only copy after 1st duplicate is detected
     for (int i = 0; i < length; i++) {
       AnnotationBinding annotation = distinctAnnotations[i];
       if (annotation == null) continue;
       TypeBinding annotationType = annotation.getAnnotationType();
       boolean foundDuplicate = false;
       for (int j = i + 1; j < length; j++) {
         AnnotationBinding otherAnnotation = distinctAnnotations[j];
         if (otherAnnotation == null) continue;
         if (otherAnnotation.getAnnotationType() == annotationType) {
           foundDuplicate = true;
           if (distinctAnnotations == annotations) {
             System.arraycopy(
                 distinctAnnotations,
                 0,
                 distinctAnnotations = new AnnotationBinding[length],
                 0,
                 length);
           }
           distinctAnnotations[j] = null; // report it only once
           scope.problemReporter().duplicateAnnotation(sourceAnnotations[j]);
         }
       }
       if (foundDuplicate) {
         scope.problemReporter().duplicateAnnotation(sourceAnnotations[i]);
       }
     }
   }
 }
예제 #25
0
  /*
  Binding creation is responsible for reporting:
  	- all modifier problems (duplicates & multiple visibility modifiers + incompatible combinations)
  		- plus invalid modifiers given the context... examples:
  			- interface methods can only be public
  			- abstract methods can only be defined by abstract classes
  	- collisions... 2 methods with identical vmSelectors
  	- multiple methods with the same message pattern but different return types
  	- ambiguous, invisible or missing return/argument/exception types
  	- check the type of any array is not void
  	- check that each exception type is Throwable or a subclass of it
  */
  void computeInheritedMethods() {
    // only want to remember inheritedMethods that can have an impact on the current type
    // if an inheritedMethod has been 'replaced' by a supertype's method then skip it

    this.inheritedMethods =
        new HashtableOfObject(
            51); // maps method selectors to an array of methods... must search to match paramaters
    // & return type
    ReferenceBinding[][] interfacesToVisit = new ReferenceBinding[3][];
    int lastPosition = -1;
    ReferenceBinding[] itsInterfaces = type.superInterfaces();
    if (itsInterfaces != NoSuperInterfaces) interfacesToVisit[++lastPosition] = itsInterfaces;

    ReferenceBinding superType =
        this.type.isClass()
            ? this.type.superclass()
            : this.type.scope.getJavaLangObject(); // check interface methods against Object
    HashtableOfObject nonVisibleDefaultMethods =
        new HashtableOfObject(3); // maps method selectors to an array of methods
    boolean allSuperclassesAreAbstract = true;

    while (superType != null) {
      if (superType.isValidBinding()) {
        if (allSuperclassesAreAbstract) {
          if (superType.isAbstract()) {
            // only need to include superinterfaces if immediate superclasses are abstract
            if ((itsInterfaces = superType.superInterfaces()) != NoSuperInterfaces) {
              if (++lastPosition == interfacesToVisit.length)
                System.arraycopy(
                    interfacesToVisit,
                    0,
                    interfacesToVisit = new ReferenceBinding[lastPosition * 2][],
                    0,
                    lastPosition);
              interfacesToVisit[lastPosition] = itsInterfaces;
            }
          } else {
            allSuperclassesAreAbstract = false;
          }
        }

        MethodBinding[] methods = superType.unResolvedMethods();
        nextMethod:
        for (int m = methods.length; --m >= 0; ) {
          MethodBinding inheritedMethod = methods[m];
          if (inheritedMethod.isPrivate()
              || inheritedMethod.isConstructor()
              || inheritedMethod.isDefaultAbstract()) continue nextMethod;
          MethodBinding[] existingMethods =
              (MethodBinding[]) this.inheritedMethods.get(inheritedMethod.selector);
          if (existingMethods != null) {
            for (int i = 0, length = existingMethods.length; i < length; i++) {
              if (doesMethodOverride(existingMethods[i], inheritedMethod)) {
                if (inheritedMethod.isDefault() && inheritedMethod.isAbstract())
                  checkPackagePrivateAbstractMethod(inheritedMethod);
                continue nextMethod;
              }
            }
          }
          MethodBinding[] nonVisible =
              (MethodBinding[]) nonVisibleDefaultMethods.get(inheritedMethod.selector);
          if (nonVisible != null)
            for (int i = 0, l = nonVisible.length; i < l; i++)
              if (doesMethodOverride(nonVisible[i], inheritedMethod)) continue nextMethod;

          if (!inheritedMethod.isDefault()
              || inheritedMethod.declaringClass.fPackage == type.fPackage) {
            if (existingMethods == null) {
              existingMethods = new MethodBinding[] {inheritedMethod};
            } else {
              int length = existingMethods.length;
              System.arraycopy(
                  existingMethods, 0, existingMethods = new MethodBinding[length + 1], 0, length);
              existingMethods[length] = inheritedMethod;
            }
            this.inheritedMethods.put(inheritedMethod.selector, existingMethods);
          } else {
            if (nonVisible == null) {
              nonVisible = new MethodBinding[] {inheritedMethod};
            } else {
              int length = nonVisible.length;
              System.arraycopy(
                  nonVisible, 0, nonVisible = new MethodBinding[length + 1], 0, length);
              nonVisible[length] = inheritedMethod;
            }
            nonVisibleDefaultMethods.put(inheritedMethod.selector, nonVisible);

            if (inheritedMethod.isAbstract()
                && !this.type
                    .isAbstract()) // non visible abstract methods cannot be overridden so the type
              // must be defined abstract
              this.problemReporter().abstractMethodCannotBeOverridden(this.type, inheritedMethod);

            MethodBinding[] current =
                (MethodBinding[]) this.currentMethods.get(inheritedMethod.selector);
            if (current
                != null) { // non visible methods cannot be overridden so a warning is issued
              foundMatch:
              for (int i = 0, length = current.length; i < length; i++) {
                if (doesMethodOverride(current[i], inheritedMethod)) {
                  this.problemReporter().overridesPackageDefaultMethod(current[i], inheritedMethod);
                  break foundMatch;
                }
              }
            }
          }
        }
        superType = superType.superclass();
      }
    }

    for (int i = 0; i <= lastPosition; i++) {
      ReferenceBinding[] interfaces = interfacesToVisit[i];
      for (int j = 0, l = interfaces.length; j < l; j++) {
        superType = interfaces[j];
        if ((superType.tagBits & InterfaceVisited) == 0) {
          superType.tagBits |= InterfaceVisited;
          if (superType.isValidBinding()) {
            if ((itsInterfaces = superType.superInterfaces()) != NoSuperInterfaces) {
              if (++lastPosition == interfacesToVisit.length)
                System.arraycopy(
                    interfacesToVisit,
                    0,
                    interfacesToVisit = new ReferenceBinding[lastPosition * 2][],
                    0,
                    lastPosition);
              interfacesToVisit[lastPosition] = itsInterfaces;
            }

            MethodBinding[] methods = superType.unResolvedMethods();
            nextMethod:
            for (int m = methods.length; --m >= 0; ) { // Interface methods are all abstract public
              MethodBinding inheritedMethod = methods[m];
              MethodBinding[] existingMethods =
                  (MethodBinding[]) this.inheritedMethods.get(inheritedMethod.selector);
              if (existingMethods == null) {
                existingMethods = new MethodBinding[] {inheritedMethod};
              } else {
                int length = existingMethods.length;
                for (int e = 0; e < length; e++) {
                  MethodBinding existing = existingMethods[e];
                  // look to see if any of the existingMethods implement this inheritedMethod
                  if (areParametersEqual(existing, inheritedMethod)
                      && existing.declaringClass.implementsInterface(superType, true))
                    // so if the implemented method is abstract & has a different return type then
                    // did it get a bridge method?
                    continue
                        nextMethod; // skip interface method with the same signature if visible to
                  // its declaringClass
                }
                System.arraycopy(
                    existingMethods, 0, existingMethods = new MethodBinding[length + 1], 0, length);
                existingMethods[length] = inheritedMethod;
              }
              this.inheritedMethods.put(inheritedMethod.selector, existingMethods);
            }
          }
        }
      }
    }

    // bit reinitialization
    for (int i = 0; i <= lastPosition; i++) {
      ReferenceBinding[] interfaces = interfacesToVisit[i];
      for (int j = 0, length = interfaces.length; j < length; j++)
        interfaces[j].tagBits &= ~InterfaceVisited;
    }
  }
예제 #26
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;
  }
  /**
   * The main algorithm in this class.
   *
   * @param currentMethod focus method
   * @param srcMethod AST of 'currentMethod' if present
   * @param hasReturnNonNullDefault is a @NonNull default applicable for the return type of
   *     currentMethod?
   * @param hasParameterNonNullDefault is a @NonNull default applicable for parameters of
   *     currentMethod?
   * @param shouldComplain should we report any errors found? (see also comment about flows into
   *     this method, below).
   * @param inheritedMethod one overridden method from a super type
   * @param allInheritedMethods look here to see if nonnull-unannotated conflict already exists in
   *     one super type
   * @param scope provides context for error reporting etc.
   * @param inheritedNonNullnessInfos if non-null, this array of non-null elements is used for
   *     interim recording of nullness information from inheritedMethod rather than prematurely
   *     updating currentMethod. Index position 0 is used for the return type, positions i+1 for
   *     argument i.
   */
  void checkNullSpecInheritance(
      MethodBinding currentMethod,
      AbstractMethodDeclaration srcMethod,
      boolean hasReturnNonNullDefault,
      boolean hasParameterNonNullDefault,
      boolean shouldComplain,
      MethodBinding inheritedMethod,
      MethodBinding[] allInheritedMethods,
      Scope scope,
      InheritedNonNullnessInfo[] inheritedNonNullnessInfos) {
    // Note that basically two different flows lead into this method:
    // (1) during MethodVerifyer15.checkMethods() we want to report errors (against srcMethod or
    // against the current type)
    //     In this case this method is directly called from MethodVerifier15
    // (checkAgainstInheritedMethod / checkConcreteInheritedMethod)
    // (2) during on-demand invocation we are mainly interested in the side effects of copying
    // inherited null annotations
    //     In this case this method is called via checkImplicitNullAnnotations from
    //     - MessageSend.resolveType(..)
    //     - SourceTypeBinding.createArgumentBindings(..)
    //     - recursive calls within this class
    //     Still we *might* want to complain about problems found (controlled by 'complain')

    if ((inheritedMethod.tagBits & TagBits.IsNullnessKnown) == 0) {
      // TODO (stephan): even here we may need to report problems? How to discriminate?
      this.buddyImplicitNullAnnotationsVerifier.checkImplicitNullAnnotations(
          inheritedMethod, null, false, scope);
    }
    boolean useTypeAnnotations = this.environment.usesNullTypeAnnotations();
    long inheritedNullnessBits = getReturnTypeNullnessTagBits(inheritedMethod, useTypeAnnotations);
    long currentNullnessBits = getReturnTypeNullnessTagBits(currentMethod, useTypeAnnotations);

    boolean shouldInherit = this.inheritNullAnnotations;

    // return type:
    returnType:
    {
      if (currentMethod.returnType == null || currentMethod.returnType.isBaseType())
        break returnType; // no nullness for primitive types
      if (currentNullnessBits == 0) {
        // unspecified, may fill in either from super or from default
        if (shouldInherit) {
          if (inheritedNullnessBits != 0) {
            if (hasReturnNonNullDefault) {
              // both inheritance and default: check for conflict?
              if (shouldComplain && inheritedNullnessBits == TagBits.AnnotationNullable)
                scope
                    .problemReporter()
                    .conflictingNullAnnotations(
                        currentMethod, ((MethodDeclaration) srcMethod).returnType, inheritedMethod);
              // 	still use the inherited bits to avoid incompatibility
            }
            if (inheritedNonNullnessInfos != null && srcMethod != null) {
              recordDeferredInheritedNullness(
                  scope,
                  ((MethodDeclaration) srcMethod).returnType,
                  inheritedMethod,
                  Boolean.valueOf(inheritedNullnessBits == TagBits.AnnotationNonNull),
                  inheritedNonNullnessInfos[0]);
            } else {
              // no need to defer, record this info now:
              applyReturnNullBits(currentMethod, inheritedNullnessBits);
            }
            break returnType; // compatible by construction, skip complain phase below
          }
        }
        if (hasReturnNonNullDefault
            && (!useTypeAnnotations
                || currentMethod.returnType
                    .acceptsNonNullDefault())) { // conflict with inheritance already checked
          currentNullnessBits = TagBits.AnnotationNonNull;
          applyReturnNullBits(currentMethod, currentNullnessBits);
        }
      }
      if (shouldComplain) {
        if ((inheritedNullnessBits & TagBits.AnnotationNonNull) != 0
            && currentNullnessBits != TagBits.AnnotationNonNull) {
          if (srcMethod != null) {
            scope
                .problemReporter()
                .illegalReturnRedefinition(
                    srcMethod, inheritedMethod, this.environment.getNonNullAnnotationName());
            break returnType;
          } else {
            scope
                .problemReporter()
                .cannotImplementIncompatibleNullness(
                    currentMethod, inheritedMethod, useTypeAnnotations);
            return;
          }
        }
        if (useTypeAnnotations) {
          TypeBinding substituteReturnType =
              null; // for TVB identity checks inside NullAnnotationMatching.analyze()
          TypeVariableBinding[] typeVariables = inheritedMethod.original().typeVariables;
          if (typeVariables != null && currentMethod.returnType.id != TypeIds.T_void) {
            ParameterizedGenericMethodBinding substitute =
                this.environment.createParameterizedGenericMethod(currentMethod, typeVariables);
            substituteReturnType = substitute.returnType;
          }
          if (NullAnnotationMatching.analyse(
                  inheritedMethod.returnType,
                  currentMethod.returnType,
                  substituteReturnType,
                  0,
                  CheckMode.OVERRIDE)
              .isAnyMismatch()) {
            if (srcMethod != null)
              scope
                  .problemReporter()
                  .illegalReturnRedefinition(
                      srcMethod, inheritedMethod, this.environment.getNonNullAnnotationName());
            else
              scope
                  .problemReporter()
                  .cannotImplementIncompatibleNullness(
                      currentMethod, inheritedMethod, useTypeAnnotations);
            return;
          }
        }
      }
    }

    // parameters:
    TypeBinding[] substituteParameters =
        null; // for TVB identity checks inside NullAnnotationMatching.analyze()
    if (shouldComplain) {
      TypeVariableBinding[] typeVariables = currentMethod.original().typeVariables;
      if (typeVariables != Binding.NO_TYPE_VARIABLES) {
        ParameterizedGenericMethodBinding substitute =
            this.environment.createParameterizedGenericMethod(inheritedMethod, typeVariables);
        substituteParameters = substitute.parameters;
      }
    }

    Argument[] currentArguments = srcMethod == null ? null : srcMethod.arguments;

    int length = 0;
    if (currentArguments != null) length = currentArguments.length;
    if (useTypeAnnotations) // need to look for type annotations on all parameters:
    length = currentMethod.parameters.length;
    else if (inheritedMethod.parameterNonNullness != null)
      length = inheritedMethod.parameterNonNullness.length;
    else if (currentMethod.parameterNonNullness != null)
      length = currentMethod.parameterNonNullness.length;

    parameterLoop:
    for (int i = 0; i < length; i++) {
      if (currentMethod.parameters[i].isBaseType()) continue;

      Argument currentArgument = currentArguments == null ? null : currentArguments[i];
      Boolean inheritedNonNullNess =
          getParameterNonNullness(inheritedMethod, i, useTypeAnnotations);
      Boolean currentNonNullNess = getParameterNonNullness(currentMethod, i, useTypeAnnotations);

      if (currentNonNullNess == null) {
        // unspecified, may fill in either from super or from default
        if (inheritedNonNullNess != null) {
          if (shouldInherit) {
            if (hasParameterNonNullDefault) {
              // both inheritance and default: check for conflict?
              if (shouldComplain
                  && inheritedNonNullNess == Boolean.FALSE
                  && currentArgument != null) {
                scope
                    .problemReporter()
                    .conflictingNullAnnotations(currentMethod, currentArgument, inheritedMethod);
              }
              // 	still use the inherited info to avoid incompatibility
            }
            if (inheritedNonNullnessInfos != null && srcMethod != null) {
              recordDeferredInheritedNullness(
                  scope,
                  srcMethod.arguments[i].type,
                  inheritedMethod,
                  inheritedNonNullNess,
                  inheritedNonNullnessInfos[i + 1]);
            } else {
              // no need to defer, record this info now:
              if (!useTypeAnnotations)
                recordArgNonNullness(
                    currentMethod, length, i, currentArgument, inheritedNonNullNess);
              else
                recordArgNonNullness18(
                    currentMethod, i, currentArgument, inheritedNonNullNess, this.environment);
            }
            continue; // compatible by construction, skip complain phase below
          }
        }
        if (hasParameterNonNullDefault) { // conflict with inheritance already checked
          currentNonNullNess = Boolean.TRUE;
          if (!useTypeAnnotations)
            recordArgNonNullness(currentMethod, length, i, currentArgument, Boolean.TRUE);
          else if (currentMethod.parameters[i].acceptsNonNullDefault())
            recordArgNonNullness18(
                currentMethod, i, currentArgument, Boolean.TRUE, this.environment);
          else currentNonNullNess = null; // cancel if parameter doesn't accept the default
        }
      }
      if (shouldComplain) {
        char[][] annotationName;
        if (inheritedNonNullNess == Boolean.TRUE) {
          annotationName = this.environment.getNonNullAnnotationName();
        } else {
          annotationName = this.environment.getNullableAnnotationName();
        }
        if (inheritedNonNullNess != Boolean.TRUE // super parameter is not restricted to @NonNull
            && currentNonNullNess == Boolean.TRUE) // current parameter is restricted to @NonNull
        {
          // incompatible
          if (currentArgument != null) {
            scope
                .problemReporter()
                .illegalRedefinitionToNonNullParameter(
                    currentArgument,
                    inheritedMethod.declaringClass,
                    (inheritedNonNullNess == null)
                        ? null
                        : this.environment.getNullableAnnotationName());
          } else {
            scope
                .problemReporter()
                .cannotImplementIncompatibleNullness(currentMethod, inheritedMethod, false);
          }
          continue;
        } else if (currentNonNullNess == null) {
          // unannotated strictly conflicts only with inherited @Nullable
          if (inheritedNonNullNess == Boolean.FALSE) {
            if (currentArgument != null) {
              scope
                  .problemReporter()
                  .parameterLackingNullableAnnotation(
                      currentArgument, inheritedMethod.declaringClass, annotationName);
            } else {
              scope
                  .problemReporter()
                  .cannotImplementIncompatibleNullness(currentMethod, inheritedMethod, false);
            }
            continue;
          } else if (inheritedNonNullNess == Boolean.TRUE) {
            // not strictly a conflict, but a configurable warning is given anyway:
            if (allInheritedMethods != null) {
              // avoid this optional warning if the conflict already existed in one supertype
              // (merging of two methods into one?)
              for (MethodBinding one : allInheritedMethods)
                if (TypeBinding.equalsEquals(inheritedMethod.declaringClass, one.declaringClass)
                    && getParameterNonNullness(one, i, useTypeAnnotations) != Boolean.TRUE)
                  continue parameterLoop;
            }
            scope
                .problemReporter()
                .parameterLackingNonnullAnnotation(
                    currentArgument, inheritedMethod.declaringClass, annotationName);
            continue;
          }
        }
        if (useTypeAnnotations) {
          TypeBinding inheritedParameter = inheritedMethod.parameters[i];
          TypeBinding substituteParameter =
              substituteParameters != null ? substituteParameters[i] : null;
          if (NullAnnotationMatching.analyse(
                  currentMethod.parameters[i],
                  inheritedParameter,
                  substituteParameter,
                  0,
                  CheckMode.OVERRIDE)
              .isAnyMismatch()) {
            if (currentArgument != null)
              scope
                  .problemReporter()
                  .illegalParameterRedefinition(
                      currentArgument, inheritedMethod.declaringClass, inheritedParameter);
            else
              scope
                  .problemReporter()
                  .cannotImplementIncompatibleNullness(currentMethod, inheritedMethod, false);
          }
        }
      }
    }
  }
예제 #28
0
  /** Generate invocation arguments, considering varargs methods */
  public void generateArguments(
      MethodBinding binding,
      Expression[] arguments,
      BlockScope currentScope,
      CodeStream codeStream) {
    if (binding.isVarargs()) {
      // 5 possibilities exist for a call to the vararg method foo(int i, int ... value) :
      //      foo(1), foo(1, null), foo(1, 2), foo(1, 2, 3, 4) & foo(1, new int[] {1, 2})
      TypeBinding[] params = binding.parameters;
      int paramLength = params.length;
      int varArgIndex = paramLength - 1;
      for (int i = 0; i < varArgIndex; i++) {
        arguments[i].generateCode(currentScope, codeStream, true);
      }
      ArrayBinding varArgsType =
          (ArrayBinding) params[varArgIndex]; // parameterType has to be an array type
      ArrayBinding codeGenVarArgsType = (ArrayBinding) binding.parameters[varArgIndex].erasure();
      int elementsTypeID = varArgsType.elementsType().id;
      int argLength = arguments == null ? 0 : arguments.length;

      if (argLength > paramLength) {
        // right number but not directly compatible or too many arguments - wrap extra into array
        // called with (argLength - lastIndex) elements : foo(1, 2) or foo(1, 2, 3, 4)
        // need to gen elements into an array, then gen each remaining element into created array
        codeStream.generateInlinedValue(argLength - varArgIndex);
        codeStream.newArray(null, codeGenVarArgsType); // create a mono-dimensional array
        for (int i = varArgIndex; i < argLength; i++) {
          codeStream.dup();
          codeStream.generateInlinedValue(i - varArgIndex);
          arguments[i].generateCode(currentScope, codeStream, true);
          codeStream.arrayAtPut(elementsTypeID, false);
        }
      } else if (argLength == paramLength) {
        // right number of arguments - could be inexact - pass argument as is
        TypeBinding lastType = arguments[varArgIndex].resolvedType;
        if (lastType == TypeBinding.NULL
            || (varArgsType.dimensions() == lastType.dimensions()
                && lastType.isCompatibleWith(varArgsType))) {
          // foo(1, new int[]{2, 3}) or foo(1, null) --> last arg is passed as-is
          arguments[varArgIndex].generateCode(currentScope, codeStream, true);
        } else {
          // right number but not directly compatible or too many arguments - wrap extra into array
          // need to gen elements into an array, then gen each remaining element into created array
          codeStream.generateInlinedValue(1);
          codeStream.newArray(null, codeGenVarArgsType); // create a mono-dimensional array
          codeStream.dup();
          codeStream.generateInlinedValue(0);
          arguments[varArgIndex].generateCode(currentScope, codeStream, true);
          codeStream.arrayAtPut(elementsTypeID, false);
        }
      } else { // not enough arguments - pass extra empty array
        // scenario: foo(1) --> foo(1, new int[0])
        // generate code for an empty array of parameterType
        codeStream.generateInlinedValue(0);
        codeStream.newArray(null, codeGenVarArgsType); // create a mono-dimensional array
      }
    } else if (arguments != null) { // standard generation for method arguments
      for (int i = 0, max = arguments.length; i < max; i++)
        arguments[i].generateCode(currentScope, codeStream, true);
    }
  }
예제 #29
0
 /** Analysing arguments of MessageSend, ExplicitConstructorCall, AllocationExpression. */
 protected void analyseArguments(
     BlockScope currentScope,
     FlowContext flowContext,
     FlowInfo flowInfo,
     MethodBinding methodBinding,
     Expression[] arguments) {
   // compare actual null-status against parameter annotations of the called method:
   if (arguments != null) {
     CompilerOptions compilerOptions = currentScope.compilerOptions();
     boolean considerTypeAnnotations =
         compilerOptions.sourceLevel >= ClassFileConstants.JDK1_8
             && compilerOptions.isAnnotationBasedNullAnalysisEnabled;
     boolean hasJDK15NullAnnotations = methodBinding.parameterNonNullness != null;
     int numParamsToCheck = methodBinding.parameters.length;
     if (considerTypeAnnotations || hasJDK15NullAnnotations) {
       // check if varargs need special treatment:
       boolean passThrough = false;
       if (methodBinding.isVarargs()) {
         int varArgPos = numParamsToCheck - 1;
         // this if-block essentially copied from generateArguments(..):
         if (numParamsToCheck == arguments.length) {
           TypeBinding varArgsType = methodBinding.parameters[varArgPos];
           TypeBinding lastType = arguments[varArgPos].resolvedType;
           if (lastType == TypeBinding.NULL
               || (varArgsType.dimensions() == lastType.dimensions()
                   && lastType.isCompatibleWith(varArgsType)))
             passThrough = true; // pass directly as-is
         }
         if (!passThrough)
           numParamsToCheck--; // with non-passthrough varargs last param is fed from individual
         // args -> don't check
       }
     }
     if (considerTypeAnnotations) {
       for (int i = 0; i < numParamsToCheck; i++) {
         TypeBinding expectedType = methodBinding.parameters[i];
         Expression argument = arguments[i];
         // prefer check based on type annotations:
         int severity = findNullTypeAnnotationMismatch(expectedType, argument.resolvedType);
         if (severity > 0) {
           // immediate reporting:
           currentScope
               .problemReporter()
               .nullityMismatchingTypeAnnotation(
                   argument,
                   argument.resolvedType,
                   expectedType,
                   severity == 1,
                   currentScope.environment());
           // next check flow-based null status against null JDK15-style annotations:
         } else if (hasJDK15NullAnnotations
             && methodBinding.parameterNonNullness[i] == Boolean.TRUE) {
           int nullStatus =
               argument.nullStatus(
                   flowInfo,
                   flowContext); // slight loss of precision: should also use the null info from
           // the receiver.
           if (nullStatus != FlowInfo.NON_NULL) // if required non-null is not provided
           flowContext.recordNullityMismatch(
                 currentScope, argument, argument.resolvedType, expectedType, nullStatus);
         }
       }
     } else if (hasJDK15NullAnnotations) {
       for (int i = 0; i < numParamsToCheck; i++) {
         if (methodBinding.parameterNonNullness[i] == Boolean.TRUE) {
           TypeBinding expectedType = methodBinding.parameters[i];
           Expression argument = arguments[i];
           int nullStatus =
               argument.nullStatus(
                   flowInfo,
                   flowContext); // slight loss of precision: should also use the null info from
           // the receiver.
           if (nullStatus != FlowInfo.NON_NULL) // if required non-null is not provided
           flowContext.recordNullityMismatch(
                 currentScope, argument, argument.resolvedType, expectedType, nullStatus);
         }
       }
     }
   }
 }
  /** Locate declaration in the current class file. This class file is always in a jar. */
  public void locateMatches(MatchLocator locator, ClassFile classFile, IBinaryType info)
      throws CoreException {
    SearchPattern pattern = locator.pattern;

    // check annotations references
    matchAnnotations(pattern, locator, classFile, info);

    // check class definition
    BinaryType binaryType = (BinaryType) classFile.getType();
    if (matchBinary(pattern, info, null)) {
      binaryType =
          new ResolvedBinaryType(
              (JavaElement) binaryType.getParent(),
              binaryType.getElementName(),
              binaryType.getKey());
      locator.reportBinaryMemberDeclaration(null, binaryType, null, info, SearchMatch.A_ACCURATE);
      return;
    }

    // Define arrays to store methods/fields from binary type if necessary
    IBinaryMethod[] binaryMethods = info.getMethods();
    int bMethodsLength = binaryMethods == null ? 0 : binaryMethods.length;
    IBinaryMethod[] unresolvedMethods = null;
    char[][] binaryMethodSignatures = null;
    boolean hasUnresolvedMethods = false;

    // Get fields from binary type info
    IBinaryField[] binaryFields = info.getFields();
    int bFieldsLength = binaryFields == null ? 0 : binaryFields.length;
    IBinaryField[] unresolvedFields = null;
    boolean hasUnresolvedFields = false;

    // Report as many accurate matches as possible
    int accuracy = SearchMatch.A_ACCURATE;
    boolean mustResolve = pattern.mustResolve;
    if (mustResolve) {
      BinaryTypeBinding binding = locator.cacheBinaryType(binaryType, info);
      if (binding != null) {
        // filter out element not in hierarchy scope
        if (!locator.typeInHierarchy(binding)) return;

        // Search matches on resolved methods
        MethodBinding[] availableMethods = binding.availableMethods();
        int aMethodsLength = availableMethods == null ? 0 : availableMethods.length;
        hasUnresolvedMethods = bMethodsLength != aMethodsLength;
        for (int i = 0; i < aMethodsLength; i++) {
          MethodBinding method = availableMethods[i];
          char[] methodSignature = method.genericSignature();
          if (methodSignature == null) methodSignature = method.signature();

          // Report the match if possible
          int level = locator.patternLocator.resolveLevel(method);
          if (level != PatternLocator.IMPOSSIBLE_MATCH) {
            IMethod methodHandle =
                binaryType.getMethod(
                    new String(
                        method.isConstructor()
                            ? binding.compoundName[binding.compoundName.length - 1]
                            : method.selector),
                    CharOperation.toStrings(
                        Signature.getParameterTypes(convertClassFileFormat(methodSignature))));
            accuracy =
                level == PatternLocator.ACCURATE_MATCH
                    ? SearchMatch.A_ACCURATE
                    : SearchMatch.A_INACCURATE;
            locator.reportBinaryMemberDeclaration(null, methodHandle, method, info, accuracy);
          }

          // Remove method from unresolved list
          if (hasUnresolvedMethods) {
            if (binaryMethodSignatures
                == null) { // Store binary method signatures to avoid multiple computation
              binaryMethodSignatures = new char[bMethodsLength][];
              for (int j = 0; j < bMethodsLength; j++) {
                IBinaryMethod binaryMethod = binaryMethods[j];
                char[] signature = binaryMethod.getGenericSignature();
                if (signature == null) signature = binaryMethod.getMethodDescriptor();
                binaryMethodSignatures[j] = signature;
              }
            }
            for (int j = 0; j < bMethodsLength; j++) {
              if (CharOperation.equals(binaryMethods[j].getSelector(), method.selector)
                  && CharOperation.equals(binaryMethodSignatures[j], methodSignature)) {
                if (unresolvedMethods == null) {
                  System.arraycopy(
                      binaryMethods,
                      0,
                      unresolvedMethods = new IBinaryMethod[bMethodsLength],
                      0,
                      bMethodsLength);
                }
                unresolvedMethods[j] = null;
                break;
              }
            }
          }
        }

        // Search matches on resolved fields
        FieldBinding[] availableFields = binding.availableFields();
        int aFieldsLength = availableFields == null ? 0 : availableFields.length;
        hasUnresolvedFields = bFieldsLength != aFieldsLength;
        for (int i = 0; i < aFieldsLength; i++) {
          FieldBinding field = availableFields[i];

          // Report the match if possible
          int level = locator.patternLocator.resolveLevel(field);
          if (level != PatternLocator.IMPOSSIBLE_MATCH) {
            IField fieldHandle = binaryType.getField(new String(field.name));
            accuracy =
                level == PatternLocator.ACCURATE_MATCH
                    ? SearchMatch.A_ACCURATE
                    : SearchMatch.A_INACCURATE;
            locator.reportBinaryMemberDeclaration(null, fieldHandle, field, info, accuracy);
          }

          // Remove the field from unresolved list
          if (hasUnresolvedFields) {
            for (int j = 0; j < bFieldsLength; j++) {
              if (CharOperation.equals(binaryFields[j].getName(), field.name)) {
                if (unresolvedFields == null) {
                  System.arraycopy(
                      binaryFields,
                      0,
                      unresolvedFields = new IBinaryField[bFieldsLength],
                      0,
                      bFieldsLength);
                }
                unresolvedFields[j] = null;
                break;
              }
            }
          }
        }

        // If all methods/fields were accurate then returns now
        if (!hasUnresolvedMethods && !hasUnresolvedFields) {
          return;
        }
      }
      accuracy = SearchMatch.A_INACCURATE;
    }

    // Report inaccurate methods
    if (mustResolve) binaryMethods = unresolvedMethods;
    bMethodsLength = binaryMethods == null ? 0 : binaryMethods.length;
    for (int i = 0; i < bMethodsLength; i++) {
      IBinaryMethod method = binaryMethods[i];
      if (method == null) continue; // impossible match or already reported as accurate
      if (matchBinary(pattern, method, info)) {
        char[] name;
        if (method.isConstructor()) {
          name = info.getName();
          int lastSlash = CharOperation.lastIndexOf('/', name);
          if (lastSlash != -1) {
            name = CharOperation.subarray(name, lastSlash + 1, name.length);
          }
        } else {
          name = method.getSelector();
        }
        String selector = new String(name);
        char[] methodSignature = binaryMethodSignatures == null ? null : binaryMethodSignatures[i];
        if (methodSignature == null) {
          methodSignature = method.getGenericSignature();
          if (methodSignature == null) methodSignature = method.getMethodDescriptor();
        }
        String[] parameterTypes =
            CharOperation.toStrings(
                Signature.getParameterTypes(convertClassFileFormat(methodSignature)));
        IMethod methodHandle = binaryType.getMethod(selector, parameterTypes);
        methodHandle =
            new ResolvedBinaryMethod(binaryType, selector, parameterTypes, methodHandle.getKey());
        locator.reportBinaryMemberDeclaration(null, methodHandle, null, info, accuracy);
      }
    }

    // Report inaccurate fields
    if (mustResolve) binaryFields = unresolvedFields;
    bFieldsLength = binaryFields == null ? 0 : binaryFields.length;
    for (int i = 0; i < bFieldsLength; i++) {
      IBinaryField field = binaryFields[i];
      if (field == null) continue; // impossible match or already reported as accurate
      if (matchBinary(pattern, field, info)) {
        String fieldName = new String(field.getName());
        IField fieldHandle = binaryType.getField(fieldName);
        fieldHandle = new ResolvedBinaryField(binaryType, fieldName, fieldHandle.getKey());
        locator.reportBinaryMemberDeclaration(null, fieldHandle, null, info, accuracy);
      }
    }
  }