diff --git a/base-test/org.eclipse.jdt.groovy.core.tests.builder/src/org/eclipse/jdt/core/groovy/tests/search/MethodReferenceSearchTests.java b/base-test/org.eclipse.jdt.groovy.core.tests.builder/src/org/eclipse/jdt/core/groovy/tests/search/MethodReferenceSearchTests.java index 8b88e0298f..16a59324b0 100644 --- a/base-test/org.eclipse.jdt.groovy.core.tests.builder/src/org/eclipse/jdt/core/groovy/tests/search/MethodReferenceSearchTests.java +++ b/base-test/org.eclipse.jdt.groovy.core.tests.builder/src/org/eclipse/jdt/core/groovy/tests/search/MethodReferenceSearchTests.java @@ -234,6 +234,46 @@ public void testOverloadedMethodReferences4() throws Exception { false, 0, "xxx"); } + @Test // https://github.com/groovy/groovy-eclipse/issues/373 + public void testOverloadedMethodReferences5() throws Exception { + doTestForTwoMethodReferences( + "class First {\n" + + " URL doSomething(String s, URL u) { }\n" + // search for references + " URL doSomething(Integer i, URL u) { }\n" + + "}", + "class Second {\n" + + " First first\n" + + " def other\n" + + " void xxx() {\n" + + " URL u = new URL('www.example.com')\n" + + " first.doSomething('ciao', u)\n" + //yes + " first.doSomething(1L, u)\n" + //no! + " first.&doSomething\n" + //yes + " }\n" + + "}", + true, 2, "doSomething"); // "true, 2" says both matches are in xxx() (aka Second.children[2]) + } + + @Test // https://github.com/groovy/groovy-eclipse/issues/373 + public void testOverloadedMethodReferences6() throws Exception { + doTestForTwoMethodReferences( + "class First {\n" + + " URL doSomething(Integer i, URL u) { }\n" + // search for references + " URL doSomething(String s, URL u) { }\n" + + "}", + "class Second {\n" + + " First first\n" + + " def other\n" + + " void xxx() {\n" + + " URL u = 'www.example.com'.toURL()\n" + + " first.doSomething(1, u)\n" + //yes + " first.doSomething('', u)\n" + //no! + " first.&doSomething\n" + //yes + " }\n" + + "}", + true, 2, "doSomething");// "true, 2" says both matches are in xxx() (aka Second.children[2]) + } + @Test public void testMethodWithDefaultParameters1() throws Exception { doTestForTwoMethodReferences( diff --git a/base/org.eclipse.jdt.groovy.core/src/org/eclipse/jdt/groovy/search/MethodReferenceSearchRequestor.java b/base/org.eclipse.jdt.groovy.core/src/org/eclipse/jdt/groovy/search/MethodReferenceSearchRequestor.java index d8fb7413b8..69c4ba8a07 100644 --- a/base/org.eclipse.jdt.groovy.core/src/org/eclipse/jdt/groovy/search/MethodReferenceSearchRequestor.java +++ b/base/org.eclipse.jdt.groovy.core/src/org/eclipse/jdt/groovy/search/MethodReferenceSearchRequestor.java @@ -23,6 +23,7 @@ import java.util.Set; import org.codehaus.groovy.ast.ASTNode; +import org.codehaus.groovy.ast.ClassHelper; import org.codehaus.groovy.ast.ClassNode; import org.codehaus.groovy.ast.MethodNode; import org.codehaus.groovy.ast.expr.StaticMethodCallExpression; @@ -87,9 +88,9 @@ public MethodReferenceSearchRequestor(MethodPattern pattern, SearchRequestor req } } if (!methods.isEmpty()) { - declaringType = methods.getLast().getDeclaringType(); - char[] superTypeName = declaringType.getElementName().toCharArray(); - char[] packageName = declaringType.getPackageFragment().getElementName().toCharArray(); + IType type = methods.getLast().getDeclaringType(); + char[] superTypeName = type.getElementName().toCharArray(); + char[] packageName = type.getPackageFragment().getElementName().toCharArray(); declaringQualifiedName = CharOperation.concat(packageName, superTypeName, '.'); } } @@ -117,24 +118,35 @@ public MethodReferenceSearchRequestor(MethodPattern pattern, SearchRequestor req protected static String[] getParameterTypeNames(MethodPattern pattern, String[] parameterTypeSignatures, IType declaringType) { int n = parameterTypeSignatures.length; String[] typeNames = new String[n]; - for (int i = 0; i < n; i += 1) { - if (pattern.parameterQualifications[i] != null || isPrimitiveType(pattern.parameterSimpleNames[i])) { - typeNames[i] = String.valueOf(CharOperation.concat(pattern.parameterQualifications[i], pattern.parameterSimpleNames[i], '.')); - } else { - int arrayCount = Signature.getArrayCount(parameterTypeSignatures[i]); - try { - String[][] resolved = declaringType.resolveType(String.valueOf(pattern.parameterSimpleNames[i], 0, pattern.parameterSimpleNames[i].length - (2*arrayCount))); - typeNames[i] = Signature.toQualifiedName(resolved[0]); - if (typeNames[i].charAt(0) == '.') { // default pkg - typeNames[i] = typeNames[i].substring(1); + if (declaringType != null) // TODO: Should searches like "main(String[])", which have null declaring type, check param types? + try { + int candidates = 0; + if (n > 0) { // check for method overloads + for (IMethod m : declaringType.getMethods()) { + if (equal(pattern.selector, m.getElementName()) && n == m.getNumberOfParameters()) { // TODO: What about variadic methods? + candidates += 1; } - while (arrayCount-- > 0) { - typeNames[i] += "[]"; + } + } + if (candidates > 1) { + for (int i = 0; i < n; i += 1) { + if (pattern.parameterQualifications[i] != null || isPrimitiveType(pattern.parameterSimpleNames[i])) { + typeNames[i] = String.valueOf(CharOperation.concat(pattern.parameterQualifications[i], pattern.parameterSimpleNames[i], '.')); + } else { + int arrayCount = Signature.getArrayCount(parameterTypeSignatures[i]); + String[][] resolved = declaringType.resolveType(String.valueOf(pattern.parameterSimpleNames[i], 0, pattern.parameterSimpleNames[i].length - (2*arrayCount))); + typeNames[i] = Signature.toQualifiedName(resolved[0]); + if (typeNames[i].charAt(0) == '.') { // default pkg + typeNames[i] = typeNames[i].substring(1); + } + while (arrayCount-- > 0) { + typeNames[i] += "[]"; + } } - } catch (Exception e) { - Util.log(e); } } + } catch (Exception e) { + Util.log(e); } return typeNames; } @@ -237,9 +249,10 @@ public VisitStatus acceptASTNode(ASTNode node, TypeLookupResult result, IJavaEle } /** - * When matching method references and declarations, we can't actually match - * on parameter types. Instead, we match on the number of parameterrs and - * assume that it is slightly more preceise than just matching on name. + * When matching method references and declarations, match on the number of + * parameterrs and assume that it is slightly more accurate than matching on + * name alone. If parameters and arguments are equal length, check the type + * compatibility of each pair. * * The heuristic that is used in this method is this: *