PY-1243 "Unreachable code" false positive with try/finally and raised exception

This commit is contained in:
Oleg Shpynov
2010-07-09 16:07:36 +04:00
parent 56b55d562f
commit e476a0721d
6 changed files with 40 additions and 25 deletions
@@ -476,46 +476,49 @@ public class PyControlFlowBuilder extends PyRecursiveElementVisitor {
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();
if (pendingElement == null || !PsiTreeUtil.isAncestor(tryPart, pendingElement, false)) {
myBuilder.addPendingEdge(pendingScope, instruction);
return;
}
// Process raise statements
if (PsiTreeUtil.isAncestor(tryPart, pendingElement, false) &&
PsiTreeUtil.getParentOfType(pendingElement, PyRaiseStatement.class) != null) {
for (Instruction rescueInstruction : exceptInstructions) {
myBuilder.addEdge(instruction, rescueInstruction);
// 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());
}
myBuilder.addPendingEdge(pendingScope, instruction);
return;
}
// Add except statements
if (PsiTreeUtil.isAncestor(tryPart, pendingElement, false)) {
for (Instruction rescueInstruction : exceptInstructions) {
myBuilder.addEdge(instruction, rescueInstruction);
else if (pendingElement != null && PsiTreeUtil.isAncestor(tryPart, pendingElement, false)){
for (Instruction inst : exceptInstructions) {
myBuilder.addEdge(instruction, inst);
}
}
// Process finally
if (!finallyRef.isNull()) {
// handle return pending instructions inside try if final block exists
if (!finallyRef.isNull() &&
PsiTreeUtil.isAncestor(tryPart, pendingElement, false)) {
myBuilder.addEdge(instruction, finallyRef.get());
if (!lastFinallyRef.isNull() &&
PsiTreeUtil.getParentOfType(pendingElement, PyReturnStatement.class, false) != null) {
myBuilder.addPendingEdge(null, lastFinallyRef.get());
}
myBuilder.addPendingEdge(null, lastFinallyRef.get());
return;
}
// Handle pending instructions inside try with final block
if (finallyPart!=null && pendingScope !=finallyPart &&
PsiTreeUtil.isAncestor(tryPart, pendingElement, false)) {
myBuilder.addEdge(instruction, finallyRef.get());
return;
}
myBuilder.addPendingEdge(pendingScope, instruction);
}
});
}
private boolean isRaiseInstruction(final PsiElement pendingElement) {
return pendingElement != null && PsiTreeUtil.getParentOfType(pendingElement, PyRaiseStatement.class) != null;
}
@Override
public void visitPyComprehensionElement(final PyComprehensionElement node) {
myBuilder.startNode(node);
@@ -2,7 +2,7 @@
1(2) element: PyTryExceptStatement
2(3) element: PyTryPart
3(4) element: PyRaiseStatement
4(5,11) READ ACCESS: Exception
4(5) READ ACCESS: Exception
5(6) element: PyExceptPart
6(7) element: PyAssignmentStatement
7(8) READ ACCESS: Exception
@@ -0,0 +1,4 @@
try:
raise KeyboardInterrupt
finally:
print 'test'
@@ -0,0 +1,8 @@
0(1) element: null
1(2) element: PyTryExceptStatement
2(3) element: PyTryPart
3(4) element: PyRaiseStatement
4(5) READ ACCESS: KeyboardInterrupt
5(6) element: PyFinallyPart
6(7) element: PyPrintStatement
7() element: null
@@ -35,7 +35,7 @@
<problem>
<file>unreachable.py</file>
<line>40</line>
<line>46</line>
<description>This code is unreachable</description>
</problem>
</problems>
@@ -115,7 +115,7 @@ public class PyControlFlowBuilderTest extends LightMarkedTestCase {
doTest();
}
public void testExit() throws Exception {
public void testTryRaiseFinally() throws Exception {
doTest();
}