/* * Copyright 2009-2017 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.eclipse.jdt.core.groovy.tests.search; import static org.junit.Assert.assertEquals; import java.util.List; import org.codehaus.jdt.groovy.model.GroovyCompilationUnit; import org.eclipse.core.runtime.NullProgressMonitor; import org.eclipse.jdt.core.IJavaElement; import org.eclipse.jdt.core.IMethod; import org.eclipse.jdt.core.groovy.tests.MockSearchRequestor; import org.eclipse.jdt.core.search.IJavaSearchConstants; import org.eclipse.jdt.core.search.SearchEngine; import org.eclipse.jdt.core.search.SearchMatch; import org.eclipse.jdt.core.search.SearchParticipant; import org.eclipse.jdt.core.search.SearchPattern; import org.junit.Test; public final class MethodReferenceSearchTests extends SearchTestSuite { @Test public void testMethodReferencesInScript1() throws Exception { doTestForTwoMethodReferencesInScript("new First().xxx\nnew First()\n.\nxxx"); } @Test public void testMethodReferencesInScript1GRE_1180() throws Exception { doTestForTwoMethodReferencesInScript("new First().xxx\n'xxx'\n\"xxx\"\n\"\"\"xxx\"\"\"\nnew First()\n.\nxxx"); } @Test public void testMethodReferencesInScript2() throws Exception { doTestForTwoMethodReferencesInScript("First f = new First()\n f.xxx = f.xxx"); } @Test public void testMethodReferencesInScript3() throws Exception { doTestForTwoMethodReferencesInScript("First f = new First()\n \"$f.xxx\"\n\"$f.xxx\""); } @Test public void testMethodReferencesInScript4() throws Exception { doTestForTwoMethodReferencesInScriptWithQuotes("First f = new First()\n f.'xxx'\nf.'xxx'"); } @Test public void testMethodReferencesInScript5() throws Exception { doTestForTwoMethodReferencesInScript("First f = new First()\n f.xxx\ndef xxx = 0\nxxx++\nf.xxx"); } @Test public void testMethodReferencesInScript6() throws Exception { doTestForTwoMethodReferencesInScript("class SubClass extends First { } \n SubClass f = new SubClass()\n f.xxx\ndef xxx = 0\nxxx++\nf.xxx"); } @Test public void testMethodReferencesInScript7() throws Exception { createUnit("Other.groovy", "class Other { def xxx }"); doTestForTwoMethodReferencesInScript("class SubClass extends First { } \n SubClass f = new SubClass()\n f.xxx\nnew Other().xxx = 0\nf.xxx"); } @Test public void testMethodReferencesInScript8() throws Exception { doTestForTwoMethodReferencesInScript( "class SubClass extends First { } \n " + "def f = new SubClass()\n " + "f.xxx\n" + // here "f = 9\n" + "f.xxx\n" + // invalid reference "f = new SubClass()\n" + "f.xxx"); // here } @Test public void testMethodReferencesInClass1() throws Exception { doTestForTwoMethodReferencesInClass("class Second extends First { \ndef method() { this.xxx }\ndef xxx() { }\n def method2() { super.xxx }}"); } @Test public void testMethodReferencesInClass2() throws Exception { doTestForTwoMethodReferencesInClass("class Second extends First { \ndef method() { xxx }\ndef xxx() { }\n def method2(xxx) { xxx = super.xxx }}"); } @Test public void testMethodReferencesInClass3() throws Exception { doTestForTwoMethodReferencesInClass( "class Second extends First {\n" + " def method() {\n" + " this.xxx = 'nothing'\n" + // yes " }\n" + " def xxx() { }\n" + // no " def method2() {\n" + // no " def nothing = super.xxx()\n" + // yes...field reference used as a closure " }\n" + "}"); } @Test public void testMethodReferencesInClass4() throws Exception { createUnit("Third", "class Third {\n" + " def xxx() { }\n" + // no "}\n"); doTestForTwoMethodReferencesInClass( "class Second extends First {\n" + " def method() {\n" + " this.xxx = 'nothing'\n" + // yes " }\n" + " def xxx() { }\n" + // no " def method3(xxx) {\n" + // no " new Third().xxx()\n" + // no " xxx()\n" + // no...this will try to execute the xxx parameter, not the method " xxx = xxx\n" + // no, no " def nothing = super.xxx\n" + // yes...method reference passed as a closure " }\n" + "}"); } @Test public void testOverloadedMethodReferences1() throws Exception { // should match on the method reference with precise # of args as well as method reference with unmatched number of args doTestForTwoMethodReferences( "interface First {\n" + " void xxx()\n" + " void xxx(a)\n" + "}", "public class Second implements First {\n" + " public void other() {\n" + " xxx()\n" + " }\n" + " public void xxx() {\n" + " xxx(a)\n" + " }\n" + " void xxx(a) {\n" + " xxx(a,b)\n" + " }\n" + "}", false, 0, "xxx" ); } @Test public void testOverloadedMethodReferences2() throws Exception { // should match on the method reference with precise # of args as well as method reference with unmatched number of args doTestForTwoMethodReferences( "interface First {\n" + " void xxx(a)\n" + " void xxx()\n" + "}", "public class Second implements First {\n" + " public void other() {\n" + " xxx(a)\n" + " }\n" + " public void xxx() {\n" + " xxx()\n" + " }\n" + " void xxx(a) {\n" + " xxx(a,b)\n" + " }\n" + "}", false, 0, "xxx" ); } @Test public void testOverloadedMethodReferences3() throws Exception { // should match on the method reference with precise # of args as well as method reference with unmatched number of args createUnit("Sub", "interface Sub extends First { void xxx(a) }"); doTestForTwoMethodReferences( "interface First {\n" + " void xxx(a)\n" + " void xxx()\n" + "}", "public class Second implements Sub {\n" + " public void other() {\n" + " xxx(a)\n" + " }\n" + " public void xxx() {\n" + " xxx()\n" + " }\n" + " void xxx(a) {\n" + " xxx(a,b)\n" + " }\n" + "}", false, 0, "xxx" ); } @Test public void testOverloadedMethodReferences4() throws Exception { // should match on the method reference with precise # of args as well as method reference with unmatched number of args createUnit("Sub", "interface Sub extends First {\n" + " void xxx(a)\n" + " void xxx(a,b,c)\n" + "}"); doTestForTwoMethodReferences( "interface First {\n" + " void xxx(a,b)\n" + " void xxx(a)\n" + "}", "public class Second implements Sub {\n" + " public void other() {\n" + " First f\n" + " f.xxx(a,b,c)\n" + " }\n" + " public void xxx() {\n" + " xxx(a)\n" + " xxx(a,b,c)\n" + " Sub s\n" + " s.xxx(a)\n" + " s.xxx(a,b,c)\n" + " }\n" + " void xxx(a) {\n" + " Sub s\n" + " s.xxx(a,b)\n" + " }\n" + "}", false, 0, "xxx" ); } @Test public void testMethodWithDefaultParameters1() throws Exception { doTestForTwoMethodReferences( "class First {\n" + " void xxx(a, b = 9) { }\n" + " void xxx(a, b, c) { }\n" + "}", "class Second {\n" + " void other0() {\n" + " First f\n" + " f.xxx(a)\n" + " }\n" + " void other1() {\n" + " First f\n" + " f.xxx(a,b,c)\n" + " }\n" + " void other2() {\n" + " First f\n" + " f.xxx(a,b)\n" + " }\n" + "}", false, 0, "xxx" ); } @Test public void testMethodWithDefaultParameters2() throws Exception { doTestForTwoMethodReferences( "class First {\n" + " void xxx(a, b = 9) { }\n" + " void xxx(a, b, c) { }\n" + "}", "class Second {\n" + " void other0() {\n" + " First f\n" + " f.xxx(a)\n" + " }\n" + " void other1() {\n" + " First f\n" + " f.xxx(a,b,c)\n" + " }\n" + " void other2() {\n" + " First f\n" + " f.xxx\n" + " }\n" + "}", false, 0, "xxx" ); } @Test public void testConstructorReferenceSearch() throws Exception { String groovyContents = "package p\n" + "class Foo {\n" + " Foo() {\n" + " new Foo()\n" + " }\n" + " Foo(a) {\n" + " new Foo(a)\n" + " }\n" + "}"; String otherContents = "import p.Foo\n" + "new Foo()\n" + "new Foo(a)\n" + "new p.Foo()\n" + "new p.Foo(a)\n"; GroovyCompilationUnit first = createUnit("p", "Foo", groovyContents); createUnit("", "Other", otherContents); IMethod constructor = first.getType("Foo").getMethods()[0]; MockSearchRequestor requestor = new MockSearchRequestor(); SearchEngine engine = new SearchEngine(); engine.search(SearchPattern.createPattern(constructor, IJavaSearchConstants.REFERENCES), new SearchParticipant[] { SearchEngine.getDefaultSearchParticipant() }, SearchEngine.createJavaSearchScope(new IJavaElement[] { first.getPackageFragmentRoot() }, false), requestor, new NullProgressMonitor()); List<SearchMatch> matches = requestor.getMatches(); assertEquals("Incorrect number of matches:\n" + matches, 6, matches.size()); // two from Foo and two from other int fooCnt = 0, otherCnt = 0; for (SearchMatch match : matches) { if (match.getElement() instanceof IMethod) { if (((IMethod) match.getElement()).getResource().getName().equals("Foo.groovy")) { fooCnt++; } else if (((IMethod) match.getElement()).getResource().getName().equals("Other.groovy")) { otherCnt++; } } } assertEquals("Should have found 2 matches in Foo.groovy", 2, fooCnt); assertEquals("Should have found 4 matches in Other.groovy", 4, otherCnt); } //-------------------------------------------------------------------------- private void doTestForTwoMethodReferencesInScript(String secondContents) throws Exception { doTestForTwoMethodReferences(FIRST_CONTENTS_CLASS_FOR_METHODS, secondContents, true, 3, "xxx"); } private void doTestForTwoMethodReferencesInScriptWithQuotes(String secondContents) throws Exception { doTestForTwoMethodReferences(FIRST_CONTENTS_CLASS_FOR_METHODS, secondContents, true, 3, "'xxx'"); } private void doTestForTwoMethodReferencesInClass(String secondContents) throws Exception { doTestForTwoMethodReferences(FIRST_CONTENTS_CLASS_FOR_METHODS, secondContents, false, 0, "xxx"); } }