diff --git a/java/java-impl/resources/META-INF/JavaPlugin.xml b/java/java-impl/resources/META-INF/JavaPlugin.xml
index a90db3222d3a..fe2a17e12ed4 100644
--- a/java/java-impl/resources/META-INF/JavaPlugin.xml
+++ b/java/java-impl/resources/META-INF/JavaPlugin.xml
@@ -2292,6 +2292,10 @@
+
JAVA
diff --git a/java/java-impl/src/com/intellij/codeInsight/JavaProjectCodeInsightSettings.java b/java/java-impl/src/com/intellij/codeInsight/JavaProjectCodeInsightSettings.java
index 56e350c9e5d6..e48c33487a70 100644
--- a/java/java-impl/src/com/intellij/codeInsight/JavaProjectCodeInsightSettings.java
+++ b/java/java-impl/src/com/intellij/codeInsight/JavaProjectCodeInsightSettings.java
@@ -43,8 +43,7 @@ public class JavaProjectCodeInsightSettings implements PersistentStateComponent<
public boolean isStaticAutoImportClass(@Nullable String name) {
if (name == null) return false;
- return includedAutoStaticNames.contains(name) ||
- JavaIdeCodeInsightSettings.getInstance().includedAutoStaticNames.contains(name);
+ return getAllIncludedAutoStaticNames().contains(name);
}
public boolean isExcluded(@NotNull String name) {
diff --git a/java/java-impl/src/com/intellij/codeInsight/intention/impl/AddOnDemandStaticImportAction.java b/java/java-impl/src/com/intellij/codeInsight/intention/impl/AddOnDemandStaticImportAction.java
index 6bafddead943..3c1664934d35 100644
--- a/java/java-impl/src/com/intellij/codeInsight/intention/impl/AddOnDemandStaticImportAction.java
+++ b/java/java-impl/src/com/intellij/codeInsight/intention/impl/AddOnDemandStaticImportAction.java
@@ -16,6 +16,7 @@ import com.intellij.openapi.util.Ref;
import com.intellij.openapi.wm.WindowManager;
import com.intellij.pom.java.JavaFeature;
import com.intellij.psi.*;
+import com.intellij.psi.codeStyle.JavaCodeStyleManager;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.psi.util.PsiUtil;
import com.intellij.psi.util.PsiUtilCore;
@@ -114,10 +115,15 @@ public final class AddOnDemandStaticImportAction extends PsiUpdateModCommandActi
@Override
protected @Nullable Presentation getPresentation(@NotNull ActionContext context, @NotNull PsiIdentifier element) {
PsiClass classToImport = getClassToPerformStaticImport(element);
- if (classToImport != null) {
- return Presentation.of(JavaBundle.message("intention.add.on.demand.static.import.text", classToImport.getQualifiedName()));
+ if (classToImport == null) {
+ return null;
}
- return null;
+ Project project = element.getProject();
+ JavaCodeStyleManager codeStyleManager = JavaCodeStyleManager.getInstance(project);
+ if (codeStyleManager.isStaticAutoImportClass(classToImport.getQualifiedName())) {
+ return null;
+ }
+ return Presentation.of(JavaBundle.message("intention.add.on.demand.static.import.text", classToImport.getQualifiedName()));
}
public static boolean invoke(final Project project, PsiFile file, final Editor editor, @NotNull PsiElement element) {
diff --git a/java/java-impl/src/com/intellij/codeInspection/StaticImportCanBeUsedInspection.java b/java/java-impl/src/com/intellij/codeInspection/StaticImportCanBeUsedInspection.java
new file mode 100644
index 000000000000..6301001a8b84
--- /dev/null
+++ b/java/java-impl/src/com/intellij/codeInspection/StaticImportCanBeUsedInspection.java
@@ -0,0 +1,103 @@
+// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
+package com.intellij.codeInspection;
+
+import com.intellij.codeInsight.JavaProjectCodeInsightSettings;
+import com.intellij.codeInsight.intention.impl.AddOnDemandStaticImportAction;
+import com.intellij.java.JavaBundle;
+import com.intellij.modcommand.ModPsiUpdater;
+import com.intellij.modcommand.PsiUpdateModCommandQuickFix;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.util.text.StringUtil;
+import com.intellij.psi.*;
+import com.intellij.psi.codeStyle.JavaCodeStyleManager;
+import com.intellij.psi.util.PsiTreeUtil;
+import com.intellij.util.ObjectUtils;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+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());
+ List names = settings.getAllIncludedAutoStaticNames();
+ if (names.isEmpty()) {
+ return PsiElementVisitor.EMPTY_VISITOR;
+ }
+ Set shortNames = names.stream()
+ .map(name -> StringUtil.getShortName(name))
+ .collect(Collectors.toSet());
+ return new JavaElementVisitor() {
+ @Override
+ public void visitReferenceExpression(@NotNull PsiReferenceExpression expression) {
+ PsiElement reference = expression.getReferenceNameElement();
+ if (reference == null) return;
+ PsiExpression qualifierExpression = expression.getQualifierExpression();
+ if (!(qualifierExpression instanceof PsiReferenceExpression qualifierReferenceExpression)) return;
+ String name = qualifierReferenceExpression.getReferenceName();
+ PsiElement qualifierReference = qualifierReferenceExpression.getReferenceNameElement();
+ if (qualifierReference == null || name == null || !shortNames.contains(name)) return;
+ OnDemandStaticImportContext context = findOnDemandImportContext(expression);
+ if (context == null) return;
+ holder.registerProblem(qualifierReference,
+ JavaBundle.message("inspection.static.import.can.be.used.display.name"),
+ new OnDemandStaticImportFix());
+ }
+ };
+ }
+
+ private static class OnDemandStaticImportFix extends PsiUpdateModCommandQuickFix {
+ @Override
+ protected void applyFix(@NotNull Project project, @NotNull PsiElement element, @NotNull ModPsiUpdater updater) {
+ PsiElement parent = element.getParent();
+ if (!(parent instanceof PsiReferenceExpression referenceExpression)) {
+ return;
+ }
+ if (!(referenceExpression.getParent() instanceof PsiReferenceExpression targetReferenceExpression)) return;
+ JavaCodeStyleManager.getInstance(project).shortenClassReferences(targetReferenceExpression);
+ }
+
+ @Override
+ public @NotNull String getFamilyName() {
+ return JavaBundle.message("inspection.static.import.can.be.used.fix.name");
+ }
+ }
+
+ /**
+ * @param reference the reference expression to evaluate; must not be null.
+ * @return the {@link OnDemandStaticImportContext} if the reference can be on-demand static imported,
+ * or null if the criteria for such a context are not met.
+ */
+ @Nullable
+ public static OnDemandStaticImportContext findOnDemandImportContext(@NotNull PsiReferenceExpression reference) {
+ JavaCodeStyleManager javaCodeStyleManager = JavaCodeStyleManager.getInstance(reference.getProject());
+ PsiFile file = reference.getContainingFile();
+ if (!(file instanceof PsiJavaFile javaFile)) return null;
+ if (reference instanceof PsiMethodReferenceExpression) return null;
+ String memberName = reference.getReferenceName();
+ if (memberName == null) return null;
+ PsiJavaCodeReferenceElement qualifier = ObjectUtils.tryCast(reference.getQualifier(), PsiJavaCodeReferenceElement.class);
+ if (qualifier == null) return null;
+ if (GenericsUtil.isGenericReference(reference, qualifier)) return null;
+ if (PsiTreeUtil.getParentOfType(reference, PsiImportStatementBase.class) != null) return null;
+ if (!(qualifier.resolve() instanceof PsiClass psiClass)) return null;
+ String classQualifiedName = psiClass.getQualifiedName();
+ if (!javaCodeStyleManager.isStaticAutoImportClass(classQualifiedName)) return null;
+ PsiElement referenceNameElement = qualifier.getReferenceNameElement();
+ if (referenceNameElement == null) return null;
+ PsiClass anImport = AddOnDemandStaticImportAction.getClassToPerformStaticImport(referenceNameElement);
+ if (anImport == null) return null;
+ if (javaCodeStyleManager.hasConflictingOnDemandImport(javaFile, anImport, memberName)) return null;
+ PsiImportList importList = javaFile.getImportList();
+ if (importList == null) return null;
+ return new OnDemandStaticImportContext(anImport, memberName, importList);
+ }
+
+ public record OnDemandStaticImportContext(@NotNull PsiClass psiClass, @NotNull String memberName, @NotNull PsiImportList importList) {
+ }
+}
diff --git a/java/java-impl/src/com/intellij/psi/impl/source/codeStyle/ImportHelper.java b/java/java-impl/src/com/intellij/psi/impl/source/codeStyle/ImportHelper.java
index a41fd6885139..b19c4a072f2f 100644
--- a/java/java-impl/src/com/intellij/psi/impl/source/codeStyle/ImportHelper.java
+++ b/java/java-impl/src/com/intellij/psi/impl/source/codeStyle/ImportHelper.java
@@ -1004,6 +1004,43 @@ public final class ImportHelper {
return true;
}
}
+ JavaPsiFacade facade = JavaPsiFacade.getInstance(file.getProject());
+ PsiResolveHelper resolveHelper = facade.getResolveHelper();
+ for (Import anImport : resultList) {
+ if (anImport.isStatic()) {
+ String shortName = StringUtil.getShortName(anImport.name());
+ String prefix = StringUtil.getPackageName(anImport.name());
+ if (prefix.isEmpty()) continue;
+ PsiField field = psiClass.findFieldByName(shortName, true);
+ if (field != null &&
+ field.hasModifierProperty(PsiModifier.STATIC) &&
+ checkMemberAccessibility(field, resolveHelper, file, psiClass, prefix)) {
+ if (isOnDemandStaticImported(file, anImport)) {
+ return true;
+ }
+ }
+ else {
+ PsiClass inner = psiClass.findInnerClassByName(shortName, true);
+ if (inner != null &&
+ inner.hasModifierProperty(PsiModifier.STATIC) &&
+ checkMemberAccessibility(inner, resolveHelper, file, psiClass, prefix)) {
+ if (isOnDemandStaticImported(file, anImport)) {
+ return true;
+ }
+ }
+ else {
+ PsiMethod[] methods = psiClass.findMethodsByName(shortName, true);
+ if (ContainerUtil.exists(methods, psiMethod ->
+ psiMethod.hasModifierProperty(PsiModifier.STATIC) &&
+ checkMemberAccessibility(psiMethod, resolveHelper, file, psiClass, prefix))) {
+ if (isOnDemandStaticImported(file, anImport)) {
+ return true;
+ }
+ }
+ }
+ }
+ }
+ }
PsiImportList importList = file.getImportList();
if (importList == null) return false;
@@ -1022,6 +1059,21 @@ public final class ImportHelper {
return singleImports.contains(newImport);
}
+ private static boolean isOnDemandStaticImported(@NotNull PsiJavaFile file, @NotNull Import anImport) {
+ if(!anImport.isStatic()) return false;
+ PsiImportList importList = file.getImportList();
+ if(importList==null)return false;
+ for (PsiImportStaticStatement statement : importList.getImportStaticStatements()) {
+ if(!statement.isOnDemand()) return false;
+ String packageName = StringUtil.getPackageName(anImport.name);
+ if (statement.getImportReference() != null &&
+ packageName.equals(statement.getImportReference().getQualifiedName())) {
+ return true;
+ }
+ }
+ return false;
+ }
+
// returns list of (name, isImportStatic) pairs
private static @NotNull Collection collectNamesToImport(@NotNull PsiJavaFile file, @NotNull List super PsiElement> comments) {
Set imports = new HashSet<>();
diff --git a/java/java-impl/src/com/intellij/psi/impl/source/codeStyle/JavaReferenceAdjuster.java b/java/java-impl/src/com/intellij/psi/impl/source/codeStyle/JavaReferenceAdjuster.java
index bf4187ef4b7a..f87254e19c99 100644
--- a/java/java-impl/src/com/intellij/psi/impl/source/codeStyle/JavaReferenceAdjuster.java
+++ b/java/java-impl/src/com/intellij/psi/impl/source/codeStyle/JavaReferenceAdjuster.java
@@ -4,12 +4,11 @@ package com.intellij.psi.impl.source.codeStyle;
import com.intellij.application.options.CodeStyle;
import com.intellij.codeInsight.AnnotationTargetUtil;
import com.intellij.codeInsight.daemon.impl.analysis.JavaModuleGraphUtil;
-import com.intellij.codeInsight.intention.impl.AddOnDemandStaticImportAction;
+import com.intellij.codeInspection.StaticImportCanBeUsedInspection;
import com.intellij.lang.ASTNode;
import com.intellij.openapi.project.Project;
import com.intellij.psi.*;
import com.intellij.psi.codeStyle.CodeStyleSettings;
-import com.intellij.psi.codeStyle.JavaCodeStyleManager;
import com.intellij.psi.codeStyle.JavaCodeStyleSettings;
import com.intellij.psi.codeStyle.ReferenceAdjuster;
import com.intellij.psi.impl.PsiImplUtil;
@@ -22,7 +21,6 @@ import com.intellij.psi.jsp.JspFile;
import com.intellij.psi.tree.IElementType;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.psi.util.PsiUtil;
-import com.intellij.util.ObjectUtils;
import com.siyeh.ig.psiutils.CommentTracker;
import com.siyeh.ig.psiutils.ImportUtils;
import one.util.streamex.StreamEx;
@@ -139,27 +137,19 @@ public final class JavaReferenceAdjuster implements ReferenceAdjuster {
}
private static boolean tryAutoStaticallyImport(@NotNull PsiReferenceExpression reference) {
- JavaCodeStyleManager javaCodeStyleManager = JavaCodeStyleManager.getInstance(reference.getProject());
- PsiFile file = reference.getContainingFile();
- if (!(file instanceof PsiJavaFile javaFile)) return false;
- if (reference instanceof PsiMethodReferenceExpression) return false;
- String memberName = reference.getReferenceName();
- if (memberName == null) return false;
- PsiJavaCodeReferenceElement qualifier = ObjectUtils.tryCast(reference.getQualifier(), PsiJavaCodeReferenceElement.class);
- if (qualifier == null) return false;
- if (GenericsUtil.isGenericReference(reference, qualifier)) return false;
- if (PsiTreeUtil.getParentOfType(reference, PsiImportStatementBase.class) != null) return false;
- if (!(qualifier.resolve() instanceof PsiClass psiClass)) return false;
- String classQualifiedName = psiClass.getQualifiedName();
- if (!javaCodeStyleManager.isStaticAutoImportClass(classQualifiedName)) return false;
- PsiElement referenceNameElement = qualifier.getReferenceNameElement();
- if (referenceNameElement == null) return false;
- PsiClass anImport = AddOnDemandStaticImportAction.getClassToPerformStaticImport(referenceNameElement);
- if (anImport == null) return false;
- if (javaCodeStyleManager.hasConflictingOnDemandImport(javaFile, anImport, memberName)) return false;
- PsiImportList importList = javaFile.getImportList();
- if (importList == null) return false;
- PsiReferenceExpressionImpl.bindToElementViaStaticImport(anImport, memberName, importList);
+ StaticImportCanBeUsedInspection.OnDemandStaticImportContext context =
+ StaticImportCanBeUsedInspection.findOnDemandImportContext(reference);
+ if (context == null) return false;
+ PsiClass qualifierClass = context.psiClass();
+ String qualifiedName = qualifierClass.getQualifiedName();
+ List refs = PsiReferenceExpressionImpl.getImportsFromClass(context.importList(), qualifiedName);
+ for (PsiJavaCodeReferenceElement ref : refs) {
+ PsiImportStaticStatement importStatement = PsiTreeUtil.getParentOfType(ref, PsiImportStaticStatement.class);
+ if (importStatement != null) {
+ importStatement.delete();
+ }
+ }
+ context.importList().add(JavaPsiFacade.getElementFactory(qualifierClass.getProject()).createImportStaticStatement(qualifierClass, "*"));
return true;
}
diff --git a/java/java-impl/src/inspectionDescriptions/StaticImportCanBeUsed.html b/java/java-impl/src/inspectionDescriptions/StaticImportCanBeUsed.html
new file mode 100644
index 000000000000..468a95dd85ae
--- /dev/null
+++ b/java/java-impl/src/inspectionDescriptions/StaticImportCanBeUsed.html
@@ -0,0 +1,10 @@
+
+
+Reports qualifiers, which can be replaced with on-demand import static statements.
+The list of classes that will be checked can be configured in
+Settings | Editor | General | Auto Import | Java | Include auto-import of static members in
+ completion
+
+
+New in 2025.1
+
\ No newline at end of file
diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/java/PsiReferenceExpressionImpl.java b/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/java/PsiReferenceExpressionImpl.java
index 2afc8fce978c..7348583a6d6a 100644
--- a/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/java/PsiReferenceExpressionImpl.java
+++ b/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/java/PsiReferenceExpressionImpl.java
@@ -122,7 +122,15 @@ public class PsiReferenceExpressionImpl extends ExpressionPsiElement implements
}
}
- private static @NotNull List getImportsFromClass(@NotNull PsiImportList importList, String className) {
+ /**
+ * Retrieves the static import statements from the given import list that reference
+ * a specified class.
+ *
+ * @param importList the list of import statements in a Java file.
+ * @param className the fully qualified name of the class for which static imports are to be retrieved.
+ * @return a list of static import references corresponding to the specified class.
+ */
+ public static @NotNull List getImportsFromClass(@NotNull PsiImportList importList, String className) {
List array = new ArrayList<>();
for (PsiImportStaticStatement staticStatement : importList.getImportStaticStatements()) {
PsiClass psiClass = staticStatement.resolveTargetClass();
diff --git a/java/java-tests/testData/inspection/staticImportCanBeUsed/AlreadyImported.java b/java/java-tests/testData/inspection/staticImportCanBeUsed/AlreadyImported.java
new file mode 100644
index 000000000000..2e5dad0c42f1
--- /dev/null
+++ b/java/java-tests/testData/inspection/staticImportCanBeUsed/AlreadyImported.java
@@ -0,0 +1,11 @@
+package staticImportCanBeUsed;
+
+import java.util.Arrays;
+import static java.util.Arrays.sort;
+
+class Foo {
+ void test(String[] baz) {
+ Arrays.sort(baz);
+ Arrays.sort(baz);
+ }
+}
\ No newline at end of file
diff --git a/java/java-tests/testData/inspection/staticImportCanBeUsed/AlreadyImported_after.java b/java/java-tests/testData/inspection/staticImportCanBeUsed/AlreadyImported_after.java
new file mode 100644
index 000000000000..ca8e6e3ea88a
--- /dev/null
+++ b/java/java-tests/testData/inspection/staticImportCanBeUsed/AlreadyImported_after.java
@@ -0,0 +1,11 @@
+package staticImportCanBeUsed;
+
+import java.util.Arrays;
+import static java.util.Arrays.sort;
+
+class Foo {
+ void test(String[] baz) {
+ sort(baz);
+ sort(baz);
+ }
+}
\ No newline at end of file
diff --git a/java/java-tests/testData/inspection/staticImportCanBeUsed/Simple.java b/java/java-tests/testData/inspection/staticImportCanBeUsed/Simple.java
new file mode 100644
index 000000000000..427a84cd1f28
--- /dev/null
+++ b/java/java-tests/testData/inspection/staticImportCanBeUsed/Simple.java
@@ -0,0 +1,10 @@
+package staticImportCanBeUsed;
+
+import java.util.Arrays;
+
+class Foo {
+ void test(String[] baz) {
+ Arrays.sort(baz);
+ Arrays.sort(baz);
+ }
+}
\ No newline at end of file
diff --git a/java/java-tests/testData/inspection/staticImportCanBeUsed/Simple_after.java b/java/java-tests/testData/inspection/staticImportCanBeUsed/Simple_after.java
new file mode 100644
index 000000000000..013cd86257c1
--- /dev/null
+++ b/java/java-tests/testData/inspection/staticImportCanBeUsed/Simple_after.java
@@ -0,0 +1,12 @@
+package staticImportCanBeUsed;
+
+import java.util.Arrays;
+
+import static java.util.Arrays.*;
+
+class Foo {
+ void test(String[] baz) {
+ sort(baz);
+ sort(baz);
+ }
+}
\ No newline at end of file
diff --git a/java/java-tests/testData/inspection/staticImportCanBeUsed/WithConflicts.java b/java/java-tests/testData/inspection/staticImportCanBeUsed/WithConflicts.java
new file mode 100644
index 000000000000..d764e927603b
--- /dev/null
+++ b/java/java-tests/testData/inspection/staticImportCanBeUsed/WithConflicts.java
@@ -0,0 +1,12 @@
+package staticImportCanBeUsed;
+
+import java.util.Arrays;
+
+class Foo {
+ void test(String[] baz) {
+ Arrays.sort(baz);
+ Arrays.sort(baz);
+ }
+
+ public static void sort(String[] a) {}
+}
\ No newline at end of file
diff --git a/java/java-tests/testData/inspection/staticImportCanBeUsed/WithConflicts2.java b/java/java-tests/testData/inspection/staticImportCanBeUsed/WithConflicts2.java
new file mode 100644
index 000000000000..961476c2a974
--- /dev/null
+++ b/java/java-tests/testData/inspection/staticImportCanBeUsed/WithConflicts2.java
@@ -0,0 +1,13 @@
+package staticImportCanBeUsed;
+
+import java.util.Arrays;
+
+import static org.Foo2.*;
+
+class Foo {
+ void test(String[] baz) {
+ Arrays.sort(baz);
+ Arrays.sort(baz);
+ binarySearch(baz, "a");
+ }
+}
\ No newline at end of file
diff --git a/java/java-tests/testData/inspection/staticImportCanBeUsed/WithConflictsWithClass.java b/java/java-tests/testData/inspection/staticImportCanBeUsed/WithConflictsWithClass.java
new file mode 100644
index 000000000000..82649a16fe76
--- /dev/null
+++ b/java/java-tests/testData/inspection/staticImportCanBeUsed/WithConflictsWithClass.java
@@ -0,0 +1,13 @@
+package staticImportCanBeUsed;
+
+import org.Foo2;
+
+import static org.Foo3.*;
+
+class Foo {
+ void test(String[] baz) {
+ Foo2.sort(baz);
+ Foo2.sort(baz);
+ new Calculus();
+ }
+}
\ No newline at end of file
diff --git a/java/java-tests/testData/inspection/staticImportCanBeUsed/WithConflictsWithField.java b/java/java-tests/testData/inspection/staticImportCanBeUsed/WithConflictsWithField.java
new file mode 100644
index 000000000000..0c90113a32e6
--- /dev/null
+++ b/java/java-tests/testData/inspection/staticImportCanBeUsed/WithConflictsWithField.java
@@ -0,0 +1,13 @@
+package staticImportCanBeUsed;
+
+import org.Foo2;
+
+import static org.Foo3.*;
+
+class Foo {
+ void test(String[] baz) {
+ Foo2.sort(baz);
+ Foo2.sort(baz);
+ System.out.println(PI);
+ }
+}
\ No newline at end of file
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
new file mode 100644
index 000000000000..894dad510c2c
--- /dev/null
+++ b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/impl/quickfix/StaticImportCanBeUsedInspectionTest.java
@@ -0,0 +1,122 @@
+// Copyright 2000-2025 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.quickfix;
+
+import com.intellij.JavaTestUtil;
+import com.intellij.analysis.AnalysisBundle;
+import com.intellij.codeInsight.JavaProjectCodeInsightSettings;
+import com.intellij.codeInsight.intention.IntentionAction;
+import com.intellij.codeInspection.InspectionProfileEntry;
+import com.intellij.codeInspection.StaticImportCanBeUsedInspection;
+import com.siyeh.ig.LightJavaInspectionTestCase;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+
+public class StaticImportCanBeUsedInspectionTest extends LightJavaInspectionTestCase {
+
+ @Override
+ public void tearDown() throws Exception {
+ try {
+ JavaProjectCodeInsightSettings.getSettings(getProject()).includedAutoStaticNames.clear();
+ }
+ catch (Throwable e) {
+ addSuppressedException(e);
+ }
+ finally {
+ super.tearDown();
+ }
+ }
+
+ @Nullable
+ @Override
+ protected InspectionProfileEntry getInspection() {
+ return new StaticImportCanBeUsedInspection();
+ }
+
+ public void testSimple() {
+ addStaticAutoImport("java.util.Arrays");
+ doTest();
+ cleanupTest();
+ }
+
+ public void testWithConflicts() {
+ addStaticAutoImport("java.util.Arrays");
+ doTest();
+ }
+
+ public void testWithConflicts2() {
+ addStaticAutoImport("java.util.Arrays");
+ myFixture.addClass("""
+ package org;
+
+ public final class Foo2 {
+ public static void binarySearch(Object[] args, Object key) {}
+ }
+ """);
+ doTest();
+ }
+
+ public void testWithConflictsWithField() {
+ addStaticAutoImport("org.Foo2");
+ myFixture.addClass("""
+ package org;
+
+ public final class Foo2 {
+ public static final String PI = "3.14"
+ public static void sort(String[] args) {}
+ }
+ """);
+ myFixture.addClass("""
+ package org;
+
+ public final class Foo3 {
+ public static final String PI = "3.14"
+ }
+ """);
+ doTest();
+ }
+
+ public void testWithConflictsWithClass() {
+ addStaticAutoImport("org.Foo2");
+ myFixture.addClass("""
+ package org;
+
+ public final class Foo2 {
+ public static class Calculus{}
+ public static void sort(String[] args) {}
+ }
+ """);
+ myFixture.addClass("""
+ package org;
+
+ public final class Foo3 {
+ public static class Calculus{}
+ }
+ """);
+ doTest();
+ }
+
+ public void testAlreadyImported() {
+ addStaticAutoImport("java.util.Arrays");
+ doTest();
+ cleanupTest();
+ }
+
+ //todo test for inner class and for field
+
+ private void cleanupTest() {
+ IntentionAction intention = myFixture.getAvailableIntention(AnalysisBundle.message("cleanup.in.file"));
+ myFixture.launchAction(intention);
+ myFixture.checkResultByFile(getTestName(false) + "_after.java");
+ }
+
+ @Override
+ protected String getBasePath() {
+ return JavaTestUtil.getRelativeJavaTestDataPath() + "/inspection/staticImportCanBeUsed/";
+ }
+
+ @SuppressWarnings("SameParameterValue")
+ private void addStaticAutoImport(@NotNull String name) {
+ JavaProjectCodeInsightSettings.getSettings(getProject()).includedAutoStaticNames.add(name);
+ }
+}
diff --git a/java/openapi/resources/messages/JavaBundle.properties b/java/openapi/resources/messages/JavaBundle.properties
index 5d11ed908432..37fe1afda3d1 100644
--- a/java/openapi/resources/messages/JavaBundle.properties
+++ b/java/openapi/resources/messages/JavaBundle.properties
@@ -1429,6 +1429,8 @@ inspection.slow.abstract.set.remove.all.fix.family.name=Use 'Set.remove' instead
inspection.slow.list.contains.all.description=Call to 'list.containsAll(collection)' may have poor performance
inspection.slow.list.contains.all.fix.family.name=Wrap in 'HashSet' constructor
inspection.slow.list.contains.all.fix.name=Wrap ''{0}'' in ''HashSet'' constructor
+inspection.static.import.can.be.used.display.name=On-demand static import can be used
+inspection.static.import.can.be.used.fix.name=Add on-demand static import
slice.filter.parse.error.null.filter.not.applicable.for.primitive.type=''null'' filter is not applicable for primitive type {0}
slice.filter.parse.error.not.null.filter.not.applicable.for.primitive.type=''!null'' filter is not applicable for primitive type {0}
slice.filter.parse.error.enum.constant.not.found=Enum constant not found: {0}