### 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.155 diff -u -r1.155 MethodVerifyTest.java --- src/org/eclipse/jdt/core/tests/compiler/regression/MethodVerifyTest.java 10 Jul 2008 15:42:56 -0000 1.155 +++ src/org/eclipse/jdt/core/tests/compiler/regression/MethodVerifyTest.java 24 Jul 2008 18:42:41 -0000 @@ -8676,4 +8676,91 @@ "----------\n" ); } +//https://bugs.eclipse.org/bugs/show_bug.cgi?id=238014 +public void test166() { + this.runNegativeTest( + new String[] { + "X.java", + "class X extends A implements I {}\n" + + "interface I { void foo(T item); }\n" + + "class A {\n" + + " public void foo(Object item) {}\n" + + " public void foo(String item) {}\n" + + "}\n" + }, + "----------\n" + + "1. ERROR in X.java (at line 1)\n" + + " class X extends A implements I {}\n" + + " ^\n" + + "Name clash: The method foo(Object) of type A has the same erasure as foo(T) of type I but does not override it\n" + + "----------\n" + ); +} +//https://bugs.eclipse.org/bugs/show_bug.cgi?id=238817 +public void test167() { + this.runConformTest( + new String[] { + "X.java", + "class X implements I, J {\n" + + " public void foo(T3 t, String s) {}\n" + + "}\n" + + "interface I { void foo(T1 t, U1 u); }\n" + + "interface J { void foo(T2 t, U2 u); }\n" + }, + "" + ); +} +//https://bugs.eclipse.org/bugs/show_bug.cgi?id=236096 +public void test168() { + this.runNegativeTest( + new String[] { + "X.java", + "class X extends Y {\n" + + " @Override void foo(M m) { }\n" + + " @Override M bar() { return null; }\n" + + "}\n" + + "class Y {\n" + + " class M {}\n" + + " void foo(M m) {}\n" + + " M bar() { return null; }\n" + + "}" + }, + "----------\n" + + "1. WARNING in X.java (at line 1)\n" + + " class X extends Y {\n" + + " ^\n" + + "Y is a raw type. References to generic type Y should be parameterized\n" + + "----------\n" + + "2. ERROR in X.java (at line 2)\n" + + " @Override void foo(M m) { }\n" + + " ^^^^^^^^\n" + + "Name clash: The method foo(Y.M) of type X has the same erasure as foo(Y.M) of type Y but does not override it\n" + + "----------\n" + + "3. ERROR in X.java (at line 2)\n" + + " @Override void foo(M m) { }\n" + + " ^^^^^^^^\n" + + mustOverrideMessage("foo(Y.M)", "X") + + "----------\n" + + "4. WARNING in X.java (at line 2)\n" + + " @Override void foo(M m) { }\n" + + " ^\n" + + "Y.M is a raw type. References to generic type Y.M should be parameterized\n" + + "----------\n" + + "5. WARNING in X.java (at line 3)\n" + + " @Override M bar() { return null; }\n" + + " ^\n" + + "Y.M is a raw type. References to generic type Y.M should be parameterized\n" + + "----------\n" + + "6. ERROR in X.java (at line 3)\n" + + " @Override M bar() { return null; }\n" + + " ^^^^^\n" + + "Name clash: The method bar() of type X has the same erasure as bar() of type Y but does not override it\n" + + "----------\n" + + "7. ERROR in X.java (at line 3)\n" + + " @Override M bar() { return null; }\n" + + " ^^^^^\n" + + mustOverrideMessage("bar()", "X") + + "----------\n" + ); +} } \ No newline at end of file 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.745 diff -u -r1.745 GenericTypeTest.java --- src/org/eclipse/jdt/core/tests/compiler/regression/GenericTypeTest.java 24 Jul 2008 13:05:10 -0000 1.745 +++ src/org/eclipse/jdt/core/tests/compiler/regression/GenericTypeTest.java 24 Jul 2008 18:42:40 -0000 @@ -45167,7 +45167,7 @@ } //https://bugs.eclipse.org/bugs/show_bug.cgi?id=235921 - variation public void test1344() throws Exception { - this.runConformTest( + this.runNegativeTest( new String[] { "X.java", // ================= "import java.util.*;\n" + @@ -45185,7 +45185,43 @@ " }\n" + "}\n", // ================= }, - ""); + "----------\n" + + "1. WARNING in X.java (at line 7)\n" + + " public class X extends Adapter {\n" + + " ^^^^^^^\n" + + "Adapter is a raw type. References to generic type Adapter should be parameterized\n" + + "----------\n" + + "2. WARNING in X.java (at line 8)\n" + + " public X.Setter makeSetter() {\n" + + " ^^^^^^^^\n" + + "Adapter.Setter is a raw type. References to generic type Adapter.Setter should be parameterized\n" + + "----------\n" + + "3. ERROR in X.java (at line 8)\n" + + " public X.Setter makeSetter() {\n" + + " ^^^^^^^^^^^^\n" + + "Name clash: The method makeSetter() of type X has the same erasure as makeSetter() of type Adapter but does not override it\n" + + "----------\n" + + "4. WARNING in X.java (at line 9)\n" + + " return new X().new Setter() {};\n" + + " ^\n" + + "X is a raw type. References to generic type X should be parameterized\n" + + "----------\n" + + "5. WARNING in X.java (at line 9)\n" + + " return new X().new Setter() {};\n" + + " ^^^^^^\n" + + "Adapter.Setter is a raw type. References to generic type Adapter.Setter should be parameterized\n" + + "----------\n" + + "6. WARNING in X.java (at line 12)\n" + + " List l = new ArrayList();\n" + + " ^^^^^^^^^^^^^^\n" + + "Adapter.Setter is a raw type. References to generic type Adapter.Setter should be parameterized\n" + + "----------\n" + + "7. WARNING in X.java (at line 12)\n" + + " List l = new ArrayList();\n" + + " ^^^^^^^^\n" + + "Adapter.Setter is a raw type. References to generic type Adapter.Setter should be parameterized\n" + + "----------\n" + ); } //https://bugs.eclipse.org/bugs/show_bug.cgi?id=235921 - variation public void test1345() throws Exception { @@ -45207,52 +45243,53 @@ " }\n" + "}\n", // ================= }, - "----------\n" + - "1. WARNING in X.java (at line 7)\n" + - " public class X extends Adapter {\n" + - " ^^^^^^^\n" + - "Adapter is a raw type. References to generic type Adapter should be parameterized\n" + - "----------\n" + - "2. WARNING in X.java (at line 8)\n" + - " public X.Setter makeSetter() {\n" + - " ^^^^^^^^\n" + - "Adapter.Setter is a raw type. References to generic type Adapter.Setter should be parameterized\n" + - "----------\n" + - "3. WARNING in X.java (at line 8)\n" + - " public X.Setter makeSetter() {\n" + - " ^^^^^^^^^^^^\n" + - "The method makeSetter() of type X should be tagged with @Override since it actually overrides a superclass method\n" + - "----------\n" + - "4. ERROR in X.java (at line 9)\n" + - " return (String) new X().new Setter() {};\n" + - " ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n" + - "Cannot cast from new Adapter.Setter(){} to String\n" + - "----------\n" + - "5. ERROR in X.java (at line 9)\n" + - " return (String) new X().new Setter() {};\n" + - " ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n" + - "Type mismatch: cannot convert from String to Adapter.Setter\n" + - "----------\n" + - "6. WARNING in X.java (at line 9)\n" + - " return (String) new X().new Setter() {};\n" + - " ^\n" + - "X is a raw type. References to generic type X should be parameterized\n" + - "----------\n" + - "7. WARNING in X.java (at line 9)\n" + - " return (String) new X().new Setter() {};\n" + - " ^^^^^^\n" + - "Adapter.Setter is a raw type. References to generic type Adapter.Setter should be parameterized\n" + - "----------\n" + - "8. WARNING in X.java (at line 12)\n" + - " List l = new ArrayList();\n" + - " ^^^^^^^^^^^^^^\n" + - "Adapter.Setter is a raw type. References to generic type Adapter.Setter should be parameterized\n" + - "----------\n" + - "9. WARNING in X.java (at line 12)\n" + - " List l = new ArrayList();\n" + - " ^^^^^^^^\n" + - "Adapter.Setter is a raw type. References to generic type Adapter.Setter should be parameterized\n" + - "----------\n"); + "----------\n" + + "1. WARNING in X.java (at line 7)\n" + + " public class X extends Adapter {\n" + + " ^^^^^^^\n" + + "Adapter is a raw type. References to generic type Adapter should be parameterized\n" + + "----------\n" + + "2. WARNING in X.java (at line 8)\n" + + " public X.Setter makeSetter() {\n" + + " ^^^^^^^^\n" + + "Adapter.Setter is a raw type. References to generic type Adapter.Setter should be parameterized\n" + + "----------\n" + + "3. ERROR in X.java (at line 8)\n" + + " public X.Setter makeSetter() {\n" + + " ^^^^^^^^^^^^\n" + + "Name clash: The method makeSetter() of type X has the same erasure as makeSetter() of type Adapter but does not override it\n" + + "----------\n" + + "4. ERROR in X.java (at line 9)\n" + + " return (String) new X().new Setter() {};\n" + + " ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n" + + "Cannot cast from new Adapter.Setter(){} to String\n" + + "----------\n" + + "5. ERROR in X.java (at line 9)\n" + + " return (String) new X().new Setter() {};\n" + + " ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n" + + "Type mismatch: cannot convert from String to Adapter.Setter\n" + + "----------\n" + + "6. WARNING in X.java (at line 9)\n" + + " return (String) new X().new Setter() {};\n" + + " ^\n" + + "X is a raw type. References to generic type X should be parameterized\n" + + "----------\n" + + "7. WARNING in X.java (at line 9)\n" + + " return (String) new X().new Setter() {};\n" + + " ^^^^^^\n" + + "Adapter.Setter is a raw type. References to generic type Adapter.Setter should be parameterized\n" + + "----------\n" + + "8. WARNING in X.java (at line 12)\n" + + " List l = new ArrayList();\n" + + " ^^^^^^^^^^^^^^\n" + + "Adapter.Setter is a raw type. References to generic type Adapter.Setter should be parameterized\n" + + "----------\n" + + "9. WARNING in X.java (at line 12)\n" + + " List l = new ArrayList();\n" + + " ^^^^^^^^\n" + + "Adapter.Setter is a raw type. References to generic type Adapter.Setter should be parameterized\n" + + "----------\n" + ); } //https://bugs.eclipse.org/bugs/show_bug.cgi?id=235921 - variation public void test1346() throws Exception { #P org.eclipse.jdt.core 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.89 diff -u -r1.89 MethodVerifier15.java --- compiler/org/eclipse/jdt/internal/compiler/lookup/MethodVerifier15.java 27 Jun 2008 16:04:01 -0000 1.89 +++ compiler/org/eclipse/jdt/internal/compiler/lookup/MethodVerifier15.java 24 Jul 2008 18:42:43 -0000 @@ -165,17 +165,8 @@ } if (this.type.addSyntheticBridgeMethod(originalInherited, currentMethod.original()) != null) { - for (int i = 0, l = allInheritedMethods.length; i < l; i++) { - MethodBinding otherInheritedMethod = allInheritedMethods[i]; - MethodBinding otherOriginal = otherInheritedMethod.original(); - // only check inherited methods that are different & come from separate inheritance paths - if (otherOriginal == originalInherited || otherOriginal == otherInheritedMethod) continue; - if (inheritedMethod.areParametersEqual(otherInheritedMethod)) continue; - // skip it if otherInheritedMethod is defined by a subtype of inheritedMethod's declaringClass - if (otherInheritedMethod.declaringClass.erasure() != inheritedMethod.declaringClass.erasure()) - if (otherInheritedMethod.declaringClass.findSuperTypeOriginatingFrom(inheritedMethod.declaringClass) != null) - continue; - if (detectInheritedNameClash(originalInherited, otherOriginal)) + for (int i = 0, l = allInheritedMethods == null ? 0 : allInheritedMethods.length; i < l; i++) { + if (allInheritedMethods[i] != null && detectInheritedNameClash(originalInherited, allInheritedMethods[i].original())) return; } } @@ -295,9 +286,6 @@ problemReporter().duplicateInheritedMethods(this.type, inheritedMethod, otherInheritedMethod); return; } - } else if (inheritedMethod.declaringClass.findSuperTypeOriginatingFrom(otherInheritedMethod.declaringClass) != null) { - // skip it if inheritedMethod is defined by a subtype of otherInheritedMethod declaringClass - return; } // the 2 inherited methods clash because of a parameterized type overrides a raw type @@ -437,19 +425,27 @@ } int index = -1; + int inheritedLength = inherited.length; MethodBinding[] matchingInherited = new MethodBinding[inherited.length]; - byte[] foundMatch = new byte[inherited.length]; + MethodBinding[] foundMatch = new MethodBinding[inherited.length]; // null is no match, otherwise value is matching currentMethod if (current != null) { for (int i = 0, length1 = current.length; i < length1; i++) { MethodBinding currentMethod = current[i]; - for (int j = 0, length2 = inherited.length; j < length2; j++) { + MethodBinding[] nonMatchingInherited = null; + for (int j = 0; j < inheritedLength; j++) { MethodBinding inheritedMethod = computeSubstituteMethod(inherited[j], currentMethod); if (inheritedMethod != null) { - if (foundMatch[j] == 0 && isSubstituteParameterSubsignature(currentMethod, inheritedMethod)) { + if (foundMatch[j] == null && isSubstituteParameterSubsignature(currentMethod, inheritedMethod)) { matchingInherited[++index] = inheritedMethod; - foundMatch[j] = 1; // cannot null out inherited methods + foundMatch[j] = currentMethod; } else { + // best place to check each currentMethod against each non-matching inheritedMethod checkForNameClash(currentMethod, inheritedMethod); + if (inheritedLength > 1) { + if (nonMatchingInherited == null) + nonMatchingInherited = new MethodBinding[inheritedLength]; + nonMatchingInherited[j] = inheritedMethod; + } } } } @@ -457,28 +453,36 @@ // see addtional comments in https://bugs.eclipse.org/bugs/show_bug.cgi?id=122881 // if (index > 0 && currentMethod.declaringClass.isInterface()) // only check when inherited methods are from interfaces // checkInheritedReturnTypes(matchingInherited, index + 1); - checkAgainstInheritedMethods(currentMethod, matchingInherited, index + 1, inherited); // pass in the length of matching + checkAgainstInheritedMethods(currentMethod, matchingInherited, index + 1, nonMatchingInherited); // pass in the length of matching while (index >= 0) matchingInherited[index--] = null; // clear the contents of the matching methods } } } - for (int i = 0, length = inherited.length; i < length; i++) { - if (foundMatch[i] == 1) continue; - + // skip tracks which inherited methods have matched other inherited methods + // either because they match the same currentMethod or match each other + boolean[] skip = new boolean[inheritedLength]; + for (int i = 0; i < inheritedLength; i++) { + if (skip[i]) continue; MethodBinding inheritedMethod = inherited[i]; - matchingInherited[++index] = inheritedMethod; - for (int j = i + 1; j < length; j++) { + MethodBinding matchMethod = foundMatch[i]; + if (matchMethod == null) + matchingInherited[++index] = inheritedMethod; + for (int j = i + 1; j < inheritedLength; j++) { MethodBinding otherInheritedMethod = inherited[j]; - if (foundMatch[j] == 1 || canSkipInheritedMethods(inheritedMethod, otherInheritedMethod)) + if (matchMethod == foundMatch[j] && matchMethod != null) + continue; // both inherited methods matched the same currentMethod + if (canSkipInheritedMethods(inheritedMethod, otherInheritedMethod)) continue; otherInheritedMethod = computeSubstituteMethod(otherInheritedMethod, inheritedMethod); if (otherInheritedMethod != null) { if (inheritedMethod.declaringClass != otherInheritedMethod.declaringClass && isSubstituteParameterSubsignature(inheritedMethod, otherInheritedMethod)) { + if (index == -1) + matchingInherited[++index] = inheritedMethod; matchingInherited[++index] = otherInheritedMethod; - foundMatch[j] = 1; // cannot null out inherited methods - } else { + skip[j] = true; + } else if (matchMethod == null && foundMatch[j] == null) { checkInheritedMethods(inheritedMethod, otherInheritedMethod); } } @@ -487,7 +491,7 @@ if (index > 0) checkInheritedMethods(matchingInherited, index + 1); // pass in the length of matching - else if (mustImplementAbstractMethods && index == 0 && matchingInherited[0].isAbstract()) + else if (mustImplementAbstractMethods && matchingInherited[0].isAbstract()) checkAbstractMethod(matchingInherited[0]); while (index >= 0) matchingInherited[index--] = null; // clear the previous contents of the matching methods } @@ -593,17 +597,22 @@ return substitute; } boolean detectInheritedNameClash(MethodBinding inherited, MethodBinding otherInherited) { - if (!inherited.areParameterErasuresEqual(otherInherited) || inherited.returnType.erasure() != otherInherited.returnType.erasure()) return false; + if (!inherited.areParameterErasuresEqual(otherInherited) || inherited.returnType.erasure() != otherInherited.returnType.erasure()) + return false; + // skip it if otherInherited is defined by a subtype of inherited's declaringClass + if (inherited.declaringClass.erasure() != otherInherited.declaringClass.erasure()) + if (inherited.declaringClass.findSuperTypeOriginatingFrom(otherInherited.declaringClass) != null) + return false; problemReporter().inheritedMethodsHaveNameClash(this.type, inherited, otherInherited); return true; } boolean detectNameClash(MethodBinding current, MethodBinding inherited) { MethodBinding original = inherited.original(); // can be the same as inherited - if (!current.areParameterErasuresEqual(original) || current.returnType.erasure() != original.returnType.erasure()) return false; + if (!current.areParameterErasuresEqual(original) || current.returnType.erasure() != original.returnType.erasure()) + return false; - problemReporter(current).methodNameClash(current, - inherited.declaringClass.isRawType() ? inherited : original); + problemReporter(current).methodNameClash(current, inherited.declaringClass.isRawType() ? inherited : original); return true; } public boolean doesMethodOverride(MethodBinding method, MethodBinding inheritedMethod) { @@ -744,8 +753,10 @@ } if (substituteMethod instanceof ParameterizedGenericMethodBinding) { + if (method.typeVariables != Binding.NO_TYPE_VARIABLES) + return !((ParameterizedGenericMethodBinding) substituteMethod).isRaw; // since substituteMethod has substituted type variables, method cannot have a generic signature AND no variables -> its a name clash if it does - return ! (hasGenericParameter(method) && method.typeVariables == Binding.NO_TYPE_VARIABLES); + return !hasGenericParameter(method); } // if method has its own variables, then substituteMethod failed bounds check in computeSubstituteMethod()