*******************************************************************************/
package org.eclipse.jdt.internal.compiler.lookup;
-import org.eclipse.jdt.core.compiler.CharOperation;
import org.eclipse.jdt.internal.compiler.ast.MethodDeclaration;
import org.eclipse.jdt.internal.compiler.ast.TypeDeclaration;
+import org.eclipse.jdt.internal.compiler.env.IConstants;
import org.eclipse.jdt.internal.compiler.problem.ProblemReporter;
import org.eclipse.jdt.internal.compiler.util.HashtableOfObject;
-public final class MethodVerifier implements TagBits, TypeConstants {
+public class MethodVerifier implements TagBits, TypeConstants {
SourceTypeBinding type;
HashtableOfObject inheritedMethods;
HashtableOfObject currentMethods;
- defining a static class or interface inside a non-static nested class
- defining an interface as a local type (local types can only be classes)
*/
-public MethodVerifier(LookupEnvironment environment) {
+MethodVerifier(LookupEnvironment environment) {
this.type = null; // Initialized with the public method verify(SourceTypeBinding)
this.inheritedMethods = null;
this.currentMethods = null;
this.errorException = null;
this.environment = environment;
}
-private boolean areParametersEqual(MethodBinding one, MethodBinding two) {
+boolean areMethodsEqual(MethodBinding one, MethodBinding two) {
+ return areParametersEqual(one, two);
+}
+boolean areParametersEqual(MethodBinding one, MethodBinding two) {
TypeBinding[] oneArgs = one.parameters;
TypeBinding[] twoArgs = two.parameters;
if (oneArgs == twoArgs) return true;
if (!areTypesEqual(oneArgs[i], twoArgs[i])) return false;
return true;
}
-private boolean areReturnTypesEqual(MethodBinding one, MethodBinding two) {
+boolean areReturnTypesEqual(MethodBinding one, MethodBinding two) {
return areTypesEqual(one.returnType, two.returnType);
}
-private boolean areTypesEqual(TypeBinding one, TypeBinding two) {
+boolean canSkipInheritedMethods() {
+ if (this.type.superclass() != null && this.type.superclass().isAbstract())
+ return false;
+ return this.type.superInterfaces() == NoSuperInterfaces;
+}
+boolean canSkipInheritedMethods(MethodBinding one, MethodBinding two) {
+ return two == null // already know one is not null
+ || one.declaringClass == two.declaringClass;
+}
+boolean areTypesEqual(TypeBinding one, TypeBinding two) {
if (one == two) return true;
- if (one instanceof ReferenceBinding && two instanceof ReferenceBinding)
- // can compare unresolved to resolved reference bindings
- return CharOperation.equals(((ReferenceBinding) one).compoundName, ((ReferenceBinding) two).compoundName);
+
+ // its possible that an UnresolvedReferenceBinding can be compared to its resolved type
+ // when they're both UnresolvedReferenceBindings then they must be identical like all other types
+ // all wrappers of UnresolvedReferenceBindings are converted as soon as the type is resolved
+ // so its not possible to have 2 arrays where one is UnresolvedX[] and the other is X[]
+ if (one instanceof UnresolvedReferenceBinding)
+ return ((UnresolvedReferenceBinding) one).resolvedType == two;
+ if (two instanceof UnresolvedReferenceBinding)
+ return ((UnresolvedReferenceBinding) two).resolvedType == one;
return false; // all other type bindings are identical
}
-private void checkAbstractMethod(MethodBinding abstractMethod) {
- if (mustImplementAbstractMethod(abstractMethod)) {
+void checkAbstractMethod(MethodBinding abstractMethod) {
+ if (mustImplementAbstractMethod(abstractMethod.declaringClass)) {
TypeDeclaration typeDeclaration = this.type.scope.referenceContext;
if (typeDeclaration != null) {
MethodDeclaration missingAbstractMethod = typeDeclaration.addMissingAbstractMethodFor(abstractMethod);
missingAbstractMethod.scope.problemReporter().abstractMethodMustBeImplemented(this.type, abstractMethod);
} else {
- this.problemReporter().abstractMethodMustBeImplemented(this.type, abstractMethod);
+ problemReporter().abstractMethodMustBeImplemented(this.type, abstractMethod);
}
}
}
-private void checkAgainstInheritedMethods(MethodBinding currentMethod, MethodBinding[] methods, int length) {
+void checkAgainstInheritedMethods(MethodBinding currentMethod, MethodBinding[] methods, int length) {
+ boolean isAnnotationMember = this.type.isAnnotationType();
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);
+ problemReporter(currentMethod).staticAndInstanceConflict(currentMethod, inheritedMethod);
continue nextMethod;
}
- if (!currentMethod.isAbstract() && inheritedMethod.isAbstract()) {
- if ((currentMethod.modifiers & CompilerModifiers.AccOverriding) == 0)
+ if (inheritedMethod.isAbstract()) {
+ if (inheritedMethod.declaringClass.isInterface()) {
currentMethod.modifiers |= CompilerModifiers.AccImplementing;
+ } else {
+ currentMethod.modifiers |= CompilerModifiers.AccImplementing | CompilerModifiers.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 |= CompilerModifiers.AccOverriding;
}
+ if (isAnnotationMember) {
+ // annotation cannot override any method
+ problemReporter().annotationCannotOverrideMethod(currentMethod, inheritedMethod);
+ return; // do not repoort against subsequent inherited methods
+ }
if (!areReturnTypesEqual(currentMethod, inheritedMethod)) {
- this.problemReporter(currentMethod).incompatibleReturnType(currentMethod, inheritedMethod);
+ problemReporter(currentMethod).incompatibleReturnType(currentMethod, inheritedMethod);
} else {
if (currentMethod.thrownExceptions != NoExceptions)
- this.checkExceptions(currentMethod, inheritedMethod);
+ checkExceptions(currentMethod, inheritedMethod);
if (inheritedMethod.isFinal())
- this.problemReporter(currentMethod).finalMethodCannotBeOverridden(currentMethod, inheritedMethod);
- if (!this.isAsVisible(currentMethod, inheritedMethod))
- this.problemReporter(currentMethod).visibilityConflict(currentMethod, inheritedMethod);
+ problemReporter(currentMethod).finalMethodCannotBeOverridden(currentMethod, inheritedMethod);
+ if (!isAsVisible(currentMethod, inheritedMethod))
+ 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
if (i != j && methods[j].declaringClass.implementsInterface(declaringClass, false))
continue nextMethod;
- this.problemReporter(currentMethod).overridesDeprecatedMethod(currentMethod, inheritedMethod);
+ problemReporter(currentMethod).overridesDeprecatedMethod(currentMethod, inheritedMethod);
}
}
+ checkForBridgeMethod(currentMethod, inheritedMethod);
}
}
}
Assumes all exceptions are valid and throwable.
Unchecked exceptions (compatible with runtime & error) are ignored (see the spec on pg. 203).
*/
-private void checkExceptions(MethodBinding newMethod, MethodBinding inheritedMethod) {
+void checkExceptions(MethodBinding newMethod, MethodBinding inheritedMethod) {
ReferenceBinding[] newExceptions = resolvedExceptionTypesFor(newMethod);
ReferenceBinding[] inheritedExceptions = resolvedExceptionTypesFor(inheritedMethod);
for (int i = newExceptions.length; --i >= 0;) {
ReferenceBinding newException = newExceptions[i];
int j = inheritedExceptions.length;
- while (--j > -1 && !this.isSameClassOrSubclassOf(newException, inheritedExceptions[j])){/*empty*/}
+ while (--j > -1 && !isSameClassOrSubclassOf(newException, inheritedExceptions[j])){/*empty*/}
if (j == -1)
- if (!(newException.isCompatibleWith(this.runtimeException()) || newException.isCompatibleWith(this.errorException())))
- this.problemReporter(newMethod).incompatibleExceptionInThrowsClause(this.type, newMethod, inheritedMethod, newException);
+ if (!(newException.isCompatibleWith(runtimeException()) || newException.isCompatibleWith(errorException())))
+ problemReporter(newMethod).incompatibleExceptionInThrowsClause(this.type, newMethod, inheritedMethod, newException);
}
}
-private void checkInheritedMethods(MethodBinding[] methods, int length) {
+void checkForBridgeMethod(MethodBinding currentMethod, MethodBinding inheritedMethod) {
+ // no op before 1.5
+}
+void checkInheritedMethods(MethodBinding[] methods, int length) {
MethodBinding first = methods[0];
int index = length;
while (--index > 0 && areReturnTypesEqual(first, methods[index])){/*empty*/}
if (index > 0) { // All inherited methods do NOT have the same vmSignature
- this.problemReporter().inheritedMethodsHaveIncompatibleReturnTypes(this.type, methods, length);
+ problemReporter().inheritedMethodsHaveIncompatibleReturnTypes(this.type, methods, length);
return;
}
if (concreteMethod == null) {
if (this.type.isClass() && !this.type.isAbstract()) {
for (int i = length; --i >= 0;) {
- if (mustImplementAbstractMethod(methods[i])) {
+ if (mustImplementAbstractMethod(methods[i].declaringClass)) {
TypeDeclaration typeDeclaration = this.type.scope.referenceContext;
if (typeDeclaration != null) {
MethodDeclaration missingAbstractMethod = typeDeclaration.addMissingAbstractMethodFor(methods[0]);
missingAbstractMethod.scope.problemReporter().abstractMethodMustBeImplemented(this.type, methods[0]);
} else {
- this.problemReporter().abstractMethodMustBeImplemented(this.type, methods[0]);
+ problemReporter().abstractMethodMustBeImplemented(this.type, methods[0]);
}
return;
}
// Remember that interfaces can only define public instance methods
if (concreteMethod.isStatic())
// Cannot inherit a static method which is specified as an instance method by an interface
- this.problemReporter().staticInheritedMethodConflicts(type, concreteMethod, abstractMethods);
+ problemReporter().staticInheritedMethodConflicts(type, concreteMethod, abstractMethods);
if (!concreteMethod.isPublic())
// Cannot reduce visibility of a public method specified by an interface
- this.problemReporter().inheritedMethodReducesVisibility(type, concreteMethod, abstractMethods);
+ problemReporter().inheritedMethodReducesVisibility(type, concreteMethod, abstractMethods);
if (concreteMethod.thrownExceptions != NoExceptions)
for (int i = abstractMethods.length; --i >= 0;)
- this.checkExceptions(concreteMethod, abstractMethods[i]);
+ checkExceptions(concreteMethod, abstractMethods[i]);
}
/*
For each inherited method identifier (message pattern - vm signature minus the return type)
else
complain about missing implementation only if type is NOT an interface or abstract
*/
-private void checkMethods() {
- boolean mustImplementAbstractMethods = this.type.isClass() && !this.type.isAbstract();
- boolean skipInheritedMethods = mustImplementAbstractMethods && this.type.superInterfaces() == NoSuperInterfaces
- && this.type.superclass() != null && !this.type.superclass().isAbstract(); // have a single concrete superclass so only check overridden methods
+void checkMethods() {
+ boolean mustImplementAbstractMethods = ((this.type.modifiers & IConstants.AccInterface) == 0) && !this.type.isAbstract();
+ boolean skipInheritedMethods = mustImplementAbstractMethods && canSkipInheritedMethods(); // have a single concrete superclass so only check overridden methods
char[][] methodSelectors = this.inheritedMethods.keyTable;
nextSelector : for (int s = methodSelectors.length; --s >= 0;) {
if (methodSelectors[s] == null) continue nextSelector;
MethodBinding currentMethod = current[i];
for (int j = 0, length2 = inherited.length; j < length2; j++) {
MethodBinding inheritedMethod = inherited[j];
- if (inheritedMethod != null && areParametersEqual(currentMethod, inheritedMethod)) {
- matchingInherited[++index] = inheritedMethod;
- inherited[j] = null; // do not want to find it again
+ if (inheritedMethod != null) {
+ inheritedMethod = computeSubstituteMethod(inheritedMethod, currentMethod);
+ if (areMethodsEqual(currentMethod, inheritedMethod)) {
+ matchingInherited[++index] = inheritedMethod;
+ inherited[j] = null; // do not want to find it again
+ }
}
}
if (index >= 0)
- this.checkAgainstInheritedMethods(currentMethod, matchingInherited, index + 1); // pass in the length of matching
+ checkAgainstInheritedMethods(currentMethod, matchingInherited, index + 1); // pass in the length of matching
}
}
if (inheritedMethod != null) {
matchingInherited[++index] = inheritedMethod;
for (int j = i + 1; j < length; j++) {
- if (inherited[j] != null && areParametersEqual(inheritedMethod, inherited[j])) {
- matchingInherited[++index] = inherited[j];
+ MethodBinding otherInheritedMethod = inherited[j];
+ if (canSkipInheritedMethods(inheritedMethod, otherInheritedMethod))
+ continue;
+ otherInheritedMethod = computeSubstituteMethod(otherInheritedMethod, inheritedMethod);
+ if (areMethodsEqual(inheritedMethod, otherInheritedMethod)) {
+ matchingInherited[++index] = otherInheritedMethod;
inherited[j] = null; // do not want to find it again
}
}
}
if (index > 0)
- this.checkInheritedMethods(matchingInherited, index + 1); // pass in the length of matching
+ checkInheritedMethods(matchingInherited, index + 1); // pass in the length of matching
else if (mustImplementAbstractMethods && index == 0 && matchingInherited[0].isAbstract())
checkAbstractMethod(matchingInherited[0]);
}
}
}
-private void checkPackagePrivateAbstractMethod(MethodBinding abstractMethod) {
+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
- MethodBinding[] methods = superType.getMethods(selector);
- nextMethod : for (int m = methods.length; --m >= 0;) {
- MethodBinding method = methods[m];
- if (!areReturnTypesEqual(method, abstractMethod) || !areParametersEqual(method, abstractMethod))
- continue nextMethod;
- if (method.isPrivate() || method.isConstructor() || method.isDefaultAbstract())
- continue nextMethod;
- if (superType.fPackage == abstractMethod.declaringClass.fPackage) return; // found concrete implementation of abstract method in same package
+ 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);
+ problemReporter().abstractMethodCannotBeOverridden(this.type, abstractMethod);
}
/*
Binding creation is responsible for reporting:
- check the type of any array is not void
- check that each exception type is Throwable or a subclass of it
*/
-private void computeInheritedMethods() {
+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;
if (itsInterfaces != NoSuperInterfaces)
interfacesToVisit[++lastPosition] = itsInterfaces;
- ReferenceBinding superType = this.type.isClass()
- ? this.type.superclass()
+ ReferenceBinding superType = (this.type.modifiers & IConstants.AccInterface) == 0
+ ? this.type.superclass() // class or enum
: 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;
+ while (superType != null && 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 method = methods[m];
- if (method.isPrivate() || method.isConstructor() || method.isDefaultAbstract())
- continue nextMethod;
- MethodBinding[] existingMethods = (MethodBinding[]) this.inheritedMethods.get(method.selector);
- if (existingMethods != null) {
- for (int i = 0, length = existingMethods.length; i < length; i++) {
- if (areReturnTypesEqual(method, existingMethods[i]) && areParametersEqual(method, existingMethods[i])) {
- if (method.isDefault() && method.isAbstract() && method.declaringClass.fPackage != type.fPackage)
- checkPackagePrivateAbstractMethod(method);
- continue nextMethod;
- }
+ 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 && doesMethodOverride(existingMethods[i], inheritedMethod)) {
+ if (inheritedMethod.isDefault() && inheritedMethod.isAbstract())
+ checkPackagePrivateAbstractMethod(inheritedMethod);
+ continue nextMethod;
}
}
- MethodBinding[] nonVisible = (MethodBinding[]) nonVisibleDefaultMethods.get(method.selector);
- if (nonVisible != null)
- for (int i = 0, l = nonVisible.length; i < l; i++)
- if (areReturnTypesEqual(method, nonVisible[i]) && areParametersEqual(method, nonVisible[i]))
- continue nextMethod;
-
- if (!method.isDefault() || method.declaringClass.fPackage == type.fPackage) {
- if (existingMethods == null) {
- existingMethods = new MethodBinding[] {method};
- } else {
- int length = existingMethods.length;
- System.arraycopy(existingMethods, 0, existingMethods = new MethodBinding[length + 1], 0, length);
- existingMethods[length] = method;
- }
- this.inheritedMethods.put(method.selector, existingMethods);
+ }
+ 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 {
- if (nonVisible == null) {
- nonVisible = new MethodBinding[] {method};
- } else {
- int length = nonVisible.length;
- System.arraycopy(nonVisible, 0, nonVisible = new MethodBinding[length + 1], 0, length);
- nonVisible[length] = method;
- }
- nonVisibleDefaultMethods.put(method.selector, nonVisible);
-
- if (method.isAbstract() && !this.type.isAbstract()) // non visible abstract methods cannot be overridden so the type must be defined abstract
- this.problemReporter().abstractMethodCannotBeOverridden(this.type, method);
-
- MethodBinding[] current = (MethodBinding[]) this.currentMethods.get(method.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 (areReturnTypesEqual(method, current[i]) && areParametersEqual(method, current[i])) {
- this.problemReporter().overridesPackageDefaultMethod(current[i], method);
- break foundMatch;
- }
+ 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 (doesMethodOverride(current[i], inheritedMethod)) {
+ problemReporter().overridesPackageDefaultMethod(current[i], inheritedMethod);
+ break foundMatch;
}
}
}
}
- superType = superType.superclass();
}
+ superType = superType.superclass();
}
for (int i = 0; i <= lastPosition; i++) {
MethodBinding[] methods = superType.unResolvedMethods();
nextMethod : for (int m = methods.length; --m >= 0;) { // Interface methods are all abstract public
- MethodBinding method = methods[m];
- MethodBinding[] existingMethods = (MethodBinding[]) this.inheritedMethods.get(method.selector);
+ MethodBinding inheritedMethod = methods[m];
+ MethodBinding[] existingMethods = (MethodBinding[]) this.inheritedMethods.get(inheritedMethod.selector);
if (existingMethods == null) {
- existingMethods = new MethodBinding[] {method};
+ existingMethods = new MethodBinding[] {inheritedMethod};
} else {
int length = existingMethods.length;
- for (int e = 0; e < length; e++) {
- MethodBinding existing = existingMethods[e];
- if (areParametersEqual(method, existing) && existing.declaringClass.implementsInterface(superType, true))
+ // look to see if any of the existingMethods implement this inheritedMethod
+ for (int e = 0; e < length; e++)
+ if (isInterfaceMethodImplemented(inheritedMethod, existingMethods[e], superType))
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] = method;
+ existingMethods[length] = inheritedMethod;
}
- this.inheritedMethods.put(method.selector, existingMethods);
+ this.inheritedMethods.put(inheritedMethod.selector, existingMethods);
}
}
}
interfaces[j].tagBits &= ~InterfaceVisited;
}
}
-private void computeMethods() {
+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
}
}
}
-private ReferenceBinding errorException() {
+MethodBinding computeSubstituteMethod(MethodBinding inheritedMethod, MethodBinding currentMethod) {
+ return inheritedMethod;
+}
+public boolean doesMethodOverride(MethodBinding method, MethodBinding inheritedMethod) {
+ return areReturnTypesEqual(method, inheritedMethod) && areParametersEqual(method, inheritedMethod);
+}
+ReferenceBinding errorException() {
if (errorException == null)
this.errorException = this.type.scope.getJavaLangError();
return errorException;
}
-private boolean isAsVisible(MethodBinding newMethod, MethodBinding inheritedMethod) {
+boolean isAsVisible(MethodBinding newMethod, MethodBinding inheritedMethod) {
if (inheritedMethod.modifiers == newMethod.modifiers) return true;
if (newMethod.isPublic()) return true; // Covers everything
return !newMethod.isPrivate(); // The inheritedMethod cannot be private since it would not be visible
}
-private boolean isSameClassOrSubclassOf(ReferenceBinding testClass, ReferenceBinding superclass) {
+boolean isInterfaceMethodImplemented(MethodBinding inheritedMethod, MethodBinding existingMethod, ReferenceBinding superType) {
+ // skip interface method with the same signature if visible to its declaringClass
+ return areParametersEqual(existingMethod, inheritedMethod) && existingMethod.declaringClass.implementsInterface(superType, true);
+}
+boolean isSameClassOrSubclassOf(ReferenceBinding testClass, ReferenceBinding superclass) {
do {
if (testClass == superclass) return true;
} while ((testClass = testClass.superclass()) != null);
return false;
}
-private boolean mustImplementAbstractMethod(MethodBinding abstractMethod) {
+boolean mustImplementAbstractMethod(ReferenceBinding declaringClass) {
// if the type's superclass is an abstract class, then all abstract methods must be implemented
// otherwise, skip it if the type's superclass must implement any of the inherited methods
ReferenceBinding superclass = this.type.superclass();
- ReferenceBinding declaringClass = abstractMethod.declaringClass;
if (declaringClass.isClass()) {
while (superclass.isAbstract() && superclass != declaringClass)
superclass = superclass.superclass(); // find the first concrete superclass or the abstract declaringClass
}
return superclass.isAbstract(); // if it is a concrete class then we have already reported problem against it
}
-private ProblemReporter problemReporter() {
+ProblemReporter problemReporter() {
return this.type.scope.problemReporter();
}
-private ProblemReporter problemReporter(MethodBinding currentMethod) {
+ProblemReporter problemReporter(MethodBinding currentMethod) {
ProblemReporter reporter = problemReporter();
if (currentMethod.declaringClass == type) // only report against the currentMethod if its implemented by the type
reporter.referenceContext = currentMethod.sourceMethod();
if (!(method.declaringClass instanceof BinaryTypeBinding))
return TypeConstants.NoExceptions; // safety check
- BinaryTypeBinding binaryType = (BinaryTypeBinding) method.declaringClass;
for (int i = exceptions.length; --i >= 0;)
- if (exceptions[i] instanceof UnresolvedReferenceBinding)
- exceptions[i] = (ReferenceBinding) binaryType.resolveType(exceptions[i]);
+ exceptions[i] = BinaryTypeBinding.resolveType(exceptions[i], this.environment, true);
return exceptions;
}
-private ReferenceBinding runtimeException() {
+ReferenceBinding runtimeException() {
if (runtimeException == null)
this.runtimeException = this.type.scope.getJavaLangRuntimeException();
return runtimeException;
}
-public void verify(SourceTypeBinding someType) {
+void verify(SourceTypeBinding someType) {
this.type = someType;
- this.computeMethods();
- this.computeInheritedMethods();
- this.checkMethods();
+ computeMethods();
+ computeInheritedMethods();
+ checkMethods();
}
public String toString() {
StringBuffer buffer = new StringBuffer(10);