added PY-3348 Inspection to highlight occurrences of @classmethod and @staticmethod on methods outside of a class

This commit is contained in:
Ekaterina Tuzova
2011-05-05 15:39:48 +04:00
parent f9178a133d
commit ba067edb9c
9 changed files with 126 additions and 0 deletions
@@ -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
@@ -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();
}
}
@@ -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());
}
}
}
}
@@ -59,6 +59,7 @@ public class PythonInspectionToolProvider implements InspectionToolProvider {
PyMissingConstructorInspection.class,
PyArgumentEqualDefaultInspection.class,
PySetFunctionToLiteralInspection.class,
PyDecoratorInspection.class,
};
}
}
@@ -0,0 +1,8 @@
class C:
@classmethod
def foo(self):
pass
<warning descr="Decorator @classmethod on method outside class">@classmethod</warning>
def foo(self):
print ("Constructor C was called")
@@ -0,0 +1,8 @@
class C:
@classmethod
def foo(self):
pass
<warning descr="Decorator @classmethod on method outside class"><caret>@classmethod</warning>
def foo(self):
print ("Constructor C was called")
@@ -0,0 +1,7 @@
class C:
@classmethod
def foo(self):
pass
def foo(self):
print ("Constructor C was called")
@@ -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,
@@ -344,4 +344,8 @@ public class PythonInspectionsTest extends PyLightFixtureTestCase {
setLanguageLevel(LanguageLevel.PYTHON27);
doHighlightingTest(PySetFunctionToLiteralInspection.class);
}
public void testPyDecoratorInspection() { //PY-3348
doHighlightingTest(PyDecoratorInspection.class);
}
}