diff --git a/java/java-analysis-impl/src/META-INF/JavaAnalysisPlugin.xml b/java/java-analysis-impl/src/META-INF/JavaAnalysisPlugin.xml index 6f6b2112d3e2..b3cf28eeb9f2 100644 --- a/java/java-analysis-impl/src/META-INF/JavaAnalysisPlugin.xml +++ b/java/java-analysis-impl/src/META-INF/JavaAnalysisPlugin.xml @@ -331,5 +331,6 @@ + diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/ex/EntryPointsManagerBase.java b/java/java-analysis-impl/src/com/intellij/codeInspection/ex/EntryPointsManagerBase.java index 33911f31c468..e87d50294611 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInspection/ex/EntryPointsManagerBase.java +++ b/java/java-analysis-impl/src/com/intellij/codeInspection/ex/EntryPointsManagerBase.java @@ -5,27 +5,29 @@ import com.intellij.codeInsight.AnnotationUtil; import com.intellij.codeInsight.MetaAnnotationUtil; import com.intellij.codeInsight.daemon.DaemonCodeAnalyzer; import com.intellij.codeInsight.daemon.QuickFixBundle; -import com.intellij.codeInsight.intention.IntentionAction; -import com.intellij.codeInsight.intention.preview.IntentionPreviewInfo; -import com.intellij.codeInspection.LocalQuickFix; -import com.intellij.codeInspection.ProblemDescriptor; +import com.intellij.codeInsight.options.JavaClassValidator; +import com.intellij.codeInspection.options.OptPane; +import com.intellij.codeInspection.options.OptionContainer; +import com.intellij.codeInspection.options.OptionController; +import com.intellij.codeInspection.options.OptionControllerProvider; import com.intellij.codeInspection.reference.*; +import com.intellij.codeInspection.util.IntentionName; import com.intellij.configurationStore.XmlSerializer; +import com.intellij.java.JavaBundle; +import com.intellij.modcommand.ActionContext; +import com.intellij.modcommand.ModCommand; +import com.intellij.modcommand.ModCommandAction; +import com.intellij.modcommand.Presentation; import com.intellij.openapi.application.ReadAction; -import com.intellij.openapi.command.undo.BasicUndoableAction; -import com.intellij.openapi.command.undo.UndoManager; import com.intellij.openapi.components.PersistentStateComponent; import com.intellij.openapi.components.State; -import com.intellij.openapi.editor.Editor; import com.intellij.openapi.extensions.ExtensionPointName; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.Comparing; import com.intellij.openapi.util.JDOMExternalizableStringList; import com.intellij.openapi.util.NlsSafe; -import com.intellij.openapi.vfs.VirtualFile; import com.intellij.profile.codeInspection.ProjectInspectionProfileManager; import com.intellij.psi.*; -import com.intellij.util.IncorrectOperationException; import com.intellij.util.containers.ContainerUtil; import com.intellij.util.xmlb.annotations.Attribute; import com.intellij.util.xmlb.annotations.Tag; @@ -40,7 +42,8 @@ import java.util.regex.Pattern; import java.util.regex.PatternSyntaxException; @State(name = "EntryPointsManager") -public abstract class EntryPointsManagerBase extends EntryPointsManager implements PersistentStateComponent { +public abstract class EntryPointsManagerBase extends EntryPointsManager implements PersistentStateComponent, + OptionContainer { @ApiStatus.Internal public static final ExtensionPointName DEAD_CODE_EP_NAME = new ExtensionPointName<>("com.intellij.deadCode"); @@ -622,21 +625,31 @@ public abstract class EntryPointsManagerBase extends EntryPointsManager implemen } } - public class AddImplicitlyWriteAnnotation implements IntentionAction, LocalQuickFix { - @NotNull - private final String myQualifiedName; + @Override + public @NotNull OptionController getOptionController() { + return OptionContainer.super.getOptionController() + .withRootPane(() -> OptPane.pane( + OptPane.stringList("myWriteAnnotations", JavaBundle.message("separator.mark.field.as.implicitly.written.if.annotated.by"), + new JavaClassValidator().annotationsOnly()), + OptPane.stringList("ADDITIONAL_ANNOTATIONS", JavaBundle.message("separator.mark.as.entry.point.if.annotated.by"), + new JavaClassValidator().annotationsOnly())) + ); + } - public AddImplicitlyWriteAnnotation(@NotNull String qualifiedName) {myQualifiedName = qualifiedName;} + private static class AddAnnotation implements ModCommandAction { + private final @NotNull String myQualifiedName; + private final @NotNull String myBindId; + private final @NotNull @IntentionName String myMessage; - @Override - @NotNull - public String getText() { - return QuickFixBundle.message("fix.add.write.annotation.text", myQualifiedName); + private AddAnnotation(@NotNull String qualifiedName, @NotNull String bindId, @NotNull @IntentionName String message) { + myQualifiedName = qualifiedName; + myBindId = bindId; + myMessage = message; } @Override - public @NotNull String getName() { - return getText(); + public @NotNull Presentation getPresentation(@NotNull ActionContext context) { + return Presentation.of(myMessage); } @Override @@ -646,59 +659,49 @@ public abstract class EntryPointsManagerBase extends EntryPointsManager implemen } @Override - public void applyFix(@NotNull Project project, @NotNull ProblemDescriptor descriptor) { - performAction(descriptor.getStartElement().getContainingFile()); - } - - @Override - public @NotNull IntentionPreviewInfo generatePreview(@NotNull Project project, @NotNull Editor editor, @NotNull PsiFile file) { - return new IntentionPreviewInfo.Html(QuickFixBundle.message("fix.add.write.annotation.description", myQualifiedName)); - } - - @Override - public @NotNull IntentionPreviewInfo generatePreview(@NotNull Project project, @NotNull ProblemDescriptor previewDescriptor) { - return new IntentionPreviewInfo.Html(QuickFixBundle.message("fix.add.write.annotation.description", myQualifiedName)); - } - - @Override - public boolean isAvailable(@NotNull Project project1, Editor editor, PsiFile file) { - return true; - } - - @Override - public void invoke(@NotNull Project project, Editor editor, PsiFile file) throws IncorrectOperationException { - performAction(file); - } - - private void performAction(@NotNull PsiFile file) { - Project project = file.getProject(); - VirtualFile vFile = file.getVirtualFile(); - doAddAnnotation(project); - UndoManager.getInstance(project).undoableActionPerformed(new BasicUndoableAction(vFile) { - @Override - public void undo() { - if (myWriteAnnotations.removeAll(List.of(myQualifiedName))) { - ProjectInspectionProfileManager.getInstance(project).fireProfileChanged(); - } - } - - @Override - public void redo() { - doAddAnnotation(project); - } + public @NotNull ModCommand perform(@NotNull ActionContext context) { + return ModCommand.updateOption(context.file(), myBindId, oldValue -> { + @SuppressWarnings("unchecked") List list = (List)oldValue; + list.add(myQualifiedName); + list.sort(null); + return list; }); } + } - private void doAddAnnotation(@NotNull Project project) { - if (!myWriteAnnotations.contains(myQualifiedName)) { - myWriteAnnotations.add(myQualifiedName); - ProjectInspectionProfileManager.getInstance(project).fireProfileChanged(); - } + /** + * @param qualifiedName annotation qualified name + * @return an action that adds the specified annotation qualified name to the list of implicitly written fields annotations + */ + public static @NotNull ModCommandAction createAddImplicitWriteAnnotation(@NotNull String qualifiedName) { + return new AddAnnotation(qualifiedName, "EntryPointsManager.myWriteAnnotations", + QuickFixBundle.message("fix.add.write.annotation.text", qualifiedName)); + } + + /** + * @param qualifiedName annotation qualified name + * @return an action that adds the specified annotation qualified name to the list of entry point annotations + */ + public static @NotNull ModCommandAction createAddEntryPointAnnotation(@NotNull String qualifiedName) { + return new AddAnnotation(qualifiedName, "EntryPointsManager.ADDITIONAL_ANNOTATIONS", + QuickFixBundle.message("fix.unused.symbol.injection.text", qualifiedName)); + } + + /** + * Provides bindId = "EntryPointsManager.myWriteAnnotations" and "EntryPointsManager.ADDITIONAL_ANNOTATIONS" + * lists to control entry points + */ + public static final class Provider implements OptionControllerProvider { + @Override + public @NotNull OptionController forContext(@NotNull PsiElement context) { + Project project = context.getProject(); + return getInstance(project).getOptionController() + .onValueSet((bindId, value) -> ProjectInspectionProfileManager.getInstance(project).fireProfileChanged()); } @Override - public boolean startInWriteAction() { - return false; + public @NotNull String name() { + return "EntryPointsManager"; } } } diff --git a/java/java-impl/src/com/intellij/codeInsight/intention/impl/config/QuickFixFactoryImpl.java b/java/java-impl/src/com/intellij/codeInsight/intention/impl/config/QuickFixFactoryImpl.java index 6e74e1b360ab..831cd0fb5989 100644 --- a/java/java-impl/src/com/intellij/codeInsight/intention/impl/config/QuickFixFactoryImpl.java +++ b/java/java-impl/src/com/intellij/codeInsight/intention/impl/config/QuickFixFactoryImpl.java @@ -21,7 +21,6 @@ import com.intellij.codeInspection.dataFlow.fix.DeleteSwitchLabelFix; import com.intellij.codeInspection.ex.EntryPointsManagerBase; import com.intellij.codeInspection.ex.InspectionToolWrapper; import com.intellij.codeInspection.util.IntentionName; -import com.intellij.codeInspection.util.SpecialAnnotationsUtil; import com.intellij.diagnostic.CoreAttachmentFactory; import com.intellij.ide.scratch.ScratchUtil; import com.intellij.java.JavaBundle; @@ -746,18 +745,13 @@ public final class QuickFixFactoryImpl extends QuickFixFactory { @Override public IntentionAction createAddToDependencyInjectionAnnotationsFix(@NotNull Project project, @NotNull String qualifiedName) { - final EntryPointsManagerBase entryPointsManager = EntryPointsManagerBase.getInstance(project); - return SpecialAnnotationsUtil.createAddToSpecialAnnotationsListIntentionAction( - QuickFixBundle.message("fix.unused.symbol.injection.text", qualifiedName), - QuickFixBundle.message("fix.unused.symbol.injection.family"), - JavaBundle.message("separator.mark.as.entry.point.if.annotated.by"), entryPointsManager.ADDITIONAL_ANNOTATIONS, qualifiedName); + return EntryPointsManagerBase.createAddEntryPointAnnotation(qualifiedName).asIntention(); } @NotNull @Override public IntentionAction createAddToImplicitlyWrittenFieldsFix(@NotNull Project project, @NotNull final String qualifiedName) { - EntryPointsManagerBase entryPointsManagerBase = EntryPointsManagerBase.getInstance(project); - return entryPointsManagerBase.new AddImplicitlyWriteAnnotation(qualifiedName); + return EntryPointsManagerBase.createAddImplicitWriteAnnotation(qualifiedName).asIntention(); } @NotNull diff --git a/java/java-impl/src/com/intellij/codeInspection/util/SpecialAnnotationsUtil.java b/java/java-impl/src/com/intellij/codeInspection/util/SpecialAnnotationsUtil.java index 9ee142e4f920..4d980349c64c 100644 --- a/java/java-impl/src/com/intellij/codeInspection/util/SpecialAnnotationsUtil.java +++ b/java/java-impl/src/com/intellij/codeInspection/util/SpecialAnnotationsUtil.java @@ -2,8 +2,6 @@ package com.intellij.codeInspection.util; -import com.intellij.codeInsight.intention.IntentionAction; -import com.intellij.codeInsight.intention.preview.IntentionPreviewInfo; import com.intellij.codeInspection.ui.InspectionOptionsPanel; import com.intellij.ide.DataManager; import com.intellij.ide.util.ClassFilter; @@ -14,15 +12,11 @@ import com.intellij.openapi.actionSystem.ActionToolbarPosition; import com.intellij.openapi.actionSystem.ActionUpdateThread; import com.intellij.openapi.actionSystem.AnActionEvent; import com.intellij.openapi.actionSystem.CommonDataKeys; -import com.intellij.openapi.editor.Editor; import com.intellij.openapi.project.Project; import com.intellij.openapi.project.ProjectManager; import com.intellij.openapi.ui.Messages; import com.intellij.openapi.util.NlsContexts; -import com.intellij.openapi.util.NlsSafe; -import com.intellij.profile.codeInspection.ProjectInspectionProfileManager; import com.intellij.psi.PsiClass; -import com.intellij.psi.PsiFile; import com.intellij.psi.search.GlobalSearchScope; import com.intellij.ui.AnActionButton; import com.intellij.ui.AnActionButtonRunnable; @@ -30,18 +24,14 @@ import com.intellij.ui.SortedListModel; import com.intellij.ui.ToolbarDecorator; import com.intellij.ui.components.JBList; import com.intellij.util.IconUtil; -import com.intellij.util.IncorrectOperationException; import com.intellij.util.ui.JBUI; import com.intellij.util.ui.UI; -import one.util.streamex.StreamEx; -import org.jetbrains.annotations.Nls; import org.jetbrains.annotations.NotNull; import javax.swing.*; import javax.swing.event.ListDataEvent; import javax.swing.event.ListDataListener; import java.awt.*; -import java.util.Collections; import java.util.Comparator; import java.util.List; import java.util.function.Predicate; @@ -163,47 +153,4 @@ public final class SpecialAnnotationsUtil { .resizeY(true) .createPanel(); } - - public static IntentionAction createAddToSpecialAnnotationsListIntentionAction(final @IntentionName String text, - final @IntentionFamilyName String family, - final @Nls String listTitle, - final List targetList, - final String qualifiedName) { - return new IntentionAction() { - @Override - @NotNull - public String getText() { - return text; - } - - @Override - @NotNull - public String getFamilyName() { - return family; - } - - @Override - public boolean isAvailable(@NotNull Project project, Editor editor, PsiFile file) { - return true; - } - - @Override - public void invoke(@NotNull Project project, Editor editor, PsiFile file) throws IncorrectOperationException { - targetList.add(qualifiedName); - Collections.sort(targetList); - ProjectInspectionProfileManager.getInstance(project).fireProfileChanged(); - } - - @Override - public boolean startInWriteAction() { - return false; - } - - @Override - public @NotNull IntentionPreviewInfo generatePreview(@NotNull Project project, @NotNull Editor editor, @NotNull PsiFile file) { - List<@NlsSafe String> prefixes = StreamEx.of(targetList).append(qualifiedName).sorted().toList(); - return IntentionPreviewInfo.addListOption(prefixes, qualifiedName, listTitle); - } - }; - } } diff --git a/java/java-impl/src/com/siyeh/ig/style/FieldMayBeFinalInspection.java b/java/java-impl/src/com/siyeh/ig/style/FieldMayBeFinalInspection.java index 1ca039cd9048..7b53ee3e0f91 100644 --- a/java/java-impl/src/com/siyeh/ig/style/FieldMayBeFinalInspection.java +++ b/java/java-impl/src/com/siyeh/ig/style/FieldMayBeFinalInspection.java @@ -51,7 +51,7 @@ public class FieldMayBeFinalInspection extends BaseInspection implements Cleanup PsiField field = (PsiField)infos[0]; fixes.add(MakeFieldFinalFix.buildFixUnconditional(field)); SpecialAnnotationsUtilBase.processUnknownAnnotations(field, annoName -> { - fixes.add(EntryPointsManagerBase.getInstance(field.getProject()).new AddImplicitlyWriteAnnotation(annoName)); + fixes.add(LocalQuickFix.from(EntryPointsManagerBase.createAddImplicitWriteAnnotation(annoName))); return true; }); return fixes.toArray(LocalQuickFix.EMPTY_ARRAY); diff --git a/plugins/kotlin/idea/tests/testData/quickfix/unusedSuppressAnnotation/simple.kt b/plugins/kotlin/idea/tests/testData/quickfix/unusedSuppressAnnotation/simple.kt index 84fc7e573342..ade59f33b6b5 100644 --- a/plugins/kotlin/idea/tests/testData/quickfix/unusedSuppressAnnotation/simple.kt +++ b/plugins/kotlin/idea/tests/testData/quickfix/unusedSuppressAnnotation/simple.kt @@ -6,4 +6,4 @@ annotation class XXX @XXX class UnusedClass -// FUS_QUICKFIX_NAME: com.intellij.codeInspection.util.SpecialAnnotationsUtil$4 \ No newline at end of file +// FUS_QUICKFIX_NAME: com.intellij.codeInspection.ex.EntryPointsManagerBase$AddAnnotation \ No newline at end of file diff --git a/plugins/kotlin/idea/tests/testData/quickfix/unusedSuppressAnnotation/simple.kt.after b/plugins/kotlin/idea/tests/testData/quickfix/unusedSuppressAnnotation/simple.kt.after index 84fc7e573342..ade59f33b6b5 100644 --- a/plugins/kotlin/idea/tests/testData/quickfix/unusedSuppressAnnotation/simple.kt.after +++ b/plugins/kotlin/idea/tests/testData/quickfix/unusedSuppressAnnotation/simple.kt.after @@ -6,4 +6,4 @@ annotation class XXX @XXX class UnusedClass -// FUS_QUICKFIX_NAME: com.intellij.codeInspection.util.SpecialAnnotationsUtil$4 \ No newline at end of file +// FUS_QUICKFIX_NAME: com.intellij.codeInspection.ex.EntryPointsManagerBase$AddAnnotation \ No newline at end of file