mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
Fixed false positive in unreachable code inspection for 'raise' inside 'with' that suppressed errors (PY-7420)
We have to be more conservative and assume that any context manager can suppress exceptions. Otherwise we will get false positives.
This commit is contained in:
@@ -3,14 +3,11 @@ package com.jetbrains.python.codeInsight.controlflow;
|
||||
import com.intellij.codeInsight.controlflow.ControlFlow;
|
||||
import com.intellij.codeInsight.controlflow.ControlFlowBuilder;
|
||||
import com.intellij.codeInsight.controlflow.Instruction;
|
||||
import com.intellij.lang.ASTNode;
|
||||
import com.intellij.openapi.util.Pair;
|
||||
import com.intellij.openapi.util.Ref;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.PsiNamedElement;
|
||||
import com.intellij.psi.tree.TokenSet;
|
||||
import com.intellij.psi.util.PsiTreeUtil;
|
||||
import com.jetbrains.python.PyElementTypes;
|
||||
import com.jetbrains.python.PyNames;
|
||||
import com.jetbrains.python.psi.*;
|
||||
import com.jetbrains.python.psi.impl.ParamHelper;
|
||||
@@ -26,9 +23,6 @@ import java.util.List;
|
||||
* @author oleg
|
||||
*/
|
||||
public class PyControlFlowBuilder extends PyRecursiveElementVisitor {
|
||||
|
||||
public static final TokenSet CALL_OR_REF_EXPR = TokenSet.create(PyElementTypes.CALL_EXPRESSION, PyElementTypes.REFERENCE_EXPRESSION);
|
||||
public static final String SELF_ASSERT_RAISES = "self.assertRaises";
|
||||
private final ControlFlowBuilder myBuilder = new ControlFlowBuilder();
|
||||
|
||||
public ControlFlow buildControlFlow(@NotNull final ScopeOwner owner) {
|
||||
@@ -711,42 +705,18 @@ public class PyControlFlowBuilder extends PyRecursiveElementVisitor {
|
||||
|
||||
@Override
|
||||
public void visitPyWithStatement(final PyWithStatement node) {
|
||||
boolean withSelfAssertRaises = false;
|
||||
final PyWithItem[] items = node.getWithItems();
|
||||
if (items.length == 1){
|
||||
final PyWithItem item = items[0];
|
||||
final ASTNode callNode = item.getNode().findChildByType(CALL_OR_REF_EXPR);
|
||||
if (callNode != null) {
|
||||
final PsiElement element = callNode.getPsi();
|
||||
if (element instanceof PyCallExpression) {
|
||||
final PyExpression callee = ((PyCallExpression)element).getCallee();
|
||||
if (callee != null) {
|
||||
final String repr = PyUtil.getReadableRepr(callee, true);
|
||||
withSelfAssertRaises = SELF_ASSERT_RAISES.equals(repr);
|
||||
}
|
||||
}
|
||||
if (element instanceof PyReferenceExpression){
|
||||
withSelfAssertRaises = SELF_ASSERT_RAISES.equals(element.getText());
|
||||
}
|
||||
}
|
||||
}
|
||||
super.visitPyWithStatement(node);
|
||||
if (withSelfAssertRaises){
|
||||
myBuilder.processPending(new ControlFlowBuilder.PendingProcessor() {
|
||||
public void process(final PsiElement pendingScope, final Instruction instruction) {
|
||||
final PsiElement element = instruction.getElement();
|
||||
if (element == null){
|
||||
myBuilder.addPendingEdge(pendingScope, instruction);
|
||||
}
|
||||
else if (PsiTreeUtil.getParentOfType(element, PyRaiseStatement.class) != null){
|
||||
myBuilder.addPendingEdge(node, instruction);
|
||||
}
|
||||
else {
|
||||
myBuilder.addPendingEdge(pendingScope, instruction);
|
||||
}
|
||||
myBuilder.processPending(new ControlFlowBuilder.PendingProcessor() {
|
||||
public void process(final PsiElement pendingScope, final Instruction instruction) {
|
||||
final PsiElement element = instruction.getElement();
|
||||
if (PsiTreeUtil.getParentOfType(element, PyRaiseStatement.class) != null) {
|
||||
myBuilder.addPendingEdge(node, instruction);
|
||||
}
|
||||
else {
|
||||
myBuilder.addPendingEdge(pendingScope, instruction);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void abruptFlow(final PsiElement node) {
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
class C(object):
|
||||
def __enter__(self):
|
||||
return self
|
||||
|
||||
def __exit__(self, exc, value, traceback):
|
||||
return True
|
||||
|
||||
|
||||
def f():
|
||||
with C():
|
||||
raise Exception()
|
||||
x = 1 #pass
|
||||
+19
-9
@@ -9,19 +9,29 @@ import com.jetbrains.python.psi.LanguageLevel;
|
||||
public class PyUnreachableCodeInspectionTest extends PyTestCase {
|
||||
private static final String TEST_DIRECTORY = "inspections/PyUnreachableCodeInspection/";
|
||||
|
||||
// All previous unreachable tests
|
||||
// All previous unreachable tests, feel free to split them
|
||||
public void testUnreachable() {
|
||||
doTest();
|
||||
}
|
||||
|
||||
private void doTest() {
|
||||
runWithLanguageLevel(LanguageLevel.PYTHON27, new Runnable() {
|
||||
runWithLanguageLevel(LanguageLevel.PYTHON26, new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
myFixture.configureByFile(TEST_DIRECTORY + getTestName(false) + ".py");
|
||||
myFixture.enableInspections(PyUnreachableCodeInspection.class);
|
||||
myFixture.checkHighlighting(true, false, false);
|
||||
doTest();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// PY-7420
|
||||
public void testWithSuppressedExceptions() {
|
||||
runWithLanguageLevel(LanguageLevel.PYTHON26, new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
doTest();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void doTest() {
|
||||
myFixture.configureByFile(TEST_DIRECTORY + getTestName(false) + ".py");
|
||||
myFixture.enableInspections(PyUnreachableCodeInspection.class);
|
||||
myFixture.checkHighlighting(true, false, false);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user