From 536d97891723cef57d7ddd773f2dc2a70c5e69a1 Mon Sep 17 00:00:00 2001 From: Ekaterina Tuzova Date: Wed, 29 May 2013 16:35:09 +0400 Subject: [PATCH] fixed PY-9654 Make function from method/Make method static: correctly update class calls with first instance argument --- .../quickfix/PyMakeMethodStaticQuickFix.java | 37 ++++++++++++++++++- .../PyMakeMethodStaticQuickFixTest/test.py | 6 +++ .../PyMakeMethodStaticQuickFixTest/usage.py | 6 +++ .../usageImport.py | 3 ++ .../usageImport_after.py | 3 ++ .../usage_after.py | 7 ++++ .../PyMakeFunctionFromMethodQuickFixTest.java | 16 +------- .../PyMakeMethodStaticQuickFixTest.java | 8 ++++ .../python/quickFixes/PyQuickFixTestCase.java | 16 ++++++++ 9 files changed, 87 insertions(+), 15 deletions(-) create mode 100644 python/testData/quickFixes/PyMakeMethodStaticQuickFixTest/test.py create mode 100644 python/testData/quickFixes/PyMakeMethodStaticQuickFixTest/usage.py create mode 100644 python/testData/quickFixes/PyMakeMethodStaticQuickFixTest/usageImport.py create mode 100644 python/testData/quickFixes/PyMakeMethodStaticQuickFixTest/usageImport_after.py create mode 100644 python/testData/quickFixes/PyMakeMethodStaticQuickFixTest/usage_after.py diff --git a/python/src/com/jetbrains/python/inspections/quickfix/PyMakeMethodStaticQuickFix.java b/python/src/com/jetbrains/python/inspections/quickfix/PyMakeMethodStaticQuickFix.java index 565fd8aea98e..4318a6d2b8f0 100644 --- a/python/src/com/jetbrains/python/inspections/quickfix/PyMakeMethodStaticQuickFix.java +++ b/python/src/com/jetbrains/python/inspections/quickfix/PyMakeMethodStaticQuickFix.java @@ -4,9 +4,12 @@ import com.intellij.codeInspection.LocalQuickFix; import com.intellij.codeInspection.ProblemDescriptor; import com.intellij.openapi.project.Project; import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiReference; import com.intellij.psi.util.PsiTreeUtil; +import com.intellij.usageView.UsageInfo; import com.jetbrains.python.PyBundle; import com.jetbrains.python.psi.*; +import com.jetbrains.python.refactoring.PyRefactoringUtil; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; @@ -35,8 +38,9 @@ public class PyMakeMethodStaticQuickFix implements LocalQuickFix { final PsiElement element = descriptor.getPsiElement(); final PyFunction problemFunction = PsiTreeUtil.getParentOfType(element, PyFunction.class); if (problemFunction == null) return; - PyUtil.deleteParameter(problemFunction, 0); + final List usages = PyRefactoringUtil.findUsages(problemFunction, false); + PyUtil.deleteParameter(problemFunction, 0); final PyDecoratorList problemDecoratorList = problemFunction.getDecoratorList(); List decoTexts = new ArrayList(); decoTexts.add("@staticmethod"); @@ -56,5 +60,36 @@ public class PyMakeMethodStaticQuickFix implements LocalQuickFix { else { problemFunction.addBefore(decoratorList, problemFunction.getFirstChild()); } + + for (UsageInfo usage : usages) { + final PsiElement usageElement = usage.getElement(); + if (usageElement instanceof PyReferenceExpression) { + updateUsage((PyReferenceExpression)usageElement); + } + } + } + + private static void updateUsage(@NotNull final PyReferenceExpression element) { + final PyExpression qualifier = element.getQualifier(); + if (qualifier == null) return; + final PsiReference reference = qualifier.getReference(); + if (reference == null) return; + final PsiElement resolved = reference.resolve(); + if (resolved instanceof PyClass) { //call with first instance argument A.m(A()) + updateArgumentList(element); + } + } + + private static void updateArgumentList(@NotNull final PyReferenceExpression element) { + final PyCallExpression callExpression = PsiTreeUtil.getParentOfType(element, PyCallExpression.class); + if (callExpression == null) return; + PyArgumentList argumentList = callExpression.getArgumentList(); + if (argumentList == null) return; + final PyExpression[] arguments = argumentList.getArguments(); + if (arguments.length > 0) { + final PyExpression argument = arguments[0]; + PyUtil.eraseWhitespaceAndComma(argument.getParent().getNode(), argument, false); + argument.delete(); + } } } diff --git a/python/testData/quickFixes/PyMakeMethodStaticQuickFixTest/test.py b/python/testData/quickFixes/PyMakeMethodStaticQuickFixTest/test.py new file mode 100644 index 000000000000..ccae40ee238a --- /dev/null +++ b/python/testData/quickFixes/PyMakeMethodStaticQuickFixTest/test.py @@ -0,0 +1,6 @@ +__author__ = 'ktisha' + +class A: + def foo(self): + print("Hello Pycharm!") + diff --git a/python/testData/quickFixes/PyMakeMethodStaticQuickFixTest/usage.py b/python/testData/quickFixes/PyMakeMethodStaticQuickFixTest/usage.py new file mode 100644 index 000000000000..cddacb0b24da --- /dev/null +++ b/python/testData/quickFixes/PyMakeMethodStaticQuickFixTest/usage.py @@ -0,0 +1,6 @@ +class A: + def m(self, x): + return x + + +print A.m(A(), 1) \ No newline at end of file diff --git a/python/testData/quickFixes/PyMakeMethodStaticQuickFixTest/usageImport.py b/python/testData/quickFixes/PyMakeMethodStaticQuickFixTest/usageImport.py new file mode 100644 index 000000000000..e04161a92cec --- /dev/null +++ b/python/testData/quickFixes/PyMakeMethodStaticQuickFixTest/usageImport.py @@ -0,0 +1,3 @@ +import test + +test.A().foo(1) \ No newline at end of file diff --git a/python/testData/quickFixes/PyMakeMethodStaticQuickFixTest/usageImport_after.py b/python/testData/quickFixes/PyMakeMethodStaticQuickFixTest/usageImport_after.py new file mode 100644 index 000000000000..e04161a92cec --- /dev/null +++ b/python/testData/quickFixes/PyMakeMethodStaticQuickFixTest/usageImport_after.py @@ -0,0 +1,3 @@ +import test + +test.A().foo(1) \ No newline at end of file diff --git a/python/testData/quickFixes/PyMakeMethodStaticQuickFixTest/usage_after.py b/python/testData/quickFixes/PyMakeMethodStaticQuickFixTest/usage_after.py new file mode 100644 index 000000000000..bb27c1a4e49f --- /dev/null +++ b/python/testData/quickFixes/PyMakeMethodStaticQuickFixTest/usage_after.py @@ -0,0 +1,7 @@ +class A: + @staticmethod + def m(x): + return x + + +print A.m(1) \ No newline at end of file diff --git a/python/testSrc/com/jetbrains/python/quickFixes/PyMakeFunctionFromMethodQuickFixTest.java b/python/testSrc/com/jetbrains/python/quickFixes/PyMakeFunctionFromMethodQuickFixTest.java index 839e35af5f6d..d824ea8088cf 100644 --- a/python/testSrc/com/jetbrains/python/quickFixes/PyMakeFunctionFromMethodQuickFixTest.java +++ b/python/testSrc/com/jetbrains/python/quickFixes/PyMakeFunctionFromMethodQuickFixTest.java @@ -1,6 +1,5 @@ package com.jetbrains.python.quickFixes; -import com.intellij.codeInsight.intention.IntentionAction; import com.jetbrains.python.PyBundle; import com.jetbrains.python.inspections.PyMethodMayBeStaticInspection; @@ -46,21 +45,10 @@ public class PyMakeFunctionFromMethodQuickFixTest extends PyQuickFixTestCase { } public void testUsageImport() { - doTest(); + doMultifilesTest(PyMethodMayBeStaticInspection.class, PyBundle.message("QFIX.NAME.make.function"), new String[]{"test.py"}); } public void testUsageImport1() { - doTest(); - } - - - protected void doTest() { - final String testFileName = getTestName(true); - myFixture.enableInspections(PyMethodMayBeStaticInspection.class); - myFixture.configureByFiles("test.py", testFileName + ".py"); - final IntentionAction intentionAction = myFixture.findSingleIntention(PyBundle.message("QFIX.NAME.make.function")); - assertNotNull(intentionAction); - myFixture.launchAction(intentionAction); - myFixture.checkResultByFile(testFileName + ".py", testFileName + "_after.py", true); + doMultifilesTest(PyMethodMayBeStaticInspection.class, PyBundle.message("QFIX.NAME.make.function"), new String[]{"test.py"}); } } diff --git a/python/testSrc/com/jetbrains/python/quickFixes/PyMakeMethodStaticQuickFixTest.java b/python/testSrc/com/jetbrains/python/quickFixes/PyMakeMethodStaticQuickFixTest.java index c2096112ae44..dc34bb60cce1 100644 --- a/python/testSrc/com/jetbrains/python/quickFixes/PyMakeMethodStaticQuickFixTest.java +++ b/python/testSrc/com/jetbrains/python/quickFixes/PyMakeMethodStaticQuickFixTest.java @@ -32,4 +32,12 @@ public class PyMakeMethodStaticQuickFixTest extends PyQuickFixTestCase { doInspectionTest(PyMethodMayBeStaticInspection.class, PyBundle.message("QFIX.NAME.make.static")); } + public void testUsage() { + doInspectionTest(PyMethodMayBeStaticInspection.class, PyBundle.message("QFIX.NAME.make.static")); + } + + public void testUsageImport() { + doMultifilesTest(PyMethodMayBeStaticInspection.class, PyBundle.message("QFIX.NAME.make.static"), new String[]{"test.py"}); + } + } diff --git a/python/testSrc/com/jetbrains/python/quickFixes/PyQuickFixTestCase.java b/python/testSrc/com/jetbrains/python/quickFixes/PyQuickFixTestCase.java index 660dcdf13959..cbc582cc9c2f 100644 --- a/python/testSrc/com/jetbrains/python/quickFixes/PyQuickFixTestCase.java +++ b/python/testSrc/com/jetbrains/python/quickFixes/PyQuickFixTestCase.java @@ -4,6 +4,9 @@ import com.intellij.codeInsight.intention.IntentionAction; import com.jetbrains.python.PythonTestUtil; import com.jetbrains.python.fixtures.PyTestCase; import org.jetbrains.annotations.NonNls; +import org.jetbrains.annotations.NotNull; + +import java.util.Arrays; /** * User: ktisha @@ -25,4 +28,17 @@ public abstract class PyQuickFixTestCase extends PyTestCase { myFixture.launchAction(intentionAction); myFixture.checkResultByFile(testFileName + "_after.py", true); } + + protected void doMultifilesTest(@NotNull final Class inspectionClass, @NotNull final String hint, @NotNull final String[] files) { + final String testFileName = getTestName(true); + myFixture.enableInspections(inspectionClass); + String [] filenames = Arrays.copyOf(files, files.length + 1); + + filenames[files.length] = testFileName + ".py"; + myFixture.configureByFiles(filenames); + final IntentionAction intentionAction = myFixture.findSingleIntention(hint); + assertNotNull(intentionAction); + myFixture.launchAction(intentionAction); + myFixture.checkResultByFile(testFileName + ".py", testFileName + "_after.py", true); + } }