mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
[java-intention] New ModCommands
ChangeExtendsToImplementsFix, ClassMayBeInterfaceInspection, MethodRefCanBeReplacedWithLambdaInspection GitOrigin-RevId: 1ef6864503e633a37c1f1dda1f5604cc9ae978de
This commit is contained in:
committed by
intellij-monorepo-bot
parent
2c12f7c579
commit
1a157d9e68
+55
-18
@@ -17,33 +17,70 @@
|
||||
package com.intellij.codeInsight.daemon.impl.quickfix;
|
||||
|
||||
import com.intellij.codeInsight.daemon.QuickFixBundle;
|
||||
import com.intellij.codeInsight.intention.HighPriorityAction;
|
||||
import com.intellij.codeInspection.util.IntentionName;
|
||||
import com.intellij.psi.PsiClass;
|
||||
import com.intellij.psi.PsiClassType;
|
||||
import com.intellij.psi.PsiKeyword;
|
||||
import com.intellij.codeInsight.intention.PriorityAction;
|
||||
import com.intellij.modcommand.ModPsiUpdater;
|
||||
import com.intellij.modcommand.PsiUpdateModCommandAction;
|
||||
import com.intellij.psi.*;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
/**
|
||||
* changes 'class a extends b' to 'class a implements b' or vice versa
|
||||
*/
|
||||
public class ChangeExtendsToImplementsFix extends ExtendsListFix implements HighPriorityAction {
|
||||
private final @IntentionName String myName;
|
||||
public class ChangeExtendsToImplementsFix extends PsiUpdateModCommandAction<PsiClass> {
|
||||
@Nullable
|
||||
protected final SmartPsiElementPointer<PsiClass> myClassToExtendFromPointer;
|
||||
private final boolean myToAdd;
|
||||
private final PsiClassType myTypeToExtendFrom;
|
||||
|
||||
public ChangeExtendsToImplementsFix(@NotNull PsiClass aClass, @NotNull PsiClassType classToExtendFrom) {
|
||||
super(aClass, classToExtendFrom, true);
|
||||
PsiClass classToExtendFromPointer = myClassToExtendFromPointer != null ? myClassToExtendFromPointer.getElement() : null;
|
||||
|
||||
myName = classToExtendFromPointer == null ? getFamilyName() :
|
||||
QuickFixBundle.message("exchange.extends.implements.keyword",
|
||||
aClass.isInterface() == classToExtendFromPointer.isInterface() ? PsiKeyword.IMPLEMENTS : PsiKeyword.EXTENDS,
|
||||
aClass.isInterface() == classToExtendFromPointer.isInterface() ? PsiKeyword.EXTENDS : PsiKeyword.IMPLEMENTS,
|
||||
classToExtendFromPointer.getName());
|
||||
public ChangeExtendsToImplementsFix(@NotNull PsiClass aClass, @NotNull PsiClassType classTypeToExtendFrom) {
|
||||
super(aClass);
|
||||
PsiClass classToExtendFrom = classTypeToExtendFrom.resolve();
|
||||
myClassToExtendFromPointer = classToExtendFrom == null ? null : SmartPointerManager.createPointer(classToExtendFrom);
|
||||
myToAdd = true;
|
||||
myTypeToExtendFrom = aClass instanceof PsiTypeParameter ? classTypeToExtendFrom
|
||||
: (PsiClassType)GenericsUtil.eliminateWildcards(classTypeToExtendFrom);
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public String getText() {
|
||||
return myName;
|
||||
public String getFamilyName() {
|
||||
return QuickFixBundle.message("change.extends.list.family");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected @Nullable Presentation getPresentation(@NotNull ActionContext context, @NotNull PsiClass myClass) {
|
||||
if (!myTypeToExtendFrom.isValid()) return null;
|
||||
PsiClass classToExtendFrom = myClassToExtendFromPointer != null ? myClassToExtendFromPointer.getElement() : null;
|
||||
boolean available = classToExtendFrom != null && classToExtendFrom.isValid()
|
||||
&& !classToExtendFrom.hasModifierProperty(PsiModifier.FINAL)
|
||||
&& (classToExtendFrom.isInterface() ||
|
||||
!myClass.isInterface() && myClass.getExtendsList() != null
|
||||
&& (myClass.getExtendsList().getReferencedTypes().length == 0) == myToAdd);
|
||||
if (!available) return null;
|
||||
String name = QuickFixBundle.message(
|
||||
"exchange.extends.implements.keyword",
|
||||
myClass.isInterface() == classToExtendFrom.isInterface() ? PsiKeyword.IMPLEMENTS : PsiKeyword.EXTENDS,
|
||||
myClass.isInterface() == classToExtendFrom.isInterface() ? PsiKeyword.EXTENDS : PsiKeyword.IMPLEMENTS,
|
||||
classToExtendFrom.getName());
|
||||
return Presentation.of(name).withPriority(PriorityAction.Priority.HIGH);
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void invoke(@NotNull ActionContext context, @NotNull PsiClass myClass, @NotNull ModPsiUpdater updater) {
|
||||
PsiClass classToExtendFrom = myClassToExtendFromPointer != null ? myClassToExtendFromPointer.getElement() : null;
|
||||
|
||||
PsiReferenceList extendsList = !(myClass instanceof PsiTypeParameter) && classToExtendFrom != null &&
|
||||
myClass.isInterface() != classToExtendFrom.isInterface() ?
|
||||
myClass.getImplementsList() : myClass.getExtendsList();
|
||||
PsiReferenceList otherList = extendsList == myClass.getImplementsList() ?
|
||||
myClass.getExtendsList() : myClass.getImplementsList();
|
||||
if (extendsList != null) {
|
||||
ExtendsListFix.modifyList(extendsList, myToAdd, -1, myTypeToExtendFrom);
|
||||
}
|
||||
if (otherList != null) {
|
||||
ExtendsListFix.modifyList(otherList, false, -1, myTypeToExtendFrom);
|
||||
}
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -439,7 +439,7 @@ public final class QuickFixFactoryImpl extends QuickFixFactory {
|
||||
@NotNull
|
||||
@Override
|
||||
public IntentionAction createChangeExtendsToImplementsFix(@NotNull PsiClass aClass, @NotNull PsiClassType classToExtendFrom) {
|
||||
return new ChangeExtendsToImplementsFix(aClass, classToExtendFrom);
|
||||
return new ChangeExtendsToImplementsFix(aClass, classToExtendFrom).asIntention();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
|
||||
+1
-1
@@ -1,7 +1,7 @@
|
||||
// "Change 'extends Runnable' to 'implements Runnable'" "true-preview"
|
||||
import java.io.*;
|
||||
|
||||
class a <caret>implements Runnable {
|
||||
class a implements <caret>Runnable {
|
||||
public void run() {
|
||||
}
|
||||
}
|
||||
|
||||
+13
-35
@@ -15,12 +15,13 @@
|
||||
*/
|
||||
package com.siyeh.ig.classlayout;
|
||||
|
||||
import com.intellij.codeInsight.FileModificationService;
|
||||
import com.intellij.codeInsight.daemon.impl.analysis.HighlightingFeature;
|
||||
import com.intellij.codeInsight.intention.preview.IntentionPreviewInfo;
|
||||
import com.intellij.codeInspection.LocalQuickFix;
|
||||
import com.intellij.codeInspection.ProblemDescriptor;
|
||||
import com.intellij.codeInspection.options.OptPane;
|
||||
import com.intellij.openapi.application.WriteAction;
|
||||
import com.intellij.modcommand.ModCommand;
|
||||
import com.intellij.modcommand.ModCommandQuickFix;
|
||||
import com.intellij.modcommand.ModCommands;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.util.WriteExternalException;
|
||||
import com.intellij.psi.*;
|
||||
@@ -32,7 +33,6 @@ import com.intellij.util.containers.ContainerUtil;
|
||||
import com.siyeh.InspectionGadgetsBundle;
|
||||
import com.siyeh.ig.BaseInspection;
|
||||
import com.siyeh.ig.BaseInspectionVisitor;
|
||||
import com.siyeh.ig.InspectionGadgetsFix;
|
||||
import com.siyeh.ig.memory.InnerClassReferenceVisitor;
|
||||
import com.siyeh.ig.psiutils.ClassUtils;
|
||||
import com.siyeh.ig.psiutils.MethodUtils;
|
||||
@@ -71,11 +71,11 @@ public class ClassMayBeInterfaceInspection extends BaseInspection {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected InspectionGadgetsFix buildFix(Object... infos) {
|
||||
protected LocalQuickFix buildFix(Object... infos) {
|
||||
return new ClassMayBeInterfaceFix();
|
||||
}
|
||||
|
||||
private static class ClassMayBeInterfaceFix extends InspectionGadgetsFix {
|
||||
private static class ClassMayBeInterfaceFix extends ModCommandQuickFix {
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
@@ -84,12 +84,7 @@ public class ClassMayBeInterfaceInspection extends BaseInspection {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean startInWriteAction() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void doFix(@NotNull Project project, @NotNull ProblemDescriptor descriptor) {
|
||||
public @NotNull ModCommand perform(@NotNull Project project, @NotNull ProblemDescriptor descriptor) {
|
||||
final PsiIdentifier classNameIdentifier = (PsiIdentifier)descriptor.getPsiElement();
|
||||
final PsiClass interfaceClass = (PsiClass)classNameIdentifier.getParent();
|
||||
final SearchScope searchScope = interfaceClass.getUseScope();
|
||||
@@ -98,30 +93,13 @@ public class ClassMayBeInterfaceInspection extends BaseInspection {
|
||||
for (final PsiClass inheritor : ClassInheritorsSearch.search(interfaceClass, searchScope, false)) {
|
||||
elements.add(inheritor);
|
||||
}
|
||||
if (!FileModificationService.getInstance().preparePsiElementsForWrite(elements)) {
|
||||
return;
|
||||
}
|
||||
WriteAction.run(() -> {
|
||||
moveSubClassExtendsToImplements(elements);
|
||||
changeClassToInterface(interfaceClass);
|
||||
moveImplementsToExtends(interfaceClass);
|
||||
return ModCommands.psiUpdate(interfaceClass, (cls, updater) -> {
|
||||
moveSubClassExtendsToImplements(ContainerUtil.map(elements, updater::getWritable));
|
||||
changeClassToInterface(cls);
|
||||
moveImplementsToExtends(cls);
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull IntentionPreviewInfo generatePreview(@NotNull Project project, @NotNull ProblemDescriptor previewDescriptor) {
|
||||
final PsiIdentifier classNameIdentifier = (PsiIdentifier)previewDescriptor.getPsiElement();
|
||||
final PsiClass interfaceClass = (PsiClass)classNameIdentifier.getParent();
|
||||
// In preview, limit search to current file only
|
||||
List<PsiClass> inheritorsInThisFile = SyntaxTraverser.psiTraverser(classNameIdentifier.getContainingFile()).filter(PsiClass.class)
|
||||
.filter(cls -> cls.isInheritor(interfaceClass, false))
|
||||
.toList();
|
||||
moveSubClassExtendsToImplements(ContainerUtil.prepend(inheritorsInThisFile, interfaceClass));
|
||||
changeClassToInterface(interfaceClass);
|
||||
moveImplementsToExtends(interfaceClass);
|
||||
return IntentionPreviewInfo.DIFF;
|
||||
}
|
||||
|
||||
private static void changeClassToInterface(PsiClass aClass) {
|
||||
for (PsiMethod method : aClass.getMethods()) {
|
||||
if (isEmptyConstructor(method)) {
|
||||
@@ -258,7 +236,7 @@ public class ClassMayBeInterfaceInspection extends BaseInspection {
|
||||
return allMethodsPublicAbstract(aClass) && allFieldsPublicStaticFinal(aClass) && allInnerClassesPublic(aClass);
|
||||
}
|
||||
|
||||
private boolean allFieldsPublicStaticFinal(PsiClass aClass) {
|
||||
private static boolean allFieldsPublicStaticFinal(PsiClass aClass) {
|
||||
boolean allFieldsStaticFinal = true;
|
||||
final PsiField[] fields = aClass.getFields();
|
||||
for (final PsiField field : fields) {
|
||||
@@ -292,7 +270,7 @@ public class ClassMayBeInterfaceInspection extends BaseInspection {
|
||||
return true;
|
||||
}
|
||||
|
||||
private boolean allInnerClassesPublic(PsiClass aClass) {
|
||||
private static boolean allInnerClassesPublic(PsiClass aClass) {
|
||||
final PsiClass[] innerClasses = aClass.getInnerClasses();
|
||||
for (PsiClass innerClass : innerClasses) {
|
||||
if (!innerClass.hasModifierProperty(PsiModifier.PUBLIC)) {
|
||||
|
||||
+29
-28
@@ -3,8 +3,11 @@ package com.siyeh.ig.style;
|
||||
|
||||
import com.intellij.codeInsight.FileModificationService;
|
||||
import com.intellij.codeInsight.intention.preview.IntentionPreviewInfo;
|
||||
import com.intellij.codeInspection.LocalQuickFix;
|
||||
import com.intellij.codeInspection.ProblemDescriptor;
|
||||
import com.intellij.ide.DataManager;
|
||||
import com.intellij.modcommand.ModPsiUpdater;
|
||||
import com.intellij.modcommand.PsiUpdateModCommandQuickFix;
|
||||
import com.intellij.openapi.actionSystem.CommonDataKeys;
|
||||
import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.openapi.application.WriteAction;
|
||||
@@ -39,7 +42,7 @@ public class MethodRefCanBeReplacedWithLambdaInspection extends BaseInspection {
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
protected InspectionGadgetsFix buildFix(Object... infos) {
|
||||
protected LocalQuickFix buildFix(Object... infos) {
|
||||
final PsiMethodReferenceExpression methodReferenceExpression = (PsiMethodReferenceExpression)infos[0];
|
||||
final boolean onTheFly = (Boolean)infos[1];
|
||||
if (LambdaRefactoringUtil.canConvertToLambdaWithoutSideEffects(methodReferenceExpression)) {
|
||||
@@ -61,7 +64,7 @@ public class MethodRefCanBeReplacedWithLambdaInspection extends BaseInspection {
|
||||
}
|
||||
}
|
||||
|
||||
private static class MethodRefToLambdaFix extends InspectionGadgetsFix {
|
||||
private static class MethodRefToLambdaFix extends PsiUpdateModCommandQuickFix {
|
||||
@Nls
|
||||
@NotNull
|
||||
@Override
|
||||
@@ -70,26 +73,22 @@ public class MethodRefCanBeReplacedWithLambdaInspection extends BaseInspection {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doFix(@NotNull Project project, @NotNull ProblemDescriptor descriptor) {
|
||||
final PsiElement element = descriptor.getPsiElement();
|
||||
if (element instanceof PsiMethodReferenceExpression) {
|
||||
doFix(project, (PsiMethodReferenceExpression)element);
|
||||
protected void applyFix(@NotNull Project project, @NotNull PsiElement element, @NotNull ModPsiUpdater updater) {
|
||||
if (element instanceof PsiMethodReferenceExpression methodRef) {
|
||||
LambdaRefactoringUtil.convertMethodReferenceToLambda(methodRef, false, true);
|
||||
}
|
||||
}
|
||||
|
||||
protected void doFix(Project project, @NotNull PsiMethodReferenceExpression methodReferenceExpression) {
|
||||
LambdaRefactoringUtil.convertMethodReferenceToLambda(methodReferenceExpression, false, true);
|
||||
}
|
||||
}
|
||||
|
||||
private static class SideEffectsMethodRefToLambdaFix extends MethodRefToLambdaFix {
|
||||
private static class SideEffectsMethodRefToLambdaFix extends InspectionGadgetsFix {
|
||||
@Nls
|
||||
@NotNull
|
||||
@Override
|
||||
public String getFamilyName() {
|
||||
return ApplicationManager.getApplication().isUnitTestMode() ? (InspectionGadgetsBundle
|
||||
.message("side.effects.method.ref.to.lambda.fix.family.name",
|
||||
super.getFamilyName())) : super.getFamilyName();
|
||||
return ApplicationManager.getApplication().isUnitTestMode() ?
|
||||
(InspectionGadgetsBundle.message("side.effects.method.ref.to.lambda.fix.family.name",
|
||||
InspectionGadgetsBundle.message("method.ref.can.be.replaced.with.lambda.quickfix"))) :
|
||||
InspectionGadgetsBundle.message("method.ref.can.be.replaced.with.lambda.quickfix");
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -97,20 +96,6 @@ public class MethodRefCanBeReplacedWithLambdaInspection extends BaseInspection {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doFix(Project project, @NotNull PsiMethodReferenceExpression methodReferenceExpression) {
|
||||
DataManager.getInstance()
|
||||
.getDataContextFromFocusAsync()
|
||||
.onSuccess(context -> {
|
||||
final Editor editor = CommonDataKeys.EDITOR.getData(context);
|
||||
if (editor != null) {
|
||||
CommandProcessor.getInstance()
|
||||
.executeCommand(project, () -> doFixAndRemoveSideEffects(editor, methodReferenceExpression),
|
||||
getFamilyName(), null);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull IntentionPreviewInfo generatePreview(@NotNull Project project, @NotNull ProblemDescriptor previewDescriptor) {
|
||||
PsiMethodReferenceExpression methodRef = ObjectUtils.tryCast(previewDescriptor.getPsiElement(), PsiMethodReferenceExpression.class);
|
||||
@@ -121,6 +106,22 @@ public class MethodRefCanBeReplacedWithLambdaInspection extends BaseInspection {
|
||||
return IntentionPreviewInfo.DIFF;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doFix(@NotNull Project project, @NotNull ProblemDescriptor descriptor) {
|
||||
final PsiElement element = descriptor.getPsiElement();
|
||||
if (element instanceof PsiMethodReferenceExpression methodRef) {
|
||||
DataManager.getInstance()
|
||||
.getDataContextFromFocusAsync()
|
||||
.onSuccess(context -> {
|
||||
final Editor editor = CommonDataKeys.EDITOR.getData(context);
|
||||
if (editor != null) {
|
||||
CommandProcessor.getInstance()
|
||||
.executeCommand(project, () -> doFixAndRemoveSideEffects(editor, methodRef), getFamilyName(), null);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private static void doFixAndRemoveSideEffects(@NotNull Editor editor, @NotNull PsiMethodReferenceExpression methodReferenceExpression) {
|
||||
if (!FileModificationService.getInstance().preparePsiElementsForWrite(methodReferenceExpression)) return;
|
||||
final PsiLambdaExpression lambdaExpression =
|
||||
|
||||
Reference in New Issue
Block a user