예제 #1
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);
     }
   }
 }
예제 #2
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);
  }
예제 #3
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;
  }
  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$
  }
  /** 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);
      }
    }
  }
예제 #6
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;
    }
  }
  /**
   * 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;
    }
  }
예제 #8
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(ReferenceBinding superclass, ReferenceBinding[] superInterfaces) {
    // 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 = null;
    int nextPosition = 0;
    ReferenceBinding[] itsInterfaces = superInterfaces;
    if (itsInterfaces != null) {
      nextPosition = itsInterfaces.length;
      interfacesToVisit = itsInterfaces;
    }

    ReferenceBinding superType = superclass;
    HashtableOfObject nonVisibleDefaultMethods =
        new HashtableOfObject(3); // maps method selectors to an array of methods
    boolean allSuperclassesAreAbstract = true;

    while (superType != null && superType.isValidBinding()) {
      if (allSuperclassesAreAbstract) {
        if (superType.isAbstract()) {
        } 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 (existingMethods[i].declaringClass != inheritedMethod.declaringClass
                && areMethodsCompatible(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 (areMethodsCompatible(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
          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 (areMethodsCompatible(current[i], inheritedMethod)) {
                problemReporter().overridesPackageDefaultMethod(current[i], inheritedMethod);
                break foundMatch;
              }
            }
          }
        }
      }
      superType = superType.superclass();
    }
    if (nextPosition == 0) return;

    for (int i = 0; i < nextPosition; i++) {
      superType = interfacesToVisit[i];
      if (superType.isValidBinding()) {
        MethodBinding[] methods = superType.unResolvedMethods();
        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;

            System.arraycopy(
                existingMethods, 0, existingMethods = new MethodBinding[length + 1], 0, length);
            existingMethods[length] = inheritedMethod;
          }
          this.inheritedMethods.put(inheritedMethod.selector, existingMethods);
        }
      }
    }
  }