mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
Add pending edge from left operand in boolean expressions (PY-25974)
This commit is contained in:
@@ -20,13 +20,13 @@ import com.intellij.codeInsight.codeFragment.CodeFragmentUtil;
|
||||
import com.intellij.codeInsight.codeFragment.Position;
|
||||
import com.intellij.codeInsight.controlflow.ControlFlow;
|
||||
import com.intellij.codeInsight.controlflow.Instruction;
|
||||
import com.intellij.openapi.util.Condition;
|
||||
import com.intellij.openapi.util.Pair;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.util.PsiTreeUtil;
|
||||
import com.intellij.usageView.UsageInfo;
|
||||
import com.intellij.util.ArrayUtil;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import com.jetbrains.python.PyBundle;
|
||||
import com.jetbrains.python.PyTokenTypes;
|
||||
import com.jetbrains.python.codeInsight.controlflow.ControlFlowCache;
|
||||
import com.jetbrains.python.codeInsight.controlflow.ReadWriteInstruction;
|
||||
import com.jetbrains.python.codeInsight.controlflow.ScopeOwner;
|
||||
@@ -218,7 +218,14 @@ public class PyCodeFragmentUtil {
|
||||
final boolean isExceptTarget = target instanceof PyExceptPart || target instanceof PyFinallyPart;
|
||||
final boolean isLoopTarget = target instanceof PyWhileStatement || PyForStatementNavigator.getPyForStatementByIterable(target) != null;
|
||||
|
||||
if (target != null && !isExceptTarget && !isLoopTarget) {
|
||||
final PyBinaryExpression binaryExpression = PsiTreeUtil.getParentOfType(source, PyBinaryExpression.class);
|
||||
final boolean isOppositeBinaryTarget =
|
||||
binaryExpression != null &&
|
||||
ArrayUtil.contains(binaryExpression.getOperator(), PyTokenTypes.AND_KEYWORD, PyTokenTypes.OR_KEYWORD) &&
|
||||
binaryExpression.getLeftExpression() == source &&
|
||||
binaryExpression.getRightExpression() == target;
|
||||
|
||||
if (target != null && !isExceptTarget && !isLoopTarget && !isOppositeBinaryTarget) {
|
||||
targetInstructions.add(targetInstruction);
|
||||
}
|
||||
|
||||
|
||||
@@ -415,12 +415,15 @@ public class PyControlFlowBuilder extends PyRecursiveElementVisitor {
|
||||
final PyElementType operator = node.getOperator();
|
||||
if (operator == PyTokenTypes.AND_KEYWORD || operator == PyTokenTypes.OR_KEYWORD) {
|
||||
myBuilder.startNode(node);
|
||||
final PyExpression left = node.getLeftExpression();
|
||||
final PyTypeAssertionEvaluator assertionEvaluator = new PyTypeAssertionEvaluator(operator == PyTokenTypes.AND_KEYWORD);
|
||||
|
||||
final PyExpression left = node.getLeftExpression();
|
||||
if (left != null) {
|
||||
left.accept(this);
|
||||
left.accept(assertionEvaluator);
|
||||
myBuilder.addPendingEdge(node, myBuilder.prevInstruction);
|
||||
}
|
||||
|
||||
final PyExpression right = node.getRightExpression();
|
||||
if (right != null) {
|
||||
InstructionBuilder.addAssertInstructions(myBuilder, assertionEvaluator);
|
||||
|
||||
@@ -1,7 +1 @@
|
||||
class A:
|
||||
pass
|
||||
|
||||
|
||||
var = object()
|
||||
if isinstance(var, A) and var:
|
||||
pass
|
||||
foo = bar and baz
|
||||
@@ -1,17 +1,7 @@
|
||||
0(1) element: null
|
||||
1(2) element: PyClass: A
|
||||
2(3) WRITE ACCESS: A
|
||||
3(4) element: PyAssignmentStatement
|
||||
4(5) READ ACCESS: object
|
||||
5(6) WRITE ACCESS: var
|
||||
6(7) element: PyIfStatement
|
||||
7(8) element: PyBinaryExpression
|
||||
8(9) READ ACCESS: isinstance
|
||||
9(10) READ ACCESS: var
|
||||
10(11) READ ACCESS: A
|
||||
11(12) ASSERTTYPE ACCESS: var
|
||||
12(13,15) READ ACCESS: var
|
||||
13(14) element: PyStatementList. Condition: isinstance(var, A) and var:true
|
||||
14(16) ASSERTTYPE ACCESS: var
|
||||
15(16) ASSERTTYPE ACCESS: var
|
||||
16() element: null
|
||||
1(2) element: PyAssignmentStatement
|
||||
2(3) element: PyBinaryExpression
|
||||
3(4,5) READ ACCESS: bar
|
||||
4(5) READ ACCESS: baz
|
||||
5(6) WRITE ACCESS: foo
|
||||
6() element: null
|
||||
@@ -8,7 +8,7 @@
|
||||
7(8) element: PyIfStatement
|
||||
8(9) element: PyBinaryExpression
|
||||
9(10) READ ACCESS: hour
|
||||
10(11) READ ACCESS: start
|
||||
10(11,13,3,16) READ ACCESS: start
|
||||
11(12) READ ACCESS: hour
|
||||
12(13,3,16) READ ACCESS: end
|
||||
13(14) element: PyStatementList. Condition: hour >= start and hour < end:true
|
||||
|
||||
@@ -22,8 +22,8 @@
|
||||
21(22) element: PyAssignmentStatement
|
||||
22(23) element: PyBinaryExpression
|
||||
23(24) element: PyBinaryExpression
|
||||
24(25) READ ACCESS: collapse
|
||||
25(26) element: PyLambdaExpression
|
||||
24(25,26) READ ACCESS: collapse
|
||||
25(26,27) element: PyLambdaExpression
|
||||
26(27) element: PyLambdaExpression
|
||||
27(28) WRITE ACCESS: processFunc
|
||||
28(29) element: PyPrintStatement
|
||||
|
||||
@@ -1,11 +1 @@
|
||||
class A:
|
||||
pass
|
||||
|
||||
|
||||
class B:
|
||||
pass
|
||||
|
||||
|
||||
if isinstance(var, A):
|
||||
if isinstance(var, B) or var:
|
||||
pass
|
||||
foo = bar or baz
|
||||
@@ -1,23 +1,7 @@
|
||||
0(1) element: null
|
||||
1(2) element: PyClass: A
|
||||
2(3) WRITE ACCESS: A
|
||||
3(4) element: PyClass: B
|
||||
4(5) WRITE ACCESS: B
|
||||
5(6) element: PyIfStatement
|
||||
6(7) READ ACCESS: isinstance
|
||||
7(8) READ ACCESS: var
|
||||
8(9,21) READ ACCESS: A
|
||||
9(10) element: PyStatementList. Condition: isinstance(var, A):true
|
||||
10(11) ASSERTTYPE ACCESS: var
|
||||
11(12) element: PyIfStatement
|
||||
12(13) element: PyBinaryExpression
|
||||
13(14) READ ACCESS: isinstance
|
||||
14(15) READ ACCESS: var
|
||||
15(16) READ ACCESS: B
|
||||
16(17) ASSERTTYPE ACCESS: var
|
||||
17(18,20) READ ACCESS: var
|
||||
18(19) element: PyStatementList. Condition: isinstance(var, B) or var:true
|
||||
19(22) ASSERTTYPE ACCESS: var
|
||||
20(22) ASSERTTYPE ACCESS: var
|
||||
21(22) ASSERTTYPE ACCESS: var
|
||||
22() element: null
|
||||
1(2) element: PyAssignmentStatement
|
||||
2(3) element: PyBinaryExpression
|
||||
3(4,5) READ ACCESS: bar
|
||||
4(5) READ ACCESS: baz
|
||||
5(6) WRITE ACCESS: foo
|
||||
6() element: null
|
||||
@@ -0,0 +1,7 @@
|
||||
class A:
|
||||
pass
|
||||
|
||||
|
||||
var = object()
|
||||
if isinstance(var, A) and var:
|
||||
pass
|
||||
@@ -0,0 +1,11 @@
|
||||
class A:
|
||||
pass
|
||||
|
||||
|
||||
class B:
|
||||
pass
|
||||
|
||||
|
||||
if isinstance(var, A):
|
||||
if isinstance(var, B) or var:
|
||||
pass
|
||||
@@ -0,0 +1,2 @@
|
||||
import sys
|
||||
FOO = abc or sys.exit()
|
||||
@@ -229,11 +229,21 @@ public class PyControlFlowBuilderTest extends LightMarkedTestCase {
|
||||
}
|
||||
|
||||
// PY-20889
|
||||
public void testAndBooleanExpression() {
|
||||
public void testTypesInAndBooleanExpression() {
|
||||
doTest();
|
||||
}
|
||||
|
||||
// PY-20889
|
||||
public void testTypesInOrBooleanExpression() {
|
||||
doTest();
|
||||
}
|
||||
|
||||
// PY-25974
|
||||
public void testAndBooleanExpression() {
|
||||
doTest();
|
||||
}
|
||||
|
||||
// PY-25974
|
||||
public void testOrBooleanExpression() {
|
||||
doTest();
|
||||
}
|
||||
|
||||
@@ -33,6 +33,11 @@ public class PyUnreachableCodeInspectionTest extends PyInspectionTestCase {
|
||||
runWithLanguageLevel(LanguageLevel.PYTHON26, () -> doTest());
|
||||
}
|
||||
|
||||
// PY-25974
|
||||
public void testExprOrSysExitAssignedToVar() {
|
||||
doTest();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
protected Class<? extends PyInspection> getInspectionClass() {
|
||||
|
||||
Reference in New Issue
Block a user