From 6d101f8467e265a4629f782ff1315ef740be7809 Mon Sep 17 00:00:00 2001 From: Mikhail Pyltsin Date: Tue, 23 Jul 2024 12:15:58 +0200 Subject: [PATCH] [java-inspection] IDEA-356699 Support JEP 477. UnusedImportInspection doesn't support implicit imports and modules GitOrigin-RevId: b3fbb9aea04067e704e3ef3dba9e16262e33b0c6 --- .../unusedImport/ImportsAreUsedVisitor.java | 13 +++++ .../unusedImport/UnusedImportInspection.java | 10 +++- .../ImplicitLangImport/expected.xml | 9 ++++ .../expected.xml | 9 ++++ .../RedundantModuleImport/expected.xml | 9 ++++ .../UnusedImportGlobalInspectionTest.java | 49 +++++++++++++++++++ 6 files changed, 98 insertions(+), 1 deletion(-) create mode 100644 java/java-tests/testData/ig/com/siyeh/igtest/imports/globalInspection/ImplicitLangImport/expected.xml create mode 100644 java/java-tests/testData/ig/com/siyeh/igtest/imports/globalInspection/RedundantImportWithImplicitClass/expected.xml create mode 100644 java/java-tests/testData/ig/com/siyeh/igtest/imports/globalInspection/RedundantModuleImport/expected.xml diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/unusedImport/ImportsAreUsedVisitor.java b/java/java-analysis-impl/src/com/intellij/codeInspection/unusedImport/ImportsAreUsedVisitor.java index 6d4909058269..e69b7c5f95bf 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInspection/unusedImport/ImportsAreUsedVisitor.java +++ b/java/java-analysis-impl/src/com/intellij/codeInspection/unusedImport/ImportsAreUsedVisitor.java @@ -20,6 +20,7 @@ import com.intellij.psi.*; import com.intellij.psi.util.InheritanceUtil; import com.siyeh.ig.psiutils.ImportUtils; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import java.util.ArrayList; import java.util.Arrays; @@ -31,6 +32,7 @@ class ImportsAreUsedVisitor extends JavaRecursiveElementWalkingVisitor { private final PsiJavaFile myFile; private final List importStatements; private final List usedImportStatements = new ArrayList<>(); + private final List implicitlyUsedImportStatements = new ArrayList<>(); ImportsAreUsedVisitor(@NotNull PsiJavaFile file) { myFile = file; @@ -40,6 +42,7 @@ class ImportsAreUsedVisitor extends JavaRecursiveElementWalkingVisitor { } else { final PsiImportStatementBase[] importStatements = importList.getAllImportStatements(); this.importStatements = new ArrayList<>(Arrays.asList(importStatements)); + this.implicitlyUsedImportStatements.addAll(ImportUtils.getAllImplicitImports(file)); this.importStatements.sort(ImportStatementComparator.getInstance()); } } @@ -84,6 +87,9 @@ class ImportsAreUsedVisitor extends JavaRecursiveElementWalkingVisitor { if (findImport(member, usedImportStatements) != null) { return; } + if (findImport(member, implicitlyUsedImportStatements) != null) { + return; + } final PsiImportStatementBase foundImport = findImport(member, importStatements); if (foundImport != null) { importStatements.remove(foundImport); @@ -91,6 +97,7 @@ class ImportsAreUsedVisitor extends JavaRecursiveElementWalkingVisitor { } } + @Nullable private PsiImportStatementBase findImport(@NotNull PsiMember member, List importStatements) { final String memberQualifiedName; final String memberPackageName; @@ -127,6 +134,12 @@ class ImportsAreUsedVisitor extends JavaRecursiveElementWalkingVisitor { if (hasOnDemandImportConflict) { continue; } + if (importStatement instanceof PsiImportModuleStatement psiImportModuleStatement && + !member.hasModifierProperty(PsiModifier.STATIC)) { + if (psiImportModuleStatement.findImportedPackage(memberPackageName) != null) { + return importStatement; + } + } final PsiElement target = importStatement.resolve(); if (target instanceof PsiPackage aPackage) { if (memberPackageName.equals(aPackage.getQualifiedName())) { diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/unusedImport/UnusedImportInspection.java b/java/java-analysis-impl/src/com/intellij/codeInspection/unusedImport/UnusedImportInspection.java index e343e9273731..f950e90d49e0 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInspection/unusedImport/UnusedImportInspection.java +++ b/java/java-analysis-impl/src/com/intellij/codeInspection/unusedImport/UnusedImportInspection.java @@ -39,8 +39,16 @@ public final class UnusedImportInspection extends GlobalSimpleInspectionTool { if (!(file instanceof PsiJavaFile javaFile) || FileTypeUtils.isInServerPageFile(file)) return; final ImportsAreUsedVisitor visitor = new ImportsAreUsedVisitor(javaFile); javaFile.accept(visitor); + PsiPolyVariantReference reference; for (PsiImportStatementBase unusedImportStatement : visitor.getUnusedImportStatements()) { - PsiJavaCodeReferenceElement reference = unusedImportStatement.getImportReference(); + if (unusedImportStatement instanceof PsiImportModuleStatement moduleStatement) { + PsiJavaModuleReferenceElement moduleReference = moduleStatement.getModuleReference(); + if (moduleReference == null) continue; + reference = moduleReference.getReference(); + } + else { + reference = unusedImportStatement.getImportReference(); + } if (reference != null && reference.multiResolve(false).length > 0 && !(PsiTreeUtil.skipWhitespacesForward(unusedImportStatement) instanceof PsiErrorElement)) { diff --git a/java/java-tests/testData/ig/com/siyeh/igtest/imports/globalInspection/ImplicitLangImport/expected.xml b/java/java-tests/testData/ig/com/siyeh/igtest/imports/globalInspection/ImplicitLangImport/expected.xml new file mode 100644 index 000000000000..b536a8fc97b1 --- /dev/null +++ b/java/java-tests/testData/ig/com/siyeh/igtest/imports/globalInspection/ImplicitLangImport/expected.xml @@ -0,0 +1,9 @@ + + + + Main.java + 3 + Unused import + Unused import <code>import java.lang.String;</code> #loc + + \ No newline at end of file diff --git a/java/java-tests/testData/ig/com/siyeh/igtest/imports/globalInspection/RedundantImportWithImplicitClass/expected.xml b/java/java-tests/testData/ig/com/siyeh/igtest/imports/globalInspection/RedundantImportWithImplicitClass/expected.xml new file mode 100644 index 000000000000..e122b36c0b3c --- /dev/null +++ b/java/java-tests/testData/ig/com/siyeh/igtest/imports/globalInspection/RedundantImportWithImplicitClass/expected.xml @@ -0,0 +1,9 @@ + + + + a.java + 1 + Unused import + Unused import <code>import java.util.List;/**/</code> #loc + + \ No newline at end of file diff --git a/java/java-tests/testData/ig/com/siyeh/igtest/imports/globalInspection/RedundantModuleImport/expected.xml b/java/java-tests/testData/ig/com/siyeh/igtest/imports/globalInspection/RedundantModuleImport/expected.xml new file mode 100644 index 000000000000..23ac85ee646b --- /dev/null +++ b/java/java-tests/testData/ig/com/siyeh/igtest/imports/globalInspection/RedundantModuleImport/expected.xml @@ -0,0 +1,9 @@ + + + + Main.java + 1 + Unused import + Unused import <code>import module java.base;</code> #loc + + \ No newline at end of file diff --git a/java/java-tests/testSrc/com/siyeh/ig/imports/UnusedImportGlobalInspectionTest.java b/java/java-tests/testSrc/com/siyeh/ig/imports/UnusedImportGlobalInspectionTest.java index dd8060216586..c04b36d08304 100644 --- a/java/java-tests/testSrc/com/siyeh/ig/imports/UnusedImportGlobalInspectionTest.java +++ b/java/java-tests/testSrc/com/siyeh/ig/imports/UnusedImportGlobalInspectionTest.java @@ -6,10 +6,14 @@ import com.intellij.codeInspection.ex.GlobalInspectionToolWrapper; import com.intellij.codeInspection.ex.InspectionToolWrapper; import com.intellij.codeInspection.unusedImport.UnusedImportInspection; import com.intellij.openapi.application.ex.PathManagerEx; +import com.intellij.pom.java.JavaFeature; +import com.intellij.testFramework.IdeaTestUtil; import com.intellij.testFramework.InspectionTestUtil; import com.intellij.testFramework.InspectionsKt; +import com.intellij.testFramework.LightProjectDescriptor; import com.intellij.testFramework.fixtures.LightJavaCodeInsightFixtureTestCase; import com.intellij.testFramework.fixtures.impl.GlobalInspectionContextForTests; +import org.jetbrains.annotations.NotNull; import java.io.File; import java.util.Collections; @@ -20,6 +24,11 @@ public class UnusedImportGlobalInspectionTest extends LightJavaCodeInsightFixtur return PathManagerEx.getCommunityHomePath() + "/java/java-tests/testData/ig/com/siyeh/igtest/imports/globalInspection"; } + @Override + protected @NotNull LightProjectDescriptor getProjectDescriptor() { + return JAVA_23; + } + public void testInnerClassImport() { myFixture.addClass(""" package pkg; @@ -224,6 +233,7 @@ public class UnusedImportGlobalInspectionTest extends LightJavaCodeInsightFixtur public void testNoWarn() { myFixture.addClass("package java.awt; public class List extends Component {}"); + myFixture.addClass("package java.awt; public class Component {}"); doTest(""" import javax.swing.*; import java.awt.*; @@ -290,6 +300,45 @@ public class UnusedImportGlobalInspectionTest extends LightJavaCodeInsightFixtur doTest(); } + public void testRedundantModuleImport() { + doTest(""" + /*Unused import 'import module java.base;'*/import module java.base;/**/ + import java.util.List; + import java.util.ArrayList; + + class Main { + public static void main(String[] args) { + List a = new ArrayList<>(); + } + }"""); + } + + public void testImplicitLangImport() { + doTest(""" + import java.util.List; + import java.util.ArrayList; + /*Unused import 'import java.lang.String;'*/import java.lang.String;/**/ + + class Main { + public static void main(String[] args) { + List a = new ArrayList<>(); + } + }"""); + } + + public void testRedundantImportWithImplicitClass() { + IdeaTestUtil.withLevel(getModule(), JavaFeature.IMPLICIT_IMPORT_IN_IMPLICIT_CLASSES.getMinimumLevel(), + () -> { + doTest(""" + /*Unused import 'import java.util.List;'*/import java.util.List;/**/ + + public static void main(String[] args) { + List a = new ArrayList<>(); + } + """); + }); + } + private void doTest(String classText) { myFixture.addClass(classText);