Support positive iterations in control flow (PY-14840, PY-22003)

This commit is contained in:
Semyon Proshev
2017-12-11 15:43:05 +03:00
parent da35cce150
commit 2c1c972962
8 changed files with 51 additions and 3 deletions
@@ -32,6 +32,7 @@ import com.jetbrains.python.psi.impl.PyAugAssignmentStatementNavigator;
import com.jetbrains.python.psi.impl.PyConstantExpressionEvaluator;
import com.jetbrains.python.psi.impl.PyImportStatementNavigator;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.ArrayList;
import java.util.List;
@@ -455,7 +456,7 @@ public class PyControlFlowBuilder extends PyRecursiveElementVisitor {
}
final Instruction head = myBuilder.prevInstruction;
final PyElsePart elsePart = node.getElsePart();
if (elsePart == null) {
if (elsePart == null && !nonEmptyIterationSource(source)) {
myBuilder.addPendingEdge(node, myBuilder.prevInstruction);
}
final PyStatementList list = forPart.getStatementList();
@@ -490,6 +491,13 @@ public class PyControlFlowBuilder extends PyRecursiveElementVisitor {
myBuilder.flowAbrupted();
}
private static boolean nonEmptyIterationSource(@Nullable PyExpression source) {
return
source instanceof PySequenceExpression && !((PySequenceExpression)source).isEmpty() ||
source instanceof PyStringLiteralExpression && !((PyStringLiteralExpression)source).getStringValue().isEmpty() ||
source instanceof PyParenthesizedExpression && nonEmptyIterationSource(((PyParenthesizedExpression)source).getContainedExpression());
}
@Override
public void visitPyBreakStatement(final PyBreakStatement node) {
myBuilder.startNode(node);
@@ -0,0 +1,3 @@
for i in "abc":
j = 1
print(j)
@@ -0,0 +1,9 @@
0(1) element: null
1(2) element: PyForStatement
2(3) element: PyTargetExpression: i
3(4) WRITE ACCESS: i
4(5) element: PyAssignmentStatement
5(2,6) WRITE ACCESS: j
6(7) element: PyPrintStatement
7(8) READ ACCESS: j
8() element: null
@@ -5,7 +5,7 @@
4(5,55) element: PyTryPart
5(6,55) element: PyAssignmentStatement
6(7,55) WRITE ACCESS: b
7(8,53,55) element: PyForStatement
7(8,55) element: PyForStatement
8(9,55) element: PyTargetExpression: x
9(10,55) WRITE ACCESS: x
10(11,55) element: PyTryExceptStatement
@@ -0,0 +1,16 @@
def test1():
for i in "abc":
j = 1
print(j)
def test2():
for i in (1, 2):
j = 1
print(j)
def test3():
for i in [1, 2]:
j = 1
print(j)
@@ -20,7 +20,7 @@ def boo():
for i in [1,2]:
print(i)
j = 1 #pass
<weak_warning descr="Local variable 'j' value is not used">j</weak_warning> = 1 #fail
for j in [-2, -1]:
print(j)
print (j)
@@ -238,6 +238,12 @@ public class PyControlFlowBuilderTest extends LightMarkedTestCase {
doTest();
}
// PY-14840
// PY-22003
public void testPositiveIteration() {
doTest();
}
private void doTestFirstStatement() {
final String testName = getTestName(false).toLowerCase();
configureByFile(testName + ".py");
@@ -191,6 +191,12 @@ public class PyUnboundLocalVariableInspectionTest extends PyInspectionTestCase {
doTest();
}
// PY-14840
// PY-22003
public void testPositiveIteration() {
doTest();
}
@NotNull
@Override
protected Class<? extends PyInspection> getInspectionClass() {