diff --git a/base-test/org.eclipse.jdt.groovy.core.tests.compiler/src/org/eclipse/jdt/groovy/core/tests/xform/StaticCompilationTests.java b/base-test/org.eclipse.jdt.groovy.core.tests.compiler/src/org/eclipse/jdt/groovy/core/tests/xform/StaticCompilationTests.java index 4a39dfb1fd..ae4970c2bc 100644 --- a/base-test/org.eclipse.jdt.groovy.core.tests.compiler/src/org/eclipse/jdt/groovy/core/tests/xform/StaticCompilationTests.java +++ b/base-test/org.eclipse.jdt.groovy.core.tests.compiler/src/org/eclipse/jdt/groovy/core/tests/xform/StaticCompilationTests.java @@ -69,7 +69,7 @@ public void testCompileStatic1() { "1. ERROR in Main.groovy (at line 5)\n" + "\tls.add('abc')\n" + "\t^^^^^^^^^^^^^\n" + - "Groovy:[Static type checking] - Cannot call java.util.ArrayList #add(java.lang.Integer) with arguments [java.lang.String] \n" + + "Groovy:[Static type checking] - Cannot find matching method java.util.ArrayList#add(java.lang.String). Please check if the declared type is correct and if the method exists.\n" + "----------\n"); } diff --git a/base-test/org.eclipse.jdt.groovy.core.tests.compiler/src/org/eclipse/jdt/groovy/core/tests/xform/TypeCheckedTests.java b/base-test/org.eclipse.jdt.groovy.core.tests.compiler/src/org/eclipse/jdt/groovy/core/tests/xform/TypeCheckedTests.java index 2531902b4b..6a0d8ec1dd 100644 --- a/base-test/org.eclipse.jdt.groovy.core.tests.compiler/src/org/eclipse/jdt/groovy/core/tests/xform/TypeCheckedTests.java +++ b/base-test/org.eclipse.jdt.groovy.core.tests.compiler/src/org/eclipse/jdt/groovy/core/tests/xform/TypeCheckedTests.java @@ -73,7 +73,7 @@ public void testTypeChecked2() { "1. ERROR in Foo.groovy (at line 6)\n" + "\tls.add(\'abc\')\n" + "\t^^^^^^^^^^^^^\n" + - "Groovy:[Static type checking] - Cannot call java.util.ArrayList #add(java.lang.Integer) with arguments [java.lang.String] \n" + + "Groovy:[Static type checking] - Cannot find matching method java.util.ArrayList#add(java.lang.String). Please check if the declared type is correct and if the method exists.\n" + "----------\n"); } @@ -214,6 +214,40 @@ public void testTypeChecked9() { runNegativeTest(sources, ""); } + @Test + public void testTypeChecked6882() { + //@formatter:off + String[] sources = { + "Main.groovy", + "class B {\n" + + " void m() {\n" + + " print 'B'\n" + + " }\n" + + "}\n" + + "@groovy.transform.TypeChecked\n" + + "class C extends B {\n" + + " @Override\n" + + " void m() {\n" + + " print 'C'\n" + + " }\n" + + " void test() {\n" + + " def x = new Runnable() {\n" + + " @Override\n" + + " void run() {\n" + + " m()\n" + // Reference to method is ambiguous. Cannot choose between [void C#m(), void B#m()] + " }\n" + + " }\n" + + " x.run()\n" + + " m()\n" + + " }\n" + + "}\n" + + "new C().test()\n", + }; + //@formatter:on + + runConformTest(sources, "CC"); + } + @Test public void testTypeChecked7333() { //@formatter:off diff --git a/base/org.codehaus.groovy25/src/org/codehaus/groovy/transform/stc/StaticTypeCheckingSupport.java b/base/org.codehaus.groovy25/src/org/codehaus/groovy/transform/stc/StaticTypeCheckingSupport.java index 7b0f5dc546..4d281393be 100644 --- a/base/org.codehaus.groovy25/src/org/codehaus/groovy/transform/stc/StaticTypeCheckingSupport.java +++ b/base/org.codehaus.groovy25/src/org/codehaus/groovy/transform/stc/StaticTypeCheckingSupport.java @@ -1103,7 +1103,7 @@ Person foo(B i){...} Person p = foo(b) */ - Map declaringAndActualGenericsTypeMap = GenericsUtils.makeDeclaringAndActualGenericsTypeMap(declaringClassForDistance, actualReceiverForDistance); + Map declaringAndActualGenericsTypeMap = GenericsUtils.makeDeclaringAndActualGenericsTypeMapOfExactType(declaringClassForDistance, actualReceiverForDistance); Parameter[] params = makeRawTypes(safeNode.getParameters(), declaringAndActualGenericsTypeMap); int dist = measureParametersAndArgumentsDistance(params, safeArgs); if (dist >= 0) { @@ -1238,7 +1238,12 @@ private static Collection removeCovariantsAndInterfaceEquivalents(Co MethodNode two = list.get(j); if (toBeRemoved.contains(two)) continue; if (one.getParameters().length == two.getParameters().length) { + /* GRECLIPSE edit -- GROOVY-6882, GROOVY-6970 if (areOverloadMethodsInSameClass(one, two)) { + */ + ClassNode oneDC = one.getDeclaringClass(), twoDC = two.getDeclaringClass(); + if (oneDC == twoDC) { + // GRECLIPSE end if (ParameterUtils.parametersEqual(one.getParameters(), two.getParameters())) { removeMethodWithSuperReturnType(toBeRemoved, one, two); } else { @@ -1247,10 +1252,25 @@ private static Collection removeCovariantsAndInterfaceEquivalents(Co // in that case, Java marks the Object version as synthetic removeSyntheticMethodIfOne(toBeRemoved, one, two); } + /* GRECLIPSE edit -- GROOVY-6882, GROOVY-6970 } else if (areEquivalentInterfaceMethods(one, two)) { // GROOVY-6970 choose between equivalent interface methods removeMethodInSuperInterface(toBeRemoved, one, two); } + */ + } else if (!oneDC.equals(twoDC)) { + if (ParameterUtils.parametersEqual(one.getParameters(), two.getParameters())) { + // GROOVY-6882, GROOVY-6970: drop overridden or interface equivalent method + if (twoDC.isInterface() ? oneDC.implementsInterface(twoDC) + : oneDC.isDerivedFrom(twoDC)) { + toBeRemoved.add(two); + } else if (oneDC.isInterface() ? twoDC.isInterface() + : twoDC.isDerivedFrom(oneDC)) { + toBeRemoved.add(one); + } + } + } + // GRECLIPSE end } } } @@ -1260,6 +1280,7 @@ private static Collection removeCovariantsAndInterfaceEquivalents(Co return result; } + /* GRECLIPSE edit private static void removeMethodInSuperInterface(List toBeRemoved, MethodNode one, MethodNode two) { ClassNode oneDC = one.getDeclaringClass(); ClassNode twoDC = two.getDeclaringClass(); @@ -1276,6 +1297,7 @@ private static boolean areEquivalentInterfaceMethods(MethodNode one, MethodNode && two.getDeclaringClass().isInterface() && ParameterUtils.parametersEqual(one.getParameters(), two.getParameters()); } + */ private static void removeSyntheticMethodIfOne(List toBeRemoved, MethodNode one, MethodNode two) { if (one.isSynthetic() && !two.isSynthetic()) { @@ -1302,9 +1324,11 @@ private static boolean isCovariant(ClassNode left, ClassNode right) { return left.isDerivedFrom(right) || left.implementsInterface(right); } + /* GRECLIPSE edit private static boolean areOverloadMethodsInSameClass(MethodNode one, MethodNode two) { return one.getName().equals(two.getName()) && one.getDeclaringClass() == two.getDeclaringClass(); } + */ /** * Given a receiver and a method node, parameterize the method arguments using diff --git a/base/org.codehaus.groovy30/src/org/codehaus/groovy/transform/stc/StaticTypeCheckingSupport.java b/base/org.codehaus.groovy30/src/org/codehaus/groovy/transform/stc/StaticTypeCheckingSupport.java index e19d6717c5..8463f77293 100644 --- a/base/org.codehaus.groovy30/src/org/codehaus/groovy/transform/stc/StaticTypeCheckingSupport.java +++ b/base/org.codehaus.groovy30/src/org/codehaus/groovy/transform/stc/StaticTypeCheckingSupport.java @@ -1039,7 +1039,7 @@ Person foo(B i){...} Person p = foo(b) */ - Map declaringAndActualGenericsTypeMap = GenericsUtils.makeDeclaringAndActualGenericsTypeMap(declaringClassForDistance, actualReceiverForDistance); + Map declaringAndActualGenericsTypeMap = GenericsUtils.makeDeclaringAndActualGenericsTypeMapOfExactType(declaringClassForDistance, actualReceiverForDistance); Parameter[] params = makeRawTypes(safeNode.getParameters(), declaringAndActualGenericsTypeMap); int dist = measureParametersAndArgumentsDistance(params, safeArgs); if (dist >= 0) { @@ -1162,7 +1162,12 @@ private static Collection removeCovariantsAndInterfaceEquivalents(fi MethodNode two = list.get(j); if (toBeRemoved.contains(two)) continue; if (one.getParameters().length == two.getParameters().length) { + /* GRECLIPSE edit -- GROOVY-6882, GROOVY-6970 if (areOverloadMethodsInSameClass(one, two)) { + */ + ClassNode oneDC = one.getDeclaringClass(), twoDC = two.getDeclaringClass(); + if (oneDC == twoDC) { + // GRECLIPSE end if (ParameterUtils.parametersEqual(one.getParameters(), two.getParameters())) { removeMethodWithSuperReturnType(toBeRemoved, one, two); } else { @@ -1171,10 +1176,25 @@ private static Collection removeCovariantsAndInterfaceEquivalents(fi // in that case, Java marks the Object version as synthetic removeSyntheticMethodIfOne(toBeRemoved, one, two); } + /* GRECLIPSE edit -- GROOVY-6882, GROOVY-6970 } else if (areEquivalentInterfaceMethods(one, two)) { // GROOVY-6970: choose between equivalent interface methods removeMethodInSuperInterface(toBeRemoved, one, two); } + */ + } else if (!oneDC.equals(twoDC)) { + if (ParameterUtils.parametersEqual(one.getParameters(), two.getParameters())) { + // GROOVY-6882, GROOVY-6970: drop overridden or interface equivalent method + if (twoDC.isInterface() ? oneDC.implementsInterface(twoDC) + : oneDC.isDerivedFrom(twoDC)) { + toBeRemoved.add(two); + } else if (oneDC.isInterface() ? twoDC.isInterface() + : twoDC.isDerivedFrom(oneDC)) { + toBeRemoved.add(one); + } + } + } + // GRECLIPSE end } } } @@ -1184,6 +1204,7 @@ private static Collection removeCovariantsAndInterfaceEquivalents(fi return result; } + /* GRECLIPSE edit private static void removeMethodInSuperInterface(final List toBeRemoved, final MethodNode one, final MethodNode two) { ClassNode oneDC = one.getDeclaringClass(); ClassNode twoDC = two.getDeclaringClass(); @@ -1200,6 +1221,7 @@ private static boolean areEquivalentInterfaceMethods(final MethodNode one, final && two.getDeclaringClass().isInterface() && ParameterUtils.parametersEqual(one.getParameters(), two.getParameters())); } + */ private static void removeSyntheticMethodIfOne(final List toBeRemoved, final MethodNode one, final MethodNode two) { if (one.isSynthetic() && !two.isSynthetic()) { @@ -1226,9 +1248,11 @@ private static boolean isCovariant(final ClassNode left, final ClassNode right) return (left.isDerivedFrom(right) || left.implementsInterface(right)); } + /* GRECLIPSE edit private static boolean areOverloadMethodsInSameClass(final MethodNode one, final MethodNode two) { return (one.getName().equals(two.getName()) && one.getDeclaringClass() == two.getDeclaringClass()); } + */ /** * Given a receiver and a method node, parameterize the method arguments using