diff --git a/python/src/com/jetbrains/python/codeInsight/controlflow/PyTypeAssertionEvaluator.java b/python/src/com/jetbrains/python/codeInsight/controlflow/PyTypeAssertionEvaluator.java index 684426f7068d..2bce83722acf 100644 --- a/python/src/com/jetbrains/python/codeInsight/controlflow/PyTypeAssertionEvaluator.java +++ b/python/src/com/jetbrains/python/codeInsight/controlflow/PyTypeAssertionEvaluator.java @@ -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); } diff --git a/python/testSrc/com/jetbrains/python/PyTypeTest.java b/python/testSrc/com/jetbrains/python/PyTypeTest.java index af94922c3824..8e4ccff58849 100644 --- a/python/testSrc/com/jetbrains/python/PyTypeTest.java +++ b/python/testSrc/com/jetbrains/python/PyTypeTest.java @@ -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",