From 524cd03d4c8a175d1ab91e32ef393494e73e6ab7 Mon Sep 17 00:00:00 2001 From: Jon Bratseth Date: Wed, 16 Feb 2022 18:33:44 +0100 Subject: Find usages across filers and in lexical scope --- .../schema/findUsages/SdFindUsagesHandler.java | 40 ++++++++++++++-------- .../java/ai/vespa/intellij/PluginTestBase.java | 5 ++- .../vespa/intellij/findUsages/FindUsagesTest.java | 31 ++++++++--------- .../java/ai/vespa/intellij/model/SchemaTest.java | 1 - .../intellij/model/TestProjectDescriptor.java | 14 -------- 5 files changed, 44 insertions(+), 47 deletions(-) delete mode 100644 integration/intellij/src/test/java/ai/vespa/intellij/model/TestProjectDescriptor.java (limited to 'integration') diff --git a/integration/intellij/src/main/java/ai/vespa/intellij/schema/findUsages/SdFindUsagesHandler.java b/integration/intellij/src/main/java/ai/vespa/intellij/schema/findUsages/SdFindUsagesHandler.java index 4af276c26df..ebe21161667 100644 --- a/integration/intellij/src/main/java/ai/vespa/intellij/schema/findUsages/SdFindUsagesHandler.java +++ b/integration/intellij/src/main/java/ai/vespa/intellij/schema/findUsages/SdFindUsagesHandler.java @@ -13,7 +13,6 @@ import com.intellij.psi.PsiElement; import com.intellij.psi.PsiFile; import com.intellij.psi.PsiReference; import com.intellij.psi.search.GlobalSearchScope; -import com.intellij.psi.search.SearchScope; import com.intellij.psi.search.searches.ReferencesSearch; import com.intellij.psi.util.PsiTreeUtil; import com.intellij.usageView.UsageInfo; @@ -27,6 +26,7 @@ import java.util.List; * This class handles creating the "Find Usages" window. * * @author Shahar Ariel + * @author bratseth */ public class SdFindUsagesHandler extends FindUsagesHandler { @@ -38,42 +38,54 @@ public class SdFindUsagesHandler extends FindUsagesHandler { public boolean processElementUsages(PsiElement elementToSearch, Processor processor, FindUsagesOptions options) { - SearchScope scope = options.searchScope; - boolean searchText = options.isSearchForTextOccurrences && scope instanceof GlobalSearchScope; - if (options.isUsages) { if (elementToSearch instanceof SdFunctionDefinition) { findFunctionUsages((SdFunctionDefinition) elementToSearch, processor); } else { boolean success = - ReferencesSearch.search(createSearchParameters(elementToSearch, scope, options)) + ReferencesSearch.search(createSearchParameters(elementToSearch, options.searchScope, options)) .forEach((PsiReference ref) -> processor.process(new UsageInfo(ref))); if (!success) return false; } } - if (searchText) { + if (options.isSearchForTextOccurrences && options.searchScope instanceof GlobalSearchScope) { if (options.fastTrack != null) - options.fastTrack.searchCustom(consumer -> processUsagesInText(elementToSearch, processor, (GlobalSearchScope)scope)); + options.fastTrack.searchCustom(consumer -> processUsagesInText(elementToSearch, + processor, + (GlobalSearchScope)options.searchScope)); else - return processUsagesInText(elementToSearch, processor, (GlobalSearchScope)scope); + return processUsagesInText(elementToSearch, processor, (GlobalSearchScope)options.searchScope); } return true; } + /** + * Finds usages brute force. There is built-in search functionality in the IntelliJ SDK but I could + * not make it work across files. Since the lexical, scope of a rank profile will be quite small + * brute force might be faster in any case. + * + * Since search is done by a separate thread it cannot safely access the Psi tree. + * This splits Psi tree accesses into smaller chunks which are handed off to the Reader + * on the assumption that this keeps the IDE responsive. I have not found documentation + * on that. + */ private void findFunctionUsages(SdFunctionDefinition functionToFind, Processor processor) { String functionNameToFind = ReadAction.compute(functionToFind::getName); + Schema schema = ReadAction.compute(this::resolveSchema); + var rankProfile = ReadAction.compute(() -> schema.rankProfiles() + .get(PsiTreeUtil.getParentOfType(functionToFind, SdRankProfileDefinition.class).getName())); + findFunctionUsages(functionNameToFind, functionToFind, rankProfile, processor); + } + + private Schema resolveSchema() { PsiFile file = getPsiElement().getContainingFile(); - var rankProfileDefinition = PsiTreeUtil.getParentOfType(functionToFind, SdRankProfileDefinition.class); - Schema schema; if (file.getVirtualFile().getPath().endsWith(".profile")) { Path schemaFile = Path.fromString(file.getVirtualFile().getParent().getPath() + ".sd"); - schema = ReadAction.compute(() -> Schema.fromProjectFile(getProject(), schemaFile)); + return ReadAction.compute(() -> Schema.fromProjectFile(getProject(), schemaFile)); } else { // schema - schema = ReadAction.compute(() -> Schema.fromProjectFile(getProject(), Path.fromString(file.getVirtualFile().getPath()))); + return ReadAction.compute(() -> Schema.fromProjectFile(getProject(), Path.fromString(file.getVirtualFile().getPath()))); } - var rankProfile = ReadAction.compute(() -> schema.rankProfiles().get(rankProfileDefinition.getName())); - findFunctionUsages(functionNameToFind, functionToFind, rankProfile, processor); } private void findFunctionUsages(String functionNameToFind, diff --git a/integration/intellij/src/test/java/ai/vespa/intellij/PluginTestBase.java b/integration/intellij/src/test/java/ai/vespa/intellij/PluginTestBase.java index 1ba2dcf2785..699f4ebab42 100644 --- a/integration/intellij/src/test/java/ai/vespa/intellij/PluginTestBase.java +++ b/integration/intellij/src/test/java/ai/vespa/intellij/PluginTestBase.java @@ -1,7 +1,6 @@ // Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. package ai.vespa.intellij; -import ai.vespa.intellij.model.TestProjectDescriptor; import com.intellij.testFramework.LightProjectDescriptor; import com.intellij.testFramework.fixtures.LightJavaCodeInsightFixtureTestCase; import org.junit.Test; @@ -36,4 +35,8 @@ public class PluginTestBase extends LightJavaCodeInsightFixtureTestCase { @Test public void testDummy() {} + static class TestProjectDescriptor extends LightProjectDescriptor { + + } + } diff --git a/integration/intellij/src/test/java/ai/vespa/intellij/findUsages/FindUsagesTest.java b/integration/intellij/src/test/java/ai/vespa/intellij/findUsages/FindUsagesTest.java index c0ddb79606b..fd21e7ec4ad 100644 --- a/integration/intellij/src/test/java/ai/vespa/intellij/findUsages/FindUsagesTest.java +++ b/integration/intellij/src/test/java/ai/vespa/intellij/findUsages/FindUsagesTest.java @@ -2,7 +2,6 @@ package ai.vespa.intellij.findUsages; import ai.vespa.intellij.PluginTestBase; -import ai.vespa.intellij.schema.SdUtil; import ai.vespa.intellij.schema.findUsages.SdFindUsagesHandler; import ai.vespa.intellij.schema.model.Schema; import ai.vespa.intellij.schema.utils.Path; @@ -20,19 +19,6 @@ import java.util.List; */ public class FindUsagesTest extends PluginTestBase { - @Test - public void testTmp() { - useDir("src/test/applications/rankprofilemodularity"); - var tester = new UsagesTester("test.sd", getProject()); - tester.assertFunctionUsages("3 references in parent schema", 3, "outside_schema2", "fo2"); - } - - @Test - public void testTmp2() { - useDir("src/test/applications/rankprofilemodularity"); - var tester = new UsagesTester("test.sd", getProject()); - } - @Test public void testFindUsages() { useDir("src/test/applications/rankprofilemodularity"); @@ -41,16 +27,26 @@ public class FindUsagesTest extends PluginTestBase { tester.assertFunctionUsages("1 local ref in first-phase", 1, "in_schema2", "f2"); tester.assertFunctionUsages("2 local refs", 2, "in_schema2", "ff1"); tester.assertFunctionUsages("1 local ref", 1, "in_schema4", "f2"); - tester.assertFunctionUsages("1 local refa", 1, "outside_schema1", "local1"); + tester.assertFunctionUsages("1 local ref", 1, "outside_schema1", "local1"); tester.assertFunctionUsages("4 local refs", 4, "outside_schema1", "local2"); tester.assertFunctionUsages("3 refs in parent schema", 3, "outside_schema2", "fo2"); } + @Test + public void testUsageDetails() { + useDir("src/test/applications/rankprofilemodularity"); + var tester = new UsagesTester("test.sd", getProject()); + UsageInfo usage = tester.assertFunctionUsages("1 local ref", 1, "outside_schema1", "local1").get(0); + assertEquals(93, usage.getNavigationOffset()); + assertEquals(93 + 6, usage.getNavigationRange().getEndOffset()); + } + private static class UsagesTester { final Project project; final Schema schema; final SdFindUsagesHandler handler; + final MockUsageProcessor usageProcessor = new MockUsageProcessor(); UsagesTester(String schemaName, Project project) { this.project = project; @@ -58,13 +54,14 @@ public class FindUsagesTest extends PluginTestBase { this.handler = new SdFindUsagesHandler(schema.definition()); } - void assertFunctionUsages(String explanation, int expectedUsages, String profileName, String functionName) { + List assertFunctionUsages(String explanation, int expectedUsages, String profileName, String functionName) { var function = schema.rankProfiles().get(profileName).definedFunctions().get(functionName).get(0).definition(); - var usageProcessor = new MockUsageProcessor(); var options = new FindUsagesOptions(project); + usageProcessor.usages.clear(); options.isUsages = true; handler.processElementUsages(function, usageProcessor, options); assertEquals(explanation, expectedUsages, usageProcessor.usages.size()); + return usageProcessor.usages; } } diff --git a/integration/intellij/src/test/java/ai/vespa/intellij/model/SchemaTest.java b/integration/intellij/src/test/java/ai/vespa/intellij/model/SchemaTest.java index fb71e701411..9cf10cdffa2 100644 --- a/integration/intellij/src/test/java/ai/vespa/intellij/model/SchemaTest.java +++ b/integration/intellij/src/test/java/ai/vespa/intellij/model/SchemaTest.java @@ -51,7 +51,6 @@ public class SchemaTest extends PluginTestBase { assertEquals(2, profile.inherited().size()); assertEquals("outside_schema1", profile.inherited().get("outside_schema1").name()); assertEquals("outside_schema2", profile.inherited().get("outside_schema2").name()); - schema.functions().entrySet().stream().forEach(e -> System.out.println(e)); assertEquals("8 proper functions + first-phase", 9, schema.functions().size()); assertEquals(schema.rankProfiles().get("in_schema2").definedFunctions().get("ff1"), schema.functions().get("ff1")); diff --git a/integration/intellij/src/test/java/ai/vespa/intellij/model/TestProjectDescriptor.java b/integration/intellij/src/test/java/ai/vespa/intellij/model/TestProjectDescriptor.java deleted file mode 100644 index 5952b17a642..00000000000 --- a/integration/intellij/src/test/java/ai/vespa/intellij/model/TestProjectDescriptor.java +++ /dev/null @@ -1,14 +0,0 @@ -// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. -package ai.vespa.intellij.model; - -import com.intellij.testFramework.LightProjectDescriptor; - -/** - * Describes a project used in unit tests. - * https://plugins.jetbrains.com/docs/intellij/light-and-heavy-tests.html - * - * @author bratseth - */ -public class TestProjectDescriptor extends LightProjectDescriptor { - -} -- cgit v1.2.3