Inspection to check that comparisons with None are performed with 'is' rather than '=='
This commit is contained in:
alexey.ivanov
2010-03-26 16:32:36 +03:00
parent cfdba33b2c
commit 1b3528f31b
10 changed files with 165 additions and 1 deletions
@@ -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
@@ -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);
}
}
}
@@ -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());
}
}
}
}
}
}
@@ -33,7 +33,8 @@ public class PythonInspectionToolProvider implements InspectionToolProvider {
PyUnboundLocalVariableInspection.class,
PyStatementEffectInspection.class,
PySimplifyBooleanCheckInspection.class,
PyFromFutureImportInspection.class
PyFromFutureImportInspection.class,
PyComparisonWithNoneInspection.class
};
}
}
@@ -0,0 +1,2 @@
if <warning descr="Comparison with None performed with equality operators"><caret>a != None</warning>:
pass
@@ -0,0 +1,2 @@
if a is not None:
pass
@@ -0,0 +1,18 @@
<?xml version="1.0" encoding="UTF-8"?>
<problems>
<problem>
<file>test.py</file>
<line>1</line>
<description>Comparison with None performed with equality operators</description>
</problem>
<problem>
<file>test.py</file>
<line>1</line>
<description>Comparison with None performed with equality operators</description>
</problem>
<problem>
<file>test.py</file>
<line>1</line>
<description>Comparison with None performed with equality operators</description>
</problem>
</problems>
@@ -0,0 +1,5 @@
if a <> None and b != None and c == None:
pass
if a is None and b is not None:
pass
@@ -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/";
@@ -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);
}
}