SSR: remove need to wrap every pattern in a code block

This commit is contained in:
Bas Leijdekkers
2017-09-12 21:21:43 +02:00
parent 35fbe16c29
commit 20828edfde
4 changed files with 50 additions and 79 deletions
@@ -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<String, PsiNamedElement> searchedNamedElements = Collector.collectNamedElements(getCodeBlock());
Map<String, PsiNamedElement> 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<String, PsiNamedElement> namedElements = new HashMap<>(1);
public static Map<String, PsiNamedElement> collectNamedElements(PsiElement context) {
public static Map<String, PsiNamedElement> collectNamedElements(PsiElement... elements) {
final Collector collector = new Collector();
context.accept(collector);
for (PsiElement element : elements) {
element.accept(collector);
}
return collector.namedElements;
}
@@ -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<PsiElement> 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<PsiElement> 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);
}
@@ -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) {
@@ -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();