SSR: improve replacement of polyadic expressions and assertion statements

This commit is contained in:
Bas Leijdekkers
2015-05-30 15:36:42 +02:00
parent 8cf2d0c44e
commit f2f46e97ef
2 changed files with 104 additions and 27 deletions
@@ -397,25 +397,6 @@ public class JavaStructuralSearchProfile extends StructuralSearchProfile {
visitElement(expression);
}
@Override
public void visitVariable(PsiVariable field) {
super.visitVariable(field);
final PsiExpression initializer = field.getInitializer();
if (initializer != null) {
final String initText = initializer.getText();
if (StructuralSearchUtil.isTypedVariable(initText)) {
final ParameterInfo initInfo = builder.findParameterization(Replacer.stripTypedVariableDecoration(initText));
if (initInfo != null) {
initInfo.setVariableInitializerContext(true);
}
}
}
}
@Override
public void visitClass(PsiClass aClass) {
super.visitClass(aClass);
@@ -525,6 +506,13 @@ public class JavaStructuralSearchProfile extends StructuralSearchProfile {
else if (parent instanceof PsiReferenceList) {
buf.append(',');
}
else if (parent instanceof PsiPolyadicExpression) {
final PsiPolyadicExpression expression = (PsiPolyadicExpression)parent;
final PsiJavaToken token = expression.getTokenBeforeOperand(expression.getOperands()[1]);
if (token != null) {
buf.append(token.getText());
}
}
else {
buf.append(' ');
}
@@ -558,20 +546,60 @@ public class JavaStructuralSearchProfile extends StructuralSearchProfile {
@Override
public int handleNoSubstitution(ParameterInfo info, int offset, StringBuilder result) {
final int newOffset = super.handleNoSubstitution(info, offset, result);
if (newOffset != offset) {
return newOffset;
final PsiElement element = info.getElement();
final PsiElement prevSibling = PsiTreeUtil.skipSiblingsBackward(element, PsiWhiteSpace.class);
if (prevSibling instanceof PsiJavaToken && isRemovableToken(prevSibling)) {
final int start = info.getBeforeDelimiterPos() + offset - (prevSibling.getTextLength() - 1);
final int end = info.getStartIndex() + offset;
result.delete(start, end);
return offset - (end - start);
}
if (info.isVariableInitializerContext()) {
result.delete(info.getBeforeDelimiterPos() + offset, info.getAfterDelimiterPos() + offset - 1);
offset -= (info.getAfterDelimiterPos() - info.getBeforeDelimiterPos() - 1);
final PsiElement nextSibling = PsiTreeUtil.skipSiblingsForward(element, PsiWhiteSpace.class);
if (nextSibling instanceof PsiJavaToken && isRemovableToken(nextSibling)) {
final int start = info.getStartIndex() + offset;
final int end = info.getAfterDelimiterPos() + nextSibling.getTextLength() + offset;
result.delete(start, end);
return offset - 1;
}
else if (info.isStatementContext()) {
if (element == null || !(element.getParent() instanceof PsiForStatement)) {
return removeExtraSemicolon(info, offset, result, null);
}
return offset;
}
private static boolean isRemovableToken(PsiElement element) {
final PsiElement parent = element.getParent();
if (!(parent instanceof PsiAnnotationParameterList || // ',' between annotation parameters
parent instanceof PsiAssertStatement || // ':' before assertion message
parent instanceof PsiExpressionList || // ',' between expressions
parent instanceof PsiParameterList || // ',' between parameters
parent instanceof PsiPolyadicExpression || // '+', '*', '&&' etcetera
parent instanceof PsiReferenceList || // ','
parent instanceof PsiReferenceParameterList || // ','
parent instanceof PsiResourceList || // ';'
parent instanceof PsiTypeParameterList || // ','
parent instanceof PsiVariable)) { // '=' before initializer
return false;
}
final String text = element.getText();
if (text.length() != 1) {
return true;
}
switch(text.charAt(0)) {
case '<':
case '>':
case '(':
case ')':
case '{':
case '}':
case '[':
case ']':
return false;
default:
return true;
}
}
@Override
public boolean isIdentifier(PsiElement element) {
return element instanceof PsiIdentifier;
@@ -1284,7 +1284,7 @@ public class StructuralReplaceTest extends StructuralReplaceTestCase {
String expectedResult = "class A {\n" +
" public int a = 1;\n" +
" public int b ;\n" +
" public int b ;\n" +
" private int c = 2;\n" +
"}";
@@ -2259,4 +2259,53 @@ public class StructuralReplaceTest extends StructuralReplaceTestCase {
assertEquals("@SuppressWarnings(\"NONE\") @Deprecated\n" +
"class A {}", replacer.testReplace(in, what, by2, options, false));
}
public void testReplacePolyadicExpression() {
final String in1 = "class A {" +
" int i = 1 + 2 + 3;" +
"}";
final String what1 = "1 + '_a+";
final String by1 = "4";
assertEquals("class A { int i = 4;}", replacer.testReplace(in1, what1, by1, options, false));
final String by2 = "$a$";
assertEquals("class A { int i = 2+3;}", replacer.testReplace(in1, what1, by2, options, false));
final String by3 = "$a$+4";
assertEquals("class A { int i = 2+3+4;}", replacer.testReplace(in1, what1, by3, options, false));
final String what2 = "1 + 2 + 3 + '_a*";
final String by4 = "1 + 3 + $a$";
assertEquals("class A { int i = 1 + 3;}", replacer.testReplace(in1, what2, by4, options, false));
final String by5 = "$a$ + 1 + 3";
assertEquals("class A { int i = 1 + 3;}", replacer.testReplace(in1, what2, by5, options, false));
final String by6 = "1 + $a$ + 3";
assertEquals("class A { int i = 1 + 3;}", replacer.testReplace(in1, what2, by6, options, false));
final String in2 = "class A {" +
" boolean b = true && true;" +
"}";
final String what3 = "true && true && '_a*";
final String by7 = "true && true && $a$";
assertEquals("class A { boolean b = true && true;}", replacer.testReplace(in2, what3, by7, options, false));
final String by8 = "$a$ && true && true";
assertEquals("class A { boolean b = true && true;}", replacer.testReplace(in2, what3, by8, options, false));
}
public void testReplaceAssert() {
final String in = "class A {" +
" void m(int i) {" +
" assert 10 > i;" +
" }" +
"}";
final String what = "assert '_a > '_b : '_c?;";
final String by = "assert $b$ < $a$ : $c$;";
assertEquals("class A { void m(int i) { assert i < 10 ; }}", replacer.testReplace(in, what, by, options, false));
}
}