mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-04-19 13:02:30 +07:00
[java-intentions] InitializeFinalFieldInConstructorFix: ModCommand
GitOrigin-RevId: 2fafef8e7f7c086bfbadc0d7e1470359f5c677e9
This commit is contained in:
committed by
intellij-monorepo-bot
parent
9f044ceb21
commit
e8adfcce9b
@@ -291,7 +291,7 @@ convert.to.string.family=Fix character literal
|
||||
convert.to.string.text=Convert to string literal
|
||||
|
||||
initialize.final.field.in.constructor.name=Initialize in constructor
|
||||
initialize.final.field.in.constructor.choose.dialog.title=Choose Constructors to Add Initialization to
|
||||
initialize.final.field.in.constructor.choose.dialog.title=Choose Constructors to Add Initialization To
|
||||
|
||||
remove.redundant.arguments.text=Remove redundant arguments to call ''{0}''
|
||||
remove.redundant.arguments.family=Remove redundant arguments
|
||||
|
||||
@@ -3,32 +3,26 @@ package com.intellij.codeInsight.daemon.impl.quickfix;
|
||||
|
||||
import com.intellij.codeInsight.daemon.QuickFixBundle;
|
||||
import com.intellij.codeInsight.generation.PsiMethodMember;
|
||||
import com.intellij.codeInsight.intention.impl.BaseIntentionAction;
|
||||
import com.intellij.codeInsight.intention.preview.IntentionPreviewInfo;
|
||||
import com.intellij.codeInsight.lookup.LookupElement;
|
||||
import com.intellij.codeInsight.template.PsiElementResult;
|
||||
import com.intellij.codeInsight.template.TemplateBuilderFactory;
|
||||
import com.intellij.codeInsight.template.TemplateBuilderImpl;
|
||||
import com.intellij.codeInsight.template.impl.ConstantNode;
|
||||
import com.intellij.codeInspection.LocalQuickFixAndIntentionActionOnPsiElement;
|
||||
import com.intellij.ide.util.MemberChooser;
|
||||
import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.codeInspection.ModCommands;
|
||||
import com.intellij.modcommand.*;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.editor.Document;
|
||||
import com.intellij.openapi.editor.Editor;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.util.Computable;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.codeStyle.CodeStyleManager;
|
||||
import com.intellij.psi.util.PsiTreeUtil;
|
||||
import com.intellij.util.ObjectUtils;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
public class InitializeFinalFieldInConstructorFix extends LocalQuickFixAndIntentionActionOnPsiElement {
|
||||
public class InitializeFinalFieldInConstructorFix extends PsiBasedModCommandAction<PsiField> {
|
||||
private static final Logger LOG = Logger.getInstance(InitializeFinalFieldInConstructorFix.class);
|
||||
|
||||
public InitializeFinalFieldInConstructorFix(@NotNull PsiField field) {
|
||||
@@ -37,81 +31,59 @@ public class InitializeFinalFieldInConstructorFix extends LocalQuickFixAndIntent
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public String getText() {
|
||||
public String getFamilyName() {
|
||||
return QuickFixBundle.message("initialize.final.field.in.constructor.name");
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public String getFamilyName() {
|
||||
return getText();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAvailable(@NotNull Project project,
|
||||
@NotNull PsiFile file,
|
||||
@Nullable Editor editor,
|
||||
@NotNull PsiElement startElement,
|
||||
@NotNull PsiElement endElement) {
|
||||
PsiField field = ObjectUtils.tryCast(startElement, PsiField.class);
|
||||
if (field == null) return false;
|
||||
if (!field.isValid() || field.hasModifierProperty(PsiModifier.STATIC) || field.hasInitializer()) {
|
||||
return false;
|
||||
}
|
||||
protected @Nullable Presentation getPresentation(@NotNull ActionContext context, @NotNull PsiField field) {
|
||||
if (field.hasModifierProperty(PsiModifier.STATIC) || field.hasInitializer()) return null;
|
||||
|
||||
final PsiClass containingClass = field.getContainingClass();
|
||||
if (containingClass == null || containingClass.getName() == null){
|
||||
return false;
|
||||
}
|
||||
if (containingClass == null || containingClass.getName() == null) return null;
|
||||
|
||||
final PsiManager manager = field.getManager();
|
||||
return manager != null && BaseIntentionAction.canModify(field);
|
||||
return Presentation.of(getFamilyName());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void invoke(@NotNull Project project,
|
||||
@NotNull PsiFile file,
|
||||
@Nullable Editor editor,
|
||||
@NotNull PsiElement startElement,
|
||||
@NotNull PsiElement endElement) {
|
||||
PsiField field = ObjectUtils.tryCast(startElement, PsiField.class);
|
||||
if (field == null) return;
|
||||
protected @NotNull ModCommand perform(@NotNull ActionContext context, @NotNull PsiField field) {
|
||||
final PsiClass myClass = field.getContainingClass();
|
||||
if (myClass == null) return;
|
||||
if (myClass == null) return ModCommands.nop();
|
||||
if (myClass.getConstructors().length == 0) {
|
||||
ApplicationManager.getApplication().runWriteAction(
|
||||
(Computable<PsiMethod>)() -> AddDefaultConstructorFix.addDefaultConstructor(myClass));
|
||||
return ModCommands.psiUpdate(context, updater -> {
|
||||
PsiClass writableClass = updater.getWritable(myClass);
|
||||
PsiField writableField = updater.getWritable(field);
|
||||
PsiMethod ctor = AddDefaultConstructorFix.addDefaultConstructor(writableClass);
|
||||
addFieldInitialization(List.of(ctor), writableField, updater);
|
||||
});
|
||||
}
|
||||
|
||||
PsiMethod[] ctors = CreateConstructorParameterFromFieldFix.filterConstructorsIfFieldAlreadyAssigned(myClass.getConstructors(), field)
|
||||
.toArray(PsiMethod.EMPTY_ARRAY);
|
||||
final List<PsiMethod> constructors = choose(ctors, project);
|
||||
List<PsiMethod> ctors =
|
||||
CreateConstructorParameterFromFieldFix.filterConstructorsIfFieldAlreadyAssigned(myClass.getConstructors(), field);
|
||||
|
||||
ApplicationManager.getApplication().runWriteAction(() -> addFieldInitialization(constructors, field, project, editor));
|
||||
List<PsiMethodMember> allMembers = ContainerUtil.map(ctors, PsiMethodMember::new);
|
||||
if (ctors.size() == 1) {
|
||||
return getFinalCommand(field, allMembers);
|
||||
}
|
||||
|
||||
return new ModChooseMember(QuickFixBundle.message("initialize.final.field.in.constructor.choose.dialog.title"),
|
||||
allMembers, allMembers, ModChooseMember.SelectionMode.MULTIPLE,
|
||||
chosenMembers -> getFinalCommand(field, chosenMembers));
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull IntentionPreviewInfo generatePreview(@NotNull Project project, @NotNull Editor editor, @NotNull PsiFile file) {
|
||||
PsiField field = PsiTreeUtil.findSameElementInCopy(ObjectUtils.tryCast(getStartElement(), PsiField.class), file);
|
||||
if (field == null) return IntentionPreviewInfo.EMPTY;
|
||||
final PsiClass myClass = field.getContainingClass();
|
||||
if (myClass == null) return IntentionPreviewInfo.EMPTY;
|
||||
if (myClass.getConstructors().length == 0) {
|
||||
AddDefaultConstructorFix.addDefaultConstructor(myClass);
|
||||
}
|
||||
|
||||
PsiMethod[] ctors = CreateConstructorParameterFromFieldFix.filterConstructorsIfFieldAlreadyAssigned(myClass.getConstructors(), field)
|
||||
.toArray(PsiMethod.EMPTY_ARRAY);
|
||||
final List<PsiMethod> constructors = Arrays.asList(ctors);
|
||||
|
||||
addFieldInitialization(constructors, field, project, editor);
|
||||
return IntentionPreviewInfo.DIFF;
|
||||
@NotNull
|
||||
private static ModCommand getFinalCommand(@NotNull PsiField field, List<? extends @NotNull MemberChooserElement> chosenMembers) {
|
||||
return ModCommands.psiUpdate(field, (writableField, updater) -> {
|
||||
List<PsiMethod> writableConstructors =
|
||||
ContainerUtil.map(chosenMembers, member -> updater.getWritable(((PsiMethodMember)member).getElement()));
|
||||
addFieldInitialization(writableConstructors, writableField, updater);
|
||||
});
|
||||
}
|
||||
|
||||
private static void addFieldInitialization(@NotNull List<? extends PsiMethod> constructors,
|
||||
@NotNull PsiField field,
|
||||
@NotNull Project project,
|
||||
@Nullable Editor editor) {
|
||||
@NotNull ModPsiUpdater updater) {
|
||||
Project project = field.getProject();
|
||||
if (constructors.isEmpty()) return;
|
||||
|
||||
final LookupElement[] suggestedInitializers = AddVariableInitializerFix.suggestInitializer(field);
|
||||
@@ -124,22 +96,21 @@ public class InitializeFinalFieldInConstructorFix extends LocalQuickFixAndIntent
|
||||
Document doc = Objects.requireNonNull(field.getContainingFile().getViewProvider().getDocument());
|
||||
PsiDocumentManager.getInstance(project).doPostponedOperationsAndUnblockDocument(doc);
|
||||
List<PsiExpression> rExpressions = ContainerUtil.mapNotNull(rExprPointers, SmartPsiElementPointer::getElement);
|
||||
runAssignmentTemplate(rExpressions, suggestedInitializers, editor);
|
||||
runAssignmentTemplate(rExpressions, suggestedInitializers, updater);
|
||||
}
|
||||
|
||||
|
||||
private static void runAssignmentTemplate(@NotNull final List<? extends PsiExpression> initializers,
|
||||
final LookupElement @NotNull [] suggestedInitializers,
|
||||
@Nullable Editor editor) {
|
||||
if (editor == null) return;
|
||||
final LookupElement @NotNull [] suggestedInitializers,
|
||||
@NotNull ModPsiUpdater updater) {
|
||||
LOG.assertTrue(!initializers.isEmpty());
|
||||
final PsiExpression initializer = Objects.requireNonNull(ContainerUtil.getFirstItem(initializers));
|
||||
PsiElement context = initializers.size() == 1 ? initializer : PsiTreeUtil.findCommonParent(initializers);
|
||||
if (context == null) return;
|
||||
final TemplateBuilderImpl builder = (TemplateBuilderImpl)TemplateBuilderFactory.getInstance().createTemplateBuilder(context);
|
||||
ModTemplateBuilder builder = updater.templateBuilder();
|
||||
for (PsiExpression e : initializers) {
|
||||
builder.replaceElement(e, new ConstantNode(new PsiElementResult(suggestedInitializers[0].getPsiElement())).withLookupItems(suggestedInitializers));
|
||||
builder.field(e, new ConstantNode(new PsiElementResult(suggestedInitializers[0].getPsiElement())).withLookupItems(
|
||||
suggestedInitializers));
|
||||
}
|
||||
builder.run(editor, false);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@@ -156,7 +127,7 @@ public class InitializeFinalFieldInConstructorFix extends LocalQuickFixAndIntent
|
||||
}
|
||||
|
||||
final String fieldName = field.getName();
|
||||
String stmtText = fieldName + " = " + suggestedInitializers[0].getPsiElement().getText() + ";";
|
||||
String stmtText = fieldName + " = " + Objects.requireNonNull(suggestedInitializers[0].getPsiElement()).getText() + ";";
|
||||
if (methodContainsParameterWithName(constructor, fieldName)) {
|
||||
stmtText = "this." + stmtText;
|
||||
}
|
||||
@@ -171,63 +142,6 @@ public class InitializeFinalFieldInConstructorFix extends LocalQuickFixAndIntent
|
||||
}
|
||||
|
||||
private static boolean methodContainsParameterWithName(@NotNull PsiMethod constructor, @NotNull String name) {
|
||||
for (PsiParameter parameter : constructor.getParameterList().getParameters()) {
|
||||
if (name.equals(parameter.getName())) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private static List<PsiMethod> choose(PsiMethod @NotNull [] ctors, @NotNull final Project project) {
|
||||
if (ApplicationManager.getApplication().isUnitTestMode()) {
|
||||
return Arrays.asList(ctors);
|
||||
}
|
||||
|
||||
if (ctors.length == 1) {
|
||||
return Collections.singletonList(ctors[0]);
|
||||
}
|
||||
|
||||
if (ctors.length > 1) {
|
||||
final MemberChooser<PsiMethodMember> chooser = new MemberChooser<>(toPsiMethodMemberArray(ctors), false, true, project);
|
||||
chooser.setTitle(QuickFixBundle.message("initialize.final.field.in.constructor.choose.dialog.title"));
|
||||
chooser.show();
|
||||
|
||||
final List<PsiMethodMember> chosenMembers = chooser.getSelectedElements();
|
||||
if (chosenMembers != null) {
|
||||
return Arrays.asList(toPsiMethodArray(chosenMembers));
|
||||
}
|
||||
}
|
||||
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
private static PsiMethodMember @NotNull [] toPsiMethodMemberArray(PsiMethod @NotNull [] methods) {
|
||||
final PsiMethodMember[] result = new PsiMethodMember[methods.length];
|
||||
for (int i = 0; i < methods.length; i++) {
|
||||
result[i] = new PsiMethodMember(methods[i]);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private static PsiMethod @NotNull [] toPsiMethodArray(@NotNull List<? extends PsiMethodMember> methodMembers) {
|
||||
final PsiMethod[] result = new PsiMethod[methodMembers.size()];
|
||||
int i = 0;
|
||||
for (PsiMethodMember methodMember : methodMembers) {
|
||||
result[i++] = methodMember.getElement();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public PsiElement getElementToMakeWritable(@NotNull PsiFile currentFile) {
|
||||
return currentFile;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean startInWriteAction() {
|
||||
return false;
|
||||
return ContainerUtil.exists(constructor.getParameterList().getParameters(), parameter -> name.equals(parameter.getName()));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -606,7 +606,7 @@ public final class QuickFixFactoryImpl extends QuickFixFactory {
|
||||
@NotNull
|
||||
@Override
|
||||
public IntentionAction createInitializeFinalFieldInConstructorFix(@NotNull PsiField field) {
|
||||
return new InitializeFinalFieldInConstructorFix(field);
|
||||
return new InitializeFinalFieldInConstructorFix(field).asIntention();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
|
||||
@@ -82,7 +82,7 @@ public class NotNullFieldNotInitializedInspection extends AbstractBaseJavaLocalI
|
||||
fixes.add(QuickFixFactory.getInstance().createDeleteFix(annotation, JavaBundle.message("quickfix.text.remove.not.null.annotation")));
|
||||
}
|
||||
if (isOnTheFly) {
|
||||
fixes.add(new InitializeFinalFieldInConstructorFix(field));
|
||||
fixes.add(new InitializeFinalFieldInConstructorFix(field).asQuickFix());
|
||||
fixes.add(new AddVariableInitializerFix(field).asQuickFix());
|
||||
}
|
||||
|
||||
|
||||
@@ -7,6 +7,6 @@ class Main {
|
||||
}
|
||||
|
||||
private Main(int var) {
|
||||
this.var = 0;
|
||||
this.var = 0<caret>;
|
||||
}
|
||||
}<caret>
|
||||
}
|
||||
Reference in New Issue
Block a user