Fixed control flow break edges for try-except-finally (PY-3503)

This commit is contained in:
Andrey Vlasovskikh
2011-05-13 20:50:25 +04:00
parent 3080753968
commit 566d20977d
9 changed files with 70 additions and 48 deletions
@@ -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<Instruction> finallyRef = new Ref<Instruction>(finallyInstruction);
final Ref<Instruction> lastFinallyRef = new Ref<Instruction>(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();
}
}
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);
}
}
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -45,11 +45,6 @@
<line>82</line>
<description>Parameter 'x' value is not used</description>
</problem>
<problem>
<file>test.py</file>
<line>106</line>
<description>Local variable 'v' value is not used</description>
</problem>
<problem>
<file>test.py</file>
<line>114</line>