utility to flatten nested polyadic expressions to avoid reparse diffs

IDEA-192541
This commit is contained in:
Anna Kozlova
2018-05-24 16:21:15 +03:00
parent 9db096ebea
commit e6dd07e159
6 changed files with 48 additions and 15 deletions
@@ -1281,4 +1281,26 @@ public class ExpressionUtils {
}
return null;
}
/**
* Flattens second+ polyadic's operand replaced with another polyadic expression of the same type to the parent's operands.
*
* Otherwise reparse would produce different expression.
*/
public static PsiExpression replacePolyadicWithParent(PsiExpression expressionToReplace, PsiExpression replacement) {
PsiElement parent = expressionToReplace.getParent();
if (parent instanceof PsiPolyadicExpression &&
replacement instanceof PsiPolyadicExpression &&
((PsiPolyadicExpression)parent).getOperationTokenType() == ((PsiPolyadicExpression)replacement).getOperationTokenType()) {
int idx = ArrayUtil.indexOf(((PsiPolyadicExpression)parent).getOperands(), expressionToReplace);
if (idx > 0) {
PsiPolyadicExpression copyParentPolyadic = (PsiPolyadicExpression)parent.copy();
new CommentTracker().replaceAndRestoreComments(copyParentPolyadic.getOperands()[idx], replacement);
PsiExpression recreateCopyFromText = JavaPsiFacade.getElementFactory(parent.getProject())
.createExpressionFromText(copyParentPolyadic.getText(), parent);
return ((PsiPolyadicExpression)parent.replace(recreateCopyFromText)).getOperands()[idx];
}
}
return null;
}
}
@@ -18,7 +18,6 @@ package com.siyeh.ig.psiutils;
import com.intellij.psi.*;
import com.intellij.psi.tree.IElementType;
import com.intellij.psi.util.PsiPrecedenceUtil;
import com.intellij.util.ArrayUtil;
import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -184,16 +183,8 @@ public class ParenthesesUtils {
}
final PsiElement parent = parenthesizedExpression.getParent();
if (!(parent instanceof PsiExpression) || !areParenthesesNeeded(body, (PsiExpression)parent, ignoreClarifyingParentheses)) {
final PsiExpression newExpression;
int idx;
if (parent instanceof PsiPolyadicExpression && (idx = ArrayUtil.indexOf(((PsiPolyadicExpression)parent).getOperands(), parenthesizedExpression)) > 0) {
PsiPolyadicExpression copyParentPolyadic = (PsiPolyadicExpression)parent.copy();
new CommentTracker().replaceAndRestoreComments(copyParentPolyadic.getOperands()[idx], body);
PsiExpression recreateCopyFromText = JavaPsiFacade.getElementFactory(copyParentPolyadic.getProject())
.createExpressionFromText(copyParentPolyadic.getText(), parent);
newExpression = ((PsiPolyadicExpression)parent.replace(recreateCopyFromText)).getOperands()[idx];
}
else {
PsiExpression newExpression = ExpressionUtils.replacePolyadicWithParent(parenthesizedExpression, body);
if (newExpression == null){
newExpression = (PsiExpression)new CommentTracker().replaceAndRestoreComments(parenthesizedExpression, body);
}
removeParentheses(newExpression, ignoreClarifyingParentheses);
@@ -24,6 +24,7 @@ import com.intellij.psi.codeStyle.CodeStyleManager;
import com.siyeh.IntentionPowerPackBundle;
import com.siyeh.ig.psiutils.BoolUtils;
import com.siyeh.ig.psiutils.CommentTracker;
import com.siyeh.ig.psiutils.ExpressionUtils;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -74,13 +75,21 @@ public abstract class Intention extends BaseElementAtCaretIntentionAction {
}
expString = "!(" + newExpression + ')';
}
final PsiExpression newCall = factory.createExpressionFromText(expString, expression);
assert expressionToReplace != null;
final PsiElement insertedElement = tracker.replaceAndRestoreComments(expressionToReplace, newCall);
final CodeStyleManager codeStyleManager = CodeStyleManager.getInstance(project);
codeStyleManager.reformat(insertedElement);
PsiExpression newCall = factory.createExpressionFromText(expString, expression);
if (newCall instanceof PsiPolyadicExpression) {
PsiElement insertedElement = ExpressionUtils.replacePolyadicWithParent(expressionToReplace, newCall);
if (insertedElement != null) {
CodeStyleManager.getInstance(project).reformat(insertedElement);
return;
}
}
PsiElement insertedElement = tracker.replaceAndRestoreComments(expressionToReplace, newCall);
CodeStyleManager.getInstance(project).reformat(insertedElement);
}
@Nullable
PsiElement findMatchingElement(@Nullable PsiElement element, Editor editor) {
while (element != null) {
@@ -0,0 +1,5 @@
class A {
void foo(boolean a, boolean b, boolean c, boolean d) {
boolean f = a && !(b ||<caret> c || d);
}
}
@@ -0,0 +1,5 @@
class A {
void foo(boolean a, boolean b, boolean c, boolean d) {
boolean f = a && !b && !c && !d;
}
}
@@ -23,6 +23,7 @@ public class DemorgansIntentionTest extends IPPTestCase {
public void testNeedsMoreParentheses() { doTest(); }
public void testNotTooManyParentheses() { doTest(); }
public void testErrorElement() { assertIntentionNotAvailable(); }
public void testFlattenPolyadic() { doTest(); }
@Override
protected String getIntentionName() {