diff options
author | Jon Bratseth <bratseth@gmail.com> | 2022-02-18 15:40:43 +0100 |
---|---|---|
committer | Jon Bratseth <bratseth@gmail.com> | 2022-02-18 15:40:43 +0100 |
commit | 99dbe4e87730d1eb9e6d29a61b4789d3308e59a1 (patch) | |
tree | 1ea1ec9ec2807d04b58b55f766801129fe2a4c4e /integration | |
parent | f087f021607d473defd070a6ea7bc231dd2b78d4 (diff) |
Find profile definition
Diffstat (limited to 'integration')
5 files changed, 107 insertions, 3 deletions
diff --git a/integration/intellij/src/main/java/ai/vespa/intellij/schema/findUsages/RankProfileDefinitionFinder.java b/integration/intellij/src/main/java/ai/vespa/intellij/schema/findUsages/RankProfileDefinitionFinder.java new file mode 100644 index 00000000000..651b7836e5d --- /dev/null +++ b/integration/intellij/src/main/java/ai/vespa/intellij/schema/findUsages/RankProfileDefinitionFinder.java @@ -0,0 +1,68 @@ +// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package ai.vespa.intellij.schema.findUsages; + +import ai.vespa.intellij.schema.model.RankProfile; +import ai.vespa.intellij.schema.psi.SdRankProfileDefinition; +import ai.vespa.intellij.schema.utils.AST; +import com.intellij.openapi.application.ReadAction; +import com.intellij.openapi.progress.ProgressIndicatorProvider; +import com.intellij.psi.PsiElement; +import com.intellij.psi.search.SearchScope; +import com.intellij.psi.util.PsiTreeUtil; +import com.intellij.usageView.UsageInfo; +import com.intellij.util.Processor; + +import java.util.HashSet; +import java.util.Set; + +/** + * Finds the definition of a function. + * + * @author bratseth + */ +public class RankProfileDefinitionFinder extends UsageFinder { + + private final PsiElement referringElement; + private final String profileNameToFind; + private final Set<RankProfile> visited = new HashSet<>(); + + public RankProfileDefinitionFinder(PsiElement referringElement, SearchScope scope, Processor<? super UsageInfo> processor) { + super(scope, processor); + this.referringElement = referringElement; + this.profileNameToFind = ReadAction.compute(() -> referringElement.getText()); + } + + /** Returns true if this finder is appropriate for this task, false if others should be tried. */ + public boolean findDefinition() { + RankProfile referringProfile = ReadAction.compute(() -> resolveReferringProfile()); + if (referringProfile == null) return false; + findDefinitionAbove(referringProfile); + return true; + } + + /** + * Returns the profile which inherits the one we're to find the definition of, or null if + * referringElement is not the name of an inherited profile. + */ + private RankProfile resolveReferringProfile() { + SdRankProfileDefinition profileDefinition = PsiTreeUtil.getParentOfType(referringElement, SdRankProfileDefinition.class); + if (profileDefinition == null) return null; + if (AST.inherits(profileDefinition).stream().noneMatch(node -> node.getText().equals(referringElement.getText()))) return null; + return resolveSchema(profileDefinition).rankProfiles().get(profileDefinition.getName()); + } + + private void findDefinitionAbove(RankProfile profile) { + ProgressIndicatorProvider.checkCanceled(); + if ( ! visited.add(profile)) return; + ReadAction.compute(() -> findDefinitionIn(profile)); + for (var parent : ReadAction.compute(() -> profile.parents().values())) + findDefinitionAbove(parent); + } + + private boolean findDefinitionIn(RankProfile profile) { + if (profileNameToFind.equals(profile.name())) + processor().process(new UsageInfo(profile.definition())); + return true; + } + +} 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 15f3d8f3b29..7ff14b69368 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 @@ -33,8 +33,10 @@ public class SdFindUsagesHandler extends FindUsagesHandler { else if (elementToSearch instanceof SdRankProfileDefinition) { new RankProfileUsageFinder((SdRankProfileDefinition) elementToSearch, options.searchScope, processor).findUsages(); } - else { - new FunctionDefinitionFinder(elementToSearch, options.searchScope, processor).findDefinition(); + else { // try find definitions + boolean suitable = new RankProfileDefinitionFinder(elementToSearch, options.searchScope, processor).findDefinition(); + if ( ! suitable) + new FunctionDefinitionFinder(elementToSearch, options.searchScope, processor).findDefinition(); } } diff --git a/integration/intellij/src/main/java/ai/vespa/intellij/schema/utils/Tokens.java b/integration/intellij/src/main/java/ai/vespa/intellij/schema/utils/Tokens.java index 5d4ae376c77..f706ebd756d 100644 --- a/integration/intellij/src/main/java/ai/vespa/intellij/schema/utils/Tokens.java +++ b/integration/intellij/src/main/java/ai/vespa/intellij/schema/utils/Tokens.java @@ -24,9 +24,10 @@ public class Tokens { * Advances to the next token, if it is of the given type. * * @return true if the current token was of the given type and we advanced it, false - * if it was not and nothing was changed + * if it was not and nothing was changed */ public boolean skip(IElementType... tokenTypes) { + if (current() == null) return false; boolean is = is(tokenTypes); if (is) i++; @@ -40,6 +41,7 @@ public class Tokens { * if it was not and nothing was changed */ public boolean skipWhitespace() { + if (current() == null) return false; boolean is = isWhitespace(); if (is) i++; @@ -48,6 +50,7 @@ public class Tokens { /** Returns whether the current token is of the given type */ public boolean is(IElementType... tokenTypes) { + if (current() == null) return false; for (IElementType type : tokenTypes) if (current().getElementType() == type) return true; return false; @@ -55,11 +58,13 @@ public class Tokens { /** Returns whether the current token is whitespace */ public boolean isWhitespace() { + if (current() == null) return false; return current().getPsi() instanceof PsiWhiteSpace; } /** Returns whether the current token is an element */ public boolean isElement() { + if (current() == null) return false; return current() instanceof LeafPsiElement; } diff --git a/integration/intellij/src/test/java/ai/vespa/intellij/findUsages/FindRankProfileDefinitionTest.java b/integration/intellij/src/test/java/ai/vespa/intellij/findUsages/FindRankProfileDefinitionTest.java new file mode 100644 index 00000000000..5694c0587a1 --- /dev/null +++ b/integration/intellij/src/test/java/ai/vespa/intellij/findUsages/FindRankProfileDefinitionTest.java @@ -0,0 +1,20 @@ +// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package ai.vespa.intellij.findUsages; + +import ai.vespa.intellij.PluginTestBase; +import com.intellij.usageView.UsageInfo; +import org.junit.Test; + +/** + * @author bratseth + */ +public class FindRankProfileDefinitionTest extends PluginTestBase { + + @Test + public void testFindUsagesInRankProfileModularity() { + useDir("src/test/applications/rankprofilemodularity"); + var tester = new UsagesTester("test.sd", getProject()); + UsageInfo usage = tester.findRankProfileDefinition("outside_schema1", 40); + } + +} diff --git a/integration/intellij/src/test/java/ai/vespa/intellij/findUsages/UsagesTester.java b/integration/intellij/src/test/java/ai/vespa/intellij/findUsages/UsagesTester.java index 319240b9ceb..c1e6c9282b6 100644 --- a/integration/intellij/src/test/java/ai/vespa/intellij/findUsages/UsagesTester.java +++ b/integration/intellij/src/test/java/ai/vespa/intellij/findUsages/UsagesTester.java @@ -52,6 +52,15 @@ class UsagesTester { return usageProcessor.usages.get(0); } + /** Finds the rank profile referred (by inheritance) at the given character offset in the given profile. */ + UsageInfo findRankProfileDefinition(String profileName, int offset) { + PsiElement referringElement = schema.rankProfiles().get(profileName).definition().findElementAt(offset); + findUsages(referringElement); + assertEquals("Expected to find definition of " + referringElement.getText(), + 1, usageProcessor.usages.size()); + return usageProcessor.usages.get(0); + } + private void findUsages(PsiElement element) { var options = new FindUsagesOptions(project); usageProcessor.usages.clear(); |