PY-20679 Fixed: Inspection error. 'Cannot find reference in object'

Update calculation of assert expression in case of PyBinaryExpression with boolean constant on one of the sides
This commit is contained in:
Semyon Proshev
2016-09-15 16:30:12 +03:00
parent 3a730415cf
commit da153b0935
2 changed files with 105 additions and 3 deletions
@@ -1,5 +1,5 @@
/*
* Copyright 2000-2014 JetBrains s.r.o.
* Copyright 2000-2016 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -19,6 +19,7 @@ import com.intellij.psi.PsiElement;
import com.jetbrains.python.PyNames;
import com.jetbrains.python.PyTokenTypes;
import com.jetbrains.python.psi.*;
import com.jetbrains.python.psi.impl.PyConstantExpressionEvaluator;
import com.jetbrains.python.psi.types.*;
import org.jetbrains.annotations.Nullable;
@@ -111,9 +112,10 @@ public class PyTypeAssertionEvaluator extends PyRecursiveElementVisitor {
@Override
public void visitPyBinaryExpression(PyBinaryExpression node) {
final PyExpression lhs = node.getLeftExpression();
final PyExpression rhs = node.getRightExpression();
if (node.isOperator("isnot")) {
final PyExpression lhs = node.getLeftExpression();
final PyExpression rhs = node.getRightExpression();
if (lhs instanceof PyReferenceExpression && rhs instanceof PyReferenceExpression) {
final PyReferenceExpression target = (PyReferenceExpression)lhs;
if (PyNames.NONE.equals(rhs.getName())) {
@@ -130,6 +132,22 @@ public class PyTypeAssertionEvaluator extends PyRecursiveElementVisitor {
}
}
}
final Object leftValue = PyConstantExpressionEvaluator.evaluate(lhs);
final Object rightValue = PyConstantExpressionEvaluator.evaluate(rhs);
if (leftValue instanceof Boolean && rightValue instanceof Boolean) {
return;
}
if (node.isOperator(PyNames.IS) && (leftValue == Boolean.FALSE || rightValue == Boolean.FALSE) ||
node.isOperator("isnot") && (leftValue == Boolean.TRUE || rightValue == Boolean.TRUE)) {
myPositive = !myPositive;
super.visitPyBinaryExpression(node);
myPositive = !myPositive;
return;
}
super.visitPyBinaryExpression(node);
}
@@ -310,6 +310,90 @@ public class PyTypeTest extends PyTestCase {
" expr = x\n");
}
// PY-20679
public void testIsInstanceViaTrue() {
doTest("str",
"a = None\n" +
"if isinstance(a, str) is True:\n" +
" expr = a\n" +
"raise TypeError('Invalid type')");
doTest("str",
"a = None\n" +
"if True is isinstance(a, str):\n" +
" expr = a\n" +
"raise TypeError('Invalid type')");
}
// PY-20679
public void testIsInstanceViaFalse() {
doTest("str",
"a = None\n" +
"if isinstance(a, str) is not False:\n" +
" expr = a\n" +
"raise TypeError('Invalid type')");
doTest("str",
"a = None\n" +
"if False is not isinstance(a, str):\n" +
" expr = a\n" +
"raise TypeError('Invalid type')");
doTest("str",
"a = None\n" +
"if not isinstance(a, str) is False:\n" +
" expr = a\n" +
"raise TypeError('Invalid type')");
doTest("str",
"a = None\n" +
"if not False is isinstance(a, str):\n" +
" expr = a\n" +
"raise TypeError('Invalid type')");
}
// PY-20679
public void testNotIsInstanceViaTrue() {
doTest("str",
"a = None\n" +
"if not isinstance(a, str) is True:\n" +
" raise TypeError('Invalid type')\n" +
"expr = a");
doTest("str",
"a = None\n" +
"if not True is isinstance(a, str):\n" +
" raise TypeError('Invalid type')\n" +
"expr = a");
doTest("str",
"a = None\n" +
"if isinstance(a, str) is not True:\n" +
" raise TypeError('Invalid type')\n" +
"expr = a");
doTest("str",
"a = None\n" +
"if True is not isinstance(a, str):\n" +
" raise TypeError('Invalid type')\n" +
"expr = a");
}
// PY-20679
public void testNotIsInstanceViaFalse() {
doTest("str",
"a = None\n" +
"if isinstance(a, str) is False:\n" +
" raise TypeError('Invalid type')\n" +
"expr = a");
doTest("str",
"a = None\n" +
"if False is isinstance(a, str):\n" +
" raise TypeError('Invalid type')\n" +
"expr = a");
}
// PY-4279
public void testFieldReassignment() {
doTest("C1",