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