mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
PY-21175 Add implicit negative type assertion after "if" in CFG unconditionally
The check that we should add such synthetic node only if there were no pending edges inside the body of if statement (e.g. if it contained only break/continue/return for the enclosing loop) seems doubtful and doesn't cover the simplest/most common cases.
This commit is contained in:
@@ -365,13 +365,6 @@ public class PyControlFlowBuilder extends PyRecursiveElementVisitor {
|
||||
});
|
||||
myBuilder.addPendingEdge(node, myBuilder.prevInstruction);
|
||||
}
|
||||
final Ref<Boolean> pendingInScopeEdges = Ref.create(false);
|
||||
myBuilder.processPending((pendingScope, instruction) -> {
|
||||
if (pendingScope != null && PsiTreeUtil.isAncestor(node, pendingScope, false)) {
|
||||
pendingInScopeEdges.set(true);
|
||||
}
|
||||
myBuilder.addPendingEdge(pendingScope, instruction);
|
||||
});
|
||||
final PyTypeAssertionEvaluator negativeAssertionEvaluator = new PyTypeAssertionEvaluator(false);
|
||||
final PyExpression ifCondition = ifPart.getCondition();
|
||||
// TODO: Add support for 'elif'
|
||||
@@ -386,15 +379,11 @@ public class PyControlFlowBuilder extends PyRecursiveElementVisitor {
|
||||
InstructionBuilder.addAssertInstructions(myBuilder, negativeAssertionEvaluator);
|
||||
elseBranch.accept(this);
|
||||
myBuilder.addPendingEdge(node, myBuilder.prevInstruction);
|
||||
} else {
|
||||
if (!pendingInScopeEdges.get()) {
|
||||
myBuilder.prevInstruction = lastBranchingPoint;
|
||||
InstructionBuilder.addAssertInstructions(myBuilder, negativeAssertionEvaluator);
|
||||
myBuilder.addPendingEdge(node, myBuilder.prevInstruction);
|
||||
}
|
||||
else {
|
||||
myBuilder.addPendingEdge(node, lastBranchingPoint);
|
||||
}
|
||||
}
|
||||
else {
|
||||
myBuilder.prevInstruction = lastBranchingPoint;
|
||||
InstructionBuilder.addAssertInstructions(myBuilder, negativeAssertionEvaluator);
|
||||
myBuilder.addPendingEdge(node, myBuilder.prevInstruction);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
if xs is None:
|
||||
xs = [1, 2, 3]
|
||||
print(xs)
|
||||
@@ -0,0 +1,12 @@
|
||||
0(1) element: null
|
||||
1(2) element: PyIfStatement
|
||||
2(3) READ ACCESS: xs
|
||||
3(4,8) READ ACCESS: None
|
||||
4(5) element: PyStatementList. Condition: xs is None:true
|
||||
5(6) ASSERTTYPE ACCESS: xs
|
||||
6(7) element: PyAssignmentStatement
|
||||
7(9) WRITE ACCESS: xs
|
||||
8(9) ASSERTTYPE ACCESS: xs
|
||||
9(10) element: PyPrintStatement
|
||||
10(11) READ ACCESS: xs
|
||||
11() element: null
|
||||
+5
@@ -0,0 +1,5 @@
|
||||
if not isinstance(x, str):
|
||||
if x is None:
|
||||
print(x)
|
||||
print(x)
|
||||
print(x)
|
||||
+21
@@ -0,0 +1,21 @@
|
||||
0(1) element: null
|
||||
1(2) element: PyIfStatement
|
||||
2(3) READ ACCESS: isinstance
|
||||
3(4) READ ACCESS: x
|
||||
4(5,17) READ ACCESS: str
|
||||
5(6) element: PyStatementList. Condition: not isinstance(x, str):true
|
||||
6(7) ASSERTTYPE ACCESS: x
|
||||
7(8) element: PyIfStatement
|
||||
8(9) READ ACCESS: x
|
||||
9(10,14) READ ACCESS: None
|
||||
10(11) element: PyStatementList. Condition: x is None:true
|
||||
11(12) ASSERTTYPE ACCESS: x
|
||||
12(13) element: PyPrintStatement
|
||||
13(15) READ ACCESS: x
|
||||
14(15) ASSERTTYPE ACCESS: x
|
||||
15(16) element: PyPrintStatement
|
||||
16(18) READ ACCESS: x
|
||||
17(18) ASSERTTYPE ACCESS: x
|
||||
18(19) element: PyPrintStatement
|
||||
19(20) READ ACCESS: x
|
||||
20() element: null
|
||||
@@ -6,23 +6,25 @@
|
||||
5(6,9) element: PyTryPart
|
||||
6(7,9) element: PyAssignmentStatement
|
||||
7(8,9) READ ACCESS: open
|
||||
8(9,17) WRITE ACCESS: status
|
||||
8(9,18) WRITE ACCESS: status
|
||||
9(10) element: PyFinallyPart
|
||||
10(11) element: PyIfStatement
|
||||
11(12) READ ACCESS: status
|
||||
12(13,27) READ ACCESS: None
|
||||
12(13,17) READ ACCESS: None
|
||||
13(14) element: PyStatementList. Condition: status is not None:true
|
||||
14(15) ASSERTTYPE ACCESS: status
|
||||
15(16) element: PyPrintStatement
|
||||
16(27) READ ACCESS: status
|
||||
17(18) element: PyFinallyPart
|
||||
18(19) element: PyIfStatement
|
||||
19(20) READ ACCESS: status
|
||||
20(21,25) READ ACCESS: None
|
||||
21(22) element: PyStatementList. Condition: status is not None:true
|
||||
22(23) ASSERTTYPE ACCESS: status
|
||||
23(24) element: PyPrintStatement
|
||||
24(25) READ ACCESS: status
|
||||
25(26) element: PyExpressionStatement
|
||||
26(27) READ ACCESS: status
|
||||
27() element: null
|
||||
16(29) READ ACCESS: status
|
||||
17(29) ASSERTTYPE ACCESS: status
|
||||
18(19) element: PyFinallyPart
|
||||
19(20) element: PyIfStatement
|
||||
20(21) READ ACCESS: status
|
||||
21(22,26) READ ACCESS: None
|
||||
22(23) element: PyStatementList. Condition: status is not None:true
|
||||
23(24) ASSERTTYPE ACCESS: status
|
||||
24(25) element: PyPrintStatement
|
||||
25(27) READ ACCESS: status
|
||||
26(27) ASSERTTYPE ACCESS: status
|
||||
27(28) element: PyExpressionStatement
|
||||
28(29) READ ACCESS: status
|
||||
29() element: null
|
||||
@@ -238,6 +238,16 @@ public class PyControlFlowBuilderTest extends LightMarkedTestCase {
|
||||
runWithLanguageLevel(LanguageLevel.PYTHON36, this::doTest);
|
||||
}
|
||||
|
||||
// PY-21175
|
||||
public void testImplicitNegativeTypeAssertionAfterIf() {
|
||||
doTest();
|
||||
}
|
||||
|
||||
// PY-21175
|
||||
public void testImplicitNegativeTypeAssertionAfterTwoNestedIf() {
|
||||
doTest();
|
||||
}
|
||||
|
||||
private void doTestFirstStatement() {
|
||||
final String testName = getTestName(false).toLowerCase();
|
||||
configureByFile(testName + ".py");
|
||||
|
||||
Reference in New Issue
Block a user