From d3bbdc97ef5fee026b59eb2e7da5e58c0f2e9513 Mon Sep 17 00:00:00 2001 From: Dmitry Jemerov Date: Mon, 12 Jul 2010 22:42:12 +0400 Subject: [PATCH] rename refactoring handles class inheritance (PY-1236) --- .../psi/search/PySuperMethodsSearch.java | 15 +++++- .../search/PySuperMethodsSearchExecutor.java | 16 ++++--- .../rename/RenamePyFunctionProcessor.java | 47 +++++++++++++++++++ .../refactoring/rename/renameInheritors.py | 5 ++ .../rename/renameInheritors_after.py | 5 ++ .../python/refactoring/PyRenameTest.java | 26 +++++----- 6 files changed, 94 insertions(+), 20 deletions(-) create mode 100644 python/testData/refactoring/rename/renameInheritors.py create mode 100644 python/testData/refactoring/rename/renameInheritors_after.py diff --git a/python/src/com/jetbrains/python/psi/search/PySuperMethodsSearch.java b/python/src/com/jetbrains/python/psi/search/PySuperMethodsSearch.java index 6c1d81fc208a..8c58ac650eb9 100644 --- a/python/src/com/jetbrains/python/psi/search/PySuperMethodsSearch.java +++ b/python/src/com/jetbrains/python/psi/search/PySuperMethodsSearch.java @@ -13,14 +13,20 @@ public class PySuperMethodsSearch extends ExtensibleQueryFactory search(final PyFunction derivedMethod) { - final SearchParameters parameters = new SearchParameters(derivedMethod); + final SearchParameters parameters = new SearchParameters(derivedMethod, false); + return INSTANCE.createUniqueResultsQuery(parameters); + } + + public static Query search(final PyFunction derivedMethod, boolean deepSearch) { + final SearchParameters parameters = new SearchParameters(derivedMethod, deepSearch); return INSTANCE.createUniqueResultsQuery(parameters); } } diff --git a/python/src/com/jetbrains/python/psi/search/PySuperMethodsSearchExecutor.java b/python/src/com/jetbrains/python/psi/search/PySuperMethodsSearchExecutor.java index 53da9d1eeb92..7f7f48fbc2f5 100644 --- a/python/src/com/jetbrains/python/psi/search/PySuperMethodsSearchExecutor.java +++ b/python/src/com/jetbrains/python/psi/search/PySuperMethodsSearchExecutor.java @@ -20,14 +20,16 @@ public class PySuperMethodsSearchExecutor implements QueryExecutor foundMethodContainingClasses = new HashSet(); if (name != null && containingClass != null) { for (PyClass superClass : containingClass.iterateAncestors()) { - boolean isAlreadyFound = false; - for (PyClass alreadyFound : foundMethodContainingClasses) { - if (alreadyFound.isSubclass(superClass)) { - isAlreadyFound = true; + if (!queryParameters.isDeepSearch()) { + boolean isAlreadyFound = false; + for (PyClass alreadyFound : foundMethodContainingClasses) { + if (alreadyFound.isSubclass(superClass)) { + isAlreadyFound = true; + } + } + if (isAlreadyFound) { + continue; } - } - if (isAlreadyFound) { - continue; } PyFunction superMethod = superClass.findMethodByName(name, false); if (superMethod != null) { diff --git a/python/src/com/jetbrains/python/refactoring/rename/RenamePyFunctionProcessor.java b/python/src/com/jetbrains/python/refactoring/rename/RenamePyFunctionProcessor.java index 6e52bbbabeea..820220c6ce53 100644 --- a/python/src/com/jetbrains/python/refactoring/rename/RenamePyFunctionProcessor.java +++ b/python/src/com/jetbrains/python/refactoring/rename/RenamePyFunctionProcessor.java @@ -1,9 +1,19 @@ package com.jetbrains.python.refactoring.rename; +import com.intellij.openapi.editor.Editor; +import com.intellij.openapi.ui.Messages; import com.intellij.psi.PsiElement; import com.intellij.refactoring.rename.RenamePsiElementProcessor; +import com.intellij.util.Processor; import com.jetbrains.python.codeInsight.PyCodeInsightSettings; +import com.jetbrains.python.psi.PyClass; import com.jetbrains.python.psi.PyFunction; +import com.jetbrains.python.psi.search.PyOverridingMethodsSearch; +import com.jetbrains.python.psi.search.PySuperMethodsSearch; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; /** * @author yole @@ -38,4 +48,41 @@ public class RenamePyFunctionProcessor extends RenamePsiElementProcessor { public void setToSearchForTextOccurrences(PsiElement element, boolean enabled) { PyCodeInsightSettings.getInstance().RENAME_SEARCH_NON_CODE_FOR_FUNCTION = enabled; } + + @Override + public PsiElement substituteElementToRename(PsiElement element, Editor editor) { + PyFunction function = (PyFunction) element; + final PyClass containingClass = function.getContainingClass(); + if (containingClass == null) { + return function; + } + final List superMethods = new ArrayList(PySuperMethodsSearch.search(function, true).findAll()); + if (superMethods.size() > 0) { + // TODO this is not exactly right for multiple inheritance + final PyFunction deepestSuperMethod = (PyFunction) superMethods.get(superMethods.size()-1); + String message = "Method " + function.getName() + " of class " + containingClass.getQualifiedName() + "\noverrides method of class " + + deepestSuperMethod.getContainingClass().getQualifiedName() + ".\nDo you want to rename the base method?"; + int rc = Messages.showYesNoCancelDialog(element.getProject(), message, "Rename", Messages.getQuestionIcon()); + if (rc == 0) { + return deepestSuperMethod; + } + if (rc == 1) { + return function; + } + return null; + } + return function; + } + + @Override + public void prepareRenaming(PsiElement element, final String newName, final Map allRenames) { + PyFunction function = (PyFunction) element; + PyOverridingMethodsSearch.search(function, true).forEach(new Processor() { + @Override + public boolean process(PyFunction pyFunction) { + allRenames.put(pyFunction, newName); + return true; + } + }); + } } diff --git a/python/testData/refactoring/rename/renameInheritors.py b/python/testData/refactoring/rename/renameInheritors.py new file mode 100644 index 000000000000..b6d7d3700cf9 --- /dev/null +++ b/python/testData/refactoring/rename/renameInheritors.py @@ -0,0 +1,5 @@ +class A: + def foo(self): pass + +class B(A): + def foo(self): pass \ No newline at end of file diff --git a/python/testData/refactoring/rename/renameInheritors_after.py b/python/testData/refactoring/rename/renameInheritors_after.py new file mode 100644 index 000000000000..4c43885db799 --- /dev/null +++ b/python/testData/refactoring/rename/renameInheritors_after.py @@ -0,0 +1,5 @@ +class A: + def qu(self): pass + +class B(A): + def qu(self): pass \ No newline at end of file diff --git a/python/testSrc/com/jetbrains/python/refactoring/PyRenameTest.java b/python/testSrc/com/jetbrains/python/refactoring/PyRenameTest.java index 4d606044672f..ada298dca901 100644 --- a/python/testSrc/com/jetbrains/python/refactoring/PyRenameTest.java +++ b/python/testSrc/com/jetbrains/python/refactoring/PyRenameTest.java @@ -8,13 +8,11 @@ import com.jetbrains.python.fixtures.PyLightFixtureTestCase; * @author yole */ public class PyRenameTest extends PyLightFixtureTestCase { - public void testRenameField() throws Exception { // PY-457 - myFixture.configureByFile("refactoring/rename/" + getTestName(true) + ".py"); - myFixture.renameElementAtCaret("qu"); - myFixture.checkResultByFile("refactoring/rename/" + getTestName(true) + "_after.py"); + public void testRenameField() { // PY-457 + doTest("qu"); } - public void testSearchInStrings() throws Exception { // PY-670 + public void testSearchInStrings() { // PY-670 myFixture.configureByFile("refactoring/rename/" + getTestName(true) + ".py"); final PsiElement element = TargetElementUtilBase.findTargetElement(myFixture.getEditor(), TargetElementUtilBase.REFERENCED_ELEMENT_ACCEPTED | TargetElementUtilBase.ELEMENT_NAME_ACCEPTED); @@ -23,15 +21,21 @@ public class PyRenameTest extends PyLightFixtureTestCase { myFixture.checkResultByFile("refactoring/rename/" + getTestName(true) + "_after.py"); } - public void testRenameParameter() throws Exception { // PY-385 - myFixture.configureByFile("refactoring/rename/" + getTestName(true) + ".py"); - myFixture.renameElementAtCaret("qu"); - myFixture.checkResultByFile("refactoring/rename/" + getTestName(true) + "_after.py"); + public void testRenameParameter() { // PY-385 + doTest("qu"); } - public void testRenameMultipleDefinitionsLocal() throws Exception { // PY-727 + public void testRenameMultipleDefinitionsLocal() { // PY-727 + doTest("qu"); + } + + public void testRenameInheritors() { + doTest("qu"); + } + + private void doTest(final String newName) { myFixture.configureByFile("refactoring/rename/" + getTestName(true) + ".py"); - myFixture.renameElementAtCaret("qu"); + myFixture.renameElementAtCaret(newName); myFixture.checkResultByFile("refactoring/rename/" + getTestName(true) + "_after.py"); } }