Download
Getting Started
Members
Projects
Community
Marketplace
Events
Planet Eclipse
Newsletter
Videos
Participate
Report a Bug
Forums
Mailing Lists
Wiki
IRC
How to Contribute
Working Groups
Automotive
Internet of Things
LocationTech
Long-Term Support
PolarSys
Science
OpenMDM
More
Community
Marketplace
Events
Planet Eclipse
Newsletter
Videos
Participate
Report a Bug
Forums
Mailing Lists
Wiki
IRC
How to Contribute
Working Groups
Automotive
Internet of Things
LocationTech
Long-Term Support
PolarSys
Science
OpenMDM
Toggle navigation
Bugzilla – Attachment 117239 Details for
Bug 249134
[compiler] error message (implement abstract method) not as intended
Home
|
New
|
Browse
|
Search
|
[?]
|
Reports
|
Requests
|
Help
|
Log In
[x]
|
Terms of Use
|
Copyright Agent
[patch]
Proposed patch with testcases
patch.txt (text/plain), 28.22 KB, created by
Kent Johnson
on 2008-11-06 14:59:00 EST
(
hide
)
Description:
Proposed patch with testcases
Filename:
MIME Type:
Creator:
Kent Johnson
Created:
2008-11-06 14:59:00 EST
Size:
28.22 KB
patch
obsolete
>### 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:57:49 -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<Pet> getPets() { return null; }\n" + > " ^^^^\n" + > "Type safety: The return type List<Pet> for getPets() from the type CatShopImpl needs unchecked conversion to conform to List<? extends Cat> 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<Pet> for getPets() from the type CatShopImpl needs unchecked conversion to conform to List<? extends Cat> 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<Object, String> {}\r\n" + > " ^^^^^^^^\n" + >- "The return type is incompatible with I<Object,String>.foo(String), HalfGenericSuper.foo(String)\n" + >+ "The type Concrete must implement the inherited abstract method I<Object,String>.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,149 @@ > "----------\n" > ); > } >+ >+//https://bugs.eclipse.org/bugs/show_bug.cgi?id=249134 >+public void test180() { >+ this.runNegativeTest( >+ new String[] { >+ "I.java", >+ "interface I {\n" + >+ " String m();\n" + >+ " Object n();\n" + >+ "}\n" + >+ "abstract class A {\n" + >+ " public abstract Object m();\n" + >+ " public abstract String n();\n" + >+ "}\n" + >+ "class A2 {\n" + >+ " public abstract Object m();\n" + >+ " public abstract String n();\n" + >+ "}\n", >+ "B.java", >+ "class B extends A implements I {}", >+ "B2.java", >+ "class B2 extends A2 implements I {}" >+ }, >+ "----------\n" + >+ "1. ERROR in I.java (at line 10)\n" + >+ " public abstract Object m();\n" + >+ " ^^^\n" + >+ "The abstract method m in type A2 can only be defined by an abstract class\n" + >+ "----------\n" + >+ "2. ERROR in I.java (at line 11)\n" + >+ " public abstract String n();\n" + >+ " ^^^\n" + >+ "The abstract method n in type A2 can only be defined by an abstract class\n" + >+ "----------\n" + >+ "----------\n" + >+ "1. ERROR in B.java (at line 1)\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 1)\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" + >+ "----------\n" + >+ "1. ERROR in B2.java (at line 1)\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", >+ null, >+ true, >+ null, >+ true, >+ false, >+ false >+ ); >+ this.runNegativeTest( >+ new String[] { >+ "B.java", >+ "class B extends A implements I {}", >+ "B2.java", >+ "class B2 extends A2 implements I {}" >+ }, >+ "----------\n" + >+ "1. ERROR in B.java (at line 1)\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 1)\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" + >+ "----------\n" + >+ "1. ERROR in B2.java (at line 1)\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", >+ null, >+ false >+ ); >+} >+ >+//https://bugs.eclipse.org/bugs/show_bug.cgi?id=249134 >+public void test181() { >+ this.runNegativeTest( >+ new String[] { >+ "I.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" + >+ "abstract class A2 {\n" + >+ " public Object m() { return null; }\n" + >+ " public String n() { return null; }\n" + >+ "}\n", >+ "B.java", >+ "class B extends A implements I {}", >+ "B2.java", >+ "class B2 extends A2 implements I {}" >+ }, >+ "----------\n" + >+ "1. ERROR in B.java (at line 1)\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" + >+ "----------\n" + >+ "1. ERROR in B2.java (at line 1)\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" >+ ); >+ this.runNegativeTest( >+ new String[] { >+ "B.java", >+ "class B extends A implements I {}", >+ "B2.java", >+ "class B2 extends A2 implements I {}" >+ }, >+ "----------\n" + >+ "1. ERROR in B.java (at line 1)\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" + >+ "----------\n" + >+ "1. ERROR in B2.java (at line 1)\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", >+ null, >+ false >+ ); >+} > } >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:57:47 -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:57:49 -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:57:50 -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:57:50 -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:57:50 -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:57:50 -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:57:50 -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 > }
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Diff
View Attachment As Raw
Actions:
View
|
Diff
Attachments on
bug 249134
:
113880
|
113997
|
114598
|
117235
|
117239
|
118174
|
118376
|
118514