Пример #1
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);
          }
        }
      }
    }
  }
Пример #2
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);
    }
  }
Пример #3
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;
    }
  }
Пример #4
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);
        }
      }
    }
  }