mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
Fixed control flow break edges for try-except-finally (PY-3503)
This commit is contained in:
@@ -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>
|
||||
|
||||
Reference in New Issue
Block a user