diff --git a/python/src/com/jetbrains/python/PyBundle.properties b/python/src/com/jetbrains/python/PyBundle.properties
index f0a618f21219..fc4a17608cd6 100644
--- a/python/src/com/jetbrains/python/PyBundle.properties
+++ b/python/src/com/jetbrains/python/PyBundle.properties
@@ -42,6 +42,8 @@ QFIX.simplify=Simplify
QFIX.move.from.future.import=Move 'from __future__ import' to a correct place
+QFIX.replace.equality=Replace equality
+
# Intentions: INTN
INTN.Family.convert.import.unqualify=Convert 'import module' to 'from module import'
INTN.Family.convert.import.qualify=Convert 'from module import' to 'import module'
@@ -210,6 +212,9 @@ INSP.expression.can.be.simplified=Expression can be simplified
# PyFromFutureImportInspection
INSP.NAME.from.future.import=from __future__ import must be the first executable statement
+# PyComparisonWithNoneInspection
+INSP.NAME.comparison.with.none=Comparison with None performed with equality operators
+
# Refactoring
# introduce
refactoring.introduce.name.error=Incorrect name
diff --git a/python/src/com/jetbrains/python/actions/ComparisonWithNoneQuickFix.java b/python/src/com/jetbrains/python/actions/ComparisonWithNoneQuickFix.java
new file mode 100644
index 000000000000..2205a3f43540
--- /dev/null
+++ b/python/src/com/jetbrains/python/actions/ComparisonWithNoneQuickFix.java
@@ -0,0 +1,47 @@
+package com.jetbrains.python.actions;
+
+import com.intellij.codeInspection.LocalQuickFix;
+import com.intellij.codeInspection.ProblemDescriptor;
+import com.intellij.openapi.project.Project;
+import com.intellij.psi.PsiElement;
+import com.jetbrains.python.PyBundle;
+import com.jetbrains.python.PyTokenTypes;
+import com.jetbrains.python.PythonLanguage;
+import com.jetbrains.python.psi.PyBinaryExpression;
+import com.jetbrains.python.psi.PyElementGenerator;
+import com.jetbrains.python.psi.PyElementType;
+import com.jetbrains.python.psi.PyExpression;
+import org.jetbrains.annotations.NotNull;
+
+/**
+ * Created by IntelliJ IDEA.
+ * Author: Alexey.Ivanov
+ * Date: 24.03.2010
+ * Time: 22:00:49
+ */
+public class ComparisonWithNoneQuickFix implements LocalQuickFix {
+ @NotNull
+ public String getName() {
+ return PyBundle.message("QFIX.replace.equality");
+ }
+
+ @NotNull
+ public String getFamilyName() {
+ return PyBundle.message("INSP.GROUP.python");
+ }
+
+ public void applyFix(@NotNull Project project, @NotNull ProblemDescriptor descriptor) {
+ PsiElement problemElement = descriptor.getPsiElement();
+ if (problemElement instanceof PyBinaryExpression) {
+ PyBinaryExpression binaryExpression = (PyBinaryExpression)problemElement;
+ PyElementType operator = binaryExpression.getOperator();
+ PyElementGenerator elementGenerator = PythonLanguage.getInstance().getElementGenerator();
+ String temp;
+ temp = (operator == PyTokenTypes.EQEQ) ? "is" : "is not";
+ PyExpression expression = elementGenerator.createBinaryExpression(project, temp,
+ binaryExpression.getLeftExpression(),
+ binaryExpression.getRightExpression());
+ binaryExpression.replace(expression);
+ }
+ }
+}
diff --git a/python/src/com/jetbrains/python/inspections/PyComparisonWithNoneInspection.java b/python/src/com/jetbrains/python/inspections/PyComparisonWithNoneInspection.java
new file mode 100644
index 000000000000..cf6951cafe62
--- /dev/null
+++ b/python/src/com/jetbrains/python/inspections/PyComparisonWithNoneInspection.java
@@ -0,0 +1,74 @@
+package com.jetbrains.python.inspections;
+
+import com.intellij.codeInspection.LocalInspectionTool;
+import com.intellij.codeInspection.ProblemsHolder;
+import com.intellij.psi.PsiElementVisitor;
+import com.jetbrains.python.PyBundle;
+import com.jetbrains.python.PyNames;
+import com.jetbrains.python.PyTokenTypes;
+import com.jetbrains.python.actions.ComparisonWithNoneQuickFix;
+import com.jetbrains.python.psi.PyBinaryExpression;
+import com.jetbrains.python.psi.PyElementType;
+import com.jetbrains.python.psi.PyExpression;
+import com.jetbrains.python.psi.PyReferenceExpression;
+import org.jetbrains.annotations.Nls;
+import org.jetbrains.annotations.NotNull;
+
+/**
+ * Created by IntelliJ IDEA.
+ * Author: Alexey.Ivanov
+ * Date: 24.03.2010
+ * Time: 21:33:51
+ */
+public class PyComparisonWithNoneInspection extends LocalInspectionTool {
+ @Nls
+ @NotNull
+ @Override
+ public String getGroupDisplayName() {
+ return PyBundle.message("INSP.GROUP.python");
+ }
+
+ @Nls
+ @NotNull
+ @Override
+ public String getDisplayName() {
+ return PyBundle.message("INSP.NAME.comparison.with.none");
+ }
+
+ @NotNull
+ @Override
+ public String getShortName() {
+ return "PyComparisonWithNoneInspection";
+ }
+
+ @Override
+ public boolean isEnabledByDefault() {
+ return true;
+ }
+
+ @NotNull
+ @Override
+ public PsiElementVisitor buildVisitor(@NotNull ProblemsHolder holder, boolean isOnTheFly) {
+ return new Visitor(holder);
+ }
+
+ private static class Visitor extends PyInspectionVisitor {
+
+ public Visitor(final ProblemsHolder holder) {
+ super(holder);
+ }
+
+ @Override
+ public void visitPyBinaryExpression(PyBinaryExpression node) {
+ final PyExpression rightExpression = node.getRightExpression();
+ if (rightExpression instanceof PyReferenceExpression) {
+ if (PyNames.NONE.equals(rightExpression.getName())) {
+ final PyElementType operator = node.getOperator();
+ if (operator == PyTokenTypes.EQEQ || operator == PyTokenTypes.NE || operator == PyTokenTypes.NE_OLD) {
+ registerProblem(node, "Comparison with None performed with equality operators", new ComparisonWithNoneQuickFix());
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/python/src/com/jetbrains/python/inspections/PythonInspectionToolProvider.java b/python/src/com/jetbrains/python/inspections/PythonInspectionToolProvider.java
index 93e894a753c6..722a9880587f 100644
--- a/python/src/com/jetbrains/python/inspections/PythonInspectionToolProvider.java
+++ b/python/src/com/jetbrains/python/inspections/PythonInspectionToolProvider.java
@@ -33,7 +33,8 @@ public class PythonInspectionToolProvider implements InspectionToolProvider {
PyUnboundLocalVariableInspection.class,
PyStatementEffectInspection.class,
PySimplifyBooleanCheckInspection.class,
- PyFromFutureImportInspection.class
+ PyFromFutureImportInspection.class,
+ PyComparisonWithNoneInspection.class
};
}
}
diff --git a/python/testData/inspections/ComparisonWithNone.py b/python/testData/inspections/ComparisonWithNone.py
new file mode 100644
index 000000000000..7cc83d4cd37f
--- /dev/null
+++ b/python/testData/inspections/ComparisonWithNone.py
@@ -0,0 +1,2 @@
+if a != None:
+ pass
\ No newline at end of file
diff --git a/python/testData/inspections/ComparisonWithNone_after.py b/python/testData/inspections/ComparisonWithNone_after.py
new file mode 100644
index 000000000000..45bf98440d77
--- /dev/null
+++ b/python/testData/inspections/ComparisonWithNone_after.py
@@ -0,0 +1,2 @@
+if a is not None:
+ pass
\ No newline at end of file
diff --git a/python/testData/inspections/PyComparisonWithNoneInspection/expected.xml b/python/testData/inspections/PyComparisonWithNoneInspection/expected.xml
new file mode 100644
index 000000000000..325fd43beb3e
--- /dev/null
+++ b/python/testData/inspections/PyComparisonWithNoneInspection/expected.xml
@@ -0,0 +1,18 @@
+
+
+
+ test.py
+ 1
+ Comparison with None performed with equality operators
+
+
+ test.py
+ 1
+ Comparison with None performed with equality operators
+
+
+ test.py
+ 1
+ Comparison with None performed with equality operators
+
+
\ No newline at end of file
diff --git a/python/testData/inspections/PyComparisonWithNoneInspection/src/test.py b/python/testData/inspections/PyComparisonWithNoneInspection/src/test.py
new file mode 100644
index 000000000000..ab4489b94cef
--- /dev/null
+++ b/python/testData/inspections/PyComparisonWithNoneInspection/src/test.py
@@ -0,0 +1,5 @@
+if a <> None and b != None and c == None:
+ pass
+
+if a is None and b is not None:
+ pass
\ No newline at end of file
diff --git a/python/testSrc/com/jetbrains/python/PyQuickFixTest.java b/python/testSrc/com/jetbrains/python/PyQuickFixTest.java
index 2a950b5f7699..de1c9c2d6c8f 100644
--- a/python/testSrc/com/jetbrains/python/PyQuickFixTest.java
+++ b/python/testSrc/com/jetbrains/python/PyQuickFixTest.java
@@ -115,6 +115,11 @@ public class PyQuickFixTest extends PyLightFixtureTestCase {
PyBundle.message("QFIX.move.from.future.import"), true, true);
}
+ public void testComparisonWithNoneQuickFix() throws Exception {
+ doInspectionTest("ComparisonWithNone.py", PyComparisonWithNoneInspection.class,
+ PyBundle.message("QFIX.replace.equality"), true, true);
+ }
+
@NonNls
protected String getTestDataPath() {
return PythonTestUtil.getTestDataPath() + "/inspections/";
diff --git a/python/testSrc/com/jetbrains/python/PythonInspectionsTest.java b/python/testSrc/com/jetbrains/python/PythonInspectionsTest.java
index 310ed8497a06..35dcba397187 100644
--- a/python/testSrc/com/jetbrains/python/PythonInspectionsTest.java
+++ b/python/testSrc/com/jetbrains/python/PythonInspectionsTest.java
@@ -155,4 +155,9 @@ public class PythonInspectionsTest extends PyLightFixtureTestCase {
LocalInspectionTool inspection = new PyFromFutureImportInspection();
doTest(getTestName(false), inspection);
}
+
+ public void testPyComparisonWithNoneInspection() throws Throwable {
+ LocalInspectionTool inspection = new PyComparisonWithNoneInspection();
+ doTest(getTestName(false), inspection);
+ }
}