fixed PY-9721 "Replace <name> with self.<name>" quickfix does not handle classmethods or staticmethods correctly

This commit is contained in:
Ekaterina Tuzova
2013-05-09 20:42:51 +04:00
parent 0c1ab3eb9d
commit d15456935e
6 changed files with 49 additions and 15 deletions
@@ -62,7 +62,7 @@ QFIX.statement.effect.move.docstring=Move docstring to the proper place
QFIX.statement.effect.introduce.variable=Introduce variable
QFIX.unresolved.reference=Replace ''{0}'' with ''self.{0}''
QFIX.unresolved.reference=Replace ''{0}'' with ''{1}.{0}''
QFIX.unresolved.reference.add.param.$0=Create parameter ''{0}''
QFIX.unresolved.reference.add.param=Create parameter for reference
@@ -709,11 +709,23 @@ public class PyUnresolvedReferencesInspection extends PyInspection {
}
private void addAddSelfFix(PyElement node, PyReferenceExpression refex, List<LocalQuickFix> actions) {
PyClass containedClass = PsiTreeUtil.getParentOfType(node, PyClass.class);
if (containedClass != null) {
final PyClass containedClass = PsiTreeUtil.getParentOfType(node, PyClass.class);
final PyFunction function = PsiTreeUtil.getParentOfType(node, PyFunction.class);
if (containedClass != null && function != null) {
final PyParameter[] parameters = function.getParameterList().getParameters();
final String qualifier = parameters[0].getText();
if (parameters.length == 0) return;
final PyDecoratorList decoratorList = function.getDecoratorList();
boolean isClassmethod = false;
if (decoratorList != null) {
for (PyDecorator decorator : decoratorList.getDecorators()) {
if (PyNames.CLASSMETHOD.equals(decorator.getCallee().getText()))
isClassmethod = true;
}
}
for (PyTargetExpression target : containedClass.getInstanceAttributes()) {
if (Comparing.strEqual(node.getName(), target.getName())) {
actions.add(new UnresolvedReferenceAddSelfQuickFix(refex));
if (!isClassmethod && Comparing.strEqual(node.getName(), target.getName())) {
actions.add(new UnresolvedReferenceAddSelfQuickFix(refex, qualifier));
}
}
for (PyStatement statement : containedClass.getStatementList().getStatements()) {
@@ -725,7 +737,7 @@ public class PyUnresolvedReferencesInspection extends PyInspection {
PyType type = myTypeEvalContext.getType(callexpr);
if (type != null && type instanceof PyClassTypeImpl) {
if (((PyCallExpression)callexpr).isCalleeText(PyNames.PROPERTY)) {
actions.add(new UnresolvedReferenceAddSelfQuickFix(refex));
actions.add(new UnresolvedReferenceAddSelfQuickFix(refex, qualifier));
}
}
}
@@ -734,7 +746,7 @@ public class PyUnresolvedReferencesInspection extends PyInspection {
}
for (PyFunction method : containedClass.getMethods()) {
if (refex.getText().equals(method.getName())) {
actions.add(new UnresolvedReferenceAddSelfQuickFix(refex));
actions.add(new UnresolvedReferenceAddSelfQuickFix(refex, qualifier));
}
}
}
@@ -19,25 +19,28 @@ import org.jetbrains.annotations.NotNull;
*/
public class UnresolvedReferenceAddSelfQuickFix implements LocalQuickFix, HighPriorityAction {
private PyReferenceExpression myElement;
private String myQualifier;
public UnresolvedReferenceAddSelfQuickFix(PyReferenceExpression element) {
public UnresolvedReferenceAddSelfQuickFix(@NotNull final PyReferenceExpression element, @NotNull final String qualifier) {
myElement = element;
myQualifier = qualifier;
}
@NotNull
public String getName() {
return PyBundle.message("QFIX.unresolved.reference", myElement.getText());
return PyBundle.message("QFIX.unresolved.reference", myElement.getText(), myQualifier);
}
@NotNull
public String getFamilyName() {
return "Add 'self'";
return "Add qualifier";
}
public void applyFix(@NotNull Project project, @NotNull ProblemDescriptor descriptor) {
if (!FileModificationService.getInstance().preparePsiElementForWrite(myElement)) return;
PyElementGenerator elementGenerator = PyElementGenerator.getInstance(project);
PyExpression expression = elementGenerator.createExpressionFromText(LanguageLevel.forElement(myElement), "self." + myElement.getText());
myElement.replace(expression);
if (!FileModificationService.getInstance().preparePsiElementForWrite(myElement)) return;
PyElementGenerator elementGenerator = PyElementGenerator.getInstance(project);
PyExpression expression = elementGenerator.createExpressionFromText(LanguageLevel.forElement(myElement),
myQualifier + "." + myElement.getText());
myElement.replace(expression);
}
}
@@ -0,0 +1,7 @@
class A:
def foo(self):
pass
@classmethod
def pop(cls):
print <error descr="Unresolved reference 'foo'">fo<caret>o</error>()
@@ -0,0 +1,7 @@
class A:
def foo(self):
pass
@classmethod
def pop(cls):
print cls.foo()
@@ -83,7 +83,12 @@ public class PyQuickFixTest extends PyTestCase {
public void testAddSelfFunction() { //PY-4556
doInspectionTest("AddSelfFunction.py",
PyUnresolvedReferencesInspection.class, PyBundle.message("QFIX.unresolved.reference", "get_a"), true, true);
PyUnresolvedReferencesInspection.class, PyBundle.message("QFIX.unresolved.reference", "get_a", "self"), true, true);
}
public void testAddSelfToClassmethod() { //PY-9721
doInspectionTest("AddSelfToClassmethod.py",
PyUnresolvedReferencesInspection.class, PyBundle.message("QFIX.unresolved.reference", "foo", "cls"), true, true);
}
public void testAddCls() {