[java-inspection] IDEA-356699 Support JEP 477. UnusedImportInspection doesn't support implicit imports and modules

GitOrigin-RevId: b3fbb9aea04067e704e3ef3dba9e16262e33b0c6
This commit is contained in:
Mikhail Pyltsin
2024-07-25 09:33:08 +00:00
committed by intellij-monorepo-bot
parent ee4964a9a9
commit 6d101f8467
6 changed files with 98 additions and 1 deletions
@@ -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<PsiImportStatementBase> importStatements;
private final List<PsiImportStatementBase> usedImportStatements = new ArrayList<>();
private final List<PsiImportStatementBase> 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<? extends PsiImportStatementBase> 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())) {
@@ -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)) {
@@ -0,0 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<problems>
<problem>
<file>Main.java</file>
<line>3</line>
<problem_class id="UNUSED_IMPORT" severity="WARNING" attribute_key="WARNING_ATTRIBUTES">Unused import</problem_class>
<description>Unused import &lt;code&gt;import java.lang.String;&lt;/code&gt; #loc</description>
</problem>
</problems>
@@ -0,0 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<problems>
<problem>
<file>a.java</file>
<line>1</line>
<problem_class severity="WARNING" attribute_key="WARNING_ATTRIBUTES">Unused import</problem_class>
<description>Unused import &lt;code&gt;import java.util.List;/**/&lt;/code&gt; #loc</description>
</problem>
</problems>
@@ -0,0 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<problems>
<problem>
<file>Main.java</file>
<line>1</line>
<problem_class severity="WARNING" attribute_key="WARNING_ATTRIBUTES">Unused import</problem_class>
<description>Unused import &lt;code&gt;import module java.base;&lt;/code&gt; #loc</description>
</problem>
</problems>
@@ -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<String> 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<String> 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<String> a = new ArrayList<>();
}
""");
});
}
private void doTest(String classText) {
myFixture.addClass(classText);