diff --git a/python/src/com/jetbrains/python/PyBundle.properties b/python/src/com/jetbrains/python/PyBundle.properties index 467c6daddfbc..8700d01032a1 100644 --- a/python/src/com/jetbrains/python/PyBundle.properties +++ b/python/src/com/jetbrains/python/PyBundle.properties @@ -74,7 +74,10 @@ INSP.NAME.first.arg.assign=Reassignment of method's first argument INSP.first.arg.$0.assigned=Method''s parameter ''{0}'' reassigned # PyStringFormatInspection -INSP.NAME.str.format=Detect errors in string formatting operations. +INSP.NAME.str.format=Errors in string formatting operations + +# PyMethodOverridingInspection +INSP.NAME.method.over=Method signature does not match signature of overridden method ### Annotators ### ANN.deleting.none=deleting None diff --git a/python/src/com/jetbrains/python/inspections/PyMethodOverridingInspection.java b/python/src/com/jetbrains/python/inspections/PyMethodOverridingInspection.java new file mode 100644 index 000000000000..ebf9c764bf08 --- /dev/null +++ b/python/src/com/jetbrains/python/inspections/PyMethodOverridingInspection.java @@ -0,0 +1,82 @@ +package com.jetbrains.python.inspections; + +import com.intellij.codeInspection.LocalInspectionTool; +import com.intellij.codeInspection.ProblemsHolder; +import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiElementVisitor; +import com.jetbrains.python.PyBundle; +import com.jetbrains.python.psi.PyFunction; +import com.jetbrains.python.psi.PyNamedParameter; +import com.jetbrains.python.psi.PyParameter; +import com.jetbrains.python.psi.search.PySuperMethodsSearch; +import org.jetbrains.annotations.Nls; +import org.jetbrains.annotations.NotNull; + +/** + * Created by IntelliJ IDEA. + * User: Alexey.Ivanov + * Date: Jul 28, 2009 + * Time: 4:06:18 PM + */ +public class PyMethodOverridingInspection extends LocalInspectionTool { + + @Nls + @NotNull + public String getGroupDisplayName() { + return PyBundle.message("INSP.GROUP.python"); + } + + @Nls + @NotNull + public String getDisplayName() { + return PyBundle.message("INSP.NAME.method.over"); + } + + @NotNull + public String getShortName() { + return "PyMethodOverridingInspection"; + } + + @Override + public boolean isEnabledByDefault() { + return true; + } + + @NotNull + @Override + public PsiElementVisitor buildVisitor(@NotNull final ProblemsHolder holder, final boolean isOnTheFly) { + return new Visitor(holder); + } + + public static class Visitor extends PyInspectionVisitor { + + public Visitor(final ProblemsHolder holder) { + super(holder); + } + + @Override + public void visitPyFunction(final PyFunction function) { + for (PsiElement psiElement : PySuperMethodsSearch.search(function)) { + final PyParameter[] parameters = function.getParameterList().getParameters(); + if (psiElement instanceof PyFunction) { + final PyParameter[] superFunctionParameters = ((PyFunction)psiElement).getParameterList().getParameters(); + if (parameters.length != superFunctionParameters.length) { + registerProblem(function.getParameterList(), "Number of parameters does not match parameters of base method"); + return; + } + + for (int i = 0; i < parameters.length; ++i) { + if (parameters[i] instanceof PyNamedParameter && superFunctionParameters[i] instanceof PyNamedParameter) { + final PyNamedParameter namedParameter = (PyNamedParameter)parameters[i]; + final PyNamedParameter namedSuperFunctionParameter = (PyNamedParameter)superFunctionParameters[i]; + if (namedParameter.isKeywordContainer() != namedSuperFunctionParameter.isKeywordContainer() || + namedParameter.isPositionalContainer() != namedSuperFunctionParameter.isPositionalContainer()) { + registerProblem(namedParameter, "Method signature does not match signature of base method"); + } + } + } + } + } + } + } +} diff --git a/python/src/com/jetbrains/python/inspections/PythonInspectionToolProvider.java b/python/src/com/jetbrains/python/inspections/PythonInspectionToolProvider.java index a64609727103..6e293b7dfd25 100644 --- a/python/src/com/jetbrains/python/inspections/PythonInspectionToolProvider.java +++ b/python/src/com/jetbrains/python/inspections/PythonInspectionToolProvider.java @@ -16,7 +16,8 @@ public class PythonInspectionToolProvider implements InspectionToolProvider { PyMethodParametersInspection.class, PyUnreachableCodeInspection.class, PyMethodFirstArgAssignmentInspection.class, - PyStringFormatInspection.class + PyStringFormatInspection.class, + PyMethodOverridingInspection.class }; } } diff --git a/python/testData/inspections/PyMethodOverridingInspection/expected.xml b/python/testData/inspections/PyMethodOverridingInspection/expected.xml new file mode 100644 index 000000000000..a9f1bdb8b8d0 --- /dev/null +++ b/python/testData/inspections/PyMethodOverridingInspection/expected.xml @@ -0,0 +1,18 @@ + + + + method-overriding.py + 6 + Method signature does not match signature of base method + + + method-overriding.py + 10 + Number of parameters does not match parameters of base method + + + method-overriding.py + 14 + Method signature does not match signature of base method + + diff --git a/python/testSrc/com/jetbrains/python/PythonInspectionsTest.java b/python/testSrc/com/jetbrains/python/PythonInspectionsTest.java index 16e9a321904d..a985e5a5a7ff 100644 --- a/python/testSrc/com/jetbrains/python/PythonInspectionsTest.java +++ b/python/testSrc/com/jetbrains/python/PythonInspectionsTest.java @@ -50,6 +50,11 @@ public class PythonInspectionsTest extends PyLightFixtureTestCase { doTest(getTestName(false), inspection); } + public void testPyMethodOverridingInspection() throws Throwable { + LocalInspectionTool inspection = new PyMethodOverridingInspection(); + doTest(getTestName(false), inspection); + } + protected String getTestDataPath() { return PathManager.getHomePath() + "/plugins/python/testData/inspections/"; }