rename refactoring handles class inheritance (PY-1236)

This commit is contained in:
Dmitry Jemerov
2010-07-12 22:44:03 +04:00
parent 4d69d8d6c7
commit d3bbdc97ef
6 changed files with 94 additions and 20 deletions
@@ -13,14 +13,20 @@ public class PySuperMethodsSearch extends ExtensibleQueryFactory<PsiElement, PyS
public static class SearchParameters {
private final PyFunction myDerivedMethod;
private final boolean myDeepSearch;
public SearchParameters(final PyFunction derivedMethod) {
public SearchParameters(final PyFunction derivedMethod, boolean deepSearch) {
myDerivedMethod = derivedMethod;
myDeepSearch = deepSearch;
}
public PyFunction getDerivedMethod() {
return myDerivedMethod;
}
public boolean isDeepSearch() {
return myDeepSearch;
}
}
private PySuperMethodsSearch() {
@@ -28,7 +34,12 @@ public class PySuperMethodsSearch extends ExtensibleQueryFactory<PsiElement, PyS
}
public static Query<PsiElement> search(final PyFunction derivedMethod) {
final SearchParameters parameters = new SearchParameters(derivedMethod);
final SearchParameters parameters = new SearchParameters(derivedMethod, false);
return INSTANCE.createUniqueResultsQuery(parameters);
}
public static Query<PsiElement> search(final PyFunction derivedMethod, boolean deepSearch) {
final SearchParameters parameters = new SearchParameters(derivedMethod, deepSearch);
return INSTANCE.createUniqueResultsQuery(parameters);
}
}
@@ -20,14 +20,16 @@ public class PySuperMethodsSearchExecutor implements QueryExecutor<PsiElement, P
Set<PyClass> foundMethodContainingClasses = new HashSet<PyClass>();
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) {
@@ -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<PsiElement> superMethods = new ArrayList<PsiElement>(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<PsiElement, String> allRenames) {
PyFunction function = (PyFunction) element;
PyOverridingMethodsSearch.search(function, true).forEach(new Processor<PyFunction>() {
@Override
public boolean process(PyFunction pyFunction) {
allRenames.put(pyFunction, newName);
return true;
}
});
}
}
@@ -0,0 +1,5 @@
class A:
def f<caret>oo(self): pass
class B(A):
def foo(self): pass
@@ -0,0 +1,5 @@
class A:
def qu(self): pass
class B(A):
def qu(self): pass
@@ -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");
}
}