예제 #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
  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
  }
  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);
      }
    }
  }
예제 #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() {
    // 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;
    }
  }
예제 #5
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);
        }
      }
    }
  }