EA-401551 Fix an exception when joining IFs with assignment expressions

GitOrigin-RevId: ce9610afb4e280b2930f126861bdaf13bd69021e
This commit is contained in:
Mikhail Golubev
2021-11-19 17:55:09 +02:00
committed by intellij-monorepo-bot
parent b55d2679cc
commit f8aecd088e
9 changed files with 43 additions and 5 deletions

View File

@@ -10,8 +10,8 @@ import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.util.ArrayUtil;
import com.intellij.util.IncorrectOperationException;
import com.jetbrains.python.PyPsiBundle;
import com.jetbrains.python.PyTokenTypes;
import com.jetbrains.python.psi.*;
import com.jetbrains.python.refactoring.PyReplaceExpressionUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -81,15 +81,24 @@ public class PyJoinIfIntention extends PyBaseIntentionAction {
if (outerCondition == null || innerCondition == null) return;
PyElementGenerator elementGenerator = PyElementGenerator.getInstance(project);
StringBuilder replacementText = new StringBuilder(outerCondition.getText() + " and ");
if (innerCondition instanceof PyBinaryExpression && ((PyBinaryExpression)innerCondition).getOperator() == PyTokenTypes.OR_KEYWORD) {
LanguageLevel pyVersion = LanguageLevel.forElement(file);
PyBinaryExpression fakeAndExpression = (PyBinaryExpression)elementGenerator.createExpressionFromText(pyVersion, "foo and bar");
StringBuilder replacementText = new StringBuilder();
if (PyReplaceExpressionUtil.isNeedParenthesis(fakeAndExpression.getLeftExpression(), outerCondition)) {
replacementText.append("(").append(outerCondition.getText()).append(")");
}
else {
replacementText.append(outerCondition.getText());
}
replacementText.append(" and ");
if (PyReplaceExpressionUtil.isNeedParenthesis(fakeAndExpression.getLeftExpression(), innerCondition)) {
replacementText.append("(").append(innerCondition.getText()).append(")");
}
else {
replacementText.append(innerCondition.getText());
}
PyExpression newCondition = elementGenerator.createExpressionFromText(LanguageLevel.forElement(file), replacementText.toString());
PyExpression newCondition = elementGenerator.createExpressionFromText(pyVersion, replacementText.toString());
outerCondition.replace(newCondition);
PyStatementList innerStatementList = innerIfStatement.getIfPart().getStatementList();

View File

@@ -433,7 +433,7 @@ public final class PyReplaceExpressionUtil implements PyElementTypes {
opType == DIV || opType == FLOORDIV || opType == PERC || opType == EXP || opType == MINUS;
}
private static int getExpressionPriority(PyElement expr) {
private static int getExpressionPriority(@NotNull PyElement expr) {
int priority = 0;
if (expr instanceof PyReferenceExpression ||
expr instanceof PySubscriptionExpression ||
@@ -459,6 +459,7 @@ public final class PyReplaceExpressionUtil implements PyElementTypes {
}
else if (expr instanceof PyConditionalExpression) priority = 14;
else if (expr instanceof PyLambdaExpression) priority = 15;
else if (expr instanceof PyAssignmentExpression) priority = 16;
return -priority;
}

View File

@@ -0,0 +1,3 @@
if x:
if y := foo():
pass

View File

@@ -0,0 +1,2 @@
if x and (y := foo()):
pass

View File

@@ -0,0 +1,3 @@
if x := foo():
if y := bar():
pass

View File

@@ -0,0 +1,2 @@
if (x := foo()) and (y := bar()):
pass

View File

@@ -0,0 +1,3 @@
if x o<caret>r y:
if z:
pass

View File

@@ -0,0 +1,2 @@
if (x or y) and z:
pass

View File

@@ -153,6 +153,19 @@ public class PyIntentionTest extends PyTestCase {
doNegativeTest(PyPsiBundle.message("INTN.join.if"));
}
public void testJoinIfOrExpressionInOuterCondition() {
doTest(PyPsiBundle.message("INTN.join.if"));
}
// EA-401551
public void testJoinIfAssignmentExpressionInInnerCondition() {
doTest(PyPsiBundle.message("INTN.join.if"));
}
public void testJoinIfAssignmentExpressionsInBothConditions() {
doTest(PyPsiBundle.message("INTN.join.if"));
}
public void testDictConstructorToLiteralForm() {
doTest(PyPsiBundle.message("INTN.convert.dict.constructor.to.dict.literal"));
}