diff --git a/python/src/META-INF/python-plugin-common.xml b/python/src/META-INF/python-plugin-common.xml index f74baec7520e..bb7888c51277 100644 --- a/python/src/META-INF/python-plugin-common.xml +++ b/python/src/META-INF/python-plugin-common.xml @@ -318,6 +318,7 @@ + diff --git a/python/src/com/jetbrains/python/PyBundle.properties b/python/src/com/jetbrains/python/PyBundle.properties index faf4d15127af..a888fe16383c 100644 --- a/python/src/com/jetbrains/python/PyBundle.properties +++ b/python/src/com/jetbrains/python/PyBundle.properties @@ -476,6 +476,9 @@ INSP.NAME.class.has.no.init=Class has no __init__ method INSP.class.has.no.init=Class has no __init__ method INSP.parent.$0.has.no.init=Parent {0} has no __init__ method +#PyNoneFunctionAssignmentInspection +INSP.NAME.none.function.assignment=Assigning function call that doesn't return anything (None) +INSP.none.function.assignment=Function {0} doesn''t return anything # Refactoring # introduce diff --git a/python/src/com/jetbrains/python/inspections/PyNoneFunctionAssignmentInspection.java b/python/src/com/jetbrains/python/inspections/PyNoneFunctionAssignmentInspection.java new file mode 100644 index 000000000000..a2840609827c --- /dev/null +++ b/python/src/com/jetbrains/python/inspections/PyNoneFunctionAssignmentInspection.java @@ -0,0 +1,57 @@ +package com.jetbrains.python.inspections; + +import com.intellij.codeInspection.LocalInspectionToolSession; +import com.intellij.codeInspection.ProblemsHolder; +import com.intellij.psi.PsiElementVisitor; +import com.jetbrains.python.PyBundle; +import com.jetbrains.python.psi.PyAssignmentStatement; +import com.jetbrains.python.psi.PyCallExpression; +import com.jetbrains.python.psi.PyExpression; +import com.jetbrains.python.psi.types.PyNoneType; +import com.jetbrains.python.psi.types.PyType; +import org.jetbrains.annotations.Nls; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +/** + * User: ktisha + * + * pylint E1111 + * + * Used when an assignment is done on a function call but the inferred function doesn't return anything. + */ +public class PyNoneFunctionAssignmentInspection extends PyInspection { + @Nls + @NotNull + @Override + public String getDisplayName() { + return PyBundle.message("INSP.NAME.none.function.assignment"); + } + + @NotNull + @Override + public PsiElementVisitor buildVisitor(@NotNull ProblemsHolder holder, + boolean isOnTheFly, + @NotNull LocalInspectionToolSession session) { + return new Visitor(holder, session); + } + + + private static class Visitor extends PyInspectionVisitor { + public Visitor(@Nullable ProblemsHolder holder, @NotNull LocalInspectionToolSession session) { + super(holder, session); + } + + @Override + public void visitPyAssignmentStatement(PyAssignmentStatement node) { + final PyExpression value = node.getAssignedValue(); + if (value instanceof PyCallExpression) { + final PyType type = myTypeEvalContext.getType(value); + final PyExpression callee = ((PyCallExpression)value).getCallee(); + if (type instanceof PyNoneType && callee != null) { + registerProblem(node, PyBundle.message("INSP.none.function.assignment", callee.getName())); + } + } + } + } +} diff --git a/python/testData/inspections/PyNoneFunctionAssignmentInspection/noReturn.py b/python/testData/inspections/PyNoneFunctionAssignmentInspection/noReturn.py new file mode 100644 index 000000000000..fd8857107147 --- /dev/null +++ b/python/testData/inspections/PyNoneFunctionAssignmentInspection/noReturn.py @@ -0,0 +1,6 @@ +__author__ = 'ktisha' + +def foo(): + a = 1 + +b = foo() \ No newline at end of file diff --git a/python/testData/inspections/PyNoneFunctionAssignmentInspection/noType.py b/python/testData/inspections/PyNoneFunctionAssignmentInspection/noType.py new file mode 100644 index 000000000000..1f540cd70028 --- /dev/null +++ b/python/testData/inspections/PyNoneFunctionAssignmentInspection/noType.py @@ -0,0 +1,6 @@ +__author__ = 'ktisha' + +def foo(x): + return x + +b = foo() \ No newline at end of file diff --git a/python/testData/inspections/PyNoneFunctionAssignmentInspection/pass.py b/python/testData/inspections/PyNoneFunctionAssignmentInspection/pass.py new file mode 100644 index 000000000000..3f099ddc98f1 --- /dev/null +++ b/python/testData/inspections/PyNoneFunctionAssignmentInspection/pass.py @@ -0,0 +1,6 @@ +__author__ = 'ktisha' + +def foo(): + pass + +b = foo() \ No newline at end of file diff --git a/python/testData/inspections/PyNoneFunctionAssignmentInspection/returnNone.py b/python/testData/inspections/PyNoneFunctionAssignmentInspection/returnNone.py new file mode 100644 index 000000000000..c1d5ad50a263 --- /dev/null +++ b/python/testData/inspections/PyNoneFunctionAssignmentInspection/returnNone.py @@ -0,0 +1,6 @@ +__author__ = 'ktisha' + +def foo(): + return None + +b = foo() \ No newline at end of file diff --git a/python/testData/inspections/PyNoneFunctionAssignmentInspection/trueNegative.py b/python/testData/inspections/PyNoneFunctionAssignmentInspection/trueNegative.py new file mode 100644 index 000000000000..af29087226f1 --- /dev/null +++ b/python/testData/inspections/PyNoneFunctionAssignmentInspection/trueNegative.py @@ -0,0 +1,6 @@ +__author__ = 'ktisha' + +def foo(): + return 3 + +b = foo() \ No newline at end of file diff --git a/python/testSrc/com/jetbrains/python/inspections/PyNoneFunctionAssignmentInspectionTest.java b/python/testSrc/com/jetbrains/python/inspections/PyNoneFunctionAssignmentInspectionTest.java new file mode 100644 index 000000000000..7247cc07afe6 --- /dev/null +++ b/python/testSrc/com/jetbrains/python/inspections/PyNoneFunctionAssignmentInspectionTest.java @@ -0,0 +1,35 @@ +package com.jetbrains.python.inspections; + +import com.jetbrains.python.fixtures.PyTestCase; + +/** + * User: ktisha + */ +public class PyNoneFunctionAssignmentInspectionTest extends PyTestCase { + + public void testPass() { + doTest(); + } + + public void testReturnNone() { + doTest(); + } + + public void testNoReturn() { + doTest(); + } + + public void testTrueNegative() { + doTest(); + } + + public void testNoType() { + doTest(); + } + + private void doTest() { + myFixture.configureByFile("inspections/PyNoneFunctionAssignmentInspection/" + getTestName(true) + ".py"); + myFixture.enableInspections(PyNoneFunctionAssignmentInspection.class); + myFixture.checkHighlighting(false, false, true); + } +}