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); } } } } }
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); } }
/* 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; } }
/* 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); } } } }