VariableExtractor: support ternary conditions in assignment and return (IDEA-202048)

This commit is contained in:
Tagir Valeev
2018-11-11 11:28:18 +07:00
parent 67ba10b924
commit 5c093a995a
8 changed files with 89 additions and 7 deletions
@@ -244,12 +244,10 @@ class VariableExtractor {
}
}
}
if (firstOccurrence != null && ControlFlowUtils.canExtractStatement(firstOccurrence)) {
PsiExpression ancestorCandidate = anchor instanceof PsiIfStatement ? ((PsiIfStatement)anchor).getCondition() :
anchor instanceof PsiReturnStatement ? ((PsiReturnStatement)anchor).getReturnValue():
anchor instanceof PsiExpression ? (PsiExpression)anchor :
null;
if (PsiTreeUtil.isAncestor(ancestorCandidate, firstOccurrence, false) &&
if (firstOccurrence != null && ControlFlowUtils.canExtractStatement(firstOccurrence) &&
!PsiUtil.isAccessedForWriting(firstOccurrence)) {
PsiExpression ancestorCandidate = ExpressionUtils.getTopLevelExpression(firstOccurrence);
if (PsiTreeUtil.isAncestor(anchor, ancestorCandidate, false) &&
ReorderingUtils.canExtract(ancestorCandidate, firstOccurrence) == ThreeState.NO) {
return firstOccurrence;
}
@@ -54,6 +54,11 @@ class EnsureCodeBlockImpl {
if (parent == null) return null;
return replace(expression, parent, (oldParent, copy) -> extractFieldInitializer((PsiField)oldParent, (PsiField)copy));
}
PsiConditionalExpression ternary = findSurroundingTernary(expression);
if (ternary != null && parent instanceof PsiStatement) {
return replace(expression, parent, (oldParent, copy) -> replaceTernaryWithIf((PsiStatement)oldParent, ternary));
}
PsiPolyadicExpression condition = findSurroundingConditionChain(expression);
PsiExpression operand;
@@ -183,6 +188,28 @@ class EnsureCodeBlockImpl {
Objects.requireNonNull(whileStatement.getCondition()).replace(lOperands);
return newParent;
}
private static PsiElement replaceTernaryWithIf(PsiStatement statement, PsiConditionalExpression ternary) {
PsiElementFactory factory = JavaPsiFacade.getElementFactory(statement.getProject());
PsiIfStatement ifStatement =
(PsiIfStatement)factory.createStatementFromText("if(" + ternary.getCondition().getText() + ") {} else {}", statement);
Object mark = new Object();
PsiTreeUtil.mark(ternary, mark);
PsiStatement thenStatement = (PsiStatement)statement.copy();
PsiConditionalExpression thenTernary = Objects.requireNonNull((PsiConditionalExpression)PsiTreeUtil.releaseMark(thenStatement, mark));
PsiExpression branch1 = ternary.getThenExpression();
if (branch1 != null) {
thenTernary.replace(branch1);
}
PsiStatement elseStatement = (PsiStatement)statement.copy();
PsiConditionalExpression elseTernary = Objects.requireNonNull((PsiConditionalExpression)PsiTreeUtil.releaseMark(elseStatement, mark));
PsiExpression branch = ternary.getElseExpression();
if (branch != null) {
elseTernary.replace(branch);
}
((PsiBlockStatement)Objects.requireNonNull(ifStatement.getThenBranch())).getCodeBlock().add(thenStatement);
((PsiBlockStatement)Objects.requireNonNull(ifStatement.getElseBranch())).getCodeBlock().add(elseStatement);
return statement.replace(ifStatement);
}
private static PsiElement splitIf(PsiIfStatement outerIf, PsiPolyadicExpression andChain, PsiExpression operand) {
PsiExpression lOperands = SplitConditionUtil.getLOperands(andChain, andChain.getTokenBeforeOperand(operand));
@@ -227,6 +254,18 @@ class EnsureCodeBlockImpl {
return polyadicExpression;
}
@Nullable
private static PsiConditionalExpression findSurroundingTernary(@NotNull PsiExpression expression) {
PsiExpression current = expression;
PsiConditionalExpression ternary;
do {
current = ternary = PsiTreeUtil.getParentOfType(current, PsiConditionalExpression.class, true,
PsiStatement.class, PsiLambdaExpression.class);
}
while (ternary != null && PsiTreeUtil.isAncestor(ternary.getCondition(), expression, false));
return ternary;
}
private static boolean hasNameCollision(PsiElement declaration, PsiElement context) {
if (declaration instanceof PsiDeclarationStatement) {
PsiResolveHelper helper = JavaPsiFacade.getInstance(context.getProject()).getResolveHelper();
@@ -0,0 +1,12 @@
class Test {
String x(String s) {
String x;
if (s == null) {
x = "";
} else {
String temp = s.trim();
x = temp;
}
return x;
}
}
@@ -0,0 +1,7 @@
class Test {
String x(String s) {
String x;
x = s == null ? "" : <selection>s.trim()</selection>;
return x;
}
}
@@ -0,0 +1,10 @@
class Test {
String x(String s) {
if (s == null) {
return "";
} else {
String temp = s.trim();
return temp;
}
}
}
@@ -0,0 +1,5 @@
class Test {
String x(String s) {
return s == null ? "" : <selection>s.trim()</selection>;
}
}
@@ -238,6 +238,14 @@ public class IntroduceVariableTest extends LightCodeInsightTestCase {
public void testReturnOrChain() {
doTest(new MockIntroduceVariableHandler("temp", true, false, false, CommonClassNames.JAVA_LANG_STRING));
}
public void testReturnTernary() {
doTest(new MockIntroduceVariableHandler("temp", true, false, false, CommonClassNames.JAVA_LANG_STRING));
}
public void testAssignTernary() {
doTest(new MockIntroduceVariableHandler("temp", true, false, false, CommonClassNames.JAVA_LANG_STRING));
}
public void testLambdaAndChain() {
doTest(new MockIntroduceVariableHandler("temp", true, false, false, CommonClassNames.JAVA_LANG_STRING));
@@ -928,7 +928,10 @@ public class ControlFlowUtils {
}
}
if (parent instanceof PsiConditionalExpression && ((PsiConditionalExpression)parent).getCondition() != cur) {
return false;
PsiElement ternaryParent = PsiUtil.skipParenthesizedExprUp(parent.getParent());
return ternaryParent instanceof PsiReturnStatement ||
(ternaryParent instanceof PsiAssignmentExpression && ternaryParent.getParent() instanceof PsiExpressionStatement &&
PsiUtil.skipParenthesizedExprDown(((PsiAssignmentExpression)ternaryParent).getRExpression()) == parent);
}
if(parent instanceof PsiMethodCallExpression) {
PsiReferenceExpression methodExpression = ((PsiMethodCallExpression)parent).getMethodExpression();