diff --git a/python/src/com/jetbrains/python/codeInsight/controlflow/PyControlFlowBuilder.java b/python/src/com/jetbrains/python/codeInsight/controlflow/PyControlFlowBuilder.java index 79673cdd4a10..2e5ce2fd828c 100644 --- a/python/src/com/jetbrains/python/codeInsight/controlflow/PyControlFlowBuilder.java +++ b/python/src/com/jetbrains/python/codeInsight/controlflow/PyControlFlowBuilder.java @@ -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); diff --git a/python/testData/codeInsight/controlflow/positiveiteration.py b/python/testData/codeInsight/controlflow/positiveiteration.py new file mode 100644 index 000000000000..34ff9ee421cd --- /dev/null +++ b/python/testData/codeInsight/controlflow/positiveiteration.py @@ -0,0 +1,3 @@ +for i in "abc": + j = 1 +print(j) \ No newline at end of file diff --git a/python/testData/codeInsight/controlflow/positiveiteration.txt b/python/testData/codeInsight/controlflow/positiveiteration.txt new file mode 100644 index 000000000000..d3eb4c178da0 --- /dev/null +++ b/python/testData/codeInsight/controlflow/positiveiteration.txt @@ -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 \ No newline at end of file diff --git a/python/testData/codeInsight/controlflow/trytry.txt b/python/testData/codeInsight/controlflow/trytry.txt index b6078f8500d5..0509f5935ea2 100644 --- a/python/testData/codeInsight/controlflow/trytry.txt +++ b/python/testData/codeInsight/controlflow/trytry.txt @@ -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 diff --git a/python/testData/inspections/PyUnboundLocalVariableInspection/PositiveIteration.py b/python/testData/inspections/PyUnboundLocalVariableInspection/PositiveIteration.py new file mode 100644 index 000000000000..1ff046b66aed --- /dev/null +++ b/python/testData/inspections/PyUnboundLocalVariableInspection/PositiveIteration.py @@ -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) diff --git a/python/testData/inspections/PyUnusedLocalInspection/py2.py b/python/testData/inspections/PyUnusedLocalInspection/py2.py index bafdcbfed95e..17a5d4e8a3a6 100644 --- a/python/testData/inspections/PyUnusedLocalInspection/py2.py +++ b/python/testData/inspections/PyUnusedLocalInspection/py2.py @@ -20,7 +20,7 @@ def boo(): for i in [1,2]: print(i) - j = 1 #pass + j = 1 #fail for j in [-2, -1]: print(j) print (j) diff --git a/python/testSrc/com/jetbrains/python/PyControlFlowBuilderTest.java b/python/testSrc/com/jetbrains/python/PyControlFlowBuilderTest.java index bca2bfe9ef53..ce039ac75d2b 100644 --- a/python/testSrc/com/jetbrains/python/PyControlFlowBuilderTest.java +++ b/python/testSrc/com/jetbrains/python/PyControlFlowBuilderTest.java @@ -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"); diff --git a/python/testSrc/com/jetbrains/python/inspections/PyUnboundLocalVariableInspectionTest.java b/python/testSrc/com/jetbrains/python/inspections/PyUnboundLocalVariableInspectionTest.java index 3a048aea3174..f81cae1b6204 100644 --- a/python/testSrc/com/jetbrains/python/inspections/PyUnboundLocalVariableInspectionTest.java +++ b/python/testSrc/com/jetbrains/python/inspections/PyUnboundLocalVariableInspectionTest.java @@ -191,6 +191,12 @@ public class PyUnboundLocalVariableInspectionTest extends PyInspectionTestCase { doTest(); } + // PY-14840 + // PY-22003 + public void testPositiveIteration() { + doTest(); + } + @NotNull @Override protected Class getInspectionClass() {