SSR: improve java literal matching and error reporting

This commit is contained in:
Bas Leijdekkers
2017-11-28 19:26:50 +01:00
parent 7febd8f60d
commit 52316ebbe1
4 changed files with 56 additions and 15 deletions
@@ -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));
}
}
}
@@ -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);
}
@@ -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);
}
}
@@ -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);");
}