diff --git a/java/java-impl/src/com/intellij/ide/util/SuperMethodWarningUtil.java b/java/java-impl/src/com/intellij/ide/util/SuperMethodWarningUtil.java index ed577175a08c..5ac29a8c7231 100644 --- a/java/java-impl/src/com/intellij/ide/util/SuperMethodWarningUtil.java +++ b/java/java-impl/src/com/intellij/ide/util/SuperMethodWarningUtil.java @@ -16,12 +16,17 @@ package com.intellij.ide.util; import com.intellij.openapi.application.ApplicationManager; +import com.intellij.openapi.editor.Editor; import com.intellij.openapi.ui.DialogWrapper; +import com.intellij.openapi.ui.popup.JBPopupFactory; import com.intellij.psi.PsiClass; import com.intellij.psi.PsiElement; import com.intellij.psi.PsiMethod; import com.intellij.psi.PsiModifier; +import com.intellij.psi.presentation.java.SymbolPresentationUtil; +import com.intellij.psi.search.PsiElementProcessor; import com.intellij.psi.search.searches.DeepestSuperMethodsSearch; +import com.intellij.ui.components.JBList; import com.intellij.usageView.UsageViewUtil; import com.intellij.util.ArrayUtil; import org.jetbrains.annotations.NotNull; @@ -102,4 +107,51 @@ public class SuperMethodWarningUtil { return null; } + + public static void checkSuperMethod(final PsiMethod method, + final String actionString, + final PsiElementProcessor processor, + final Editor editor) { + PsiClass aClass = method.getContainingClass(); + if (aClass == null) { + processor.execute(method); + return; + } + + PsiMethod superMethod = method.findDeepestSuperMethod(); + if (superMethod == null) { + processor.execute(method); + return; + } + + final PsiClass containingClass = superMethod.getContainingClass(); + if (containingClass == null) { + processor.execute(method); + return; + } + + if (ApplicationManager.getApplication().isUnitTestMode()) { + processor.execute(superMethod); + return; + } + + final PsiMethod[] methods = new PsiMethod[]{superMethod, method}; + final String renameBase = actionString + " base method"; + final String renameCurrent = actionString + " only current method"; + final JBList list = new JBList(renameBase, renameCurrent); + JBPopupFactory.getInstance().createListPopupBuilder(list) + .setTitle(method.getName() + (containingClass.isInterface() && !aClass.isInterface() ? " implements" : " overrides") + " method of " + + SymbolPresentationUtil.getSymbolPresentableText(containingClass)) + .setMovable(false) + .setResizable(false) + .setRequestFocus(true) + .setItemChoosenCallback(new Runnable() { + public void run() { + final Object value = list.getSelectedValue(); + if (value instanceof String) { + processor.execute(methods[value.equals(renameBase) ? 0 : 1]); + } + } + }).createPopup().showInBestPositionFor(editor); + } } \ No newline at end of file diff --git a/java/java-impl/src/com/intellij/lang/java/JavaRefactoringSupportProvider.java b/java/java-impl/src/com/intellij/lang/java/JavaRefactoringSupportProvider.java index 4ff4ec49cf6a..6d057ff4c795 100644 --- a/java/java-impl/src/com/intellij/lang/java/JavaRefactoringSupportProvider.java +++ b/java/java-impl/src/com/intellij/lang/java/JavaRefactoringSupportProvider.java @@ -65,9 +65,6 @@ public class JavaRefactoringSupportProvider extends RefactoringSupportProvider { @Override public boolean isMemberInplaceRenameAvailable(PsiElement elementToRename, PsiElement context) { - if (elementToRename instanceof PsiMethod && ((PsiMethod)elementToRename).findDeepestSuperMethods().length > 0) { - return false; - } return elementToRename instanceof PsiMember; } diff --git a/java/java-impl/src/com/intellij/refactoring/rename/RenameJavaMethodProcessor.java b/java/java-impl/src/com/intellij/refactoring/rename/RenameJavaMethodProcessor.java index 5b751432ed29..2868623dcbaf 100644 --- a/java/java-impl/src/com/intellij/refactoring/rename/RenameJavaMethodProcessor.java +++ b/java/java-impl/src/com/intellij/refactoring/rename/RenameJavaMethodProcessor.java @@ -18,8 +18,10 @@ package com.intellij.refactoring.rename; import com.intellij.ide.util.SuperMethodWarningUtil; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.editor.Editor; +import com.intellij.openapi.util.Pass; import com.intellij.psi.*; import com.intellij.psi.search.GlobalSearchScope; +import com.intellij.psi.search.PsiElementProcessor; import com.intellij.psi.search.SearchScope; import com.intellij.psi.search.searches.ClassInheritorsSearch; import com.intellij.psi.search.searches.MethodReferencesSearch; @@ -237,6 +239,25 @@ public class RenameJavaMethodProcessor extends RenameJavaMemberProcessor { return SuperMethodWarningUtil.checkSuperMethod(psiMethod, RefactoringBundle.message("to.rename")); } + @Override + public void substituteElementToRename(@NotNull PsiElement element, + @NotNull Editor editor, + @NotNull final Pass renameCallback) { + PsiMethod psiMethod = (PsiMethod)element; + if (psiMethod.isConstructor()) { + super.substituteElementToRename(element, editor, renameCallback); + } + else { + SuperMethodWarningUtil.checkSuperMethod(psiMethod, "Rename", new PsiElementProcessor() { + @Override + public boolean execute(@NotNull PsiMethod method) { + renameCallback.pass(method); + return false; + } + }, editor); + } + } + private static void findSubmemberHidesMemberCollisions(final PsiMethod method, final String newName, final List result) { final PsiClass containingClass = method.getContainingClass(); if (containingClass == null) return; diff --git a/platform/lang-impl/src/com/intellij/refactoring/rename/RenamePsiElementProcessor.java b/platform/lang-impl/src/com/intellij/refactoring/rename/RenamePsiElementProcessor.java index 3148befc6895..ce040f54e6b1 100644 --- a/platform/lang-impl/src/com/intellij/refactoring/rename/RenamePsiElementProcessor.java +++ b/platform/lang-impl/src/com/intellij/refactoring/rename/RenamePsiElementProcessor.java @@ -21,6 +21,7 @@ import com.intellij.openapi.extensions.ExtensionPointName; import com.intellij.openapi.extensions.Extensions; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.Pair; +import com.intellij.openapi.util.Pass; import com.intellij.psi.PsiElement; import com.intellij.psi.PsiFile; import com.intellij.psi.PsiFileSystemItem; @@ -161,6 +162,18 @@ public abstract class RenamePsiElementProcessor { return element; } + /** + * Substitutes element to be renamed and initiate rename procedure. Should be used in order to prevent modal dialogs to appear during inplace rename + * @param element the element on which refactoring was invoked + * @param editor the editor in which inplace refactoring was invoked + * @param renameCallback rename procedure which should be called on the chosen substitution + */ + public void substituteElementToRename(@NotNull final PsiElement element, @NotNull Editor editor, @NotNull Pass renameCallback) { + final PsiElement psiElement = substituteElementToRename(element, editor); + if (psiElement == null) return; + renameCallback.pass(psiElement); + } + public void findCollisions(final PsiElement element, final String newName, final Map allRenames, final List result) { } diff --git a/platform/lang-impl/src/com/intellij/refactoring/rename/inplace/MemberInplaceRenameHandler.java b/platform/lang-impl/src/com/intellij/refactoring/rename/inplace/MemberInplaceRenameHandler.java index 923abea7ef0f..3000a9961214 100644 --- a/platform/lang-impl/src/com/intellij/refactoring/rename/inplace/MemberInplaceRenameHandler.java +++ b/platform/lang-impl/src/com/intellij/refactoring/rename/inplace/MemberInplaceRenameHandler.java @@ -18,12 +18,15 @@ package com.intellij.refactoring.rename.inplace; import com.intellij.codeInsight.lookup.LookupManager; import com.intellij.lang.LanguageRefactoringSupport; import com.intellij.lang.refactoring.RefactoringSupportProvider; +import com.intellij.openapi.actionSystem.DataContext; import com.intellij.openapi.editor.Editor; +import com.intellij.openapi.util.Pass; import com.intellij.psi.PsiElement; import com.intellij.psi.PsiFile; import com.intellij.psi.PsiNameIdentifierOwner; import com.intellij.psi.PsiNamedElement; import com.intellij.psi.util.PsiTreeUtil; +import com.intellij.refactoring.rename.RenamePsiElementProcessor; import org.jetbrains.annotations.NotNull; /** @@ -45,9 +48,20 @@ public class MemberInplaceRenameHandler extends VariableInplaceRenameHandler { } @Override - protected VariableInplaceRenamer createRenamer(@NotNull PsiElement elementToRename, Editor editor) { + public VariableInplaceRenamer doRename(@NotNull final PsiElement elementToRename, final Editor editor, final DataContext dataContext) { if (elementToRename instanceof PsiNameIdentifierOwner) { - return new MemberInplaceRenamer((PsiNameIdentifierOwner)elementToRename, editor); + RenamePsiElementProcessor.forElement(elementToRename).substituteElementToRename(elementToRename, editor, new Pass() { + @Override + public void pass(PsiElement element) { + final MemberInplaceRenamer renamer = new MemberInplaceRenamer((PsiNameIdentifierOwner)elementToRename, element, editor); + boolean startedRename = renamer.performInplaceRename(); + if (!startedRename) { + performDialogRename(elementToRename, editor, dataContext); + } + } + }); + } else { + performDialogRename(elementToRename, editor, dataContext); } return null; } diff --git a/platform/lang-impl/src/com/intellij/refactoring/rename/inplace/MemberInplaceRenamer.java b/platform/lang-impl/src/com/intellij/refactoring/rename/inplace/MemberInplaceRenamer.java index 6635812edf22..2e0f6b5f83e8 100644 --- a/platform/lang-impl/src/com/intellij/refactoring/rename/inplace/MemberInplaceRenamer.java +++ b/platform/lang-impl/src/com/intellij/refactoring/rename/inplace/MemberInplaceRenamer.java @@ -58,11 +58,10 @@ public class MemberInplaceRenamer extends VariableInplaceRenamer { private final PsiElement mySubstituted; private RangeMarker mySubstitutedRange; - public MemberInplaceRenamer(@NotNull PsiNameIdentifierOwner elementToRename, Editor editor) { + public MemberInplaceRenamer(@NotNull PsiNameIdentifierOwner elementToRename, PsiElement substituted, Editor editor) { super(elementToRename, editor); myOldName = elementToRename.getName(); - final RenamePsiElementProcessor processor = RenamePsiElementProcessor.forElement(elementToRename); - mySubstituted = processor.substituteElementToRename(elementToRename, myEditor); + mySubstituted = substituted; mySubstitutedRange = mySubstituted != null && mySubstituted != myElementToRename && mySubstituted.getTextRange() != null ? myEditor.getDocument().createRangeMarker(mySubstituted.getTextRange()) : null; showDialogAdvertisement("RenameElement"); diff --git a/platform/lang-impl/src/com/intellij/refactoring/rename/inplace/VariableInplaceRenameHandler.java b/platform/lang-impl/src/com/intellij/refactoring/rename/inplace/VariableInplaceRenameHandler.java index a72a435b9452..cfc21482fab4 100644 --- a/platform/lang-impl/src/com/intellij/refactoring/rename/inplace/VariableInplaceRenameHandler.java +++ b/platform/lang-impl/src/com/intellij/refactoring/rename/inplace/VariableInplaceRenameHandler.java @@ -112,23 +112,26 @@ public class VariableInplaceRenameHandler implements RenameHandler { boolean startedRename = renamer == null ? false : renamer.performInplaceRename(); if (!startedRename) { - try { - ourPreventInlineRenameFlag.set(Boolean.TRUE); - - RenameHandler handler = RenameHandlerRegistry.getInstance().getRenameHandler(dataContext); - assert handler != null; - handler.invoke( - elementToRename.getProject(), - editor, - elementToRename.getContainingFile(), dataContext - ); - } finally { - ourPreventInlineRenameFlag.set(null); - } + performDialogRename(elementToRename, editor, dataContext); } return renamer; } + protected static void performDialogRename(PsiElement elementToRename, Editor editor, DataContext dataContext) { + try { + ourPreventInlineRenameFlag.set(Boolean.TRUE); + RenameHandler handler = RenameHandlerRegistry.getInstance().getRenameHandler(dataContext); + assert handler != null; + handler.invoke( + elementToRename.getProject(), + editor, + elementToRename.getContainingFile(), dataContext + ); + } finally { + ourPreventInlineRenameFlag.set(null); + } + } + @Nullable protected VariableInplaceRenamer createRenamer(@NotNull PsiElement elementToRename, Editor editor) { return new VariableInplaceRenamer((PsiNameIdentifierOwner)elementToRename, editor);