diff --git a/java/structuralsearch-java/src/com/intellij/structuralsearch/impl/matcher/JavaMatchingVisitor.java b/java/structuralsearch-java/src/com/intellij/structuralsearch/impl/matcher/JavaMatchingVisitor.java index cae2675f92df..56eef25791e2 100644 --- a/java/structuralsearch-java/src/com/intellij/structuralsearch/impl/matcher/JavaMatchingVisitor.java +++ b/java/structuralsearch-java/src/com/intellij/structuralsearch/impl/matcher/JavaMatchingVisitor.java @@ -1147,7 +1147,7 @@ public class JavaMatchingVisitor extends JavaElementVisitor { int length = const2.getTextLength(); final String text = const2.getText(); - if (length > 2 && text.charAt(0) == '"' && text.charAt(length - 1) == '"') { + if (StringUtil.isQuotedString(text)) { length--; offset++; } @@ -1158,7 +1158,18 @@ public class JavaMatchingVisitor extends JavaElementVisitor { myMatchingVisitor.setResult(handler.match(const1, const2, myMatchingVisitor.getMatchContext())); } else { - myMatchingVisitor.setResult(myMatchingVisitor.matchText(const1, const2)); + final Object value1 = const1.getValue(); + final Object value2 = const2.getValue(); + if ((value1 instanceof String || value1 instanceof Character) && (value2 instanceof String || value2 instanceof Character)) { + myMatchingVisitor.setResult(myMatchingVisitor.matchText(value1.toString(), value2.toString())); + } + else if (value1 != null && value2 != null) { + myMatchingVisitor.setResult(value1.equals(value2)); + } + else { + // matches null literals + myMatchingVisitor.setResult(myMatchingVisitor.matchText(const1, const2)); + } } } 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 0b832a8cf52e..6660be912ae7 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 @@ -3,6 +3,7 @@ package com.intellij.structuralsearch.impl.matcher.compiler; import com.intellij.dupLocator.iterators.NodeIterator; import com.intellij.openapi.project.Project; +import com.intellij.openapi.util.text.StringUtil; import com.intellij.psi.*; import com.intellij.psi.javadoc.PsiDocComment; import com.intellij.psi.javadoc.PsiDocTag; @@ -229,16 +230,25 @@ public class JavaCompilingVisitor extends JavaRecursiveElementWalkingVisitor { @Override public void visitLiteralExpression(PsiLiteralExpression expression) { - String value = expression.getText(); + String text = expression.getText(); - if (value.length() > 2 && value.charAt(0) == '"' && value.charAt(value.length() - 1) == '"') { + if (StringUtil.isQuotedString(text)) { @Nullable MatchingHandler handler = - myCompilingVisitor.processPatternStringWithFragments(value, GlobalCompilingVisitor.OccurenceKind.LITERAL); + myCompilingVisitor.processPatternStringWithFragments(text, GlobalCompilingVisitor.OccurenceKind.LITERAL); + if (PsiType.CHAR.equals(expression.getType()) && + (handler instanceof LiteralWithSubstitutionHandler || handler == null && expression.getValue() == null)) { + throw new MalformedPatternException("Bad character literal"); + } if (handler != null) { expression.putUserData(CompiledPattern.HANDLER_KEY, handler); } } + else { + if (!PsiType.NULL.equals(expression.getType()) && expression.getValue() == null) { + throw new MalformedPatternException("Bad literal"); + } + } super.visitLiteralExpression(expression); } 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 3ac35e49de76..01d292042a8e 100644 --- a/platform/structuralsearch/source/com/intellij/structuralsearch/impl/matcher/GlobalMatchingVisitor.java +++ b/platform/structuralsearch/source/com/intellij/structuralsearch/impl/matcher/GlobalMatchingVisitor.java @@ -294,15 +294,11 @@ public class GlobalMatchingVisitor extends AbstractMatchingVisitor { } public boolean matchText(@Nullable PsiElement left, @Nullable PsiElement right) { - if (left == null) { - return right == null; - } - else if (right == null) { - return false; - } - final boolean caseSensitiveMatch = matchContext.getOptions().isCaseSensitiveMatch(); - final String leftText = left.getText(); - final String rightText = right.getText(); - return caseSensitiveMatch ? leftText.equals(rightText) : leftText.equalsIgnoreCase(rightText); + if (left == null) return right == null; + return right != null && matchText(left.getText(), right.getText()); + } + + public boolean matchText(String left, String right) { + return matchContext.getOptions().isCaseSensitiveMatch() ? left.equals(right) : left.equalsIgnoreCase(right); } } diff --git a/platform/structuralsearch/testSource/com/intellij/structuralsearch/StructuralSearchTest.java b/platform/structuralsearch/testSource/com/intellij/structuralsearch/StructuralSearchTest.java index b5bc04a47217..69d1251aef9e 100644 --- a/platform/structuralsearch/testSource/com/intellij/structuralsearch/StructuralSearchTest.java +++ b/platform/structuralsearch/testSource/com/intellij/structuralsearch/StructuralSearchTest.java @@ -456,6 +456,15 @@ public class StructuralSearchTest extends StructuralSearchTestCase { assertEquals("match literal contents", 1, findMatchesCount(s2, "\"'String:[regex( alpha )]\"")); assertEquals("negate match literal contents", 2, findMatchesCount(s2, "\"'String:[!regex( alpha )]\"")); assertEquals("match literal contents and all types", 1, findMatchesCount(s2, "\"'String:[regex( alpha ) && exprtype( .* )]\"")); + + String s3 = "class A {" + + " int i = 0x20;" + + " char c = 'a';" + + " char d = 'A';" + + " char e = 'z'" + + "}"; + assertEquals("match literal by value", 1, findMatchesCount(s3, "32")); + assertEquals("match char with substitution", 3, findMatchesCount(s3, "\\''_x\\'")); } public void testCovariantArraySearch() { @@ -2323,6 +2332,21 @@ public class StructuralSearchTest extends StructuralSearchTestCase { fail("malformed pattern warning expected"); } catch (MalformedPatternException ignored) {} + try { + findMatchesCount(source, "\\'aa\\'"); + fail("malformed pattern warning expected"); + } catch (MalformedPatternException ignored) {} + + try { + findMatchesCount(source, "\\'$var$ \\'"); + fail("malformed pattern warning expected"); + } catch (MalformedPatternException ignored) {} + + try { + findMatchesCount(s4, "0x100000000"); + fail("malformed pattern warning expected"); + } catch (MalformedPatternException ignored) {} + findMatchesCount(source, "'_ReturnType '_Method*('_ParameterType '_Parameter);"); }