From 20828edfde3fbb59df3220751f7aad3cc6c72d9c Mon Sep 17 00:00:00 2001 From: Bas Leijdekkers Date: Mon, 11 Sep 2017 15:45:44 +0200 Subject: [PATCH] SSR: remove need to wrap every pattern in a code block --- .../structuralsearch/JavaReplaceHandler.java | 65 ++++++++----------- .../JavaStructuralSearchProfile.java | 42 ++++-------- .../compiler/JavaCompilingVisitor.java | 16 ++--- .../plugin/replace/impl/Replacer.java | 6 +- 4 files changed, 50 insertions(+), 79 deletions(-) diff --git a/java/structuralsearch-java/src/com/intellij/structuralsearch/JavaReplaceHandler.java b/java/structuralsearch-java/src/com/intellij/structuralsearch/JavaReplaceHandler.java index 804cf64ea2c1..8e947be54d70 100644 --- a/java/structuralsearch-java/src/com/intellij/structuralsearch/JavaReplaceHandler.java +++ b/java/structuralsearch-java/src/com/intellij/structuralsearch/JavaReplaceHandler.java @@ -15,7 +15,6 @@ */ package com.intellij.structuralsearch; -import com.intellij.openapi.fileTypes.StdFileTypes; import com.intellij.openapi.util.text.StringUtil; import com.intellij.psi.*; import com.intellij.psi.codeStyle.JavaCodeStyleManager; @@ -46,22 +45,16 @@ import java.util.Map; */ public class JavaReplaceHandler extends StructuralReplaceHandler { private final ReplacementContext myContext; - private PsiCodeBlock codeBlock; + private final PsiElement[] patternElements; public JavaReplaceHandler(ReplacementContext context) { this.myContext = context; - } - - private PsiCodeBlock getCodeBlock() throws IncorrectOperationException { - if (codeBlock == null) { - codeBlock = (PsiCodeBlock)MatcherImplUtil.createTreeFromText( - myContext.getOptions().getMatchOptions().getSearchPattern(), - PatternTreeContext.Block, - myContext.getOptions().getMatchOptions().getFileType(), - myContext.getProject() - )[0].getParent(); - } - return codeBlock; + patternElements = MatcherImplUtil.createTreeFromText( + myContext.getOptions().getMatchOptions().getSearchPattern(), + PatternTreeContext.Block, + myContext.getOptions().getMatchOptions().getFileType(), + myContext.getProject() + ); } private static PsiElement findRealSubstitutionElement(PsiElement el) { @@ -96,17 +89,11 @@ public class JavaReplaceHandler extends StructuralReplaceHandler { } @Nullable - private PsiNamedElement getSymbolReplacementTarget(final PsiElement el) - throws IncorrectOperationException { - if (myContext.getOptions().getMatchOptions().getFileType() != StdFileTypes.JAVA) return null; //? - final PsiStatement[] searchStatements = getCodeBlock().getStatements(); - if (searchStatements.length > 0 && - searchStatements[0] instanceof PsiExpressionStatement) { - final PsiExpression expression = ((PsiExpressionStatement)searchStatements[0]).getExpression(); + private PsiNamedElement getSymbolReplacementTarget(final PsiElement el) { + if (patternElements.length == 1 && patternElements[0] instanceof PsiExpressionStatement) { + final PsiExpression expression = ((PsiExpressionStatement)patternElements[0]).getExpression(); - if (expression instanceof PsiReferenceExpression && - ((PsiReferenceExpression)expression).getQualifierExpression() == null - ) { + if (expression instanceof PsiReferenceExpression && ((PsiReferenceExpression)expression).getQualifierExpression() == null) { // looks like symbol replacements, namely replace AAA by BBB, so lets do the best if (el instanceof PsiNamedElement) { return (PsiNamedElement)el; @@ -138,7 +125,7 @@ public class JavaReplaceHandler extends StructuralReplaceHandler { return replacement; } - private boolean isSymbolReplacement(final PsiElement el) throws IncorrectOperationException { + private boolean isSymbolReplacement(final PsiElement el) { return getSymbolReplacementTarget(el) != null; } @@ -157,14 +144,14 @@ public class JavaReplaceHandler extends StructuralReplaceHandler { return; } - Map searchedNamedElements = Collector.collectNamedElements(getCodeBlock()); + Map patternNamedElements = Collector.collectNamedElements(patternElements); for (String name : originalNamedElements.keySet()) { PsiNamedElement originalNamedElement = originalNamedElements.get(name); PsiNamedElement replacementNamedElement = replacedNamedElements.get(name); String key = newNameToSearchPatternNameMap.get(name); if (key == null) key = name; - PsiNamedElement searchedNamedElement = searchedNamedElements.get(key); + PsiNamedElement patternNamedElement = patternNamedElements.get(key); if (replacementNamedElement == null && originalNamedElements.size() == 1 && replacedNamedElements.size() == 1) { replacementNamedElement = replacedNamedElements.entrySet().iterator().next().getValue(); @@ -185,7 +172,7 @@ public class JavaReplaceHandler extends StructuralReplaceHandler { } } - if (replacementNamedElement != null && searchedNamedElement != null) { + if (replacementNamedElement != null && patternNamedElement != null) { Replacer.handleComments(originalNamedElement, replacementNamedElement, myContext); } @@ -201,24 +188,24 @@ public class JavaReplaceHandler extends StructuralReplaceHandler { } if (originalNamedElement instanceof PsiModifierListOwner && - searchedNamedElement instanceof PsiModifierListOwner && + patternNamedElement instanceof PsiModifierListOwner && replacementNamedElement instanceof PsiModifierListOwner) { copyModifiersAndAnnotations((PsiModifierListOwner)originalNamedElement, - (PsiModifierListOwner)searchedNamedElement, + (PsiModifierListOwner)patternNamedElement, (PsiModifierListOwner)replacementNamedElement); } if (originalNamedElement instanceof PsiMethod && - searchedNamedElement instanceof PsiMethod && + patternNamedElement instanceof PsiMethod && replacementNamedElement instanceof PsiMethod) { - copyMethodBodyIfNotReplaced((PsiMethod)originalNamedElement, (PsiMethod)searchedNamedElement, (PsiMethod)replacementNamedElement); + copyMethodBodyIfNotReplaced((PsiMethod)originalNamedElement, (PsiMethod)patternNamedElement, (PsiMethod)replacementNamedElement); } if (originalNamedElement instanceof PsiClass && - searchedNamedElement instanceof PsiClass && + patternNamedElement instanceof PsiClass && replacementNamedElement instanceof PsiClass) { final PsiClass originalClass = (PsiClass)originalNamedElement; - final PsiClass queryClass = (PsiClass)searchedNamedElement; + final PsiClass queryClass = (PsiClass)patternNamedElement; final PsiClass replacementClass = (PsiClass)replacementNamedElement; copyExtendsListIfNotReplaced(originalClass, queryClass, replacementClass); @@ -343,7 +330,7 @@ public class JavaReplaceHandler extends StructuralReplaceHandler { queryQualifiedName.equals(originalReferenceElement.getReferenceName()); } - private PsiElement handleSymbolReplacement(PsiElement replacement, final PsiElement el) throws IncorrectOperationException { + private PsiElement handleSymbolReplacement(PsiElement replacement, final PsiElement el) { PsiNamedElement nameElement = getSymbolReplacementTarget(el); if (nameElement != null) { PsiElement oldReplacement = replacement; @@ -645,7 +632,7 @@ public class JavaReplaceHandler extends StructuralReplaceHandler { } @Nullable - private static PsiElement createSemicolon(final PsiElement space) throws IncorrectOperationException { + private static PsiElement createSemicolon(final PsiElement space) { final PsiStatement text = JavaPsiFacade.getInstance(space.getProject()).getElementFactory().createStatementFromText(";", null); return text.getFirstChild(); } @@ -653,9 +640,11 @@ public class JavaReplaceHandler extends StructuralReplaceHandler { private static class Collector extends JavaRecursiveElementWalkingVisitor { private final HashMap namedElements = new HashMap<>(1); - public static Map collectNamedElements(PsiElement context) { + public static Map collectNamedElements(PsiElement... elements) { final Collector collector = new Collector(); - context.accept(collector); + for (PsiElement element : elements) { + element.accept(collector); + } return collector.namedElements; } diff --git a/java/structuralsearch-java/src/com/intellij/structuralsearch/JavaStructuralSearchProfile.java b/java/structuralsearch-java/src/com/intellij/structuralsearch/JavaStructuralSearchProfile.java index 1a4d09fe034d..ca296d04258a 100644 --- a/java/structuralsearch-java/src/com/intellij/structuralsearch/JavaStructuralSearchProfile.java +++ b/java/structuralsearch-java/src/com/intellij/structuralsearch/JavaStructuralSearchProfile.java @@ -50,6 +50,7 @@ import com.intellij.structuralsearch.plugin.ui.SearchContext; import com.intellij.structuralsearch.plugin.ui.UIUtil; import com.intellij.util.ArrayUtil; import com.intellij.util.IncorrectOperationException; +import com.intellij.util.SmartList; import gnu.trove.THashSet; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -198,7 +199,7 @@ public class JavaStructuralSearchProfile extends StructuralSearchProfile { @Override public void compile(PsiElement[] elements, @NotNull GlobalCompilingVisitor globalVisitor) { - elements[0].getParent().accept(new JavaCompilingVisitor(globalVisitor)); + new JavaCompilingVisitor(globalVisitor).compile(elements); } @Override @@ -256,8 +257,8 @@ public class JavaStructuralSearchProfile extends StructuralSearchProfile { } final PsiElementFactory elementFactory = JavaPsiFacade.getInstance(project).getElementFactory(); if (context == PatternTreeContext.Block) { - final PsiElement element = elementFactory.createStatementFromText("{\n" + text + "\n}", null); - final PsiElement[] children = ((PsiBlockStatement)element).getCodeBlock().getChildren(); + final PsiCodeBlock codeBlock = elementFactory.createCodeBlockFromText("{\n" + text + "\n}", null); + final PsiElement[] children = codeBlock.getChildren(); final int extraChildCount = 4; if (children.length > extraChildCount) { @@ -295,24 +296,17 @@ public class JavaStructuralSearchProfile extends StructuralSearchProfile { if (endChild != null) endChild = endChild.getPrevSibling(); if (startChild == endChild) return PsiElement.EMPTY_ARRAY; // nothing produced - final PsiCodeBlock codeBlock = elementFactory.createCodeBlock(); - final List result = new ArrayList<>(3); assert startChild != null; - for (PsiElement el = startChild.getNextSibling(); el != endChild && el != null; el = el.getNextSibling()) { - if (el instanceof PsiErrorElement) continue; - result.add(codeBlock.add(el)); + final List result = new SmartList<>(); + for (PsiElement element = startChild.getNextSibling(); element != endChild && element != null; element = element.getNextSibling()) { + if (element instanceof PsiErrorElement) continue; + result.add(element); } return PsiUtilCore.toPsiElementArray(result); } else if (context == PatternTreeContext.Expression) { - final PsiExpression expression = elementFactory.createExpressionFromText(text, null); - final PsiBlockStatement statement = (PsiBlockStatement)elementFactory.createStatementFromText("{\na\n}", null); - final PsiElement[] children = statement.getCodeBlock().getChildren(); - if (children.length != 5) return PsiElement.EMPTY_ARRAY; - final PsiExpressionStatement childStatement = (PsiExpressionStatement)children[2]; - childStatement.getExpression().replace(expression); - return new PsiElement[] { childStatement }; + return new PsiElement[] {elementFactory.createExpressionFromText(text, null)}; } else { return PsiFileFactory.getInstance(project).createFileFromText("__dummy.java", JavaFileType.INSTANCE, text).getChildren(); @@ -434,26 +428,16 @@ public class JavaStructuralSearchProfile extends StructuralSearchProfile { public void checkReplacementPattern(Project project, ReplaceOptions options) { MatchOptions matchOptions = options.getMatchOptions(); FileType fileType = matchOptions.getFileType(); - PsiElement[] statements = MatcherImplUtil.createTreeFromText( - matchOptions.getSearchPattern(), - PatternTreeContext.Block, - fileType, - project - ); + PsiElement[] statements = createPatternTree(matchOptions.getSearchPattern(), PatternTreeContext.Block, fileType, project, false); final boolean searchIsExpression = statements.length == 1 && statements[0].getLastChild() instanceof PsiErrorElement; - PsiElement[] statements2 = MatcherImplUtil.createTreeFromText( - options.getReplacement(), - PatternTreeContext.Block, - fileType, - project - ); + PsiElement[] statements2 = createPatternTree(options.getReplacement(), PatternTreeContext.Block, fileType, project, false); final boolean replaceIsExpression = statements2.length == 1 && statements2[0].getLastChild() instanceof PsiErrorElement; ValidatingVisitor visitor = new ValidatingVisitor(); for (PsiElement statement : statements2) { - visitor.setCurrent((statements.length == 1 && (statement instanceof PsiExpressionStatement || statement instanceof PsiDeclarationStatement)) - ? statement : null); + visitor.setCurrent((statements.length == 1 && + (statement instanceof PsiExpressionStatement || statement instanceof PsiDeclarationStatement)) ? statement : null); statement.accept(visitor); } 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 92791239f95c..346893a25869 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 @@ -57,6 +57,14 @@ public class JavaCompilingVisitor extends JavaRecursiveElementWalkingVisitor { this.myCompilingVisitor = compilingVisitor; } + public void compile(PsiElement[] topLevelElements) { + for (PsiElement element : topLevelElements) { + element.accept(this); + final MatchingHandler matchingHandler = myCompilingVisitor.getContext().getPattern().getHandler(element); + myCompilingVisitor.getContext().getPattern().setHandler(element, new TopLevelMatchingHandler(matchingHandler)); + } + } + @Override public void visitDocTag(PsiDocTag psiDocTag) { super.visitDocTag(psiDocTag); @@ -492,8 +500,6 @@ public class JavaCompilingVisitor extends JavaRecursiveElementWalkingVisitor { @Override public void visitCodeBlock(PsiCodeBlock block) { - myCompilingVisitor.setCodeBlockLevel(myCompilingVisitor.getCodeBlockLevel() + 1); - for (PsiElement el = block.getFirstChild(); el != null; el = el.getNextSibling()) { if (GlobalCompilingVisitor.getFilter().accepts(el)) { if (el instanceof PsiWhiteSpace) { @@ -502,14 +508,8 @@ public class JavaCompilingVisitor extends JavaRecursiveElementWalkingVisitor { } else { el.accept(this); - if (myCompilingVisitor.getCodeBlockLevel() == 1) { - final MatchingHandler matchingHandler = myCompilingVisitor.getContext().getPattern().getHandler(el); - myCompilingVisitor.getContext().getPattern().setHandler(el, new TopLevelMatchingHandler(matchingHandler)); - } } } - - myCompilingVisitor.setCodeBlockLevel(myCompilingVisitor.getCodeBlockLevel() - 1); } private static boolean needsSupers(final PsiElement element, final MatchingHandler handler) { diff --git a/platform/structuralsearch/source/com/intellij/structuralsearch/plugin/replace/impl/Replacer.java b/platform/structuralsearch/source/com/intellij/structuralsearch/plugin/replace/impl/Replacer.java index ed4bddc4ead0..e34b4e386a13 100644 --- a/platform/structuralsearch/source/com/intellij/structuralsearch/plugin/replace/impl/Replacer.java +++ b/platform/structuralsearch/source/com/intellij/structuralsearch/plugin/replace/impl/Replacer.java @@ -116,7 +116,7 @@ public class Replacer { lastElement = elements[elements.length-1]; parent = firstElement.getParent(); - matchOptions.setScope(new LocalSearchScope(parent)); + matchOptions.setScope(new LocalSearchScope(elements)); } else { parent = ((LocalSearchScope)options.getMatchOptions().getScope()).getScope()[0]; firstElement = parent.getFirstChild(); @@ -133,10 +133,8 @@ public class Replacer { resultPtrList.add(buildReplacement(result)); } - sink.getMatches().clear(); - int startOffset = firstElement.getTextRange().getStartOffset(); - int endOffset = filePattern ?0: parent.getTextLength() - (lastElement.getTextRange().getEndOffset()); + int endOffset = filePattern ? 0 : parent.getTextLength() - lastElement.getTextRange().getEndOffset(); // get nodes from text may contain PsiElement prevSibling = firstElement.getPrevSibling();