From ba067edb9ce28f0ae79fd36e39f1b0300a0483a1 Mon Sep 17 00:00:00 2001 From: Ekaterina Tuzova Date: Thu, 5 May 2011 15:39:48 +0400 Subject: [PATCH] added PY-3348 Inspection to highlight occurrences of @classmethod and @staticmethod on methods outside of a class --- .../com/jetbrains/python/PyBundle.properties | 7 +++ .../actions/RemoveDecoratorQuickFix.java | 30 ++++++++++ .../inspections/PyDecoratorInspection.java | 56 +++++++++++++++++++ .../PythonInspectionToolProvider.java | 1 + .../inspections/PyDecoratorInspection/test.py | 8 +++ .../testData/inspections/RemoveDecorator.py | 8 +++ .../inspections/RemoveDecorator_after.py | 7 +++ .../com/jetbrains/python/PyQuickFixTest.java | 5 ++ .../python/PythonInspectionsTest.java | 4 ++ 9 files changed, 126 insertions(+) create mode 100644 python/src/com/jetbrains/python/actions/RemoveDecoratorQuickFix.java create mode 100644 python/src/com/jetbrains/python/inspections/PyDecoratorInspection.java create mode 100644 python/testData/inspections/PyDecoratorInspection/test.py create mode 100644 python/testData/inspections/RemoveDecorator.py create mode 100644 python/testData/inspections/RemoveDecorator_after.py diff --git a/python/src/com/jetbrains/python/PyBundle.properties b/python/src/com/jetbrains/python/PyBundle.properties index b9d90a935e51..81024d6e41cc 100644 --- a/python/src/com/jetbrains/python/PyBundle.properties +++ b/python/src/com/jetbrains/python/PyBundle.properties @@ -87,6 +87,9 @@ QFIX.replace.function.set.with.literal=Replace function call with set literal #DocstringQuickFix QFIX.docstring=Add/remove parameters docstring parameters +#RemoveDecoratorQuickFix +QFIX.remove.decorator=Remove decorator + # 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' @@ -393,6 +396,10 @@ INSP.NAME.missing.super.constructor=Missed call to constructor of super class # PySetFunctionToLiteralInspection INSP.NAME.set.function.to.literal=Function call can be replaced with set literal +# PyDecoratorInspection +INSP.NAME.decorator.outside.class=Class specific decorator on method outside class + + # Refactoring # introduce refactoring.introduce.name.error=Incorrect name diff --git a/python/src/com/jetbrains/python/actions/RemoveDecoratorQuickFix.java b/python/src/com/jetbrains/python/actions/RemoveDecoratorQuickFix.java new file mode 100644 index 000000000000..ca605c59b364 --- /dev/null +++ b/python/src/com/jetbrains/python/actions/RemoveDecoratorQuickFix.java @@ -0,0 +1,30 @@ +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 org.jetbrains.annotations.NotNull; + +/** + * User: catherine + * + * QuickFix to remove redundant argument equal default + */ +public class RemoveDecoratorQuickFix implements LocalQuickFix { + @NotNull + public String getName() { + return PyBundle.message("QFIX.remove.decorator"); + } + + @NotNull + public String getFamilyName() { + return PyBundle.message("INSP.GROUP.python"); + } + + public void applyFix(@NotNull Project project, @NotNull ProblemDescriptor descriptor) { + PsiElement element = descriptor.getPsiElement(); + element.delete(); + } +} diff --git a/python/src/com/jetbrains/python/inspections/PyDecoratorInspection.java b/python/src/com/jetbrains/python/inspections/PyDecoratorInspection.java new file mode 100644 index 000000000000..e9ec9f07f99f --- /dev/null +++ b/python/src/com/jetbrains/python/inspections/PyDecoratorInspection.java @@ -0,0 +1,56 @@ +package com.jetbrains.python.inspections; + +import com.intellij.codeInspection.ProblemsHolder; +import com.intellij.psi.PsiElementVisitor; +import com.jetbrains.python.PyBundle; +import com.jetbrains.python.actions.RemoveDecoratorQuickFix; +import com.jetbrains.python.psi.PyClass; +import com.jetbrains.python.psi.PyDecorator; +import com.jetbrains.python.psi.PyDecoratorList; +import com.jetbrains.python.psi.PyFunction; +import org.jetbrains.annotations.Nls; +import org.jetbrains.annotations.NotNull; + +/** + * User: catherine + * + * Inspection to detect occurrences of @classmethod and @staticmethod + * on methods outside of a class + */ +public class PyDecoratorInspection extends PyInspection { + @Nls + @NotNull + @Override + public String getDisplayName() { + return PyBundle.message("INSP.NAME.too.broad.exception.clauses"); + } + + @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 visitPyFunction(final PyFunction node){ + PyClass containingClass = node.getContainingClass(); + if (containingClass != null) + return; + + PyDecoratorList decorators = node.getDecoratorList(); + if (decorators == null) + return; + for (PyDecorator decorator : decorators.getDecorators()) { + String name = decorator.getText(); + if (name.equals("@classmethod") || name.equals("@staticmethod")) + registerProblem(decorator, "Decorator " + name + " on method outside class", new RemoveDecoratorQuickFix()); + } + } + } +} diff --git a/python/src/com/jetbrains/python/inspections/PythonInspectionToolProvider.java b/python/src/com/jetbrains/python/inspections/PythonInspectionToolProvider.java index bc152a531797..86a330116336 100644 --- a/python/src/com/jetbrains/python/inspections/PythonInspectionToolProvider.java +++ b/python/src/com/jetbrains/python/inspections/PythonInspectionToolProvider.java @@ -59,6 +59,7 @@ public class PythonInspectionToolProvider implements InspectionToolProvider { PyMissingConstructorInspection.class, PyArgumentEqualDefaultInspection.class, PySetFunctionToLiteralInspection.class, + PyDecoratorInspection.class, }; } } diff --git a/python/testData/inspections/PyDecoratorInspection/test.py b/python/testData/inspections/PyDecoratorInspection/test.py new file mode 100644 index 000000000000..bea3759b2ef4 --- /dev/null +++ b/python/testData/inspections/PyDecoratorInspection/test.py @@ -0,0 +1,8 @@ +class C: + @classmethod + def foo(self): + pass + +@classmethod +def foo(self): + print ("Constructor C was called") \ No newline at end of file diff --git a/python/testData/inspections/RemoveDecorator.py b/python/testData/inspections/RemoveDecorator.py new file mode 100644 index 000000000000..c9fc9cb2e6af --- /dev/null +++ b/python/testData/inspections/RemoveDecorator.py @@ -0,0 +1,8 @@ +class C: + @classmethod + def foo(self): + pass + +@classmethod +def foo(self): + print ("Constructor C was called") \ No newline at end of file diff --git a/python/testData/inspections/RemoveDecorator_after.py b/python/testData/inspections/RemoveDecorator_after.py new file mode 100644 index 000000000000..cc9672620d6f --- /dev/null +++ b/python/testData/inspections/RemoveDecorator_after.py @@ -0,0 +1,7 @@ +class C: + @classmethod + def foo(self): + pass + +def foo(self): + print ("Constructor C was called") \ 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 fd87d91cb931..b865bb6c38c1 100644 --- a/python/testSrc/com/jetbrains/python/PyQuickFixTest.java +++ b/python/testSrc/com/jetbrains/python/PyQuickFixTest.java @@ -252,6 +252,11 @@ public class PyQuickFixTest extends PyLightFixtureTestCase { PyBundle.message("QFIX.remove.argument.equal.default"), true, true); } + public void testRemoveDecorator() { //PY-3348 + doInspectionTest("RemoveDecorator.py", PyDecoratorInspection.class, + PyBundle.message("QFIX.remove.decorator"), true, true); + } + public void testSetFunctionToLiteral() { //PY-3120 setLanguageLevel(LanguageLevel.PYTHON27); doInspectionTest("SetFunctionToLiteral.py", PySetFunctionToLiteralInspection.class, diff --git a/python/testSrc/com/jetbrains/python/PythonInspectionsTest.java b/python/testSrc/com/jetbrains/python/PythonInspectionsTest.java index 87c697b6630b..6ada8f984433 100644 --- a/python/testSrc/com/jetbrains/python/PythonInspectionsTest.java +++ b/python/testSrc/com/jetbrains/python/PythonInspectionsTest.java @@ -344,4 +344,8 @@ public class PythonInspectionsTest extends PyLightFixtureTestCase { setLanguageLevel(LanguageLevel.PYTHON27); doHighlightingTest(PySetFunctionToLiteralInspection.class); } + + public void testPyDecoratorInspection() { //PY-3348 + doHighlightingTest(PyDecoratorInspection.class); + } }