From cde46ffdc1def04d965db105615f3c97ce05c961 Mon Sep 17 00:00:00 2001 From: Bas Leijdekkers Date: Wed, 28 Oct 2015 22:20:21 +0100 Subject: [PATCH] IDEA-146951 (Structural Search fails with '<' in search in pattern) --- .../JavaStructuralSearchProfile.java | 42 +++++++++++++++++-- .../impl/matcher/PatternTreeContext.java | 2 +- .../StructuralSearchTest.java | 16 +++++++ 3 files changed, 55 insertions(+), 5 deletions(-) diff --git a/java/structuralsearch-java/src/com/intellij/structuralsearch/JavaStructuralSearchProfile.java b/java/structuralsearch-java/src/com/intellij/structuralsearch/JavaStructuralSearchProfile.java index 19cc9566f5a9..54376b73688e 100644 --- a/java/structuralsearch-java/src/com/intellij/structuralsearch/JavaStructuralSearchProfile.java +++ b/java/structuralsearch-java/src/com/intellij/structuralsearch/JavaStructuralSearchProfile.java @@ -32,6 +32,7 @@ import com.intellij.structuralsearch.plugin.replace.impl.Replacer; import com.intellij.structuralsearch.plugin.ui.Configuration; import com.intellij.structuralsearch.plugin.ui.SearchContext; import com.intellij.structuralsearch.plugin.ui.UIUtil; +import com.intellij.util.IncorrectOperationException; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -202,10 +203,18 @@ public class JavaStructuralSearchProfile extends StructuralSearchProfile { if (children.length > extraChildCount) { PsiElement[] result = new PsiElement[children.length - extraChildCount]; - final int extraChildStart = 2; - System.arraycopy(children, extraChildStart, result, 0, children.length - extraChildCount); - - if (shouldTryClassPattern(result)) { + System.arraycopy(children, 2, result, 0, children.length - extraChildCount); + + if (shouldTryExpressionPattern(result)) { + try { + final PsiElement[] expressionPattern = + createPatternTree(text, PatternTreeContext.Expression, fileType, language, contextName, extension, project, false); + if (expressionPattern.length == 1) { + result = expressionPattern; + } + } catch (IncorrectOperationException ignore) {} + } + else if (shouldTryClassPattern(result)) { final PsiElement[] classPattern = createPatternTree(text, PatternTreeContext.Class, fileType, language, contextName, extension, project, false); if (classPattern.length == 1) { @@ -237,11 +246,36 @@ public class JavaStructuralSearchProfile extends StructuralSearchProfile { 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 }; + } else { return PsiFileFactory.getInstance(project).createFileFromText("__dummy.java", text).getChildren(); } } + private static boolean shouldTryExpressionPattern(PsiElement[] elements) { + if (elements.length >= 1 && elements.length <= 3) { + final PsiElement firstElement = elements[0]; + if (firstElement instanceof PsiDeclarationStatement) { + final PsiElement lastChild = firstElement.getLastChild(); + if (lastChild instanceof PsiErrorElement && PsiTreeUtil.prevLeaf(lastChild) instanceof PsiErrorElement) { + // Because an identifier followed by < (less than) is parsed as the start of a declaration + // in com.intellij.lang.java.parser.StatementParser.parseStatement() line 236 + // but it could just be a comparison + return true; + } + } + } + return false; + } + private static boolean shouldTryClassPattern(PsiElement[] result) { if (result.length == 3 && PsiModifier.STATIC.equals(result[0].getText()) && result[1] instanceof PsiWhiteSpace && result[2] instanceof PsiBlockStatement) { diff --git a/platform/structuralsearch/source/com/intellij/structuralsearch/impl/matcher/PatternTreeContext.java b/platform/structuralsearch/source/com/intellij/structuralsearch/impl/matcher/PatternTreeContext.java index 7d93c9ae82e0..1a2a0cc5bcab 100644 --- a/platform/structuralsearch/source/com/intellij/structuralsearch/impl/matcher/PatternTreeContext.java +++ b/platform/structuralsearch/source/com/intellij/structuralsearch/impl/matcher/PatternTreeContext.java @@ -4,5 +4,5 @@ package com.intellij.structuralsearch.impl.matcher; * @author Eugene.Kudelevsky */ public enum PatternTreeContext { - File, Block, Class + File, Block, Class, Expression } diff --git a/platform/structuralsearch/testSource/com/intellij/structuralsearch/StructuralSearchTest.java b/platform/structuralsearch/testSource/com/intellij/structuralsearch/StructuralSearchTest.java index a74d35d7cb7b..705b9856a146 100644 --- a/platform/structuralsearch/testSource/com/intellij/structuralsearch/StructuralSearchTest.java +++ b/platform/structuralsearch/testSource/com/intellij/structuralsearch/StructuralSearchTest.java @@ -596,6 +596,22 @@ public class StructuralSearchTest extends StructuralSearchTestCase { assertEquals("Try to find String array initializer expressions", 0, findMatchesCount(s9, "new '_{0,0}:String [] { '_* }")); + + String s10 = "int time = 99;\n" + + "String str = time < 0 ? \"\" : \"\";" + + "String str2 = time < time ? \"\" : \"\";"; + + assertEquals("Find expressions mistaken for declarations by parser in block mode", 1, + findMatchesCount(s10, "time < time")); + + assertEquals("Find expressions mistaken for declarations by parser in block mode 2", 1, + findMatchesCount(s10, "time < 0")); + + assertEquals("Find expressions mistaken for declarations by parser in block mode 3", 1, + findMatchesCount(s10, "time < 0 ? '_a : '_b")); + + assertEquals("Find expressions mistaken for declarations by parser in block mode 4", 2, + findMatchesCount(s10, "'_a < '_b")); } public void testLiteral() { -- 2.32.0