[java-inspections] CreateTypeParameterFromUsageFix: mod-command

Part of IDEA-322693 Migrate as much as possible Java intentions and quick-fixes to ModCommand API

GitOrigin-RevId: 898bf526ac0700c29641e09ffccd10bf2a7ab3f1
This commit is contained in:
Tagir Valeev
2023-10-24 17:00:37 +00:00
committed by intellij-monorepo-bot
parent f94d4a27d9
commit b59721ab73
19 changed files with 73 additions and 88 deletions
@@ -120,7 +120,7 @@ create.method.body=Create Method Body
create.method.from.usage.text=Create method ''{0}''
create.type.parameter.from.usage.family=Create type parameter from usage
create.type.parameter.from.usage.text=Create type parameter ''{0}''
create.type.parameter.from.usage.chooser.title=Place to add type parameter
create.type.parameter.from.usage.chooser.title=Place to Add Type Parameter
create.parameter.from.usage.family=Create parameter from Usage
create.property.from.usage.family=Create property From Usage
create.property.from.usage.text=Create property ''{0}''
@@ -1,40 +1,27 @@
// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package com.intellij.codeInsight.daemon.impl.quickfix;
import com.intellij.codeInsight.FileModificationService;
import com.intellij.codeInsight.daemon.QuickFixBundle;
import com.intellij.codeInsight.intention.impl.BaseIntentionAction;
import com.intellij.ide.highlighter.JavaFileType;
import com.intellij.openapi.application.Application;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.command.WriteCommandAction;
import com.intellij.openapi.editor.Editor;
import com.intellij.modcommand.*;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Pass;
import com.intellij.psi.*;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.psi.util.PsiUtil;
import com.intellij.refactoring.IntroduceTargetChooser;
import com.intellij.util.IncorrectOperationException;
import com.intellij.util.SmartList;
import com.intellij.util.containers.ContainerUtil;
import org.jetbrains.annotations.Nls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.List;
import java.util.Objects;
import static com.intellij.util.ObjectUtils.tryCast;
public class CreateTypeParameterFromUsageFix extends BaseIntentionAction {
private final SmartPsiElementPointer<PsiJavaCodeReferenceElement> myRef;
public class CreateTypeParameterFromUsageFix extends PsiBasedModCommandAction<PsiJavaCodeReferenceElement> {
public CreateTypeParameterFromUsageFix(PsiJavaCodeReferenceElement refElement) {
myRef = SmartPointerManager.getInstance(refElement.getProject()).createSmartPsiElementPointer(refElement);
}
@Nullable
private PsiJavaCodeReferenceElement getElement() {
return myRef.getElement();
super(refElement);
}
@Nls(capitalization = Nls.Capitalization.Sentence)
@@ -45,77 +32,47 @@ public class CreateTypeParameterFromUsageFix extends BaseIntentionAction {
}
@Override
public boolean isAvailable(@NotNull Project project, Editor editor, PsiFile file) {
PsiJavaCodeReferenceElement element = getElement();
if (element == null) return false;
protected @Nullable Presentation getPresentation(@NotNull ActionContext actionContext, @NotNull PsiJavaCodeReferenceElement element) {
Context context = Context.from(element, true);
boolean available = context != null;
if (available) {
setText(QuickFixBundle.message("create.type.parameter.from.usage.text", context.typeName));
}
return available;
if (context == null) return null;
return Presentation.of(QuickFixBundle.message("create.type.parameter.from.usage.text", context.typeName));
}
@Override
public void invoke(@NotNull Project project, Editor editor, PsiFile file) throws IncorrectOperationException {
PsiJavaCodeReferenceElement element = getElement();
if (element == null) return;
protected @NotNull ModCommand perform(@NotNull ActionContext actionContext, @NotNull PsiJavaCodeReferenceElement element) {
Context context = Context.from(element, false);
if (context == null) return;
if (context == null) return ModCommand.nop();
List<PsiNameIdentifierOwner> placesToAdd = context.placesToAdd;
Application application = ApplicationManager.getApplication();
if (placesToAdd.size() == 1 || application.isUnitTestMode() || editor == null) {
PsiElement first = placesToAdd.get(0);
createTypeParameter(first, context.typeName);
}
else {
IntroduceTargetChooser.showChooser(
editor,
placesToAdd,
new Pass<>() {
@Override
public void pass(PsiNameIdentifierOwner owner) {
createTypeParameter(owner, context.typeName);
}
},
PsiNamedElement::getName,
QuickFixBundle.message("create.type.parameter.from.usage.chooser.title")
);
}
}
@Override
public boolean startInWriteAction() {
return false;
return new ModChooseAction(QuickFixBundle.message("create.type.parameter.from.usage.chooser.title"),
ContainerUtil.map(placesToAdd, place ->
ModCommand.psiUpdateStep(place, Objects.requireNonNull(place.getName()),
(owner, updater) -> createTypeParameter(owner, context.typeName))));
}
private static void createTypeParameter(@NotNull PsiElement methodOrClass, @NotNull String name) {
Project project = methodOrClass.getProject();
if (!FileModificationService.getInstance().preparePsiElementsForWrite(methodOrClass)) return;
WriteCommandAction.runWriteCommandAction(project, QuickFixBundle.message("create.type.parameter.from.usage.family"), null, () -> {
PsiTypeParameterListOwner typeParameterListOwner = tryCast(methodOrClass, PsiTypeParameterListOwner.class);
if (typeParameterListOwner == null) {
throw new IllegalStateException("Only methods and classes allowed here, but was: " + methodOrClass.getClass());
}
PsiTypeParameterList typeParameterList = typeParameterListOwner.getTypeParameterList();
final String typeParameterListText;
if (typeParameterList == null) {
PsiTypeParameterListOwner typeParameterListOwner = tryCast(methodOrClass, PsiTypeParameterListOwner.class);
if (typeParameterListOwner == null) {
throw new IllegalStateException("Only methods and classes allowed here, but was: " + methodOrClass.getClass());
}
PsiTypeParameterList typeParameterList = typeParameterListOwner.getTypeParameterList();
final String typeParameterListText;
if (typeParameterList == null) {
typeParameterListText = "<" + name + ">";
}
else {
String existingTypeParameterText = typeParameterList.getText();
if (typeParameterList.getTypeParameters().length == 0) {
typeParameterListText = "<" + name + ">";
}
else {
String existingTypeParameterText = typeParameterList.getText();
if (typeParameterList.getTypeParameters().length == 0) {
typeParameterListText = "<" + name + ">";
}
else {
String prefix = existingTypeParameterText.substring(0, existingTypeParameterText.length() - 1);
typeParameterListText = prefix + ", " + name + ">";
}
String prefix = existingTypeParameterText.substring(0, existingTypeParameterText.length() - 1);
typeParameterListText = prefix + ", " + name + ">";
}
PsiTypeParameterList newTypeParameterList = createTypeParameterList(typeParameterListText, project);
replaceOrAddTypeParameterList(methodOrClass, typeParameterList, newTypeParameterList);
});
}
PsiTypeParameterList newTypeParameterList = createTypeParameterList(typeParameterListText, project);
replaceOrAddTypeParameterList(methodOrClass, typeParameterList, newTypeParameterList);
}
private static void replaceOrAddTypeParameterList(@NotNull PsiElement methodOrClass,
@@ -74,7 +74,7 @@ public class DefaultQuickFixProvider extends UnresolvedReferenceQuickFixProvider
SurroundWithQuotesAnnotationParameterValueFix.register(registrar, ref);
if (PsiUtil.isLanguageLevel5OrHigher(ref)) {
registrar.register(new CreateTypeParameterFromUsageFix(ref));
registrar.register(new CreateTypeParameterFromUsageFix(ref).asIntention());
}
}
@@ -1,4 +1,4 @@
// "Create type parameter 'T'" "true"
// "Create type parameter 'T'" "true-preview"
import java.util.concurrent.Callable;
public class Test<T> extends Callable<T> {
@@ -1,4 +1,4 @@
// "Create type parameter 'T'" "true"
// "Create type parameter 'T'" "true-preview"
import java.util.concurrent.Callable;
public class Test<T> extends Callable<T> {
@@ -1,4 +1,4 @@
// "Create type parameter 'T'" "true"
// "Create type parameter 'T'" "true-preview"
import java.util.concurrent.Callable;
public class Test<B, T> extends Callable<T> {
@@ -0,0 +1,7 @@
// "Create type parameter 'T'|->foo" "true-preview"
public class InMethod {
<T> void foo(T t) {
}
}
@@ -0,0 +1,7 @@
// "Create type parameter 'T'|->InMethod" "true-preview"
public class InMethod<T> {
void foo(T t) {
}
}
@@ -1,4 +1,4 @@
// "Create type parameter 'T'" "true"
// "Create type parameter 'T'" "true-preview"
public class Test {
<T> T foo() {
@@ -1,4 +1,4 @@
// "Create type parameter 'T'" "true"
// "Create type parameter 'T'" "true-preview"
record Point<T>(T x, T y) {
}
@@ -1,4 +1,4 @@
// "Create type parameter 'U'" "true"
// "Create type parameter 'U'" "true-preview"
public class Helpers {
@@ -1,4 +1,4 @@
// "Create type parameter 'T'" "true"
// "Create type parameter 'T'" "true-preview"
import java.util.concurrent.Callable;
public class Test extends Callable<T<caret>> {
@@ -1,4 +1,4 @@
// "Create type parameter 'T'" "true"
// "Create type parameter 'T'" "true-preview"
import java.util.concurrent.Callable;
public class Test<> extends Callable<T<caret>> {
@@ -1,4 +1,4 @@
// "Create type parameter 'T'" "true"
// "Create type parameter 'T'" "true-preview"
import java.util.concurrent.Callable;
public class Test<B> extends Callable<T<caret>> {
@@ -0,0 +1,7 @@
// "Create type parameter 'T'|->foo" "true-preview"
public class InMethod {
void foo(<caret>T t) {
}
}
@@ -0,0 +1,7 @@
// "Create type parameter 'T'|->InMethod" "true-preview"
public class InMethod {
void foo(<caret>T t) {
}
}
@@ -1,4 +1,4 @@
// "Create type parameter 'T'" "true"
// "Create type parameter 'T'" "true-preview"
public class Test {
T<caret> foo() {
@@ -1,4 +1,4 @@
// "Create type parameter 'T'" "true"
// "Create type parameter 'T'" "true-preview"
record Point(T<caret> x, T y) {
}
@@ -1,4 +1,4 @@
// "Create type parameter 'U'" "true"
// "Create type parameter 'U'" "true-preview"
public class Helpers {