From 12ff3a9f2821829ff133456a79da7ed25907f836 Mon Sep 17 00:00:00 2001 From: Bas Leijdekkers Date: Thu, 16 Apr 2020 17:30:24 +0200 Subject: [PATCH] SSR: add javadoc GitOrigin-RevId: 5431780a0728d4cb9724c2f09403a4f81dd2d24e --- .../matcher/handlers/ExpressionHandler.java | 12 ++--- .../StructuralSearchProfile.java | 46 +++++++++++++++++++ .../impl/matcher/CompiledPattern.java | 5 +- .../impl/matcher/GlobalMatchingVisitor.java | 43 ++++++++++------- .../impl/matcher/compiler/WordOptimizer.java | 6 ++- .../matcher/handlers/MatchingHandler.java | 10 +++- .../impl/matcher/handlers/SimpleHandler.java | 8 ++-- 7 files changed, 97 insertions(+), 33 deletions(-) diff --git a/java/structuralsearch-java/src/com/intellij/structuralsearch/impl/matcher/handlers/ExpressionHandler.java b/java/structuralsearch-java/src/com/intellij/structuralsearch/impl/matcher/handlers/ExpressionHandler.java index 76c8e272cc4a..e23b0fe0b4aa 100644 --- a/java/structuralsearch-java/src/com/intellij/structuralsearch/impl/matcher/handlers/ExpressionHandler.java +++ b/java/structuralsearch-java/src/com/intellij/structuralsearch/impl/matcher/handlers/ExpressionHandler.java @@ -1,4 +1,4 @@ -// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. +// Copyright 2000-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. package com.intellij.structuralsearch.impl.matcher.handlers; import com.intellij.psi.PsiElement; @@ -6,18 +6,16 @@ import com.intellij.psi.PsiExpressionStatement; import com.intellij.structuralsearch.impl.matcher.MatchContext; /** - * Handler for substitution expression search + * Handler for expression search. The pattern for an expression includes an unnecessary {@code PsiExpressionStatement}, + * this is skipped by this {@code MatchingHandler} */ public class ExpressionHandler extends MatchingHandler { @Override public boolean match(PsiElement patternNode, PsiElement matchedNode, MatchContext context) { - if (!super.match(patternNode,matchedNode,context)) { + if (!super.match(patternNode,matchedNode, context)) { return false; } - return context.getMatcher().match( - ((PsiExpressionStatement)patternNode).getExpression(), - matchedNode - ); + return context.getMatcher().match(((PsiExpressionStatement)patternNode).getExpression(), matchedNode); } } diff --git a/platform/structuralsearch/source/com/intellij/structuralsearch/StructuralSearchProfile.java b/platform/structuralsearch/source/com/intellij/structuralsearch/StructuralSearchProfile.java index fbfdc691132d..e5c9ae2f87a2 100644 --- a/platform/structuralsearch/source/com/intellij/structuralsearch/StructuralSearchProfile.java +++ b/platform/structuralsearch/source/com/intellij/structuralsearch/StructuralSearchProfile.java @@ -33,6 +33,8 @@ import java.util.Collections; import java.util.List; /** + * Entry point for supporting a specific language in Structural Search. + * * @author Eugene.Kudelevsky */ public abstract class StructuralSearchProfile { @@ -40,14 +42,43 @@ public abstract class StructuralSearchProfile { ExtensionPointName.create("com.intellij.structuralsearch.profile"); @NonNls protected static final String PATTERN_PLACEHOLDER = "$$PATTERN_PLACEHOLDER$$"; + /** + * Creates the pattern PSI tree which is stored inside CompiledPattern. + * Uses compiling visitor to visit the query PsiElements, sets the correct Filters and Handlers. + * @see #createCompiledPattern() + * @param elements + * @param globalVisitor + */ public abstract void compile(PsiElement[] elements, @NotNull GlobalCompilingVisitor globalVisitor); + /** + * The MatchingVisitor knows how to match language specific constructs, when those constructs have already been found. + * + *

For example {@code if} statements in Java: first the condition of the pattern is compared to the condition of the found + * {@code if} statement. If it matches, compare the then part of the {@code if} statement. And if the pattern has an + * {@code else} part, try to match that as well. If no {@code else} is present in the pattern, just ignore any {@code else} in the code. + * + *

In some cases MatchingVisitor also knows how to match two not quite similar things as well, + * like {@code String s = "";} and {@code var s = "";} in Java, if {@code s} has the same inferred type as the explicit type in + * the pattern. + * + * @param globalVisitor the global matching visitor which the created matching visitor can use to e.g. retrieve the current element to match. + * @return a language specific matching visitor + */ @NotNull public abstract PsiElementVisitor createMatchingVisitor(@NotNull GlobalMatchingVisitor globalVisitor); + /** + * Filter to filter out uninteresting elements that should not be matched. Usually white space and error elements. + * @return + */ @NotNull public abstract NodeFilter getLexicalNodesFilter(); + /** + * Creates language specific compiled pattern. + * @return + */ @NotNull public abstract CompiledPattern createCompiledPattern(); @@ -56,8 +87,23 @@ public abstract class StructuralSearchProfile { return Collections.emptyList(); } + /** + * @param language + * @return true, if this structural search profile can match code of the specified language. False otherwise. + */ public abstract boolean isMyLanguage(@NotNull Language language); + /** + * Converts query text into PSI tree. + * @param text the text of the search query. + * @param context + * @param fileType + * @param language + * @param contextId + * @param project + * @param physical + * @return + */ @NotNull public PsiElement[] createPatternTree(@NotNull String text, @NotNull PatternTreeContext context, diff --git a/platform/structuralsearch/source/com/intellij/structuralsearch/impl/matcher/CompiledPattern.java b/platform/structuralsearch/source/com/intellij/structuralsearch/impl/matcher/CompiledPattern.java index 1427820bbb79..96b97d1f1896 100644 --- a/platform/structuralsearch/source/com/intellij/structuralsearch/impl/matcher/CompiledPattern.java +++ b/platform/structuralsearch/source/com/intellij/structuralsearch/impl/matcher/CompiledPattern.java @@ -1,4 +1,4 @@ -// Copyright 2000-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. +// Copyright 2000-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. package com.intellij.structuralsearch.impl.matcher; import com.intellij.dupLocator.iterators.ArrayBackedNodeIterator; @@ -24,7 +24,8 @@ import java.util.List; import java.util.Map; /** - * Class to hold compiled pattern information + * Class to hold compiled pattern information. Contains the PSI pattern tree, and maps PsiElements to matching handlers. + * @see MatchingHandler */ public abstract class CompiledPattern { public static final Key HANDLER_KEY = Key.create("ss.handler"); diff --git a/platform/structuralsearch/source/com/intellij/structuralsearch/impl/matcher/GlobalMatchingVisitor.java b/platform/structuralsearch/source/com/intellij/structuralsearch/impl/matcher/GlobalMatchingVisitor.java index 6ca996841088..6a8521933586 100644 --- a/platform/structuralsearch/source/com/intellij/structuralsearch/impl/matcher/GlobalMatchingVisitor.java +++ b/platform/structuralsearch/source/com/intellij/structuralsearch/impl/matcher/GlobalMatchingVisitor.java @@ -1,4 +1,4 @@ -// Copyright 2000-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. +// Copyright 2000-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. package com.intellij.structuralsearch.impl.matcher; import com.intellij.dupLocator.AbstractMatchingVisitor; @@ -30,23 +30,32 @@ import java.util.Map; import static com.intellij.structuralsearch.impl.matcher.iterators.SingleNodeIterator.newSingleNodeIterator; /** - * Visitor class to manage pattern matching + * GlobalMatchingVisitor does the walking of the pattern tree, and invokes the language specific MatchingVisitor on elements. + * It also stores the current code element to match. MatchingVisitor visits pattern elements, not code elements. + * A language specific matching visitor can retrieve the current code element from the GlobalMatchingVisitor by calling + * {@link #getElement()} from inside the visit methods. */ public class GlobalMatchingVisitor extends AbstractMatchingVisitor { private static final Logger LOG = Logger.getInstance(GlobalMatchingVisitor.class); public static final Key> UNMATCHED_ELEMENTS_KEY = Key.create("UnmatchedElements"); - // the pattern element for visitor check + /** + * The current element to match. + */ private PsiElement myElement; - // the result of matching in visitor + /** + * The result of matching in visitor + */ private boolean myResult; - // context of matching private MatchContext matchContext; private final Map myLanguage2MatchingVisitor = new HashMap<>(1); + /** + * @return the current code element to match. + */ public PsiElement getElement() { return myElement; } @@ -105,31 +114,31 @@ public class GlobalMatchingVisitor extends AbstractMatchingVisitor { /** * Identifies the match between given element of program tree and pattern element * - * @param el1 the pattern for matching - * @param el2 the tree element for matching + * @param patternElement the pattern element + * @param matchElement the match element from the code. * @return true if equal and false otherwise */ @Override - public boolean match(PsiElement el1, PsiElement el2) { + public boolean match(PsiElement patternElement, PsiElement matchElement) { ProgressManager.checkCanceled(); - if (el1 == el2) return true; - if (el1 == null) { + if (patternElement == matchElement) return true; + if (patternElement == null) { // absence of pattern element is match return true; } - if (el2 == null) { + if (matchElement == null) { // absence of match element needs check if allowed. - return allowsAbsenceOfMatch(el1); + return allowsAbsenceOfMatch(patternElement); } // copy changed data to local stack PsiElement prevElement = myElement; - myElement = el2; + myElement = matchElement; try { - PsiElementVisitor visitor = getVisitorForElement(el1); + PsiElementVisitor visitor = getVisitorForElement(patternElement); if (visitor != null) { - el1.accept(visitor); + patternElement.accept(visitor); } } catch (ClassCastException ex) { @@ -183,9 +192,9 @@ public class GlobalMatchingVisitor extends AbstractMatchingVisitor { } /** - * Descents the tree in depth finding matches + * Descends the tree in depth finding matches * - * @param elements the element for which the sons are looked for match + * @param elements the element of which the children are checked for a match */ public void matchContext(@NotNull NodeIterator elements) { final CompiledPattern pattern = matchContext.getPattern(); diff --git a/platform/structuralsearch/source/com/intellij/structuralsearch/impl/matcher/compiler/WordOptimizer.java b/platform/structuralsearch/source/com/intellij/structuralsearch/impl/matcher/compiler/WordOptimizer.java index f0b528d9a482..de82e1594353 100644 --- a/platform/structuralsearch/source/com/intellij/structuralsearch/impl/matcher/compiler/WordOptimizer.java +++ b/platform/structuralsearch/source/com/intellij/structuralsearch/impl/matcher/compiler/WordOptimizer.java @@ -1,4 +1,4 @@ -// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. +// Copyright 2000-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. package com.intellij.structuralsearch.impl.matcher.compiler; import com.intellij.openapi.project.Project; @@ -12,6 +12,10 @@ import java.util.Collections; import java.util.List; /** + * The WordOptimizer is used for extracting words to check in the index. Basically it is just an optimization for faster search, + * because files without the extracted words don’t need to be scanned. That means you can create Structural Search for a language + * without a WordOptimizer and it will still be correct, just slower. + * * @author Bas Leijdekkers */ public interface WordOptimizer { diff --git a/platform/structuralsearch/source/com/intellij/structuralsearch/impl/matcher/handlers/MatchingHandler.java b/platform/structuralsearch/source/com/intellij/structuralsearch/impl/matcher/handlers/MatchingHandler.java index de1ba806d183..4e4f2a013ae2 100644 --- a/platform/structuralsearch/source/com/intellij/structuralsearch/impl/matcher/handlers/MatchingHandler.java +++ b/platform/structuralsearch/source/com/intellij/structuralsearch/impl/matcher/handlers/MatchingHandler.java @@ -1,4 +1,4 @@ -// Copyright 2000-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. +// Copyright 2000-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. package com.intellij.structuralsearch.impl.matcher.handlers; import com.intellij.dupLocator.iterators.NodeIterator; @@ -18,12 +18,18 @@ import java.util.HashSet; import java.util.Set; /** - * Root of handlers for pattern node matching. Handles simplest type of the match. + * Root of handlers for pattern node matching. Matching handlers know how to match a specific pattern node + * to a node in the source code. */ public abstract class MatchingHandler { protected NodeFilter filter; private PsiElement pinnedElement; + /** + * Node filters determine which kind of PsiElements can match the pattern element. + * Filters are applied to MatchingHandlers in the CompilingVisitor. + * @param filter + */ public void setFilter(NodeFilter filter) { this.filter = filter; } diff --git a/platform/structuralsearch/source/com/intellij/structuralsearch/impl/matcher/handlers/SimpleHandler.java b/platform/structuralsearch/source/com/intellij/structuralsearch/impl/matcher/handlers/SimpleHandler.java index e2eb4e76959e..f4fdb712815e 100644 --- a/platform/structuralsearch/source/com/intellij/structuralsearch/impl/matcher/handlers/SimpleHandler.java +++ b/platform/structuralsearch/source/com/intellij/structuralsearch/impl/matcher/handlers/SimpleHandler.java @@ -1,11 +1,11 @@ -// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. +// Copyright 2000-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. package com.intellij.structuralsearch.impl.matcher.handlers; import com.intellij.psi.PsiElement; import com.intellij.structuralsearch.impl.matcher.MatchContext; /** - * Root of handlers for pattern node matching. Handles simplest type of the match. + * Handles simplest type of the match: one node from the pattern to one node of the code. */ public final class SimpleHandler extends MatchingHandler { /** @@ -16,7 +16,7 @@ public final class SimpleHandler extends MatchingHandler { */ @Override public boolean match(PsiElement patternNode, PsiElement matchedNode, MatchContext context) { - if (!super.match(patternNode,matchedNode,context)) return false; - return context.getMatcher().match(patternNode,matchedNode); + if (!super.match(patternNode, matchedNode, context)) return false; + return context.getMatcher().match(patternNode, matchedNode); } }