### Eclipse Workspace Patch 1.0 #P org.eclipse.jdt.core.tests.compiler Index: src/org/eclipse/jdt/core/tests/compiler/regression/MethodVerifyTest.java =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/MethodVerifyTest.java,v retrieving revision 1.169 diff -u -r1.169 MethodVerifyTest.java --- src/org/eclipse/jdt/core/tests/compiler/regression/MethodVerifyTest.java 6 Nov 2008 17:22:26 -0000 1.169 +++ src/org/eclipse/jdt/core/tests/compiler/regression/MethodVerifyTest.java 6 Nov 2008 19:01:21 -0000 @@ -771,7 +771,7 @@ "1. ERROR in X.java (at line 1)\r\n" + " abstract class X6 extends A implements I {}\r\n" + " ^^\n" + - "The return type is incompatible with I.foo(), A.foo()\n" + + "The type X6 must implement the inherited abstract method I.foo() to override A.foo()\n" + "----------\n" ); } @@ -7858,7 +7858,7 @@ "1. ERROR in X.java (at line 1)\n" + " public abstract class X implements J, K {}\n" + " ^\n" + - "The return type is incompatible with K.foo(Number), J.foo(Number)\n" + + "The return type is incompatible with I.foo(Number), K.foo(Number), J.foo(Number)\n" + "----------\n" + "2. WARNING in X.java (at line 6)\n" + " XX foo(Number n);\n" + @@ -7957,11 +7957,6 @@ " public List getPets() { return null; }\n" + " ^^^^\n" + "Type safety: The return type List for getPets() from the type CatShopImpl needs unchecked conversion to conform to List from the type CatShop\n" + - "----------\n" + - "2. WARNING in PurebredCatShopImpl.java (at line 12)\n" + - " class PurebredCatShopImpl extends CatShopImpl implements PurebredCatShop {}\n" + - " ^^^^^^^^^^^^^^^^^^^\n" + - "Type safety: The return type List for getPets() from the type CatShopImpl needs unchecked conversion to conform to List from the type CatShop\n" + "----------\n" ); } @@ -8658,7 +8653,7 @@ "1. ERROR in Concrete.java (at line 12)\r\n" + " class Concrete extends HalfConcrete implements I {}\r\n" + " ^^^^^^^^\n" + - "The return type is incompatible with I.foo(String), HalfGenericSuper.foo(String)\n" + + "The type Concrete must implement the inherited abstract method I.foo(String) to override HalfGenericSuper.foo(String)\n" + "----------\n" ); } @@ -8927,7 +8922,7 @@ "1. ERROR in X.java (at line 1)\n" + " class X extends Y implements I { }\n" + " ^\n" + - "The type X must implement the inherited abstract method Y.m()\n" + + "The type X must implement the inherited abstract method I.m() to override Y.m()\n" + "----------\n" ); } @@ -9089,4 +9084,87 @@ "----------\n" ); } + +//https://bugs.eclipse.org/bugs/show_bug.cgi?id=249134 +public void test180() { + this.runNegativeTest( + new String[] { + "B.java", + "interface I {\n" + + " String m();\n" + + " Object n();\n" + + "}\n" + + "abstract class A {\n" + + " abstract Object m();\n" + + " abstract String n();\n" + + "}\n" + + "class B extends A implements I {}\n" + + "class A2 {\n" + + " abstract Object m();\n" + + " abstract String n();\n" + + "}\n" + + "class B2 extends A2 implements I {}" + }, + "----------\n" + + "1. ERROR in B.java (at line 9)\n" + + " class B extends A implements I {}\n" + + " ^\n" + + "The type B must implement the inherited abstract method A.n()\n" + + "----------\n" + + "2. ERROR in B.java (at line 9)\n" + + " class B extends A implements I {}\n" + + " ^\n" + + "The type B must implement the inherited abstract method I.m() to override A.m()\n" + + "----------\n" + + "3. ERROR in B.java (at line 11)\n" + + " abstract Object m();\n" + + " ^^^\n" + + "The abstract method m in type A2 can only be defined by an abstract class\n" + + "----------\n" + + "4. ERROR in B.java (at line 12)\n" + + " abstract String n();\n" + + " ^^^\n" + + "The abstract method n in type A2 can only be defined by an abstract class\n" + + "----------\n" + + "5. ERROR in B.java (at line 14)\n" + + " class B2 extends A2 implements I {}\n" + + " ^^\n" + + "The type B2 must implement the inherited abstract method I.m() to override A2.m()\n" + + "----------\n" + ); +} + +//https://bugs.eclipse.org/bugs/show_bug.cgi?id=249134 +public void test181() { + this.runNegativeTest( + new String[] { + "B.java", + "interface I {\n" + + " String m();\n" + + " Object n();\n" + + "}\n" + + "class A {\n" + + " public Object m() { return null; }\n" + + " public String n() { return null; }\n" + + "}\n" + + "class B extends A implements I {}\n" + + "abstract class A2 {\n" + + " public Object m() { return null; }\n" + + " public String n() { return null; }\n" + + "}\n" + + "class B2 extends A2 implements I {}" + }, + "----------\n" + + "1. ERROR in B.java (at line 9)\n" + + " class B extends A implements I {}\n" + + " ^\n" + + "The type B must implement the inherited abstract method I.m() to override A.m()\n" + + "----------\n" + + "2. ERROR in B.java (at line 14)\n" + + " class B2 extends A2 implements I {}\n" + + " ^^\n" + + "The type B2 must implement the inherited abstract method I.m() to override A2.m()\n" + + "----------\n" + ); +} } Index: src/org/eclipse/jdt/core/tests/compiler/regression/CompilerInvocationTests.java =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/CompilerInvocationTests.java,v retrieving revision 1.22 diff -u -r1.22 CompilerInvocationTests.java --- src/org/eclipse/jdt/core/tests/compiler/regression/CompilerInvocationTests.java 6 Nov 2008 17:19:15 -0000 1.22 +++ src/org/eclipse/jdt/core/tests/compiler/regression/CompilerInvocationTests.java 6 Nov 2008 19:01:19 -0000 @@ -631,6 +631,7 @@ expectedProblemAttributes.put("IllegalVararg", new ProblemAttributes(CategorizedProblem.CAT_MEMBER)); expectedProblemAttributes.put("OverridingMethodWithoutSuperInvocation", new ProblemAttributes(CategorizedProblem.CAT_POTENTIAL_PROGRAMMING_PROBLEM)); expectedProblemAttributes.put("MissingSynchronizedModifierInInheritedMethod", new ProblemAttributes(CategorizedProblem.CAT_POTENTIAL_PROGRAMMING_PROBLEM)); + expectedProblemAttributes.put("AbstractMethodMustBeImplementedOverConcreteMethod", new ProblemAttributes(CategorizedProblem.CAT_MEMBER)); expectedProblemAttributes.put("CodeSnippetMissingClass", new ProblemAttributes(CategorizedProblem.CAT_INTERNAL)); expectedProblemAttributes.put("CodeSnippetMissingMethod", new ProblemAttributes(CategorizedProblem.CAT_INTERNAL)); expectedProblemAttributes.put("CannotUseSuperInCodeSnippet", new ProblemAttributes(CategorizedProblem.CAT_INTERNAL)); @@ -1253,6 +1254,7 @@ expectedProblemAttributes.put("IllegalVararg", SKIP); expectedProblemAttributes.put("OverridingMethodWithoutSuperInvocation", new ProblemAttributes(JavaCore.COMPILER_PB_OVERRIDING_METHOD_WITHOUT_SUPER_INVOCATION)); expectedProblemAttributes.put("MissingSynchronizedModifierInInheritedMethod", new ProblemAttributes(JavaCore.COMPILER_PB_MISSING_SYNCHRONIZED_ON_INHERITED_METHOD)); + expectedProblemAttributes.put("AbstractMethodMustBeImplementedOverConcreteMethod", SKIP); expectedProblemAttributes.put("CodeSnippetMissingClass", SKIP); expectedProblemAttributes.put("CodeSnippetMissingMethod", SKIP); expectedProblemAttributes.put("CannotUseSuperInCodeSnippet", SKIP); Index: src/org/eclipse/jdt/core/tests/compiler/regression/GenericTypeTest.java =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/GenericTypeTest.java,v retrieving revision 1.762 diff -u -r1.762 GenericTypeTest.java --- src/org/eclipse/jdt/core/tests/compiler/regression/GenericTypeTest.java 4 Nov 2008 10:04:51 -0000 1.762 +++ src/org/eclipse/jdt/core/tests/compiler/regression/GenericTypeTest.java 6 Nov 2008 19:01:21 -0000 @@ -41814,7 +41814,7 @@ "4. ERROR in X.java (at line 13)\n" + " public interface CombinedSubInterface extends SubInterface, OtherSubInterface {}\n" + " ^^^^^^^^^^^^^^^^^^^^\n" + - "The return type is incompatible with X.OtherSubInterface.and(X.SuperInterface), X.SubInterface.and(X.SuperInterface)\n" + + "The return type is incompatible with X.SuperInterface.and(X.SuperInterface), X.OtherSubInterface.and(X.SuperInterface), X.SubInterface.and(X.SuperInterface)\n" + "----------\n" + "5. WARNING in X.java (at line 15)\n" + " public interface OtherSubInterface extends SuperInterface {\n" + #P org.eclipse.jdt.core Index: compiler/org/eclipse/jdt/core/compiler/IProblem.java =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.jdt.core/compiler/org/eclipse/jdt/core/compiler/IProblem.java,v retrieving revision 1.206 diff -u -r1.206 IProblem.java --- compiler/org/eclipse/jdt/core/compiler/IProblem.java 10 Oct 2008 17:24:31 -0000 1.206 +++ compiler/org/eclipse/jdt/core/compiler/IProblem.java 6 Nov 2008 19:01:22 -0000 @@ -778,6 +778,7 @@ int OverridingMethodWithoutSuperInvocation = MethodRelated + 416; /** @since 3.5 */ int MissingSynchronizedModifierInInheritedMethod= MethodRelated + 417; + int AbstractMethodMustBeImplementedOverConcreteMethod = MethodRelated + 418; // code snippet support int CodeSnippetMissingClass = Internal + 420; Index: compiler/org/eclipse/jdt/internal/compiler/problem/messages.properties =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/problem/messages.properties,v retrieving revision 1.242 diff -u -r1.242 messages.properties --- compiler/org/eclipse/jdt/internal/compiler/problem/messages.properties 10 Oct 2008 17:24:31 -0000 1.242 +++ compiler/org/eclipse/jdt/internal/compiler/problem/messages.properties 6 Nov 2008 19:01:22 -0000 @@ -352,6 +352,7 @@ 415 = The variable argument type {0} of the method {1} must be the last parameter 416 = The method {0} is overriding a method without making a super invocation 417 = The method {0}.{1}({2}) is overriding a synchronized method without being synchronized +418 = The type {3} must implement the inherited abstract method {2}.{0}({1}) to override {6}.{4}({5}) 420 = Code snippet support cannot find the class {0} 421 = Code snippet support cannot find the method {0}.{1}({2}) Index: compiler/org/eclipse/jdt/internal/compiler/problem/ProblemReporter.java =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/problem/ProblemReporter.java,v retrieving revision 1.380 diff -u -r1.380 ProblemReporter.java --- compiler/org/eclipse/jdt/internal/compiler/problem/ProblemReporter.java 10 Oct 2008 17:24:31 -0000 1.380 +++ compiler/org/eclipse/jdt/internal/compiler/problem/ProblemReporter.java 6 Nov 2008 19:01:22 -0000 @@ -531,6 +531,32 @@ type.sourceEnd()); } } +public void abstractMethodMustBeImplemented(SourceTypeBinding type, MethodBinding abstractMethod, MethodBinding concreteMethod) { + this.handle( + // Must implement the inherited abstract method %1 + // 8.4.3 - Every non-abstract subclass of an abstract type, A, must provide a concrete implementation of all of A's methods. + IProblem.AbstractMethodMustBeImplementedOverConcreteMethod, + new String[] { + new String(abstractMethod.selector), + typesAsString(abstractMethod.isVarargs(), abstractMethod.parameters, false), + new String(abstractMethod.declaringClass.readableName()), + new String(type.readableName()), + new String(concreteMethod.selector), + typesAsString(concreteMethod.isVarargs(), concreteMethod.parameters, false), + new String(concreteMethod.declaringClass.readableName()), + }, + new String[] { + new String(abstractMethod.selector), + typesAsString(abstractMethod.isVarargs(), abstractMethod.parameters, true), + new String(abstractMethod.declaringClass.shortReadableName()), + new String(type.shortReadableName()), + new String(concreteMethod.selector), + typesAsString(concreteMethod.isVarargs(), concreteMethod.parameters, true), + new String(concreteMethod.declaringClass.shortReadableName()), + }, + type.sourceStart(), + type.sourceEnd()); +} public void abstractMethodNeedingNoBody(AbstractMethodDeclaration method) { this.handle( IProblem.BodyForAbstractMethod, Index: compiler/org/eclipse/jdt/internal/compiler/lookup/MethodVerifier15.java =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/MethodVerifier15.java,v retrieving revision 1.94 diff -u -r1.94 MethodVerifier15.java --- compiler/org/eclipse/jdt/internal/compiler/lookup/MethodVerifier15.java 31 Oct 2008 15:45:04 -0000 1.94 +++ compiler/org/eclipse/jdt/internal/compiler/lookup/MethodVerifier15.java 6 Nov 2008 19:01:22 -0000 @@ -359,38 +359,21 @@ super.checkInheritedMethods(methods, length); } -boolean checkInheritedReturnTypes(MethodBinding[] methods, int length) { - // assumes length > 1 - // its possible in 1.5 that A is compatible with B & C, but B is not compatible with C - // so find 1 method that is compatible with every other method - // abstract classes must check every method against each other - // but if first method is concrete, then only check it against the rest - match : for (int i = 0, l = methods[0].isAbstract() ? length - 1 : 0; i <= l; i++) { - MethodBinding method = methods[i]; - next : for (int j = 0; j < length; j++) { - if (i == j) continue; - if (!areReturnTypesCompatible(method, methods[j])) { - if (this.type.isInterface()) { - for (int m = length; --m >= 0;) - if (methods[m].declaringClass.id == TypeIds.T_JavaLangObject) - return true; // do not complain since the super interface already got blamed - } else { - if (method.declaringClass.isClass() || !this.type.implementsInterface(method.declaringClass, false)) - if (methods[j].declaringClass.isClass() || !this.type.implementsInterface(methods[j].declaringClass, false)) - continue next; // do not complain since the superclass already got blamed - } - // check to see if this is just a warning, if so report it & skip to next method - if (isUnsafeReturnTypeOverride(method, methods[j])) { - problemReporter(method).unsafeReturnTypeOverride(method, methods[j], this.type); - continue next; - } - continue match; - } - } +boolean checkInheritedReturnTypes(MethodBinding method, MethodBinding otherMethod) { + if (areReturnTypesCompatible(method, otherMethod)) return true; + + if (!this.type.isInterface()) + if (method.declaringClass.isClass() || !this.type.implementsInterface(method.declaringClass, false)) + if (otherMethod.declaringClass.isClass() || !this.type.implementsInterface(otherMethod.declaringClass, false)) + return true; // do not complain since the superclass already got blamed + + // check to see if this is just a warning, if so report it & skip to next method + if (isUnsafeReturnTypeOverride(method, otherMethod)) { + if (!method.declaringClass.implementsInterface(otherMethod.declaringClass, false)) + problemReporter(method).unsafeReturnTypeOverride(method, otherMethod, this.type); return true; } - problemReporter().inheritedMethodsHaveIncompatibleReturnTypes(this.type, methods, length); return false; } void checkMethods() { Index: compiler/org/eclipse/jdt/internal/compiler/lookup/MethodVerifier.java =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/MethodVerifier.java,v retrieving revision 1.98 diff -u -r1.98 MethodVerifier.java --- compiler/org/eclipse/jdt/internal/compiler/lookup/MethodVerifier.java 10 Oct 2008 17:24:31 -0000 1.98 +++ compiler/org/eclipse/jdt/internal/compiler/lookup/MethodVerifier.java 6 Nov 2008 19:01:22 -0000 @@ -82,25 +82,10 @@ // short is compatible with int, but as far as covariance is concerned, its not if (one.returnType.isBaseType()) return false; - if (!one.declaringClass.isInterface()) { - if (one.declaringClass.id == TypeIds.T_JavaLangObject) - return two.returnType.isCompatibleWith(one.returnType); // interface methods inherit from Object - return one.returnType.isCompatibleWith(two.returnType); - } - - // check for methods from Object, every interface inherits from Object - if (two.declaringClass.id == TypeIds.T_JavaLangObject) - return one.returnType.isCompatibleWith(two.returnType); - - // both are interfaces, see if they're related - if (one.declaringClass.implementsInterface(two.declaringClass, true)) - return one.returnType.isCompatibleWith(two.returnType); - if (two.declaringClass.implementsInterface(one.declaringClass, true)) - return two.returnType.isCompatibleWith(one.returnType); - - // unrelated interfaces... one must be a subtype of the other - return one.returnType.isCompatibleWith(two.returnType) - || two.returnType.isCompatibleWith(one.returnType); + if (!one.declaringClass.isInterface() && one.declaringClass.id == TypeIds.T_JavaLangObject) + return two.returnType.isCompatibleWith(one.returnType); // interface methods inherit from Object + + return one.returnType.isCompatibleWith(two.returnType); } boolean areTypesEqual(TypeBinding one, TypeBinding two) { if (one == two) return true; @@ -322,75 +307,78 @@ } void checkInheritedMethods(MethodBinding[] methods, int length) { - if (length > 1) { - int[] overriddenInheritedMethods = findOverriddenInheritedMethods(methods, length); - if (overriddenInheritedMethods != null) { - // detected some overridden methods that can be ignored when checking return types - // but cannot ignore an overridden inherited method completely when it comes to checking for bridge methods - int index = 0; - MethodBinding[] closestMethods = new MethodBinding[length]; - for (int i = 0; i < length; i++) - if (overriddenInheritedMethods[i] == 0) - closestMethods[index++] = methods[i]; - if (index > 1 && !checkInheritedReturnTypes(closestMethods, index)) - return; - } else if (!checkInheritedReturnTypes(methods, length)) { - return; - } - } + /* + 1. find concrete method + 2. if it doesn't exist then find first inherited abstract method whose return type is compatible with all others + if no such method exists then report incompatible return type error + otherwise report abstract method must be implemented + 3. if concrete method exists, check to see if its return type is compatible with all others + if it is then check concrete method against abstract methods + if its not, then find most specific abstract method & report abstract method must be implemented since concrete method is insufficient + if no most specific return type abstract method exists, then report incompatible return type with all inherited methods + */ - MethodBinding concreteMethod = null; - if (!this.type.isInterface()) { // ignore concrete methods for interfaces - for (int i = length; --i >= 0;) { // Remember that only one of the methods can be non-abstract - if (!methods[i].isAbstract()) { - concreteMethod = methods[i]; - break; - } - } - } + MethodBinding concreteMethod = this.type.isInterface() || methods[0].isAbstract() ? null : methods[0]; if (concreteMethod == null) { - if (!this.type.isAbstract()) { - for (int i = length; --i >= 0;) { - 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 { - problemReporter().abstractMethodMustBeImplemented(this.type, methods[0]); - } - return; + MethodBinding bestAbstractMethod = length == 1 ? methods[0] : findBestInheritedAbstractMethod(methods, length); + if (bestAbstractMethod == null) { + problemReporter().inheritedMethodsHaveIncompatibleReturnTypes(this.type, methods, length); + } else if (mustImplementAbstractMethod(bestAbstractMethod.declaringClass)) { + TypeDeclaration typeDeclaration = this.type.scope.referenceContext; + MethodBinding superclassAbstractMethod = methods[0]; + if (superclassAbstractMethod == bestAbstractMethod || superclassAbstractMethod.declaringClass.isInterface()) { + if (typeDeclaration != null) { + MethodDeclaration missingAbstractMethod = typeDeclaration.addMissingAbstractMethodFor(bestAbstractMethod); + missingAbstractMethod.scope.problemReporter().abstractMethodMustBeImplemented(this.type, bestAbstractMethod); + } else { + problemReporter().abstractMethodMustBeImplemented(this.type, bestAbstractMethod); + } + } else { + if (typeDeclaration != null) { + MethodDeclaration missingAbstractMethod = typeDeclaration.addMissingAbstractMethodFor(bestAbstractMethod); + missingAbstractMethod.scope.problemReporter().abstractMethodMustBeImplemented(this.type, bestAbstractMethod, superclassAbstractMethod); + } else { + problemReporter().abstractMethodMustBeImplemented(this.type, bestAbstractMethod, superclassAbstractMethod); } } } return; } + if (length < 2) return; // nothing else to check - if (length > 1) { - MethodBinding[] abstractMethods = new MethodBinding[length - 1]; - int index = 0; - for (int i = length; --i >= 0;) - if (methods[i] != concreteMethod) - abstractMethods[index++] = methods[i]; - checkConcreteInheritedMethod(concreteMethod, abstractMethods); + int index = length; + while (--index > 0 && checkInheritedReturnTypes(concreteMethod, methods[index])) {/*empty*/} + if (index > 0) { + // concreteMethod is not the best match + MethodBinding bestAbstractMethod = findBestInheritedAbstractMethod(methods, length); + if (bestAbstractMethod == null) + problemReporter().inheritedMethodsHaveIncompatibleReturnTypes(this.type, methods, length); + else // can only happen in >= 1.5 since return types must be equal prior to 1.5 + problemReporter().abstractMethodMustBeImplemented(this.type, bestAbstractMethod, concreteMethod); + return; } -} -boolean checkInheritedReturnTypes(MethodBinding[] methods, int length) { - MethodBinding first = methods[0]; - int index = length; - while (--index > 0 && areReturnTypesCompatible(first, methods[index])){/*empty*/} - if (index == 0) - return true; - - // All inherited methods do NOT have the same vmSignature - if (this.type.isInterface()) - for (int i = length; --i >= 0;) - if (methods[i].declaringClass.id == TypeIds.T_JavaLangObject) - return false; // do not complain since the super interface already got blamed - problemReporter().inheritedMethodsHaveIncompatibleReturnTypes(this.type, methods, length); + MethodBinding[] abstractMethods = new MethodBinding[length - 1]; + index = 0; + for (int i = 0; i < length; i++) + if (methods[i].isAbstract()) + abstractMethods[index++] = methods[i]; + if (index < abstractMethods.length) + System.arraycopy(abstractMethods, 0, abstractMethods = new MethodBinding[index], 0, index); + checkConcreteInheritedMethod(concreteMethod, abstractMethods); +} + +boolean checkInheritedReturnTypes(MethodBinding method, MethodBinding otherMethod) { + if (areReturnTypesCompatible(method, otherMethod)) return true; + + if (!this.type.isInterface()) + if (method.declaringClass.isClass() || !this.type.implementsInterface(method.declaringClass, false)) + if (otherMethod.declaringClass.isClass() || !this.type.implementsInterface(otherMethod.declaringClass, false)) + return true; // do not complain since the superclass already got blamed + return false; } + /* For each inherited method identifier (message pattern - vm signature minus the return type) if current method exists @@ -722,6 +710,23 @@ return null; // noop in 1.4 } +MethodBinding findBestInheritedAbstractMethod(MethodBinding[] methods, int length) { + findMethod : for (int i = 0; i < length; i++) { + MethodBinding method = methods[i]; + if (!method.isAbstract()) continue findMethod; + for (int j = 0; j < length; j++) { + if (i == j) continue; + if (!checkInheritedReturnTypes(method, methods[j])) { + if (this.type.isInterface() && methods[j].declaringClass.id == TypeIds.T_JavaLangObject) + return method; // do not complain since the super interface already got blamed + continue findMethod; + } + } + return method; + } + return null; +} + int[] findOverriddenInheritedMethods(MethodBinding[] methods, int length) { // NOTE assumes length > 1 // inherited methods are added as we walk up the superclass hierarchy, then each superinterface @@ -809,16 +814,15 @@ 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 + if (!mustImplementAbstractMethods()) return false; ReferenceBinding superclass = this.type.superclass(); if (declaringClass.isClass()) { while (superclass.isAbstract() && superclass != declaringClass) superclass = superclass.superclass(); // find the first concrete superclass or the abstract declaringClass } else { - if (this.type.implementsInterface(declaringClass, false)) { - if (this.type.isAbstract()) return false; // leave it for the subclasses + if (this.type.implementsInterface(declaringClass, false)) if (!superclass.implementsInterface(declaringClass, true)) // only if a superclass does not also implement the interface return true; - } while (superclass.isAbstract() && !superclass.implementsInterface(declaringClass, false)) superclass = superclass.superclass(); // find the first concrete superclass or the superclass which implements the interface }