diff --git a/python/src/com/jetbrains/python/codeInsight/controlflow/PyControlFlowBuilder.java b/python/src/com/jetbrains/python/codeInsight/controlflow/PyControlFlowBuilder.java index d7d6c584d8b4..28a3a7bf1eb0 100644 --- a/python/src/com/jetbrains/python/codeInsight/controlflow/PyControlFlowBuilder.java +++ b/python/src/com/jetbrains/python/codeInsight/controlflow/PyControlFlowBuilder.java @@ -110,7 +110,11 @@ public class PyControlFlowBuilder extends PyRecursiveElementVisitor { return false; } final PyNamedParameter named = params[0].getAsNamed(); - return named != null && named.getName().equals(qualifier.getText()); + if (named == null) { + return false; + } + final String name = named.getName(); + return name != null && name.equals(qualifier.getText()); } @Override @@ -414,13 +418,13 @@ public class PyControlFlowBuilder extends PyRecursiveElementVisitor { public void visitPyTryExceptStatement(final PyTryExceptStatement node) { myBuilder.startNode(node); -// process body + // Process body final PyTryPart tryPart = node.getTryPart(); myBuilder.startNode(tryPart); tryPart.accept(this); final Instruction lastBlockInstruction = myBuilder.prevInstruction; -// Goto else block after execution, or exit + // Goto else block after execution, or exit final PyElsePart elsePart = node.getElsePart(); if (elsePart != null) { myBuilder.startNode(elsePart); @@ -458,30 +462,46 @@ public class PyControlFlowBuilder extends PyRecursiveElementVisitor { lastFinallyInstruction = myBuilder.prevInstruction; myBuilder.addPendingEdge(finallyPart, lastFinallyInstruction); } + + for (Instruction instruction : myBuilder.instructions) { + final PsiElement e = instruction.getElement(); + if (e == null || !canRaiseExceptions(instruction)) { + continue; + } + // All instructions inside the try part have edges to except and finally parts + if (PsiTreeUtil.isAncestor(tryPart, e, true)) { + for (Instruction inst : exceptInstructions) { + myBuilder.addEdge(instruction, inst); + } + if (finallyPart != null) { + myBuilder.addEdge(instruction, finallyInstruction); + } + } + if (finallyPart != null) { + // All instructions inside except parts have edges to the finally part + for (PyExceptPart exceptPart : node.getExceptParts()) { + if (PsiTreeUtil.isAncestor(exceptPart, e, true)) { + myBuilder.addEdge(instruction, finallyInstruction); + } + } + // All instructions inside the else part have edges to the finally part + if (PsiTreeUtil.isAncestor(elsePart, e, true)) { + myBuilder.addEdge(instruction, finallyInstruction); + } + } + } + final Ref finallyRef = new Ref(finallyInstruction); final Ref lastFinallyRef = new Ref(lastFinallyInstruction); + myBuilder.processPending(new ControlFlowBuilder.PendingProcessor() { - @SuppressWarnings({"ConstantConditions"}) public void process(final PsiElement pendingScope, final Instruction instruction) { final PsiElement pendingElement = instruction.getElement(); - - // Handle raise statements inside try part - if (isRaiseInstruction(pendingElement) && PsiTreeUtil.isAncestor(tryPart, pendingElement, false)) { - for (Instruction inst : exceptInstructions) { - myBuilder.addEdge(instruction, inst); - } - if (finallyPart!=null) { - myBuilder.addEdge(instruction, finallyRef.get()); - } + if (pendingElement == null) { return; } - else if (pendingElement != null && PsiTreeUtil.isAncestor(tryPart, pendingElement, false)){ - for (Instruction inst : exceptInstructions) { - myBuilder.addEdge(instruction, inst); - } - } - // handle return pending instructions inside try if final block exists + // Handle return pending instructions inside try if final block exists final boolean isPending = PsiTreeUtil.isAncestor(node, pendingElement, false) && (finallyPart == null || !PsiTreeUtil.isAncestor(finallyPart, pendingElement, false)); if (!finallyRef.isNull() && isPending) { @@ -500,10 +520,6 @@ public class PyControlFlowBuilder extends PyRecursiveElementVisitor { }); } - private boolean isRaiseInstruction(final PsiElement pendingElement) { - return pendingElement != null && PsiTreeUtil.getParentOfType(pendingElement, PyRaiseStatement.class) != null; - } - @Override public void visitPyComprehensionElement(final PyComprehensionElement node) { PyExpression prevCondition = null; @@ -667,4 +683,15 @@ public class PyControlFlowBuilder extends PyRecursiveElementVisitor { myBuilder.flowAbrupted(); } -} \ No newline at end of file + private static boolean canRaiseExceptions(final Instruction instruction) { + if (instruction instanceof ReadWriteInstruction) { + return true; + } + return !PsiTreeUtil.instanceOf(instruction.getElement(), + PyReturnStatement.class, + PyAssignmentStatement.class, + PyRaiseStatement.class, + PyStatementList.class); + } +} + diff --git a/python/testData/codeInsight/controlflow/doubletry.txt b/python/testData/codeInsight/controlflow/doubletry.txt index 8a3fd8097c6f..4a98ba533cc8 100644 --- a/python/testData/codeInsight/controlflow/doubletry.txt +++ b/python/testData/codeInsight/controlflow/doubletry.txt @@ -1,8 +1,8 @@ 0(1) element: null 1(2) element: PyTryExceptStatement 2(3) element: PyTryPart -3(4) element: PyFromImportStatement -4(5) READ ACCESS: mercurial +3(4,6) element: PyFromImportStatement +4(5,6) READ ACCESS: mercurial 5(6,10) READ ACCESS: lsprof 6(7) element: PyExceptPart 7(8) READ ACCESS: ImportError diff --git a/python/testData/codeInsight/controlflow/fortrycontinue.txt b/python/testData/codeInsight/controlflow/fortrycontinue.txt index ca76031e4ac2..8180e38ea8b4 100644 --- a/python/testData/codeInsight/controlflow/fortrycontinue.txt +++ b/python/testData/codeInsight/controlflow/fortrycontinue.txt @@ -9,8 +9,8 @@ 8(9) element: PyTryPart 9(10,14,5,17) element: PyForStatement 10(11) element: PyStatementList -11(12) WRITE ACCESS: t -12(13) element: PyPrintStatement +11(12,14) WRITE ACCESS: t +12(13,14) element: PyPrintStatement 13(10,14,5,17) READ ACCESS: t 14(15) element: PyExceptPart 15(16) READ ACCESS: Exception diff --git a/python/testData/codeInsight/controlflow/raise.txt b/python/testData/codeInsight/controlflow/raise.txt index 1461a143404e..e3f9d533f122 100644 --- a/python/testData/codeInsight/controlflow/raise.txt +++ b/python/testData/codeInsight/controlflow/raise.txt @@ -2,7 +2,7 @@ 1(2) element: PyTryExceptStatement 2(3) element: PyTryPart 3(4) element: PyRaiseStatement -4(5) READ ACCESS: Exception +4(5,11) READ ACCESS: Exception 5(6) element: PyExceptPart 6(7) element: PyAssignmentStatement 7(8) READ ACCESS: Exception diff --git a/python/testData/codeInsight/controlflow/try.txt b/python/testData/codeInsight/controlflow/try.txt index f776b114ad50..763b1b9da84d 100644 --- a/python/testData/codeInsight/controlflow/try.txt +++ b/python/testData/codeInsight/controlflow/try.txt @@ -4,14 +4,14 @@ 3(4) element: PyTryExceptStatement 4(5) element: PyTryPart 5(6) element: PyAssignmentStatement -6(7) READ ACCESS: open -7(8) WRITE ACCESS: f +6(7,15,22,25) READ ACCESS: open +7(8,15,22,25) WRITE ACCESS: f 8(9) element: PyAssignmentStatement -9(10) READ ACCESS: f -10(11) WRITE ACCESS: s +9(10,15,22,25) READ ACCESS: f +10(11,15,22,25) WRITE ACCESS: s 11(12) element: PyAssignmentStatement -12(13) READ ACCESS: int -13(14) READ ACCESS: s +12(13,15,22,25) READ ACCESS: int +13(14,15,22,25) READ ACCESS: s 14(15,22,25,30) WRITE ACCESS: i 15(16) element: PyExceptPart 16(17) READ ACCESS: IOError diff --git a/python/testData/codeInsight/controlflow/trybreak.txt b/python/testData/codeInsight/controlflow/trybreak.txt index c6bfba1fd0f7..8015ea851fa7 100644 --- a/python/testData/codeInsight/controlflow/trybreak.txt +++ b/python/testData/codeInsight/controlflow/trybreak.txt @@ -1,10 +1,10 @@ 0(1) element: null 1(2) element: PyTryExceptStatement 2(3) element: PyTryPart -3(4) element: PyForStatement +3(4,8) element: PyForStatement 4(5,8,11) READ ACCESS: bar 5(6) element: PyStatementList -6(7) WRITE ACCESS: i +6(7,8) WRITE ACCESS: i 7(8,11) element: PyBreakStatement 8(9) element: PyExceptPart 9(10) element: PyRaiseStatement diff --git a/python/testData/codeInsight/controlflow/tryexceptelsefinally.txt b/python/testData/codeInsight/controlflow/tryexceptelsefinally.txt index fbee361d8659..cea2b6a1c881 100644 --- a/python/testData/codeInsight/controlflow/tryexceptelsefinally.txt +++ b/python/testData/codeInsight/controlflow/tryexceptelsefinally.txt @@ -5,14 +5,14 @@ 4(5) element: PyTryExceptStatement 5(6) element: PyTryPart 6(7) element: PyAssignmentStatement -7(8) element: PySubscriptionExpression -8(9) READ ACCESS: d -9(10,13) WRITE ACCESS: v +7(8,13,16) element: PySubscriptionExpression +8(9,13,16) READ ACCESS: d +9(10,13,16) WRITE ACCESS: v 10(11) element: PyElsePart -11(12) element: PyPrintStatement +11(12,16) element: PyPrintStatement 12(16) READ ACCESS: v 13(14) element: PyExceptPart -14(15) READ ACCESS: KeyError +14(15,16) READ ACCESS: KeyError 15(16) element: PyPrintStatement 16(17) element: PyFinallyPart 17(18) element: PyPrintStatement diff --git a/python/testData/codeInsight/controlflow/tryfinally.txt b/python/testData/codeInsight/controlflow/tryfinally.txt index 66914e427d74..db2646c389dd 100644 --- a/python/testData/codeInsight/controlflow/tryfinally.txt +++ b/python/testData/codeInsight/controlflow/tryfinally.txt @@ -5,7 +5,7 @@ 4(5) element: PyTryExceptStatement 5(6) element: PyTryPart 6(7) element: PyAssignmentStatement -7(8) READ ACCESS: open +7(8,9) READ ACCESS: open 8(9) WRITE ACCESS: status 9(10) element: PyFinallyPart 10(11) element: PyIfStatement diff --git a/python/testData/inspections/PyUnusedLocalVariableInspection/expected.xml b/python/testData/inspections/PyUnusedLocalVariableInspection/expected.xml index 11e552f5b12f..36f6272dafdd 100644 --- a/python/testData/inspections/PyUnusedLocalVariableInspection/expected.xml +++ b/python/testData/inspections/PyUnusedLocalVariableInspection/expected.xml @@ -45,11 +45,6 @@ 82 Parameter 'x' value is not used - - test.py - 106 - Local variable 'v' value is not used - test.py 114