diff --git a/java/java-impl/src/com/intellij/application/options/editor/JavaAutoImportOptions.kt b/java/java-impl/src/com/intellij/application/options/editor/JavaAutoImportOptions.kt index b41da98b238c..53b3a8ebcf4e 100644 --- a/java/java-impl/src/com/intellij/application/options/editor/JavaAutoImportOptions.kt +++ b/java/java-impl/src/com/intellij/application/options/editor/JavaAutoImportOptions.kt @@ -53,12 +53,8 @@ public class JavaAutoImportOptions(public val project: Project) : UiDslUnnamedCo JavaBundle.message("auto.static.import.scope")) { override fun validate(value: Any?, component: JComponent?): ValidationInfo? { - val info = super.validate(value, component) - if (info != null && value is String && value.startsWith("-")) { - val cutInfo = super.validate(value.substring(1), component) - if (cutInfo == null) return null - } - return info + if (value !is String) return null + return super.validate(value.substring(if (value.startsWith("-")) 1 else 0), component) } override fun getIdeRows(): Array { diff --git a/java/java-impl/src/com/intellij/codeInsight/JavaProjectCodeInsightSettings.java b/java/java-impl/src/com/intellij/codeInsight/JavaProjectCodeInsightSettings.java index 721087001e7a..240fa9f17576 100644 --- a/java/java-impl/src/com/intellij/codeInsight/JavaProjectCodeInsightSettings.java +++ b/java/java-impl/src/com/intellij/codeInsight/JavaProjectCodeInsightSettings.java @@ -23,10 +23,7 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.TestOnly; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.LinkedHashSet; -import java.util.List; +import java.util.*; import java.util.concurrent.ConcurrentMap; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -44,22 +41,25 @@ public class JavaProjectCodeInsightSettings implements PersistentStateComponent< return project.getService(JavaProjectCodeInsightSettings.class); } + @NotNull public AutoStaticNameContainer getAllIncludedAutoStaticNames() { List names = new ArrayList<>(includedAutoStaticNames); names.addAll(JavaIdeCodeInsightSettings.getInstance().includedAutoStaticNames); return AutoStaticNameContainer.create(names); } - public record AutoStaticNameContainer(LinkedHashSet includedNames, LinkedHashSet excludedNames) { + public record AutoStaticNameContainer(@NotNull Set includedNames, + @NotNull Set excludedNames) { public boolean containsName(@NotNull String name) { return (includedNames.contains(name) || includedNames.contains(StringUtil.getPackageName(name))) && !(excludedNames.contains(name) || excludedNames.contains(StringUtil.getPackageName(name))); } - public static AutoStaticNameContainer create(List allNames) { - LinkedHashSet includedNames = new LinkedHashSet<>(); - LinkedHashSet excludedNames = new LinkedHashSet<>(); + @NotNull + public static AutoStaticNameContainer create(@NotNull List allNames) { + Set includedNames = new HashSet<>(); + Set excludedNames = new HashSet<>(); for (String name : allNames) { if (name == null) continue; if (StringUtil.isEmptyOrSpaces(name)) continue; diff --git a/java/java-impl/src/com/intellij/codeInspection/StaticImportCanBeUsedInspection.java b/java/java-impl/src/com/intellij/codeInspection/StaticImportCanBeUsedInspection.java index 14cecf5fc5b2..f3482b6267e5 100644 --- a/java/java-impl/src/com/intellij/codeInspection/StaticImportCanBeUsedInspection.java +++ b/java/java-impl/src/com/intellij/codeInspection/StaticImportCanBeUsedInspection.java @@ -15,31 +15,32 @@ import com.intellij.psi.*; import com.intellij.psi.codeStyle.JavaCodeStyleManager; import com.intellij.psi.util.PsiTreeUtil; import com.intellij.util.ObjectUtils; +import one.util.streamex.StreamEx; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import java.util.ArrayList; +import java.util.List; import java.util.Set; -import java.util.stream.Collectors; public final class StaticImportCanBeUsedInspection extends AbstractBaseJavaLocalInspectionTool implements CleanupLocalInspectionTool { @Override public @NotNull PsiElementVisitor buildVisitor(@NotNull ProblemsHolder holder, boolean isOnTheFly, @NotNull LocalInspectionToolSession session) { - JavaProjectCodeInsightSettings settings = JavaProjectCodeInsightSettings.getSettings(holder.getProject()); + Project project = holder.getProject(); + JavaProjectCodeInsightSettings settings = JavaProjectCodeInsightSettings.getSettings(project); JavaProjectCodeInsightSettings.AutoStaticNameContainer autoStaticNames = settings.getAllIncludedAutoStaticNames(); if (autoStaticNames.includedNames().isEmpty()) { return PsiElementVisitor.EMPTY_VISITOR; } - Set shortNames = autoStaticNames.includedNames().stream() - .map(name -> StringUtil.getShortName(name)) - .collect(Collectors.toSet()); - Set classShortNames = autoStaticNames.includedNames().stream() - .map(name -> StringUtil.getShortName(StringUtil.getPackageName(name))) - .filter(name -> !name.isBlank()) - .collect(Collectors.toSet()); - shortNames.addAll(classShortNames); + Set shortNames = StreamEx.of(autoStaticNames.includedNames()) + .map(name -> StringUtil.getShortName(name)) + .append(autoStaticNames.includedNames().stream() + .map(name -> StringUtil.getShortName(StringUtil.getPackageName(name))) + .filter(name -> !name.isBlank())) + .toSet(); return new JavaElementVisitor() { @Override @@ -53,34 +54,50 @@ public final class StaticImportCanBeUsedInspection extends AbstractBaseJavaLocal if (qualifierReference == null || name == null || !shortNames.contains(name)) return; StaticImportContext context = findOnDemandImportContext(expression); if (context == null) return; + List fixes = new ArrayList<>(); + fixes.add(new StaticImportFix()); + fixes.add(new DeleteSettingsFromAutoImportTable(context.fqn, project)); + + JavaProjectCodeInsightSettings projectSettings = JavaProjectCodeInsightSettings.getSettings(project); + JavaIdeCodeInsightSettings ideSettings = JavaIdeCodeInsightSettings.getInstance(); + String packageName = StringUtil.getPackageName(context.fqn); + if (!projectSettings.includedAutoStaticNames.contains(context.fqn) && + projectSettings.includedAutoStaticNames.contains(packageName) || + !ideSettings.includedAutoStaticNames.contains(context.fqn) && + ideSettings.includedAutoStaticNames.contains(packageName)) { + fixes.add(new AddExclusionFromAutoImportTable(context.fqn, project)); + } holder.registerProblem(qualifierReference, JavaBundle.message("inspection.static.import.can.be.used.display.name"), - new StaticImportFix(), - new DeleteSettingsFromAutoImportTable(context.fqn), - new AddExclusionFromAutoImportTable(context.fqn)); + fixes.toArray(LocalQuickFix.EMPTY_ARRAY)); } }; } private static class AddExclusionFromAutoImportTable extends ModCommandQuickFix { - private final String myFqn; + private final @NotNull String myFqn; + private final boolean myIsProjectSettings; - private AddExclusionFromAutoImportTable(String fqn) { myFqn = fqn; } + private AddExclusionFromAutoImportTable(@NotNull String fqn, @NotNull Project project) { + myFqn = fqn; + JavaProjectCodeInsightSettings settings = JavaProjectCodeInsightSettings.getSettings(project); + myIsProjectSettings = settings.includedAutoStaticNames.contains(myFqn) || + settings.includedAutoStaticNames.contains(StringUtil.getPackageName(myFqn)); + } @Override public @NotNull ModCommand perform(@NotNull Project project, @NotNull ProblemDescriptor descriptor) { PsiElement element = descriptor.getPsiElement(); if (element == null) return ModCommand.nop(); - JavaIdeCodeInsightSettings settings = JavaIdeCodeInsightSettings.getInstance(); - if (settings.includedAutoStaticNames.contains(myFqn) || settings.includedAutoStaticNames.contains(StringUtil.getPackageName(myFqn))) { + if (myIsProjectSettings) { return ModCommand.updateOptionList(element, - "JavaIdeCodeInsightSettings.includedAutoStaticNames", + "JavaProjectCodeInsightSettings.includedAutoStaticNames", strings -> { strings.add("-" + myFqn); }); } return ModCommand.updateOptionList(element, - "JavaProjectCodeInsightSettings.includedAutoStaticNames", + "JavaIdeCodeInsightSettings.includedAutoStaticNames", strings -> { strings.add("-" + myFqn); }); @@ -88,7 +105,8 @@ public final class StaticImportCanBeUsedInspection extends AbstractBaseJavaLocal @Override public @NotNull String getName() { - return JavaBundle.message("inspection.static.import.can.be.used.exclude.from.auto.import.name", myFqn); + return JavaBundle.message("inspection.static.import.can.be.used.exclude.from.auto.import.name", myFqn, + myIsProjectSettings ? 0 : 1); } @Override @@ -98,38 +116,46 @@ public final class StaticImportCanBeUsedInspection extends AbstractBaseJavaLocal } private static class DeleteSettingsFromAutoImportTable extends ModCommandQuickFix { - private final String myFqn; + private final @NotNull String myFqn; + private final boolean myIsProjectSettings; - private DeleteSettingsFromAutoImportTable(String fqn) { myFqn = fqn; } + private DeleteSettingsFromAutoImportTable(@NotNull String fqn, @NotNull Project project) { + myFqn = fqn; + JavaProjectCodeInsightSettings settings = JavaProjectCodeInsightSettings.getSettings(project); + myIsProjectSettings = settings.includedAutoStaticNames.contains(myFqn) || + settings.includedAutoStaticNames.contains(StringUtil.getPackageName(myFqn)); + } @Override public @NotNull ModCommand perform(@NotNull Project project, @NotNull ProblemDescriptor descriptor) { PsiElement element = descriptor.getPsiElement(); if (element == null) return ModCommand.nop(); - JavaIdeCodeInsightSettings settings = JavaIdeCodeInsightSettings.getInstance(); - if (settings.includedAutoStaticNames.contains(myFqn) || settings.includedAutoStaticNames.contains(StringUtil.getPackageName(myFqn))) { + String packageName = StringUtil.getPackageName(myFqn); + if (myIsProjectSettings) { return ModCommand.updateOptionList(element, - "JavaIdeCodeInsightSettings.includedAutoStaticNames", + "JavaProjectCodeInsightSettings.includedAutoStaticNames", strings -> { strings.removeIf(t -> - t.startsWith(StringUtil.getPackageName(myFqn)) || - t.startsWith("-" + StringUtil.getPackageName(myFqn)) + t.equals(myFqn) || + t.equals(packageName) || + t.equals("-" + packageName) ); }); } return ModCommand.updateOptionList(element, - "JavaProjectCodeInsightSettings.includedAutoStaticNames", + "JavaIdeCodeInsightSettings.includedAutoStaticNames", strings -> { - strings.removeIf(t-> - t.startsWith(StringUtil.getPackageName(myFqn)) || - t.startsWith("-" + StringUtil.getPackageName(myFqn)) - ); + strings.removeIf(t -> + t.equals(myFqn) || + t.equals(packageName) || + t.equals("-" + packageName) + ); }); } @Override public @NotNull String getName() { - return JavaBundle.message("inspection.static.import.can.be.used.remove.from.auto.import.name", myFqn); + return JavaBundle.message("inspection.static.import.can.be.used.remove.from.auto.import.name", myFqn, myIsProjectSettings ? 0 : 1); } @Override diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/daemon/impl/quickfix/StaticImportCanBeUsedInspectionTest.java b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/impl/quickfix/StaticImportCanBeUsedInspectionTest.java index 0bc6052098b9..fb9c2d5fa287 100644 --- a/java/java-tests/testSrc/com/intellij/codeInsight/daemon/impl/quickfix/StaticImportCanBeUsedInspectionTest.java +++ b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/impl/quickfix/StaticImportCanBeUsedInspectionTest.java @@ -46,7 +46,7 @@ public class StaticImportCanBeUsedInspectionTest extends LightJavaInspectionTest public void testSimple() { try { - addStaticAutoImport("java.util.Arrays"); + addStaticAutoImportToProject("java.util.Arrays"); doTest(); cleanupTest(); } @@ -57,8 +57,8 @@ public class StaticImportCanBeUsedInspectionTest extends LightJavaInspectionTest public void testSimpleWithExclusion() { try { - addStaticAutoImport("java.util.Arrays"); - addStaticAutoImport("-java.util.Arrays.sort"); + addStaticAutoImportToProject("java.util.Arrays"); + addStaticAutoImportToProject("-java.util.Arrays.sort"); doTest(); } finally { @@ -68,11 +68,11 @@ public class StaticImportCanBeUsedInspectionTest extends LightJavaInspectionTest public void testRemoveAutoImportProject() { try { - addStaticAutoImport("java.util.Arrays"); - addStaticAutoImport("-java.util.Arrays.binarySearch"); + addStaticAutoImportToProject("java.util.Arrays"); + addStaticAutoImportToProject("-java.util.Arrays.binarySearch"); doTest(); IntentionAction intention = myFixture.getAvailableIntention( - JavaBundle.message("inspection.static.import.can.be.used.remove.from.auto.import.name", "java.util.Arrays.sort")); + JavaBundle.message("inspection.static.import.can.be.used.remove.from.auto.import.name", "java.util.Arrays.sort", 0)); myFixture.launchAction(intention); checkAutoImportDoesntContain("java.util.Arrays"); } @@ -81,13 +81,33 @@ public class StaticImportCanBeUsedInspectionTest extends LightJavaInspectionTest } } - public void testExcludeAutoImportProject() { + public void testRemoveAutoImportProjectAdditionalImports() { try { - addStaticAutoImport("java.util.Arrays"); - addStaticAutoImport("-java.util.Arrays.binarySearch"); + addStaticAutoImportToProject("java.util.Arrays"); + addStaticAutoImportToProject("java.util.Arrays2"); + addStaticAutoImportToProject("java.util.A"); + addStaticAutoImportToProject("java.util"); doNamedTest("RemoveAutoImportProject"); IntentionAction intention = myFixture.getAvailableIntention( - JavaBundle.message("inspection.static.import.can.be.used.exclude.from.auto.import.name", "java.util.Arrays.sort")); + JavaBundle.message("inspection.static.import.can.be.used.remove.from.auto.import.name", "java.util.Arrays.sort", 0)); + myFixture.launchAction(intention); + checkAutoImportDoesntContain("java.util.Arrays.sort"); + checkAutoImportContains("java.util.Arrays2"); + checkAutoImportContains("java.util.A"); + checkAutoImportContains("java.util"); + } + finally { + cleanTable(); + } + } + + public void testExcludeAutoImportProject() { + try { + addStaticAutoImportToProject("java.util.Arrays"); + addStaticAutoImportToProject("-java.util.Arrays.binarySearch"); + doNamedTest("RemoveAutoImportProject"); + IntentionAction intention = myFixture.getAvailableIntention( + JavaBundle.message("inspection.static.import.can.be.used.exclude.from.auto.import.name", "java.util.Arrays.sort", 0)); myFixture.launchAction(intention); checkAutoImportContains("java.util.Arrays"); checkAutoImportDoesntContain("java.util.Arrays.sort"); @@ -104,7 +124,7 @@ public class StaticImportCanBeUsedInspectionTest extends LightJavaInspectionTest addStaticAutoImportToIde("-java.util.Arrays.binarySearch"); doTest(); IntentionAction intention = myFixture.getAvailableIntention( - JavaBundle.message("inspection.static.import.can.be.used.remove.from.auto.import.name", "java.util.Arrays.sort")); + JavaBundle.message("inspection.static.import.can.be.used.remove.from.auto.import.name", "java.util.Arrays.sort", 1)); myFixture.launchAction(intention); checkAutoImportDoesntContain("java.util.Arrays"); } @@ -119,7 +139,7 @@ public class StaticImportCanBeUsedInspectionTest extends LightJavaInspectionTest addStaticAutoImportToIde("-java.util.Arrays.binarySearch"); doNamedTest("RemoveAutoImportIde"); IntentionAction intention = myFixture.getAvailableIntention( - JavaBundle.message("inspection.static.import.can.be.used.exclude.from.auto.import.name", "java.util.Arrays.sort")); + JavaBundle.message("inspection.static.import.can.be.used.exclude.from.auto.import.name", "java.util.Arrays.sort", 1)); myFixture.launchAction(intention); checkAutoImportContains("java.util.Arrays"); checkAutoImportDoesntContain("java.util.Arrays.sort"); @@ -130,6 +150,18 @@ public class StaticImportCanBeUsedInspectionTest extends LightJavaInspectionTest } } + public void testExcludeAutoImportIdeMethodAdded() { + try { + addStaticAutoImportToIde("java.util.Arrays.sort"); + doNamedTest("RemoveAutoImportIde"); + String message = JavaBundle.message("inspection.static.import.can.be.used.exclude.from.auto.import.name", "java.util.Arrays.sort", 1); + assertNull(myFixture.getAvailableIntention(message)); + } + finally { + cleanTable(); + } + } + private void checkAutoImportDoesntContain(@NotNull String fqn) { assertFalse(JavaCodeStyleManager.getInstance(getProject()).isStaticAutoImportName(fqn)); } @@ -139,7 +171,7 @@ public class StaticImportCanBeUsedInspectionTest extends LightJavaInspectionTest } public void testSimpleWithOnDemand() { - addStaticAutoImport("java.util.Arrays"); + addStaticAutoImportToProject("java.util.Arrays"); JavaCodeStyleSettings javaSettings = JavaCodeStyleSettings.getInstance(getProject()); PackageEntry entry = new PackageEntry(true, "java.util.Arrays", false); PackageEntryTable onDemand = javaSettings.PACKAGES_TO_USE_IMPORT_ON_DEMAND; @@ -157,7 +189,7 @@ public class StaticImportCanBeUsedInspectionTest extends LightJavaInspectionTest public void testSimpleMethod() { try { - addStaticAutoImport("java.util.Arrays.sort"); + addStaticAutoImportToProject("java.util.Arrays.sort"); doTest(); cleanupTest(); } @@ -167,7 +199,7 @@ public class StaticImportCanBeUsedInspectionTest extends LightJavaInspectionTest } public void testSimpleMethodOnDemand() { - addStaticAutoImport("java.util.Arrays.sort"); + addStaticAutoImportToProject("java.util.Arrays.sort"); JavaCodeStyleSettings javaSettings = JavaCodeStyleSettings.getInstance(getProject()); PackageEntry entry = new PackageEntry(true, "java.util.Arrays", false); PackageEntryTable onDemand = javaSettings.PACKAGES_TO_USE_IMPORT_ON_DEMAND; @@ -185,7 +217,7 @@ public class StaticImportCanBeUsedInspectionTest extends LightJavaInspectionTest public void testWithConflicts() { try { - addStaticAutoImport("java.util.Arrays"); + addStaticAutoImportToProject("java.util.Arrays"); doTest(); } finally { @@ -195,7 +227,7 @@ public class StaticImportCanBeUsedInspectionTest extends LightJavaInspectionTest public void testWithConflicts2() { try { - addStaticAutoImport("java.util.Arrays"); + addStaticAutoImportToProject("java.util.Arrays"); myFixture.addClass(""" package org; @@ -212,7 +244,7 @@ public class StaticImportCanBeUsedInspectionTest extends LightJavaInspectionTest public void testWithConflictsWithField() { try { - addStaticAutoImport("org.Foo2"); + addStaticAutoImportToProject("org.Foo2"); myFixture.addClass(""" package org; @@ -237,7 +269,7 @@ public class StaticImportCanBeUsedInspectionTest extends LightJavaInspectionTest public void testWithConflictsWithClass() { try { - addStaticAutoImport("org.Foo2"); + addStaticAutoImportToProject("org.Foo2"); myFixture.addClass(""" package org; @@ -262,7 +294,7 @@ public class StaticImportCanBeUsedInspectionTest extends LightJavaInspectionTest public void testAlreadyImported() { try { - addStaticAutoImport("java.util.Arrays"); + addStaticAutoImportToProject("java.util.Arrays"); doTest(); cleanupTest(); } @@ -283,11 +315,11 @@ public class StaticImportCanBeUsedInspectionTest extends LightJavaInspectionTest } @SuppressWarnings("SameParameterValue") - private void addStaticAutoImport(@NotNull String name) { + private void addStaticAutoImportToProject(@NotNull String name) { JavaProjectCodeInsightSettings.getSettings(getProject()).includedAutoStaticNames.add(name); } private static void addStaticAutoImportToIde(@NotNull String name) { JavaIdeCodeInsightSettings.getInstance().includedAutoStaticNames.add(name); } -} +} \ No newline at end of file diff --git a/java/openapi/resources/messages/JavaBundle.properties b/java/openapi/resources/messages/JavaBundle.properties index 77c3e7ee613c..0aa37b2ae297 100644 --- a/java/openapi/resources/messages/JavaBundle.properties +++ b/java/openapi/resources/messages/JavaBundle.properties @@ -1445,9 +1445,9 @@ inspection.slow.list.contains.all.fix.name=Wrap ''{0}'' in ''HashSet'' construct inspection.static.import.can.be.used.display.name=Static import can be used based on the auto-import table inspection.static.import.can.be.used.fix.name=Add static import inspection.static.import.can.be.used.remove.from.auto.import.family.name=Remove on-demand static import from the auto-import table -inspection.static.import.can.be.used.remove.from.auto.import.name=Remove ''{0}'' and its parent from the auto-import table +inspection.static.import.can.be.used.remove.from.auto.import.name=Remove ''{0}'' and its parent from the {1, choice, 0#project|1#IDE} auto-import table inspection.static.import.can.be.used.exclude.from.auto.import.family.name=Add exclusion for on-demand static import to the auto-import table -inspection.static.import.can.be.used.exclude.from.auto.import.name=Add exclusion for ''{0}'' to the auto-import table +inspection.static.import.can.be.used.exclude.from.auto.import.name=Add exclusion for ''{0}'' to the {1, choice, 0#project|1#IDE} auto-import table slice.filter.parse.error.null.filter.not.applicable.for.primitive.type=''null'' filter is not applicable to primitive type {0} slice.filter.parse.error.not.null.filter.not.applicable.for.primitive.type=''!null'' filter is not applicable to primitive type {0}