diff --git a/java/structuralsearch-java/src/com/intellij/structuralsearch/impl/matcher/compiler/JavaCompilingVisitor.java b/java/structuralsearch-java/src/com/intellij/structuralsearch/impl/matcher/compiler/JavaCompilingVisitor.java index 6660be912ae7..b8e3c962569c 100644 --- a/java/structuralsearch-java/src/com/intellij/structuralsearch/impl/matcher/compiler/JavaCompilingVisitor.java +++ b/java/structuralsearch-java/src/com/intellij/structuralsearch/impl/matcher/compiler/JavaCompilingVisitor.java @@ -20,10 +20,12 @@ import com.intellij.structuralsearch.impl.matcher.filters.*; import com.intellij.structuralsearch.impl.matcher.handlers.*; import com.intellij.structuralsearch.impl.matcher.iterators.DocValuesIterator; import com.intellij.structuralsearch.impl.matcher.predicates.RegExpPredicate; +import com.intellij.util.SmartList; import com.intellij.util.containers.ContainerUtil; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.Nullable; +import java.util.List; import java.util.Set; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -47,7 +49,7 @@ public class JavaCompilingVisitor extends JavaRecursiveElementWalkingVisitor { } public void compile(PsiElement[] topLevelElements) { - final WordOptimizer optimizer = new WordOptimizer(); + final JavaWordOptimizer optimizer = new JavaWordOptimizer(); final CompiledPattern pattern = myCompilingVisitor.getContext().getPattern(); for (PsiElement element : topLevelElements) { element.accept(this); @@ -56,29 +58,29 @@ public class JavaCompilingVisitor extends JavaRecursiveElementWalkingVisitor { } } - private class WordOptimizer extends JavaRecursiveElementWalkingVisitor { + private class JavaWordOptimizer extends JavaRecursiveElementWalkingVisitor implements WordOptimizer { @Override public void visitReferenceElement(PsiJavaCodeReferenceElement reference) { - if (!handleWord(reference.getReferenceName())) return; + if (!handleWord(reference.getReferenceName(), myCompilingVisitor.getContext())) return; super.visitReferenceElement(reference); } @Override public void visitMethod(PsiMethod method) { - if (!handleWord(method.getName())) return; + if (!handleWord(method.getName(), myCompilingVisitor.getContext())) return; super.visitMethod(method); } @Override public void visitVariable(PsiVariable variable) { - if (!handleWord(variable.getName())) return; + if (!handleWord(variable.getName(), myCompilingVisitor.getContext())) return; super.visitVariable(variable); } @Override public void visitClass(PsiClass aClass) { - if (!handleWord(aClass.getName())) return; + if (!handleWord(aClass.getName(), myCompilingVisitor.getContext())) return; super.visitClass(aClass); } @@ -102,65 +104,29 @@ public class JavaCompilingVisitor extends JavaRecursiveElementWalkingVisitor { } } - /** - * @param word word to check index with - * @return true, if psi tree should be processed deeper, false otherwise. - */ - private boolean handleWord(@Nullable String word) { - if (word == null) { - return true; - } - final CompileContext compileContext = myCompilingVisitor.getContext(); - final CompiledPattern pattern = compileContext.getPattern(); - if (pattern.isTypedVar(word)) { - final SubstitutionHandler handler = (SubstitutionHandler)pattern.getHandler(word); - if (handler == null || handler.getMinOccurs() == 0) { - // don't call super - return false; - } - - final RegExpPredicate predicate = handler.findRegExpPredicate(); - if (predicate != null && predicate.couldBeOptimized()) { - if (handler.isStrictSubtype() || handler.isSubtype()) { - addDescendantsOf(predicate.getRegExp(), handler.isSubtype(), compileContext); - } - else { - GlobalCompilingVisitor.addFilesToSearchForGivenWord(predicate.getRegExp(), true, GlobalCompilingVisitor.OccurenceKind.CODE, - compileContext); - } - } - } - else { - GlobalCompilingVisitor.addFilesToSearchForGivenWord(word, true, GlobalCompilingVisitor.OccurenceKind.CODE, compileContext); - } - return true; - } - - private void addDescendantsOf(String className, boolean includeSelf, CompileContext context) { - final OptimizingSearchHelper searchHelper = context.getSearchHelper(); - if (!searchHelper.doOptimizing()) return; - final Project project = context.getProject(); + public List getDescendantsOf(String className, boolean includeSelf, Project project) { + SmartList result = new SmartList<>(); // use project and libraries scope, because super class may be outside the scope of the search final GlobalSearchScope projectAndLibraries = ProjectScope.getAllScope(project); final PsiClass[] classes = PsiShortNamesCache.getInstance(project).getClassesByName(className, projectAndLibraries); if (classes.length == 0) { // to fail fast with "does not match anything in scope" result on unknown class name - GlobalCompilingVisitor.addFilesToSearchForGivenWord(className, true, GlobalCompilingVisitor.OccurenceKind.CODE, context); - return; + result.add(className); + return result; } for (PsiClass aClass : classes) { if (includeSelf) { final String name = aClass.getName(); - if (name != null) searchHelper.addWordToSearchInCode(name); + if (name != null) result.add(name);; } ClassInheritorsSearch.search(aClass, projectAndLibraries, true).forEach(c -> { final String name = c.getName(); - if (name != null) searchHelper.addWordToSearchInCode(name); + if (name != null) result.add(name); return true; }); } - searchHelper.endTransaction(); + return result; } } 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 new file mode 100644 index 000000000000..ef31845b8124 --- /dev/null +++ b/platform/structuralsearch/source/com/intellij/structuralsearch/impl/matcher/compiler/WordOptimizer.java @@ -0,0 +1,70 @@ +// Copyright 2000-2017 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; +import com.intellij.structuralsearch.impl.matcher.CompiledPattern; +import com.intellij.structuralsearch.impl.matcher.handlers.SubstitutionHandler; +import com.intellij.structuralsearch.impl.matcher.predicates.RegExpPredicate; +import org.jetbrains.annotations.Nullable; + +import java.util.Collections; +import java.util.List; + +import static com.intellij.structuralsearch.impl.matcher.compiler.GlobalCompilingVisitor.OccurenceKind.CODE; + +/** + * @author Bas Leijdekkers + */ +public interface WordOptimizer { + + /** + * @param word word to check index with + * @return true, if psi tree should be processed deeper, false otherwise. + */ + default boolean handleWord(@Nullable String word, CompileContext compileContext) { + final OptimizingSearchHelper searchHelper = compileContext.getSearchHelper(); + if (!searchHelper.doOptimizing()) { + return false; + } + if (word == null) { + return true; + } + final CompiledPattern pattern = compileContext.getPattern(); + if (pattern.isTypedVar(word)) { + final SubstitutionHandler handler = (SubstitutionHandler)pattern.getHandler(word); + if (handler == null || handler.getMinOccurs() == 0) { + // don't call super + return false; + } + + final RegExpPredicate predicate = handler.findRegExpPredicate(); + if (predicate != null && predicate.couldBeOptimized()) { + if (handler.isStrictSubtype() || handler.isSubtype()) { + final List descendants = getDescendantsOf(predicate.getRegExp(), handler.isSubtype(), compileContext.getProject()); + for (String descendant : descendants) { + searchHelper.addWordToSearchInCode(descendant); + } + searchHelper.endTransaction(); + } + else { + GlobalCompilingVisitor.addFilesToSearchForGivenWord(predicate.getRegExp(), true, CODE, compileContext); + } + } + } + else { + GlobalCompilingVisitor.addFilesToSearchForGivenWord(word, true, CODE, compileContext); + } + return true; + } + + /** + * Subtype handling for those structural search implementations that support it. If subtype matching is not supported, this + * method does not need to be overridden. + * @param className the name of the class to search for subclasses of + * @param includeSelf include the class itself in the search + * @param context + */ + default List getDescendantsOf(String className, boolean includeSelf, Project project) { + return Collections.emptyList(); + } +} diff --git a/platform/structuralsearch/source/com/intellij/structuralsearch/impl/matcher/compiler/XmlCompilingVisitor.java b/platform/structuralsearch/source/com/intellij/structuralsearch/impl/matcher/compiler/XmlCompilingVisitor.java index 692633eada5f..5d1e3f24174d 100644 --- a/platform/structuralsearch/source/com/intellij/structuralsearch/impl/matcher/compiler/XmlCompilingVisitor.java +++ b/platform/structuralsearch/source/com/intellij/structuralsearch/impl/matcher/compiler/XmlCompilingVisitor.java @@ -10,12 +10,9 @@ import com.intellij.psi.xml.XmlText; import com.intellij.psi.xml.XmlToken; import com.intellij.structuralsearch.impl.matcher.CompiledPattern; import com.intellij.structuralsearch.impl.matcher.filters.TagValueFilter; -import com.intellij.structuralsearch.impl.matcher.handlers.SubstitutionHandler; import com.intellij.structuralsearch.impl.matcher.handlers.TopLevelMatchingHandler; -import com.intellij.structuralsearch.impl.matcher.predicates.RegExpPredicate; -import org.jetbrains.annotations.Nullable; -import static com.intellij.structuralsearch.impl.matcher.compiler.GlobalCompilingVisitor.OccurenceKind.*; +import static com.intellij.structuralsearch.impl.matcher.compiler.GlobalCompilingVisitor.OccurenceKind.TEXT; /** * @author Eugene.Kudelevsky @@ -28,7 +25,7 @@ public class XmlCompilingVisitor extends XmlRecursiveElementVisitor { } public void compile(PsiElement[] topLevelElements) { - final WordOptimizer optimizer = new WordOptimizer(); + final XmlWordOptimizer optimizer = new XmlWordOptimizer(); final CompiledPattern pattern = myCompilingVisitor.getContext().getPattern(); for (PsiElement element : topLevelElements) { element.accept(this); @@ -37,18 +34,18 @@ public class XmlCompilingVisitor extends XmlRecursiveElementVisitor { } } - private class WordOptimizer extends XmlRecursiveElementWalkingVisitor { + private class XmlWordOptimizer extends XmlRecursiveElementWalkingVisitor implements WordOptimizer { @Override public void visitXmlTag(XmlTag tag) { - if (!handleWord(tag.getName())) return; + if (!handleWord(tag.getName(), myCompilingVisitor.getContext())) return; super.visitXmlTag(tag); } @Override public void visitXmlAttribute(XmlAttribute attribute) { - if (!handleWord(attribute.getName())) return; - handleWord(attribute.getValue()); + if (!handleWord(attribute.getName(), myCompilingVisitor.getContext())) return; + handleWord(attribute.getValue(), myCompilingVisitor.getContext()); super.visitXmlAttribute(attribute); } @@ -60,34 +57,6 @@ public class XmlCompilingVisitor extends XmlRecursiveElementVisitor { } super.visitXmlText(text); } - - /** - * @param word word to check index with - * @return true, if psi tree should be processed deeper, false otherwise. - */ - private boolean handleWord(@Nullable String word) { - if (word == null) { - return true; - } - final CompileContext compileContext = myCompilingVisitor.getContext(); - final CompiledPattern pattern = compileContext.getPattern(); - if (pattern.isTypedVar(word)) { - final SubstitutionHandler handler = (SubstitutionHandler)pattern.getHandler(word); - if (handler == null || handler.getMinOccurs() == 0) { - // don't call super - return false; - } - - final RegExpPredicate predicate = handler.findRegExpPredicate(); - if (predicate != null && predicate.couldBeOptimized()) { - GlobalCompilingVisitor.addFilesToSearchForGivenWord(predicate.getRegExp(), true, CODE, compileContext); - } - } - else { - GlobalCompilingVisitor.addFilesToSearchForGivenWord(word, true, CODE, compileContext); - } - return true; - } } @Override public void visitElement(PsiElement element) {