diff options
| author | Manoj Palat | 2016-04-15 11:06:49 +0000 |
|---|---|---|
| committer | Manoj Palat | 2016-04-18 02:23:24 +0000 |
| commit | d6cbb5f758ded5eeca102e76e753b701b04256d0 (patch) | |
| tree | 7a7b8866891098a588515526174d66c249932d23 | |
| parent | fb827f06601fdcd90551f67eba805b5f12b452c5 (diff) | |
| download | eclipse.jdt.core-d6cbb5f758ded5eeca102e76e753b701b04256d0.tar.gz eclipse.jdt.core-d6cbb5f758ded5eeca102e76e753b701b04256d0.tar.xz eclipse.jdt.core-d6cbb5f758ded5eeca102e76e753b701b04256d0.zip | |
Fix for Bug 484367 call hierarchy does not finds calls via method
references on interface implementations
2 files changed, 147 insertions, 2 deletions
diff --git a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/JavaSearchBugs8Tests.java b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/JavaSearchBugs8Tests.java index 373dc70ea3..748b8dfb51 100644 --- a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/JavaSearchBugs8Tests.java +++ b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/JavaSearchBugs8Tests.java @@ -4761,6 +4761,114 @@ public void testBug485805_001() throws CoreException { assertFalse("Failed", true); } } +public void testBug484367_0001() throws CoreException { + this.workingCopies = new ICompilationUnit[1]; + this.workingCopies[0] = getWorkingCopy("/JavaSearchBugs/src/X.java", + "interface Bar {\n" + + " public void print();\n" + + "}\n" + + "\n" + + "@FunctionalInterface\n" + + "interface Foo {\n" + + " void process(Bar bar);\n" + + "}\n" + + "class BarImpl implements Bar{\n" + + " @Override\n" + + "//call hierarchy on print does not finds invocation in the below TestMethod class \n" + + " public void print() {}\n" + + "}\n" + + "\n" + + "public class X {\n" + + " public void test(){\n" + + " Foo foo1 = (bar)->bar.print();\n" + + " Foo foo2 = Bar::print;\n" + + " }\n" + + "}\n" + ); + IType type = this.workingCopies[0].getType("BarImpl"); + IMethod method = type.getMethod("print", null); + search(method, REFERENCES, EXACT_RULE); + assertSearchResults( + "src/X.java void void X.test():<lambda #1>.process(Bar) [print()] EXACT_MATCH\n" + + "src/X.java void X.test() [print] EXACT_MATCH" + ); +} +public void testBug484367_0002() throws CoreException { + this.workingCopies = new ICompilationUnit[1]; + this.workingCopies[0] = getWorkingCopy("/JavaSearchBugs/src/X.java", + "interface Bar2 {\n" + + " public void print();\n" + + "}\n" + + "interface Bar1 extends Bar2 {\n" + + " public void print();\n" + + "}\n" + + "class Bar implements Bar1 {\n" + + "\n" + + " @Override\n" + + " public void print() {}\n" + + "}\n" + + "\n" + + "@FunctionalInterface\n" + + "interface Foo {\n" + + " void process(Bar bar);\n" + + "}\n" + + "class BarImpl extends Bar{\n" + + " public void print() {}\n" + + "}\n" + + "\n" + + "public class X {\n" + + " @SuppressWarnings(\"unused\")\n" + + " public void test(){\n" + + " Foo foo1 = (bar)->bar.print();\n" + + " Foo foo2 = Bar::print;\n" + + " }\n" + + "}\n" + ); + IType type = this.workingCopies[0].getType("Bar1"); + IMethod method = type.getMethod("print", null); + search(method, REFERENCES, EXACT_RULE); + assertSearchResults( + "src/X.java void void X.test():<lambda #1>.process(Bar) [print()] EXACT_MATCH\n" + + "src/X.java void X.test() [print] EXACT_MATCH" + ); +} + +public void testBug484367_0003() throws CoreException { + this.workingCopies = new ICompilationUnit[1]; + this.workingCopies[0] = getWorkingCopy("/JavaSearchBugs/src/X.java", + "interface Bar1 {\n" + + " public void print();\n" + + "}\n" + + "class Bar implements Bar1 {\n" + + "\n" + + " @Override\n" + + " public void print() {}\n" + + "}\n" + + "\n" + + "@FunctionalInterface\n" + + "interface Foo {\n" + + " void process(Bar bar);\n" + + "}\n" + + "class BarImpl extends Bar{\n" + + " public void print() {}\n" + + "}\n" + + "\n" + + "public class X {\n" + + " @SuppressWarnings(\"unused\")\n" + + " public void test(){\n" + + " Foo foo1 = (bar)->bar.print();\n" + + " Foo foo2 = Bar::print;\n" + + " }\n" + + "}\n" + ); + IType type = this.workingCopies[0].getType("Bar"); + IMethod method = type.getMethod("print", null); + search(method, REFERENCES, EXACT_RULE); + assertSearchResults( + "src/X.java void void X.test():<lambda #1>.process(Bar) [print()] EXACT_MATCH\n" + + "src/X.java void X.test() [print] EXACT_MATCH" + ); +} // Add new tests in JavaSearchBugs8Tests } diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/MethodLocator.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/MethodLocator.java index f31cbae336..eb56de5f6b 100644 --- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/MethodLocator.java +++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/MethodLocator.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2000, 2015 IBM Corporation and others. + * Copyright (c) 2000, 2016 IBM Corporation and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at @@ -150,6 +150,22 @@ protected boolean isVirtualInvoke(MethodBinding method, MessageSend messageSend) && !(method.isDefault() && this.pattern.focus != null && !CharOperation.equals(this.pattern.declaringPackageName, method.declaringClass.qualifiedPackageName())); } +protected ReferenceBinding checkMethodRef(MethodBinding method, ReferenceExpression referenceExpression) { + boolean result = (!method.isStatic() && !method.isPrivate() + && referenceExpression.isMethodReference() + && !(method.isDefault() && this.pattern.focus != null + && !CharOperation.equals(this.pattern.declaringPackageName, method.declaringClass.qualifiedPackageName()))); + if (result) { + Expression lhs = referenceExpression.lhs; + if (lhs instanceof NameReference) { + Binding binding = ((NameReference) lhs).binding; + if (binding instanceof ReferenceBinding) + return (ReferenceBinding) binding; + } + } + + return null; +} public int match(ASTNode node, MatchingNodeSet nodeSet) { int declarationsLevel = IMPOSSIBLE_MATCH; if (this.pattern.findReferences) { @@ -793,7 +809,28 @@ protected int resolveLevel(ReferenceExpression referenceExpression) { // receiver type if (this.pattern.declaringSimpleName == null && this.pattern.declaringQualification == null) return methodLevel; // since any declaring class will do - int declaringLevel = resolveLevelForType(this.pattern.declaringSimpleName, this.pattern.declaringQualification, method.declaringClass); + int declaringLevel; + ReferenceBinding ref = checkMethodRef(method, referenceExpression); + if (ref != null) { + declaringLevel = resolveLevelAsSubtype(this.pattern.declaringSimpleName, this.pattern.declaringQualification, ref, method.selector, method.parameters, ref.qualifiedPackageName(), method.isDefault()); + if (declaringLevel == IMPOSSIBLE_MATCH) { + if (method.declaringClass == null || this.allSuperDeclaringTypeNames == null) { + declaringLevel = INACCURATE_MATCH; + } else { + char[][][] superTypeNames = (method.isDefault() && this.pattern.focus == null) ? this.samePkgSuperDeclaringTypeNames: this.allSuperDeclaringTypeNames; + if (superTypeNames != null && resolveLevelAsSuperInvocation(ref, method.parameters, superTypeNames, true)) { + declaringLevel = methodLevel // since this is an ACCURATE_MATCH so return the possibly weaker match + | SUPER_INVOCATION_FLAVOR; // TODO: not an invocation really but ref -> add flavor to returned level + } + } + } + if ((declaringLevel & FLAVORS_MASK) != 0) { + // level got some flavors => return it + return declaringLevel; + } + } else { + declaringLevel = resolveLevelForType(this.pattern.declaringSimpleName, this.pattern.declaringQualification, method.declaringClass); + } return (methodLevel & MATCH_LEVEL_MASK) > (declaringLevel & MATCH_LEVEL_MASK) ? declaringLevel : methodLevel; // return the weaker match } |
