diff --git a/java/java-analysis-impl/intellij.java.analysis.impl.iml b/java/java-analysis-impl/intellij.java.analysis.impl.iml
index 2574fb64a1f1..6b0a31999446 100644
--- a/java/java-analysis-impl/intellij.java.analysis.impl.iml
+++ b/java/java-analysis-impl/intellij.java.analysis.impl.iml
@@ -29,5 +29,6 @@
+
\ No newline at end of file
diff --git a/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/PostHighlightingVisitor.java b/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/PostHighlightingVisitor.java
index 9d11b0cea735..f02878550faf 100644
--- a/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/PostHighlightingVisitor.java
+++ b/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/PostHighlightingVisitor.java
@@ -156,16 +156,16 @@ class PostHighlightingVisitor extends JavaElementVisitor {
if (!(myFile instanceof PsiJavaFile) || myUnusedSymbolInspection == null) {
return false;
}
- InspectionProfile profile = getCurrentProfile();
+ InspectionProfile profile = getCurrentProfile(myFile);
return profile.isToolEnabled(displayKey, myFile) &&
HighlightingLevelManager.getInstance(myProject).shouldInspect(myFile) &&
!HighlightingLevelManager.getInstance(myProject).runEssentialHighlightingOnly(myFile);
}
@NotNull
- private InspectionProfile getCurrentProfile() {
- Function super InspectionProfile, ? extends InspectionProfileWrapper> custom = InspectionProfileWrapper.getCustomInspectionProfileWrapper(myFile);
- InspectionProfileImpl currentProfile = InspectionProjectProfileManager.getInstance(myProject).getCurrentProfile();
+ private static InspectionProfile getCurrentProfile(@NotNull PsiFile file) {
+ Function super InspectionProfile, ? extends InspectionProfileWrapper> custom = InspectionProfileWrapper.getCustomInspectionProfileWrapper(file);
+ InspectionProfileImpl currentProfile = InspectionProjectProfileManager.getInstance(file.getProject()).getCurrentProfile();
return custom != null ? custom.apply(currentProfile).getInspectionProfile() : currentProfile;
}
@@ -552,7 +552,7 @@ class PostHighlightingVisitor extends JavaElementVisitor {
boolean predefinedImport = imports != null && imports.contains(importStatement.getText());
String description = !predefinedImport ? JavaAnalysisBundle.message("unused.import.statement") :
JavaAnalysisBundle.message("text.unused.import.in.template");
- InspectionProfile profile = getCurrentProfile();
+ InspectionProfile profile = getCurrentProfile(myFile);
TextAttributesKey key = ObjectUtils.notNull(profile.getEditorAttributes(unusedImportKey.toString(), myFile),
JavaHighlightInfoTypes.UNUSED_IMPORT.getAttributesKey());
HighlightInfoType.HighlightInfoTypeImpl configHighlightType =
@@ -563,8 +563,7 @@ class PostHighlightingVisitor extends JavaElementVisitor {
.descriptionAndTooltip(description)
.group(GeneralHighlightingPass.POST_UPDATE_ALL);
- IntentionAction removeFix = QuickFixFactory.getInstance().createDeleteFix(importStatement, JavaErrorBundle.message("remove.unused.import.quickfix.text"));
- builder.registerFix(removeFix, null, HighlightDisplayKey.getDisplayNameByKey(unusedImportKey), null, unusedImportKey);
+ builder.registerFix(new RemoveAllUnusedImportsFix(), null, HighlightDisplayKey.getDisplayNameByKey(unusedImportKey), null, unusedImportKey);
IntentionAction switchFix = QuickFixFactory.getInstance().createEnableOptimizeImportsOnTheFlyFix();
builder.registerFix(switchFix, null, HighlightDisplayKey.getDisplayNameByKey(unusedImportKey), null, unusedImportKey);
@@ -573,4 +572,10 @@ class PostHighlightingVisitor extends JavaElementVisitor {
}
addInfo(holder, builder);
}
+ static boolean isUnusedImportHighlightInfo(@NotNull PsiFile psiFile, @NotNull HighlightInfo info) {
+ TextAttributesKey key = info.type.getAttributesKey();
+ InspectionProfile profile = getCurrentProfile(psiFile);
+ return key.equals(profile.getEditorAttributes(UnusedImportInspection.SHORT_NAME, psiFile))
+ || key.equals(JavaHighlightInfoTypes.UNUSED_IMPORT.getAttributesKey());
+ }
}
diff --git a/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/RemoveAllUnusedImportsFix.java b/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/RemoveAllUnusedImportsFix.java
new file mode 100644
index 000000000000..5e1101010967
--- /dev/null
+++ b/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/RemoveAllUnusedImportsFix.java
@@ -0,0 +1,61 @@
+// 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.analysis;
+
+import com.intellij.codeInsight.daemon.JavaErrorBundle;
+import com.intellij.codeInsight.daemon.impl.DaemonCodeAnalyzerEx;
+import com.intellij.codeInsight.intention.IntentionAction;
+import com.intellij.codeInsight.intention.QuickFixFactory;
+import com.intellij.lang.annotation.HighlightSeverity;
+import com.intellij.openapi.editor.Editor;
+import com.intellij.openapi.project.Project;
+import com.intellij.psi.*;
+import com.intellij.psi.util.PsiTreeUtil;
+import com.intellij.util.IncorrectOperationException;
+import org.jetbrains.annotations.NotNull;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class RemoveAllUnusedImportsFix implements IntentionAction {
+ @Override
+ public @NotNull String getFamilyName() {
+ return JavaErrorBundle.message("remove.unused.imports.quickfix.text");
+ }
+
+ @Override
+ public @NotNull String getText() {
+ return getFamilyName();
+ }
+
+ @Override
+ public boolean isAvailable(@NotNull Project project, Editor editor, PsiFile file) {
+ return file instanceof PsiJavaFile && editor != null;
+ }
+
+ @Override
+ public void invoke(@NotNull Project project, Editor editor, PsiFile psiFile) throws IncorrectOperationException {
+ if (!(psiFile instanceof PsiJavaFile javaFile) || editor == null) return;
+ PsiImportList importList = javaFile.getImportList();
+ if (importList == null) return;
+ List importStatements = new ArrayList<>();
+ DaemonCodeAnalyzerEx.processHighlights(editor.getDocument(), project, HighlightSeverity.INFORMATION, importList.getTextRange().getStartOffset(), importList.getTextRange().getEndOffset(), info -> {
+ if (PostHighlightingVisitor.isUnusedImportHighlightInfo(psiFile, info)) {
+ PsiImportStatement importStatement = PsiTreeUtil.findElementOfClassAtOffset(psiFile, info.getActualStartOffset(), PsiImportStatement.class, false);
+ if (importStatement != null) {
+ importStatements.add(importStatement);
+ }
+ }
+ return true;
+ });
+
+ if (!importStatements.isEmpty()) {
+ IntentionAction deleteAll = QuickFixFactory.getInstance().createDeleteFix(importStatements.toArray(PsiElement.EMPTY_ARRAY));
+ deleteAll.invoke(project, editor, psiFile);
+ }
+ }
+
+ @Override
+ public boolean startInWriteAction() {
+ return false;
+ }
+}
diff --git a/java/java-psi-impl/src/messages/JavaErrorBundle.properties b/java/java-psi-impl/src/messages/JavaErrorBundle.properties
index ae90eba4d504..a1fe42e24d58 100644
--- a/java/java-psi-impl/src/messages/JavaErrorBundle.properties
+++ b/java/java-psi-impl/src/messages/JavaErrorBundle.properties
@@ -582,4 +582,4 @@ error.unnamed.class.contains.no.main.method=Unnamed class contains no 'main' met
error.unnamed.class.has.invalid.file.name=Unnamed class's file name is not a valid identifier
error.package.statement.not.allowed.for.unnamed.class=Package statement is not allowed for unnamed class
error.initializers.are.not.allowed.in.unnamed.classes=Initializers are not allowed in unnamed classes
-remove.unused.import.quickfix.text=Remove unused import
\ No newline at end of file
+remove.unused.imports.quickfix.text=Remove unused imports
\ No newline at end of file
diff --git a/java/java-tests/testSrc/com/intellij/java/psi/OptimizeImportsTest.java b/java/java-tests/testSrc/com/intellij/java/psi/OptimizeImportsTest.java
index c61f44963d3f..af1fc30eed91 100644
--- a/java/java-tests/testSrc/com/intellij/java/psi/OptimizeImportsTest.java
+++ b/java/java-tests/testSrc/com/intellij/java/psi/OptimizeImportsTest.java
@@ -4,6 +4,7 @@ package com.intellij.java.psi;
import com.intellij.application.options.CodeStyle;
import com.intellij.application.options.codeStyle.excludedFiles.NamedScopeDescriptor;
import com.intellij.codeInsight.CodeInsightWorkspaceSettings;
+import com.intellij.codeInsight.daemon.JavaErrorBundle;
import com.intellij.codeInsight.intention.IntentionAction;
import com.intellij.codeInsight.intention.QuickFixFactory;
import com.intellij.codeInspection.deadCode.UnusedDeclarationInspection;
@@ -21,7 +22,6 @@ import com.intellij.openapi.application.ReadAction;
import com.intellij.openapi.application.ex.PathManagerEx;
import com.intellij.openapi.command.WriteCommandAction;
import com.intellij.openapi.vfs.VirtualFile;
-import com.intellij.pom.java.LanguageLevel;
import com.intellij.psi.PsiDocumentManager;
import com.intellij.psi.PsiFile;
import com.intellij.psi.codeStyle.CodeStyleSettings;
@@ -214,7 +214,7 @@ public class OptimizeImportsTest extends OptimizeImportsTestCase {
import java.util.Collection;
class Foo {}""");
- myFixture.launchAction(myFixture.findSingleIntention("Remove unused import"));
+ myFixture.launchAction(myFixture.findSingleIntention(JavaErrorBundle.message("remove.unused.imports.quickfix.text")));
// whatever: main thing it didn't throw
myFixture.checkResult("""
@@ -233,7 +233,7 @@ public class OptimizeImportsTest extends OptimizeImportsTestCase {
import java.util.Map;
class Foo {}""");
- myFixture.launchAction(myFixture.findSingleIntention("Remove unused import"));
+ myFixture.launchAction(myFixture.findSingleIntention(JavaErrorBundle.message("remove.unused.imports.quickfix.text")));
// whatever: main thing it didn't throw
assertNotEmpty(myFixture.doHighlighting(HighlightSeverity.ERROR));
@@ -259,7 +259,7 @@ public class OptimizeImportsTest extends OptimizeImportsTestCase {
import java.util.Set;
""");
- myFixture.launchAction(myFixture.findSingleIntention("Remove unused import"));
+ myFixture.launchAction(myFixture.findSingleIntention(JavaErrorBundle.message("remove.unused.imports.quickfix.text")));
myFixture.checkResult("package p;\n\n");
}
public void testRemoveUnusedImportFixShownEvenForUnresolvedImport() {
@@ -270,9 +270,36 @@ public class OptimizeImportsTest extends OptimizeImportsTestCase {
import java.blahblah.Set;
""");
- myFixture.launchAction(myFixture.findSingleIntention("Remove unused import"));
+ myFixture.launchAction(myFixture.findSingleIntention(JavaErrorBundle.message("remove.unused.imports.quickfix.text")));
myFixture.checkResult("package p;\n\n");
}
+ public void testRemoveUnusedImportFixMustDeleteAllUnusedImports() {
+ myFixture.enableInspections(new UnusedImportInspection());
+ myFixture.configureByText("a.java", """
+ package p;
+
+ // just remove, not reorganize
+ import java.util.List;
+ import java.util.HashSet;
+ // this for sure
+ import java.util.Set;
+ import java.util.ArrayList;
+ import java.util.HashMap;
+
+ class X { List a = new ArrayList(); }
+ """);
+ myFixture.launchAction(myFixture.findSingleIntention(JavaErrorBundle.message("remove.unused.imports.quickfix.text")));
+ myFixture.checkResult("""
+ package p;
+
+ // just remove, not reorganize
+ import java.util.List;
+ // this for sure
+ import java.util.ArrayList;
+
+ class X { List a = new ArrayList(); }
+ """);
+ }
public void testPerFileImportSettings() {
CodeStyle.dropTemporarySettings(getProject());