[mod-commands] Use RenamerFactory when executing rename to make it more similar to normal rename

Provide an interface to specify suggested names from outside
Still part of IDEA-338334

GitOrigin-RevId: 7bb09b7150b463ed8a0c24453c968d60d9e716fa
This commit is contained in:
Tagir Valeev
2023-11-23 10:39:44 +01:00
committed by intellij-monorepo-bot
parent 59074e21c9
commit 853a7a46fc
25 changed files with 127 additions and 112 deletions

View File

@@ -4,7 +4,7 @@ import java.io.*;
class a {
void f(InputStream in) {
final int n;
int n1<caret>;
int <caret>n1;
try {
n1 = in.read();
} catch (IOException e) {

View File

@@ -4,7 +4,7 @@ import java.io.*;
class a {
void f(InputStream in) {
final int n;
int n1<caret>;
int <caret>n1;
if (in==null) {
n1 = 2;
n1 = 2;

View File

@@ -4,7 +4,7 @@ import java.io.*;
class a {
void f(InputStream in) {
final int n;
int n1<caret>;
int <caret>n1;
if (in==null) {
n1 = 2;
n1 = 2;

View File

@@ -4,7 +4,7 @@ import java.io.*;
class a {
final int n;
a(InputStream in) {
int n1<caret>;
int <caret>n1;
if (in==null) {
n1 = 2;
n1 = 2;

View File

@@ -4,7 +4,7 @@ import java.io.*;
class a {
void f(int k) {
final int i;
int i1<caret>;
int <caret>i1;
i1 = 4;
i1 = 4;
i = i1;

View File

@@ -4,7 +4,7 @@ import java.io.*;
class a {
final int n;
{
int n1<caret>;
int <caret>n1;
n1 =3;
n1 =3;
n = n1;

View File

@@ -4,7 +4,7 @@ import java.io.*;
class a {
final int n;
a(int n) {
int n1<caret>;
int <caret>n1;
n1 =n;
n1 =n;
this.n = n1;

View File

@@ -4,7 +4,7 @@ import java.io.*;
class a {
void f(InputStream in) {
final int n;
int n1<caret>;
int <caret>n1;
try {
n1 = in.read();
} catch (IOException e) {

View File

@@ -2,7 +2,7 @@ class C {
void foo(int n) {
String s = "";
if (n > 0) {
String x<caret> = "x";
String <caret>x = "x";
}
}
}

View File

@@ -4,7 +4,7 @@ class Test {
List<String> getList(int x) {
if (x == 0) {
List<String> strings<caret> = new ArrayList<>();
List<String> <caret>strings = new ArrayList<>();
strings.add("0");
return (strings);
} else {

View File

@@ -2,7 +2,7 @@ class A {
private A() {
}
static A createA<caret>() {
static A <caret>createA() {
return new A();
}
}

View File

@@ -13,21 +13,22 @@ import com.intellij.codeInsight.lookup.LookupElement;
import com.intellij.codeInsight.lookup.LookupElementBuilder;
import com.intellij.codeInsight.lookup.LookupFocusDegree;
import com.intellij.codeInsight.template.*;
import com.intellij.codeInsight.template.impl.TemplateManagerImpl;
import com.intellij.codeInspection.options.OptionController;
import com.intellij.codeInspection.options.OptionControllerProvider;
import com.intellij.diff.comparison.ComparisonManager;
import com.intellij.diff.comparison.ComparisonPolicy;
import com.intellij.diff.fragments.DiffFragment;
import com.intellij.ide.DataManager;
import com.intellij.ide.util.MemberChooser;
import com.intellij.lang.LangBundle;
import com.intellij.lang.LanguageRefactoringSupport;
import com.intellij.lang.injection.InjectedLanguageManager;
import com.intellij.lang.refactoring.RefactoringSupportProvider;
import com.intellij.modcommand.*;
import com.intellij.modcommand.ModChooseMember.SelectionMode;
import com.intellij.modcommand.ModUpdateFileText.Fragment;
import com.intellij.openapi.actionSystem.ActionPlaces;
import com.intellij.openapi.actionSystem.CommonDataKeys;
import com.intellij.openapi.actionSystem.DataContext;
import com.intellij.openapi.actionSystem.impl.SimpleDataContext;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.application.ReadAction;
import com.intellij.openapi.application.WriteAction;
@@ -42,7 +43,6 @@ import com.intellij.openapi.progress.DumbProgressIndicator;
import com.intellij.openapi.progress.ProgressManager;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.NlsContexts;
import com.intellij.openapi.util.Pass;
import com.intellij.openapi.util.TextRange;
import com.intellij.openapi.vfs.ReadonlyStatusHandler;
import com.intellij.openapi.vfs.VirtualFile;
@@ -51,13 +51,10 @@ import com.intellij.psi.*;
import com.intellij.psi.impl.PsiManagerEx;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.refactoring.RefactoringBundle;
import com.intellij.refactoring.rename.RenameDialog;
import com.intellij.refactoring.rename.RenamePsiElementProcessor;
import com.intellij.refactoring.rename.inplace.MemberInplaceRenamer;
import com.intellij.refactoring.rename.*;
import com.intellij.refactoring.suggested.*;
import com.intellij.refactoring.ui.ConflictsDialog;
import com.intellij.testFramework.LightVirtualFile;
import com.intellij.util.ArrayUtil;
import com.intellij.util.concurrency.annotations.RequiresEdt;
import com.intellij.util.containers.ContainerUtil;
import com.intellij.util.containers.MultiMap;
@@ -412,48 +409,19 @@ public class ModCommandExecutorImpl implements ModCommandExecutor {
if (namedElement == null) return false;
Editor finalEditor = getEditor(project, editor, file);
if (finalEditor == null) return false;
PsiElement nameIdentifier = namedElement instanceof PsiNameIdentifierOwner owner ? owner.getNameIdentifier() : null;
final RenamePsiElementProcessor processor = RenamePsiElementProcessor.forElement(namedElement);
processor.substituteElementToRename(namedElement, finalEditor, new Pass<>() {
@Override
public void pass(PsiElement substitutedElement) {
RefactoringSupportProvider supportProvider = LanguageRefactoringSupport.INSTANCE.forContext(namedElement);
if (supportProvider != null &&
supportProvider.isInplaceRenameAvailable(namedElement, namedElement)) {
if (TemplateManager.getInstance(project) instanceof TemplateManagerImpl manager &&
manager.shouldSkipInTests()) {
if (nameIdentifier != null) {
int offset = nameIdentifier.getTextRange().getEndOffset();
executeNavigate(project, new ModNavigate(file, offset, offset, offset));
}
return;
}
finalEditor.getCaretModel().moveToOffset(requireNonNullElse(nameIdentifier, namedElement).getTextOffset());
final MemberInplaceRenamer renamer = new MemberInplaceRenamer(namedElement, substitutedElement, finalEditor);
final LinkedHashSet<String> nameSuggestions = new LinkedHashSet<>(rename.nameSuggestions());
renamer.performInplaceRefactoring(nameSuggestions);
}
else {
RenameDialog dialog = new RenameDialog(project, namedElement, null, finalEditor) {
@Override
public String[] getSuggestedNames() {
return ArrayUtil.toStringArray(rename.nameSuggestions());
}
};
if (ApplicationManager.getApplication().isUnitTestMode()) {
try {
dialog.performRename(rename.nameSuggestions().stream().min(Comparator.naturalOrder()).orElse("undefined"));
}
finally {
dialog.close();
}
}
else {
dialog.show();
}
}
}
});
DataContext context = DataManager.getInstance().getDataContext(finalEditor.getComponent());
DataContext finalContext = SimpleDataContext.builder()
.setParent(context)
.add(CommonDataKeys.PSI_ELEMENT, namedElement)
.add(PsiElementRenameHandler.NAME_SUGGESTIONS, rename.nameSuggestions())
.build();
PsiElement anchor = namedElement instanceof PsiNameIdentifierOwner owner ?
requireNonNullElse(owner.getNameIdentifier(), namedElement) : namedElement;
finalEditor.getCaretModel().moveToOffset(anchor.getTextOffset());
Renamer renamer = RenamerFactory.EP_NAME.getExtensionList().stream().flatMap(factory -> factory.createRenamers(finalContext).stream())
.findFirst().orElse(null);
if (renamer == null) return false;
renamer.performRename();
return true;
}
@@ -464,38 +432,6 @@ public class ModCommandExecutorImpl implements ModCommandExecutor {
return finalEditor;
}
static class NameExpression extends Expression {
private final String myOrig;
private final LookupElement[] cachedLookupElements;
NameExpression(String orig, List<String> suggestions) {
myOrig = orig;
cachedLookupElements = suggestions.stream()
.map(LookupElementBuilder::create)
.toArray(LookupElement[]::new);
}
@Override
public boolean requiresCommittedPSI() {
return false;
}
@Override
public com.intellij.codeInsight.template.Result calculateResult(ExpressionContext context) {
return new TextResult(myOrig);
}
@Override
public @NotNull LookupFocusDegree getLookupFocusDegree() {
return LookupFocusDegree.UNFOCUSED;
}
@Override
public LookupElement[] calculateLookupItems(ExpressionContext context) {
return cachedLookupElements;
}
}
private static final class ErrorInTestException extends RuntimeException {
private ErrorInTestException(String message) {
super(message);

View File

@@ -44,10 +44,8 @@ import org.jetbrains.annotations.Nullable;
import javax.swing.*;
import java.awt.*;
import java.util.HashMap;
import java.util.LinkedHashSet;
import java.util.*;
import java.util.List;
import java.util.Map;
public class RenameDialog extends RefactoringDialog implements RenameRefactoringDialog {
private SuggestedNameInfo mySuggestedNameInfo;
@@ -65,6 +63,7 @@ public class RenameDialog extends RefactoringDialog implements RenameRefactoring
private String myOldName;
private ScopeChooserCombo myScopeCombo;
private final LinkedHashSet<String> myPredefinedSuggestedNames = new LinkedHashSet<>();
public RenameDialog(@NotNull Project project, @NotNull PsiElement psiElement, @Nullable PsiElement nameSuggestionContext, Editor editor) {
super(project, true);
@@ -74,6 +73,11 @@ public class RenameDialog extends RefactoringDialog implements RenameRefactoring
myPsiElement = psiElement;
myNameSuggestionContext = nameSuggestionContext;
myEditor = editor;
myHelpID = RenamePsiElementProcessor.forElement(psiElement).getHelpID(psiElement);
}
protected void initUI() {
if (myNameSuggestionsField != null) return;
setTitle(getRefactoringName());
createNewNameComponent();
@@ -89,7 +93,6 @@ public class RenameDialog extends RefactoringDialog implements RenameRefactoring
}
if (!ApplicationManager.getApplication().isUnitTestMode()) validateButtons();
myHelpID = RenamePsiElementProcessor.forElement(psiElement).getHelpID(psiElement);
}
public static void showRenameDialog(DataContext dataContext, RenameDialog dialog) {
@@ -103,6 +106,12 @@ public class RenameDialog extends RefactoringDialog implements RenameRefactoring
}
}
@Override
public void show() {
initUI();
super.show();
}
@NotNull
protected @NlsContexts.Label String getLabelText() {
return RefactoringBundle.message("rename.0.and.its.usages.to", getFullName());
@@ -120,7 +129,9 @@ public class RenameDialog extends RefactoringDialog implements RenameRefactoring
@Override
protected void dispose() {
myNameSuggestionsField.removeDataChangedListener(myNameChangedListener);
if (myNameSuggestionsField != null) {
myNameSuggestionsField.removeDataChangedListener(myNameChangedListener);
}
super.dispose();
}
@@ -162,6 +173,15 @@ public class RenameDialog extends RefactoringDialog implements RenameRefactoring
validateButtons();
}
@Override
public void addSuggestedNames(@NotNull Collection<@NotNull String> names) {
if (names.isEmpty()) return;
myPredefinedSuggestedNames.addAll(names);
if (myNameSuggestionsField != null) {
myNameSuggestionsField.setSuggestions(getSuggestedNames());
}
}
@Override
public String[] getSuggestedNames() {
final LinkedHashSet<String> result = new LinkedHashSet<>();
@@ -169,6 +189,7 @@ public class RenameDialog extends RefactoringDialog implements RenameRefactoring
if (initialName != null) {
result.add(initialName);
}
result.addAll(myPredefinedSuggestedNames);
result.add(UsageViewUtil.getShortName(myPsiElement));
mySuggestedNameInfo = NameSuggestionProvider.suggestNames(myPsiElement, myNameSuggestionContext, result);
return ArrayUtilRt.toStringArray(result);
@@ -181,7 +202,7 @@ public class RenameDialog extends RefactoringDialog implements RenameRefactoring
@NotNull
public SearchScope getRefactoringScope() {
SearchScope scope = myScopeCombo.getSelectedScope();
SearchScope scope = myScopeCombo == null ? null : myScopeCombo.getSelectedScope();
return scope != null ? scope : GlobalSearchScope.projectScope(myProject);
}
@@ -329,6 +350,7 @@ public class RenameDialog extends RefactoringDialog implements RenameRefactoring
@Override
public void performRename(@NotNull String newName) {
initUI();
final RenamePsiElementProcessor elementProcessor = RenamePsiElementProcessor.forElement(myPsiElement);
elementProcessor.setToSearchInComments(myPsiElement, isSearchInComments());
if (isSearchForTextOccurrencesEnabled()) {
@@ -355,10 +377,12 @@ public class RenameDialog extends RefactoringDialog implements RenameRefactoring
}
public RenameProcessor createRenameProcessorEx(@NotNull String newName) {
initUI();
return createRenameProcessor(newName);
}
protected RenameProcessor createRenameProcessor(@NotNull String newName) {
initUI();
return new RenameProcessor(getProject(), myPsiElement, newName, getRefactoringScope(), isSearchInComments(), isSearchInNonJavaFiles());
}

View File

@@ -41,6 +41,7 @@ import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.awt.*;
import java.util.List;
public class MemberInplaceRenameHandler extends VariableInplaceRenameHandler {
@Override
@@ -79,7 +80,8 @@ public class MemberInplaceRenameHandler extends VariableInplaceRenameHandler {
@Override
public void pass(PsiElement element) {
final MemberInplaceRenamer renamer = createMemberRenamer(element, (PsiNameIdentifierOwner)elementToRename, editor);
boolean startedRename = renamer.performInplaceRename();
List<String> names = dataContext == null ? null : PsiElementRenameHandler.NAME_SUGGESTIONS.getData(dataContext);
boolean startedRename = renamer.performInplaceRename(names);
if (!startedRename) {
performDialogRename(elementToRename, editor, createDataContext(contextComponent, newName, elementToRename), renamer.myInitialName);
}

View File

@@ -23,6 +23,8 @@ import com.intellij.refactoring.rename.RenameHandlerRegistry;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.List;
public class VariableInplaceRenameHandler implements RenameHandler {
private static final ThreadLocal<String> ourPreventInlineRenameFlag = new ThreadLocal<>();
private static final Logger LOG = Logger.getInstance(VariableInplaceRenameHandler.class);
@@ -114,7 +116,8 @@ public class VariableInplaceRenameHandler implements RenameHandler {
@NotNull Editor editor,
@Nullable DataContext dataContext) {
VariableInplaceRenamer renamer = createRenamer(elementToRename, editor);
boolean startedRename = renamer != null && renamer.performInplaceRename();
List<String> names = dataContext == null ? null : PsiElementRenameHandler.NAME_SUGGESTIONS.getData(dataContext);
boolean startedRename = renamer != null && renamer.performInplaceRename(names);
if (!startedRename && dataContext != null) {
performDialogRename(elementToRename, editor, dataContext, renamer != null ? renamer.myInitialName : null);

View File

@@ -88,6 +88,10 @@ public class VariableInplaceRenamer extends InplaceRefactoring {
}
public boolean performInplaceRename() {
return performInplaceRename(null);
}
public boolean performInplaceRename(@Nullable Collection<String> nameSuggestions) {
final String refactoringId = getRefactoringId();
PsiNamedElement elementToRename = getVariable();
if (refactoringId != null) {
@@ -97,7 +101,7 @@ public class VariableInplaceRenamer extends InplaceRefactoring {
myProject.getMessageBus()
.syncPublisher(RefactoringEventListener.REFACTORING_EVENT_TOPIC).refactoringStarted(refactoringId, beforeData);
}
return performInplaceRefactoring(null);
return performInplaceRefactoring(nameSuggestions == null ? null : new LinkedHashSet<>(nameSuggestions));
}
@Override

View File

@@ -30,6 +30,10 @@ import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import static java.util.Objects.requireNonNullElse;
/**
* created at Nov 13, 2001
@@ -41,6 +45,8 @@ public class PsiElementRenameHandler implements RenameHandler {
private static final ExtensionPointName<Condition<? super PsiElement>> VETO_RENAME_CONDITION_EP = ExtensionPointName.create("com.intellij.vetoRenameCondition");
public static final DataKey<String> DEFAULT_NAME = DataKey.create("DEFAULT_NAME");
public static final DataKey<List<String>> NAME_SUGGESTIONS = DataKey.create("renameNameSuggestions");
@Override
public void invoke(@NotNull Project project, Editor editor, PsiFile file, @NotNull DataContext dataContext) {
@@ -59,7 +65,9 @@ public class PsiElementRenameHandler implements RenameHandler {
editor.getScrollingModel().scrollToCaret(ScrollType.MAKE_VISIBLE);
final PsiElement nameSuggestionContext = InjectedLanguageUtilBase.findElementAtNoCommit(file, editor.getCaretModel().getOffset());
invoke(element, project, nameSuggestionContext, editor, shouldCheckInProject());
boolean checkInProject = shouldCheckInProject();
List<String> suggestedNames = requireNonNullElse(NAME_SUGGESTIONS.getData(dataContext), List.of());
invoke(element, project, nameSuggestionContext, suggestedNames, editor, checkInProject);
}
@Override
@@ -86,7 +94,20 @@ public class PsiElementRenameHandler implements RenameHandler {
invoke(element, project, nameSuggestionContext, editor, true);
}
public static void invoke(@NotNull PsiElement element, @NotNull Project project, PsiElement nameSuggestionContext, @Nullable Editor editor, boolean checkInProject) {
public static void invoke(@NotNull PsiElement element,
@NotNull Project project,
PsiElement nameSuggestionContext,
@Nullable Editor editor,
boolean checkInProject) {
invoke(element, project, nameSuggestionContext, List.of(), editor, checkInProject);
}
private static void invoke(@NotNull PsiElement element,
@NotNull Project project,
PsiElement nameSuggestionContext,
@NotNull List<String> suggestedNames,
@Nullable Editor editor,
boolean checkInProject) {
if (!canRename(project, editor, element)) {
return;
}
@@ -104,7 +125,8 @@ public class PsiElementRenameHandler implements RenameHandler {
}
}
rename(element, project, nameSuggestionContext, editor);
var processor = RenamePsiElementProcessorBase.forPsiElement(element);
rename(element, project, nameSuggestionContext, suggestedNames, editor, null, processor);
}
public static boolean canRename(@NotNull Project project, Editor editor, PsiElement element) throws CommonRefactoringUtil.RefactoringErrorHintException {
@@ -166,10 +188,21 @@ public class PsiElementRenameHandler implements RenameHandler {
Editor editor,
String defaultName,
RenamePsiElementProcessorBase processor) {
rename(element, project, nameSuggestionContext, List.of(), editor, defaultName, processor);
}
private static void rename(@NotNull PsiElement element,
@NotNull Project project,
PsiElement nameSuggestionContext,
@NotNull Collection<String> suggestedNames,
Editor editor,
String defaultName,
RenamePsiElementProcessorBase processor) {
PsiElement substituted = processor.substituteElementToRename(element, editor);
if (substituted == null || !canRename(project, editor, substituted)) return;
RenameRefactoringDialog dialog = processor.createDialog(project, substituted, nameSuggestionContext, editor);
dialog.addSuggestedNames(suggestedNames);
if (defaultName == null && ApplicationManager.getApplication().isUnitTestMode()) {
String[] strings = dialog.getSuggestedNames();

View File

@@ -3,8 +3,21 @@ package com.intellij.refactoring.rename;
import org.jetbrains.annotations.NotNull;
import java.util.Collection;
public interface RenameRefactoringDialog {
String[] getSuggestedNames();
/**
* Add an explicit set of suggested names in addition to submitted by providers.
* Implementations may ignore this method or suggest them to the user.
*
* @param names names to add
*/
default void addSuggestedNames(@NotNull Collection<@NotNull String> names) {
}
void performRename(@NotNull String newName);
void show();

View File

@@ -1,6 +1,6 @@
class MyList extends ArrayList {
def foo() {
for (x<caret> in this) {
for (<caret>x in this) {
print x;
}
}

View File

@@ -1,4 +1,4 @@
def list = [1, 2, 3]
for (it<caret> in list) {
for (<caret>it in list) {
print it;
}

View File

@@ -1,5 +1,5 @@
def list=[1, 2, 3]
for (final int x<caret> in list) {
for (final int <caret>x in list) {
print x;
{
soSomething();

View File

@@ -1,4 +1,4 @@
def list = [1, 2, 3]
for (x<caret> in list) {
for (<caret>x in list) {
print x;
}

View File

@@ -1,4 +1,4 @@
for (it<caret> in []) {
for (<caret>it in []) {
if (it == 2) {
println 2
}

View File

@@ -2,7 +2,7 @@
// AFTER-WARNING: The expression is unused
// AFTER-WARNING: The expression is unused
fun foo(i : Int) {
val b<caret> = 0 == i
val <caret>b = 0 == i
if (b) 1
else if (b) 2
}

View File

@@ -5,7 +5,7 @@ object G {
}
fun test(x: Int, y: Int): String {
val n<caret> = G.cat(x, y)
val <caret>n = G.cat(x, y)
if (n == 1) return "one"
else if (n == 2) return "two"
else return "big"