[java-import] IDEA-369199 Preserve module imports even if they are not used

- new options
- don't highlight such imports as unused
- delete imports of nested modules
- preserve high-level modules during 'optimize import'

GitOrigin-RevId: 3728f41a934f320767caac0a643a5869ccc84bcc
This commit is contained in:
Mikhail Pyltsin
2025-05-14 20:29:11 +00:00
committed by intellij-monorepo-bot
parent 66b1e9b6e5
commit cebd8c18cd
87 changed files with 2046 additions and 24 deletions
@@ -1,4 +1,4 @@
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
// 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.analysis;
import com.intellij.codeInsight.daemon.HighlightDisplayKey;
@@ -29,11 +29,14 @@ import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.profile.codeInspection.InspectionProjectProfileManager;
import com.intellij.psi.*;
import com.intellij.psi.codeStyle.JavaCodeStyleManager;
import com.intellij.psi.codeStyle.JavaCodeStyleSettings;
import com.intellij.psi.util.PsiUtilCore;
import com.intellij.util.ObjectUtils;
import com.siyeh.ig.psiutils.ImportUtils;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.List;
import java.util.Set;
import java.util.function.Function;
@@ -166,6 +169,13 @@ class UnusedImportsVisitor extends JavaElementVisitor {
}
}
}
if (isRedundant && importStatement instanceof PsiImportModuleStatement moduleStatement &&
!JavaCodeStyleSettings.getInstance(javaFile).isDeleteUnusedModuleImports()) {
List<PsiImportModuleStatement> moduleStatements = ImportUtils.optimizeModuleImports(javaFile);
if (moduleStatements.contains(moduleStatement)) {
return false;
}
}
return isRedundant;
}
@@ -17,14 +17,13 @@ package com.intellij.codeInspection.unusedImport;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.psi.*;
import com.intellij.psi.codeStyle.JavaCodeStyleSettings;
import com.intellij.util.containers.ContainerUtil;
import com.siyeh.ig.psiutils.ImportUtils;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.*;
import static com.intellij.psi.util.ImportsUtil.getAllImplicitImports;
@@ -34,17 +33,30 @@ class ImportsAreUsedVisitor extends JavaRecursiveElementWalkingVisitor {
private final List<PsiImportStatementBase> importStatements;
private final List<PsiImportStatementBase> usedImportStatements = new ArrayList<>();
private final List<PsiImportStatementBase> implicitlyUsedImportStatements = new ArrayList<>();
private final Set<PsiImportStatementBase> highLevelModuleImports = new HashSet<>();
private final JavaCodeStyleSettings settings;
ImportsAreUsedVisitor(@NotNull PsiJavaFile file) {
myFile = file;
settings = JavaCodeStyleSettings.getInstance(file);
final PsiImportList importList = file.getImportList();
if (importList == null) {
importStatements = Collections.emptyList();
} else {
}
else {
final PsiImportStatementBase[] importStatements = importList.getAllImportStatements();
this.importStatements = new ArrayList<>(Arrays.asList(importStatements));
this.implicitlyUsedImportStatements.addAll(getAllImplicitImports(file));
this.importStatements.sort(ImportStatementComparator.getInstance());
highLevelModuleImports.addAll(ImportUtils.optimizeModuleImports(myFile));
List<PsiImportStatementBase> unusedModuleImports =
ContainerUtil.filter(this.importStatements,
t -> t instanceof PsiImportModuleStatement importModuleStatement &&
!highLevelModuleImports.contains(importModuleStatement));
this.importStatements.removeAll(unusedModuleImports);
this.importStatements.addAll(unusedModuleImports);
}
}
@@ -178,6 +190,10 @@ class ImportsAreUsedVisitor extends JavaRecursiveElementWalkingVisitor {
if (importStatements.isEmpty()) {
return PsiImportStatementBase.EMPTY_ARRAY;
}
if (!settings.isDeleteUnusedModuleImports()) {
importStatements.removeAll(highLevelModuleImports);
}
return importStatements.toArray(PsiImportStatementBase.EMPTY_ARRAY);
}
}
@@ -23,6 +23,7 @@ import com.intellij.openapi.util.text.StringUtil;
import com.intellij.pom.java.JavaFeature;
import com.intellij.psi.*;
import com.intellij.psi.codeStyle.JavaFileCodeStyleFacade;
import com.intellij.psi.impl.source.resolve.JavaResolveUtil;
import com.intellij.psi.search.GlobalSearchScope;
import com.intellij.psi.search.PsiShortNamesCache;
import com.intellij.psi.util.*;
@@ -858,6 +859,48 @@ public final class ImportUtils {
return conflictingRef.booleanValue();
}
/**
* Optimizes the module imports within the specified Java file by removing module import statements,
* which are included in other module import statements.
*
* @param file the Java file for which module imports need to be optimized
* @return a list of optimized module import statements.
*/
@NotNull
public static List<PsiImportModuleStatement> optimizeModuleImports(@NotNull PsiJavaFile file) {
return CachedValuesManager.getCachedValue(file, () -> {
PsiImportList importList = file.getImportList();
if (importList == null) {
return new CachedValueProvider.Result<>(List.of(), PsiModificationTracker.MODIFICATION_COUNT);
}
List<PsiImportModuleStatement> statements = Arrays.asList((importList.getImportModuleStatements()));
List<PsiImportModuleStatement> implicit =
ContainerUtil.filterIsInstance(getAllImplicitImports(file), PsiImportModuleStatement.class);
List<PsiImportModuleStatement> results = new ArrayList<>(statements);
Map<PsiImportModuleStatement, PsiJavaModule> modules = new HashMap<>();
Map<PsiJavaModule, Set<PsiJavaModule>> dependencies = new HashMap<>();
Set<PsiImportModuleStatement> toDelete = new HashSet<>();
for (PsiImportModuleStatement current : statements) {
PsiJavaModule currentModule = modules.computeIfAbsent(current, m -> m.resolveTargetModule());
if (currentModule == null) continue;
for (PsiImportModuleStatement higher : ContainerUtil.concat(implicit, statements)) {
if(toDelete.contains(higher)) continue;
if (higher == current) continue;
PsiJavaModule higherModule = modules.computeIfAbsent(higher, m -> m.resolveTargetModule());
if (higherModule == null) continue;
Set<PsiJavaModule> higherDependencies =
dependencies.computeIfAbsent(higherModule, m -> JavaResolveUtil.getAllTransitiveModulesIncludeCurrent(m));
if (higherDependencies.contains(currentModule)) {
toDelete.add(current);
break;
}
}
}
results.removeAll(toDelete);
return new CachedValueProvider.Result<>(results, PsiModificationTracker.MODIFICATION_COUNT);
});
}
private static class ConflictingClassReferenceVisitor extends JavaRecursiveElementWalkingVisitor {
private final String name;
@@ -43,7 +43,8 @@ checkbox.spaces.before.deconstruction.list=Deconstruction list
checkbox.spaces.inside.one.line.enum=Inside one line enum braces
checkbox.use.fully.qualified.class.names=Use fully qualified class names
checkbox.use.single.class.import=Use single class import
checkbox.preserve.module.import=Preserve module imports
checkbox.no.separate.module.import=Do not separate module imports into single or package imports
checkbox.delete.unused.module.import=Delete unused module imports
checkbox.use.throws.rather.than.exception=Use @throws rather than @exception
checkbox.wrap.at.right.margin=Wrap at right margin
@@ -21,6 +21,7 @@ import java.util.List;
class JavaCodeStyleImportsPanel extends CodeStyleImportsPanelBase {
private FullyQualifiedNamesInJavadocOptionProvider myFqnInJavadocOption;
private @Nullable JCheckBox myCbPreserveModuleImports;
private @Nullable JCheckBox myCbDeleteUnusedModuleImports;
private ListTableModel<InnerClassItem> doNotInsertInnerListModel;
private static final ColumnInfo<?, ?>[] INNER_CLASS_COLUMNS = {
@@ -45,10 +46,11 @@ class JavaCodeStyleImportsPanel extends CodeStyleImportsPanelBase {
@Override
protected CodeStyleImportsBaseUI createKotlinUI(JComponent packages, JComponent importLayout) {
createDoNotImportInnerList();
myCbPreserveModuleImports = new JBCheckBox(JavaFrontbackBundle.message("checkbox.preserve.module.import"));
myCbPreserveModuleImports = new JBCheckBox(JavaFrontbackBundle.message("checkbox.no.separate.module.import"));
myCbDeleteUnusedModuleImports = new JBCheckBox(JavaFrontbackBundle.message("checkbox.delete.unused.module.import"));
myFqnInJavadocOption = new FullyQualifiedNamesInJavadocOptionProvider();
JavaCodeStyleImportsUI result =
new JavaCodeStyleImportsUI(packages, importLayout, mydoNotInsertInnerTable, myCbPreserveModuleImports, myFqnInJavadocOption.getPanel());
new JavaCodeStyleImportsUI(packages, importLayout, mydoNotInsertInnerTable, myCbPreserveModuleImports, myCbDeleteUnusedModuleImports, myFqnInJavadocOption.getPanel());
result.init();
return result;
}
@@ -60,6 +62,8 @@ class JavaCodeStyleImportsPanel extends CodeStyleImportsPanelBase {
myFqnInJavadocOption.apply(settings);
JCheckBox cbPreserveModuleImports = myCbPreserveModuleImports;
if(cbPreserveModuleImports!=null) javaSettings.setPreserveModuleImports(cbPreserveModuleImports.isSelected());
JCheckBox cbDeleteUnusedModuleImports = myCbDeleteUnusedModuleImports;
if(cbDeleteUnusedModuleImports!=null) javaSettings.setDeleteUnusedModuleImports(cbDeleteUnusedModuleImports.isSelected());
javaSettings.setDoNotImportInner(getInnerClassesNames());
javaSettings.setLayoutOnDemandImportFromSamePackageFirst(myImportLayoutPanel.isLayoutOnDemandImportsFromSamePackageFirst());
}
@@ -76,6 +80,9 @@ class JavaCodeStyleImportsPanel extends CodeStyleImportsPanelBase {
JCheckBox cbPreserveModuleImports = myCbPreserveModuleImports;
if (cbPreserveModuleImports != null) cbPreserveModuleImports.setSelected(javaSettings.isPreserveModuleImports());
JCheckBox cbDeleteUnusedModuleImports = myCbDeleteUnusedModuleImports;
if (cbDeleteUnusedModuleImports != null) cbDeleteUnusedModuleImports.setSelected(javaSettings.isDeleteUnusedModuleImports());
JBCheckBox cbLayoutOnDemandImportsFromSamePackageFirst = myImportLayoutPanel.getCbLayoutOnDemandImportsFromSamePackageFirst();
if (cbLayoutOnDemandImportsFromSamePackageFirst != null) cbLayoutOnDemandImportsFromSamePackageFirst.setSelected(javaSettings.isLayoutOnDemandImportFromSamePackageFirst());
}
@@ -88,10 +95,13 @@ class JavaCodeStyleImportsPanel extends CodeStyleImportsPanelBase {
isModified |= !javaSettings.getDoNotImportInner().equals(getInnerClassesNames());
JCheckBox cbPreserveModuleImports = myCbPreserveModuleImports;
if (cbPreserveModuleImports != null) isModified |= CodeStyleImportsPanelBase.isModified(cbPreserveModuleImports, javaSettings.isPreserveModuleImports());
if (cbPreserveModuleImports != null) isModified |= isModified(cbPreserveModuleImports, javaSettings.isPreserveModuleImports());
JCheckBox cbDeleteUnusedModuleImports = myCbDeleteUnusedModuleImports;
if (cbDeleteUnusedModuleImports != null) isModified |= isModified(cbDeleteUnusedModuleImports, javaSettings.isDeleteUnusedModuleImports());
JBCheckBox cbLayoutOnDemandImportsFromSamePackageFirst = myImportLayoutPanel.getCbLayoutOnDemandImportsFromSamePackageFirst();
if (cbLayoutOnDemandImportsFromSamePackageFirst != null) isModified |= CodeStyleImportsPanelBase.isModified(cbLayoutOnDemandImportsFromSamePackageFirst, javaSettings.isLayoutOnDemandImportFromSamePackageFirst());
if (cbLayoutOnDemandImportsFromSamePackageFirst != null) isModified |= isModified(cbLayoutOnDemandImportsFromSamePackageFirst, javaSettings.isLayoutOnDemandImportFromSamePackageFirst());
return isModified;
}
@@ -1,4 +1,4 @@
// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
// 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.application.options
import com.intellij.application.options.JavaCodeStyleImportsPanel.InnerClassItem
@@ -19,6 +19,7 @@ internal class JavaCodeStyleImportsUI(packages: JComponent,
importLayout: JComponent,
private val doNotInsertInnerTable: TableView<InnerClassItem>,
private val preserveModuleImports: JCheckBox,
private val deleteUnusedModuleImports: JCheckBox,
private val fqnInJavadocOption: JComponent) : CodeStyleImportsBaseUI(packages, importLayout) {
override fun init() {
@@ -34,6 +35,11 @@ internal class JavaCodeStyleImportsUI(packages: JComponent,
isOpaque = false
}
}
row {
cell(deleteUnusedModuleImports).applyToComponent {
isOpaque = false
}
}
indent {
row {
val decorator = ToolbarDecorator.createDecorator(doNotInsertInnerTable)
@@ -1,4 +1,4 @@
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
// 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.psi.codeStyle;
import com.intellij.application.options.CodeStyle;
@@ -177,6 +177,7 @@ public class JavaCodeStyleSettings extends CustomCodeStyleSettings implements Im
public boolean LAYOUT_STATIC_IMPORTS_SEPARATELY = true;
public boolean LAYOUT_ON_DEMAND_IMPORT_FROM_SAME_PACKAGE_FIRST = true;
public boolean PRESERVE_MODULE_IMPORTS = true;
public boolean DELETE_UNUSED_MODULE_IMPORTS = false;
public boolean USE_FQ_CLASS_NAMES;
public boolean USE_SINGLE_CLASS_IMPORTS = true;
public boolean INSERT_INNER_CLASS_IMPORTS;
@@ -363,6 +364,14 @@ public class JavaCodeStyleSettings extends CustomCodeStyleSettings implements Im
PRESERVE_MODULE_IMPORTS = value;
}
public boolean isDeleteUnusedModuleImports() {
return DELETE_UNUSED_MODULE_IMPORTS;
}
public void setDeleteUnusedModuleImports(boolean value) {
this.DELETE_UNUSED_MODULE_IMPORTS = value;
}
@Override
public void setUseSingleClassImports(boolean value) {
USE_SINGLE_CLASS_IMPORTS = value;
@@ -1,4 +1,4 @@
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
// 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.psi.impl.source.codeStyle;
import com.intellij.application.options.CodeStyle;
@@ -124,7 +124,11 @@ public final class ImportHelper extends ImportHelperBase {
ImportUtils.ImplicitImportChecker checker = ImportUtils.createImplicitImportChecker(file);
Set<String> classesToUseSingle = findSingleImports(file, resultList, classesOrPackagesToImportOnDemand.keySet(),
moduleStatementMap.keySet(), checker);
Set<String> toReimport = calculateOnDemandImportConflicts(file, classesOrPackagesToImportOnDemand, moduleStatementMap.values(),
Collection<PsiImportModuleStatement> moduleImports =
mySettings.isDeleteUnusedModuleImports() ? moduleStatementMap.values() : previousModuleStatements;
Set<String> toReimport = calculateOnDemandImportConflicts(file, classesOrPackagesToImportOnDemand, moduleImports,
moduleStatementMap.keySet());
classesToUseSingle.addAll(toReimport);
@@ -138,6 +142,7 @@ public final class ImportHelper extends ImportHelperBase {
classesToUseSingle,
checker,
moduleStatementMap,
previousModuleStatements,
onDemandFirst,
items.moduleIndex());
for (PsiElement nonImport : nonImports) {
@@ -199,9 +204,8 @@ public final class ImportHelper extends ImportHelperBase {
private static @NotNull Map<String, PsiImportModuleStatement> collectNamesImportedByModules(@NotNull PsiJavaFile file,
@NotNull List<PsiImportModuleStatement> statements,
@NotNull List<Import> list) {
List<PsiImportStatementBase> implicitImports = ImportsUtil.getAllImplicitImports(file);
List<PsiImportModuleStatement> moduleImports =
new ArrayList<>(ContainerUtil.filterIsInstance(implicitImports, PsiImportModuleStatement.class));
new ArrayList<>(ContainerUtil.filterIsInstance(ImportsUtil.getAllImplicitImports(file), PsiImportModuleStatement.class));
moduleImports.addAll(statements);
Map<String, PsiImportModuleStatement> usedClasses = new HashMap<>();
@@ -227,6 +231,7 @@ public final class ImportHelper extends ImportHelperBase {
/**
* Collects the module import statements from the specified Java file, considering the code style settings, to insert in the new import list
* If there are two modules, one of which (parent) includes another, only this parent will be taken
*
* @param file the Java file from which module import statements are collected.
* @param settings the code style settings that determine whether module imports should be preserved.
@@ -236,7 +241,7 @@ public final class ImportHelper extends ImportHelperBase {
if (!settings.isPreserveModuleImports()) return Collections.emptyList();
PsiImportList importList = file.getImportList();
if (importList == null) return Collections.emptyList();
return Arrays.asList(importList.getImportModuleStatements());
return ImportUtils.optimizeModuleImports(file);
}
public static void collectOnDemandImports(@NotNull List<Import> resultList,
@@ -504,11 +509,12 @@ public final class ImportHelper extends ImportHelperBase {
return result;
}
private static @NotNull StringBuilder buildImportListText(@NotNull List<Import> imports,
private @NotNull StringBuilder buildImportListText(@NotNull List<Import> imports,
@NotNull Set<String> packagesOrClassesToImportOnDemand,
@NotNull Set<String> namesToUseSingle,
@NotNull ImportUtils.ImplicitImportChecker implicitImportContext,
@NotNull Map<String, PsiImportModuleStatement> moduleStatementMap,
@NotNull List<PsiImportModuleStatement> previousModuleStatements,
boolean onDemandImportsFirst,
int moduleIndex) {
Set<String> importedPackagesOrClasses = new HashSet<>();
@@ -547,6 +553,9 @@ public final class ImportHelper extends ImportHelperBase {
}
}
if (!mySettings.isDeleteUnusedModuleImports()) {
usedModuleImports = new HashSet<>(previousModuleStatements);
}
StringBuilder moduleStatements = new StringBuilder();
usedModuleImports.stream()
.sorted(Comparator.comparing(m -> {
@@ -69,6 +69,7 @@
"class_names_in_javadoc": 1,
"continuation_indent_size": 8,
"deconstruction_list_wrap": "normal",
"delete_unused_module_imports": false,
"do_not_indent_top_level_class_members": false,
"do_not_wrap_after_single_annotation": false,
"do_not_wrap_after_single_annotation_in_parameter": false,
@@ -69,6 +69,7 @@
"class_names_in_javadoc": 1,
"continuation_indent_size": 8,
"deconstruction_list_wrap": "normal",
"delete_unused_module_imports": false,
"do_not_indent_top_level_class_members": false,
"do_not_wrap_after_single_annotation": false,
"do_not_wrap_after_single_annotation_in_parameter": false,
@@ -0,0 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<problems>
<problem>
<file>Main.java</file>
<line>1</line>
<problem_class id="UNUSED_IMPORT" 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>
@@ -0,0 +1,3 @@
<?xml version="1.0" encoding="UTF-8"?>
<problems>
</problems>
@@ -0,0 +1,3 @@
<?xml version="1.0" encoding="UTF-8"?>
<problems>
</problems>
@@ -0,0 +1,15 @@
<?xml version="1.0" encoding="UTF-8"?>
<problems>
<problem>
<file>Main.java</file>
<line>1</line>
<problem_class id="UNUSED_IMPORT" severity="WARNING" attribute_key="WARNING_ATTRIBUTES">Unused import</problem_class>
<description>Unused import &lt;code&gt;import module my.source.moduleB;&lt;/code&gt; #loc</description>
</problem>
<problem>
<file>Main.java</file>
<line>2</line>
<problem_class id="UNUSED_IMPORT" severity="WARNING" attribute_key="WARNING_ATTRIBUTES">Unused import</problem_class>
<description>Unused import &lt;code&gt;import module my.source.moduleE;&lt;/code&gt; #loc</description>
</problem>
</problems>
@@ -0,0 +1,3 @@
<?xml version="1.0" encoding="UTF-8"?>
<problems>
</problems>
@@ -0,0 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<problems>
<problem>
<file>Main.java</file>
<line>2</line>
<problem_class id="UNUSED_IMPORT" severity="WARNING" attribute_key="WARNING_ATTRIBUTES">Unused import</problem_class>
<description>Unused import &lt;code&gt;import module my.source.moduleE;&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>2</line>
<problem_class id="UNUSED_IMPORT" severity="WARNING" attribute_key="WARNING_ATTRIBUTES">Unused import</problem_class>
<description>Unused import &lt;code&gt;import module my.source.moduleC;&lt;/code&gt; #loc</description>
</problem>
</problems>
@@ -0,0 +1,21 @@
<?xml version="1.0" encoding="UTF-8"?>
<problems>
<problem>
<file>Main.java</file>
<line>1</line>
<problem_class id="UNUSED_IMPORT" severity="WARNING" attribute_key="WARNING_ATTRIBUTES">Unused import</problem_class>
<description>Unused import &lt;code&gt;import module my.source.moduleB;&lt;/code&gt; #loc</description>
</problem>
<problem>
<file>Main.java</file>
<line>2</line>
<problem_class id="UNUSED_IMPORT" severity="WARNING" attribute_key="WARNING_ATTRIBUTES">Unused import</problem_class>
<description>Unused import &lt;code&gt;import module my.source.moduleC;&lt;/code&gt; #loc</description>
</problem>
<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 module my.source.moduleE;&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>2</line>
<problem_class id="UNUSED_IMPORT" severity="WARNING" attribute_key="WARNING_ATTRIBUTES">Unused import</problem_class>
<description>Unused import &lt;code&gt;import module my.source.moduleC;&lt;/code&gt; #loc</description>
</problem>
</problems>
@@ -0,0 +1,15 @@
<?xml version="1.0" encoding="UTF-8"?>
<problems>
<problem>
<file>Main.java</file>
<line>2</line>
<problem_class id="UNUSED_IMPORT" severity="WARNING" attribute_key="WARNING_ATTRIBUTES">Unused import</problem_class>
<description>Unused import &lt;code&gt;import module my.source.moduleC;&lt;/code&gt; #loc</description>
</problem>
<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 module my.source.moduleE;&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>2</line>
<problem_class id="UNUSED_IMPORT" severity="WARNING" attribute_key="WARNING_ATTRIBUTES">Unused import</problem_class>
<description>Unused import &lt;code&gt;import module my.source.moduleC;&lt;/code&gt; #loc</description>
</problem>
</problems>
@@ -0,0 +1,15 @@
<?xml version="1.0" encoding="UTF-8"?>
<problems>
<problem>
<file>Main.java</file>
<line>2</line>
<problem_class id="UNUSED_IMPORT" severity="WARNING" attribute_key="WARNING_ATTRIBUTES">Unused import</problem_class>
<description>Unused import &lt;code&gt;import module my.source.moduleC;&lt;/code&gt; #loc</description>
</problem>
<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 module my.source.moduleE;&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>2</line>
<problem_class id="UNUSED_IMPORT" severity="WARNING" attribute_key="WARNING_ATTRIBUTES">Unused import</problem_class>
<description>Unused import &lt;code&gt;import module my.source.moduleC;&lt;/code&gt; #loc</description>
</problem>
</problems>
@@ -0,0 +1,15 @@
<?xml version="1.0" encoding="UTF-8"?>
<problems>
<problem>
<file>Main.java</file>
<line>2</line>
<problem_class id="UNUSED_IMPORT" severity="WARNING" attribute_key="WARNING_ATTRIBUTES">Unused import</problem_class>
<description>Unused import &lt;code&gt;import module my.source.moduleC;&lt;/code&gt; #loc</description>
</problem>
<problem>
<file>Main.java</file>
<line>5</line>
<problem_class id="UNUSED_IMPORT" severity="WARNING" attribute_key="WARNING_ATTRIBUTES">Unused import</problem_class>
<description>Unused import &lt;code&gt;import my.source.moduleC.*;&lt;/code&gt; #loc</description>
</problem>
</problems>
@@ -0,0 +1,21 @@
<?xml version="1.0" encoding="UTF-8"?>
<problems>
<problem>
<file>Main.java</file>
<line>2</line>
<problem_class id="UNUSED_IMPORT" severity="WARNING" attribute_key="WARNING_ATTRIBUTES">Unused import</problem_class>
<description>Unused import &lt;code&gt;import module my.source.moduleC;&lt;/code&gt; #loc</description>
</problem>
<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 module my.source.moduleE;&lt;/code&gt; #loc</description>
</problem>
<problem>
<file>Main.java</file>
<line>5</line>
<problem_class id="UNUSED_IMPORT" severity="WARNING" attribute_key="WARNING_ATTRIBUTES">Unused import</problem_class>
<description>Unused import &lt;code&gt;import my.source.moduleC.*;&lt;/code&gt; #loc</description>
</problem>
</problems>
@@ -0,0 +1,21 @@
<?xml version="1.0" encoding="UTF-8"?>
<problems>
<problem>
<file>Main.java</file>
<line>2</line>
<problem_class id="UNUSED_IMPORT" severity="WARNING" attribute_key="WARNING_ATTRIBUTES">Unused import</problem_class>
<description>Unused import &lt;code&gt;import module my.source.moduleC;&lt;/code&gt; #loc</description>
</problem>
<problem>
<file>Main.java</file>
<line>5</line>
<problem_class id="UNUSED_IMPORT" severity="WARNING" attribute_key="WARNING_ATTRIBUTES">Unused import</problem_class>
<description>Unused import &lt;code&gt;import my.source.moduleB.*;&lt;/code&gt; #loc</description>
</problem>
<problem>
<file>Main.java</file>
<line>6</line>
<problem_class id="UNUSED_IMPORT" severity="WARNING" attribute_key="WARNING_ATTRIBUTES">Unused import</problem_class>
<description>Unused import &lt;code&gt;import my.source.moduleC.*;&lt;/code&gt; #loc</description>
</problem>
</problems>
@@ -0,0 +1,27 @@
<?xml version="1.0" encoding="UTF-8"?>
<problems>
<problem>
<file>Main.java</file>
<line>2</line>
<problem_class id="UNUSED_IMPORT" severity="WARNING" attribute_key="WARNING_ATTRIBUTES">Unused import</problem_class>
<description>Unused import &lt;code&gt;import module my.source.moduleC;&lt;/code&gt; #loc</description>
</problem>
<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 module my.source.moduleE;&lt;/code&gt; #loc</description>
</problem>
<problem>
<file>Main.java</file>
<line>5</line>
<problem_class id="UNUSED_IMPORT" severity="WARNING" attribute_key="WARNING_ATTRIBUTES">Unused import</problem_class>
<description>Unused import &lt;code&gt;import my.source.moduleB.*;&lt;/code&gt; #loc</description>
</problem>
<problem>
<file>Main.java</file>
<line>6</line>
<problem_class id="UNUSED_IMPORT" severity="WARNING" attribute_key="WARNING_ATTRIBUTES">Unused import</problem_class>
<description>Unused import &lt;code&gt;import my.source.moduleC.*;&lt;/code&gt; #loc</description>
</problem>
</problems>
@@ -0,0 +1,15 @@
<?xml version="1.0" encoding="UTF-8"?>
<problems>
<problem>
<file>Main.java</file>
<line>2</line>
<problem_class id="UNUSED_IMPORT" severity="WARNING" attribute_key="WARNING_ATTRIBUTES">Unused import</problem_class>
<description>Unused import &lt;code&gt;import module my.source.moduleC;&lt;/code&gt; #loc</description>
</problem>
<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 module my.source.moduleE;&lt;/code&gt; #loc</description>
</problem>
</problems>
@@ -0,0 +1,15 @@
<?xml version="1.0" encoding="UTF-8"?>
<problems>
<problem>
<file>Main.java</file>
<line>2</line>
<problem_class id="UNUSED_IMPORT" severity="WARNING" attribute_key="WARNING_ATTRIBUTES">Unused import</problem_class>
<description>Unused import &lt;code&gt;import module my.source.moduleC;&lt;/code&gt; #loc</description>
</problem>
<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 module my.source.moduleD;&lt;/code&gt; #loc</description>
</problem>
</problems>
@@ -0,0 +1,21 @@
<?xml version="1.0" encoding="UTF-8"?>
<problems>
<problem>
<file>Main.java</file>
<line>2</line>
<problem_class id="UNUSED_IMPORT" severity="WARNING" attribute_key="WARNING_ATTRIBUTES">Unused import</problem_class>
<description>Unused import &lt;code&gt;import module my.source.moduleC;&lt;/code&gt; #loc</description>
</problem>
<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 module my.source.moduleD;&lt;/code&gt; #loc</description>
</problem>
<problem>
<file>Main.java</file>
<line>4</line>
<problem_class id="UNUSED_IMPORT" severity="WARNING" attribute_key="WARNING_ATTRIBUTES">Unused import</problem_class>
<description>Unused import &lt;code&gt;import module my.source.moduleE;&lt;/code&gt; #loc</description>
</problem>
</problems>
@@ -0,0 +1,15 @@
<?xml version="1.0" encoding="UTF-8"?>
<problems>
<problem>
<file>Main.java</file>
<line>2</line>
<problem_class id="UNUSED_IMPORT" severity="WARNING" attribute_key="WARNING_ATTRIBUTES">Unused import</problem_class>
<description>Unused import &lt;code&gt;import module my.source.moduleC;&lt;/code&gt; #loc</description>
</problem>
<problem>
<file>Main.java</file>
<line>5</line>
<problem_class id="UNUSED_IMPORT" severity="WARNING" attribute_key="WARNING_ATTRIBUTES">Unused import</problem_class>
<description>Unused import &lt;code&gt;import my.source.moduleB.*;&lt;/code&gt; #loc</description>
</problem>
</problems>
@@ -0,0 +1,21 @@
<?xml version="1.0" encoding="UTF-8"?>
<problems>
<problem>
<file>Main.java</file>
<line>2</line>
<problem_class id="UNUSED_IMPORT" severity="WARNING" attribute_key="WARNING_ATTRIBUTES">Unused import</problem_class>
<description>Unused import &lt;code&gt;import module my.source.moduleC;&lt;/code&gt; #loc</description>
</problem>
<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 module my.source.moduleE;/*unused*/&lt;/code&gt; #loc</description>
</problem>
<problem>
<file>Main.java</file>
<line>5</line>
<problem_class id="UNUSED_IMPORT" severity="WARNING" attribute_key="WARNING_ATTRIBUTES">Unused import</problem_class>
<description>Unused import &lt;code&gt;import my.source.moduleB.*;&lt;/code&gt; #loc</description>
</problem>
</problems>
@@ -1,3 +1,5 @@
import module java.base;
public class beforeAdjustComments {
//many comments
private final String field = "field";
@@ -1,3 +1,4 @@
import module java.base;
import test.List;
public class beforeC<caret>onflictModuleImport {
@@ -1,3 +1,4 @@
import module java.base;
import test.List;
public class beforeC<caret>onflictModuleImportDemandOverModule {
@@ -1,3 +1,5 @@
import module java.base;
public class beforeSimple {
private final String field = "field";
@@ -1,3 +1,5 @@
import module java.base;
public class beforeSimple2 {
private final String field = "field";
@@ -1,3 +1,5 @@
import module java.base;
import static java.io.IO.println;
public class beforeWit<caret>hPrint {
@@ -0,0 +1,21 @@
package p2;
import module java.base;
import p1.A1;
import p1.A2;
import p1.A3;
import p1.A4;
import p1.A5;
class C {
A1 a1;
A2 a2;
A3 a3;
A4 a4;
A5 a5;
List myName;
}
@@ -0,0 +1,18 @@
package p2;
import module java.base;
import p1.*;
import java.util.List;
class C {
A1 a1;
A2 a2;
A3 a3;
A4 a4;
A5 a5;
List myName;
}
@@ -0,0 +1,22 @@
import module java.base;
import one.Super;
import two.*;
import three.*;
class DoNotInsertImportForClassVisibleByInheritanceWithModuleConflict implements Super {
One one;
Two two;
Three three;
Four four;
Five five;
Six six;
Seven seven;
Eight eight;
Nine nine;
Ten ten;
Result x() {
return new Result();
}
}
@@ -0,0 +1,21 @@
import module java.base;
import one.Super;
import three.*;
import two.*;
class DoNotInsertImportForClassVisibleByInheritanceWithModuleConflict implements Super {
One one;
Two two;
Three three;
Four four;
Five five;
Six six;
Seven seven;
Eight eight;
Nine nine;
Ten ten;
Result x() {
return new Result();
}
}
@@ -0,0 +1,5 @@
import module java.base;
import java.io.*;
import java.util.HashMap;
import java.util.Map;<caret>
@@ -0,0 +1 @@
<caret>import module java.base;
@@ -0,0 +1,7 @@
import module my.source.moduleB;
import module my.source.moduleE;
final class Main {
public static void main(String[] args) {
}
}
@@ -0,0 +1,7 @@
<warning descr="Unused import statement">import module my.source.moduleB;/*unused*/</warning>
<warning descr="Unused import statement">import module my.source.moduleE;/*unused*/</warning>
final class Main {
public static void main(String[] args) {
}
}
@@ -0,0 +1,4 @@
final class Main {
public static void main(String[] args) {
}
}
@@ -0,0 +1,7 @@
import module my.source.moduleB;
import module my.source.moduleE;
final class Main {
public static void main(String[] args) {
}
}
@@ -0,0 +1,8 @@
import module my.source.moduleB;
import module my.source.moduleE;
final class Main {
public static void main(String[] args) {
new Sql();
}
}
@@ -0,0 +1,8 @@
import module my.source.moduleB;
<warning descr="Unused import statement">import module my.source.moduleE;/*unused*/</warning>
final class Main {
public static void main(String[] args) {
new Sql();
}
}
@@ -0,0 +1,7 @@
import module my.source.moduleB;
final class Main {
public static void main(String[] args) {
new Sql();
}
}
@@ -0,0 +1,8 @@
import module my.source.moduleB;
import module my.source.moduleE;
final class Main {
public static void main(String[] args) {
new Sql();
}
}
@@ -0,0 +1,8 @@
import module my.source.moduleB;
<warning descr="Unused import statement">import module my.source.moduleC;/*unused*/</warning>
import module my.source.moduleE;
final class Main {
public static void main(String[] args) {
}
}
@@ -0,0 +1,7 @@
import module my.source.moduleB;
import module my.source.moduleE;
final class Main {
public static void main(String[] args) {
}
}
@@ -0,0 +1,9 @@
import module my.source.moduleB;
<warning descr="Unused import statement">import module my.source.moduleC;</warning>
import module my.source.moduleE;
final class Main {
public static void main() {
new Sql();
}
}
@@ -0,0 +1,9 @@
import module my.source.moduleB;
<warning descr="Unused import statement">import module my.source.moduleC;/*unused*/</warning>
<warning descr="Unused import statement">import module my.source.moduleE;/*unused*/</warning>
final class Main {
public static void main(String[] args) {
new Sql();
}
}
@@ -0,0 +1,7 @@
import module my.source.moduleB;
final class Main {
public static void main(String[] args) {
new Sql();
}
}
@@ -0,0 +1,8 @@
import module my.source.moduleB;
import module my.source.moduleE;
final class Main {
public static void main() {
new Sql();
}
}
@@ -0,0 +1,9 @@
import module my.source.moduleB;
<warning descr="Unused import statement">import module my.source.moduleC;/*unused*/</warning>
import module my.source.moduleE;
final class Main {
public static void main(String[] args) {
new Sql();
}
}
@@ -0,0 +1,9 @@
import module my.source.moduleB;
<warning descr="Unused import statement">import module my.source.moduleC;/*unused*/</warning>
<warning descr="Unused import statement">import module my.source.moduleE;/*unused*/</warning>
final class Main {
public static void main(String[] args) {
new Sql();
}
}
@@ -0,0 +1,7 @@
import module my.source.moduleB;
final class Main {
public static void main(String[] args) {
new Sql();
}
}
@@ -0,0 +1,8 @@
import module my.source.moduleB;
import module my.source.moduleE;
final class Main {
public static void main(String[] args) {
new Sql();
}
}
@@ -0,0 +1,10 @@
import module my.source.moduleB;
<warning descr="Unused import statement">import module my.source.moduleC;/*unused*/</warning>
import module my.source.moduleE;
final class Main {
public static void main(String[] args) {
new Sql();
new Transaction();
}
}
@@ -0,0 +1,12 @@
import module my.source.moduleB;
<warning descr="Unused import statement">import module my.source.moduleC;/*unused*/</warning>
import module my.source.moduleE;
import my.source.moduleC.*;/*unused*/ //not highlighted, on-fly
final class Main {
public static void main(String[] args) {
new Sql();
new Transaction();
}
}
@@ -0,0 +1,12 @@
import module my.source.moduleB;
<warning descr="Unused import statement">import module my.source.moduleC;/*unused*/</warning>
<warning descr="Unused import statement">import module my.source.moduleE;/*unused*/</warning>
import my.source.moduleC.*;/*unused*/ //on-fly
final class Main {
public static void main(String[] args) {
new Sql();
new Transaction();
}
}
@@ -0,0 +1,8 @@
import module my.source.moduleB;
final class Main {
public static void main(String[] args) {
new Sql();
new Transaction();
}
}
@@ -0,0 +1,13 @@
import module my.source.moduleB;
<warning descr="Unused import statement">import module my.source.moduleC;/*unused*/</warning>
import module my.source.moduleE;
import my.source.moduleB.*;/*unused*/ //on-fly
import my.source.moduleC.*;/*unused*/ //on-fly
final class Main {
public static void main(String[] args) {
new Sql();
new Transaction();
}
}
@@ -0,0 +1,14 @@
<warning descr="Unused import statement">import module my.source.moduleB;</warning>
<warning descr="Unused import statement">import module my.source.moduleC;/*unused*/</warning>
<warning descr="Unused import statement">import module my.source.moduleE;/*unused*/</warning>
import my.source.moduleB.*;/*unused*/ //on-fly
import my.source.moduleC.*;/*unused*/ //on-fly
final class Main {
public static void main(String[] args) {
new Sql();
new Transaction();
}
}
@@ -0,0 +1,9 @@
import module my.source.moduleB;
final class Main {
public static void main(String[] args) {
new Sql();
new Transaction();
}
}
@@ -0,0 +1,9 @@
import module my.source.moduleB;
import module my.source.moduleE;
final class Main {
public static void main(String[] args) {
new Sql();
new Transaction();
}
}
@@ -0,0 +1,9 @@
import module my.source.moduleB;
import module my.source.moduleE;
final class Main {
public static void main(String[] args) {
new Sql();
new Transaction();
}
}
@@ -0,0 +1,10 @@
import module my.source.moduleB;
<warning descr="Unused import statement">import module my.source.moduleC;/*unused*/</warning>
<warning descr="Unused import statement">import module my.source.moduleE;/*unused*/</warning>
final class Main {
public static void main(String[] args) {
new Sql();
new Transaction();
}
}
@@ -0,0 +1,8 @@
import module my.source.moduleB;
final class Main {
public static void main(String[] args) {
new Sql();
new Transaction();
}
}
@@ -0,0 +1,12 @@
import module my.source.moduleB;
<warning descr="Unused import statement">import module my.source.moduleC;/*unused*/</warning>
<warning descr="Unused import statement">import module my.source.moduleD;/*unused*/</warning>
import module my.source.moduleE;
final class Main {
public static void main(String[] args) {
new Sql();
new Transaction();
new Connection();
}
}
@@ -0,0 +1,12 @@
import module my.source.moduleB;
<warning descr="Unused import statement">import module my.source.moduleC;/*unused*/</warning>
<warning descr="Unused import statement">import module my.source.moduleD;/*unused*/</warning>
<warning descr="Unused import statement">import module my.source.moduleE;/*unused*/</warning>
final class Main {
public static void main(String[] args) {
new Sql();
new Transaction();
new Connection();
}
}
@@ -0,0 +1,9 @@
import module my.source.moduleB;
final class Main {
public static void main(String[] args) {
new Sql();
new Transaction();
new Connection();
}
}
@@ -0,0 +1,10 @@
import module my.source.moduleB;
import module my.source.moduleE;
final class Main {
public static void main(String[] args) {
new Sql();
new Transaction();
new Connection();
}
}
@@ -0,0 +1,12 @@
import module my.source.moduleB;
<warning descr="Unused import statement">import module my.source.moduleC;/*unused*/</warning>
import module my.source.moduleE;
import my.source.moduleB.*;/*unused*/ //is not highlighted, because it is on fly
final class Main {
public static void main(String[] args) {
new Sql();
new Transaction();
}
}
@@ -0,0 +1,12 @@
import module my.source.moduleB;
<warning descr="Unused import statement">import module my.source.moduleC;/*unused*/</warning>
<warning descr="Unused import statement">import module my.source.moduleE;/*unused*/</warning>
import my.source.moduleB.*;/*unused*/ //not highlighted, because it is on fly
final class Main {
public static void main(String[] args) {
new Sql();
new Transaction();
}
}
@@ -0,0 +1,8 @@
import module my.source.moduleB;
final class Main {
public static void main(String[] args) {
new Sql();
new Transaction();
}
}
@@ -0,0 +1,9 @@
import module my.source.moduleB;
import module my.source.moduleE;
final class Main {
public static void main(String[] args) {
new Sql();
new Transaction();
}
}
@@ -0,0 +1,9 @@
import module my.source.moduleB;
import module my.source.moduleE;
final class Main {
public static void main(String[] args) {
new Sql();
new Transaction();
}
}
@@ -1,4 +1,4 @@
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
// 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.java.psi;
import com.intellij.application.options.CodeStyle;
@@ -62,12 +62,14 @@ public class OptimizeImportsTest extends OptimizeImportsTestCase {
super.setUp();
JavaCodeStyleSettings javaSettings = JavaCodeStyleSettings.getInstance(getProject());
boolean preserveModuleImports = javaSettings.isPreserveModuleImports();
boolean deleteUnusedModuleImports = javaSettings.isDeleteUnusedModuleImports();
PackageEntryTable table = javaSettings.IMPORT_LAYOUT_TABLE;
int classOnDemand = javaSettings.CLASS_COUNT_TO_USE_IMPORT_ON_DEMAND;
int namesOnDemand = javaSettings.NAMES_COUNT_TO_USE_IMPORT_ON_DEMAND;
Disposer.register(getTestRootDisposable(), new Disposable() {
@Override
public void dispose() {
javaSettings.setDeleteUnusedModuleImports(deleteUnusedModuleImports);
javaSettings.setPreserveModuleImports(preserveModuleImports);
javaSettings.IMPORT_LAYOUT_TABLE = table;
javaSettings.CLASS_COUNT_TO_USE_IMPORT_ON_DEMAND = classOnDemand;
@@ -171,6 +173,18 @@ public class OptimizeImportsTest extends OptimizeImportsTestCase {
}
public void testConflictModuleImport(){
JavaCodeStyleSettings.getInstance(getProject()).setDeleteUnusedModuleImports(true);
myFixture.addClass("package p1; public class List {}");
myFixture.addClass("package p1; public class A1 {}");
myFixture.addClass("package p1; public class A2 {}");
myFixture.addClass("package p1; public class A3 {}");
myFixture.addClass("package p1; public class A4 {}");
myFixture.addClass("package p1; public class A5 {}");
doTest();
}
public void testConflictModuleImportDoNotDeleteModule(){
JavaCodeStyleSettings.getInstance(getProject()).setDeleteUnusedModuleImports(false);
myFixture.addClass("package p1; public class List {}");
myFixture.addClass("package p1; public class A1 {}");
myFixture.addClass("package p1; public class A2 {}");
@@ -754,7 +768,8 @@ public class OptimizeImportsTest extends OptimizeImportsTestCase {
}
public void testDoNotInsertImportForClassVisibleByInheritanceWithModuleConflict() {
public void testDoNotInsertImportForClassVisibleByInheritanceWithModuleConflictDoNotDeleteModule() {
JavaCodeStyleSettings.getInstance(getProject()).setDeleteUnusedModuleImports(false);
myFixture.addClass("""
package one;
public interface Super {
@@ -783,7 +798,43 @@ public class OptimizeImportsTest extends OptimizeImportsTestCase {
""");
doTest();
}
public void testDoNotInsertImportForClassVisibleByInheritanceWithModuleConflict() {
JavaCodeStyleSettings.getInstance(getProject()).setDeleteUnusedModuleImports(true);
myFixture.addClass("""
package one;
public interface Super {
class List {}
List x();
}
""");
myFixture.addClass("""
package two;
public class List {}
public class One {}
public class Two {}
public class Three {}
public class Four {}
public class Five {}
""");
myFixture.addClass("""
package three;
public class List {}
public class Six {}
public class Seven {}
public class Eight {}
public class Nine {}
public class Ten {}
""");
doTest();
}
public void testNotDeleteModuleImport() {
JavaCodeStyleSettings.getInstance(getProject()).setDeleteUnusedModuleImports(false);
doTest();
}
public void testUnresolvedReferenceAfterParenthesis() {
doTest();
}
@@ -0,0 +1,418 @@
// 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.java.psi;
import com.intellij.codeInspection.unusedImport.UnusedImportInspection;
import com.intellij.java.testFramework.fixtures.LightJava9ModulesCodeInsightFixtureTestCase;
import com.intellij.java.testFramework.fixtures.MultiModuleJava9ProjectDescriptor;
import com.intellij.openapi.Disposable;
import com.intellij.openapi.application.ex.PathManagerEx;
import com.intellij.openapi.command.WriteCommandAction;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.module.ModuleManager;
import com.intellij.openapi.roots.DependencyScope;
import com.intellij.openapi.roots.ModuleRootModificationUtil;
import com.intellij.openapi.util.Disposer;
import com.intellij.pom.java.JavaFeature;
import com.intellij.psi.PsiDocumentManager;
import com.intellij.psi.PsiFile;
import com.intellij.psi.codeStyle.JavaCodeStyleManager;
import com.intellij.psi.codeStyle.JavaCodeStyleSettings;
import com.intellij.psi.codeStyle.PackageEntryTable;
import com.intellij.psi.impl.source.PostprocessReformattingAspect;
import com.intellij.testFramework.IdeaTestUtil;
import com.intellij.testFramework.PsiTestUtil;
import org.intellij.lang.annotations.Language;
import org.jetbrains.annotations.NotNull;
import static com.intellij.java.testFramework.fixtures.MultiModuleJava9ProjectDescriptor.ModuleDescriptor.*;
public class OptimizeImportsWithModulesTest extends LightJava9ModulesCodeInsightFixtureTestCase {
static final String BASE_PATH = PathManagerEx.getTestDataPath() + "/psi/optimizeImportsWithModules";
@Override
protected String getTestDataPath() {
return BASE_PATH;
}
@Override
protected void setUp() throws Exception {
super.setUp();
com.intellij.openapi.module.Module main = ModuleManager.getInstance(getProject()).findModuleByName(MAIN.moduleName);
com.intellij.openapi.module.Module m2 = ModuleManager.getInstance(getProject()).findModuleByName(M2.moduleName);
com.intellij.openapi.module.Module m3 = ModuleManager.getInstance(getProject()).findModuleByName(M3.moduleName);
com.intellij.openapi.module.Module m4 = ModuleManager.getInstance(getProject()).findModuleByName(M4.moduleName);
Module m5 = ModuleManager.getInstance(getProject()).findModuleByName(M5.moduleName);
//m2(B) -> m4(C) -> m5(D)
//m3(E)
ModuleRootModificationUtil.addDependency(m2, m4, DependencyScope.COMPILE, true);
ModuleRootModificationUtil.addDependency(m4, m5, DependencyScope.COMPILE, true);
ModuleRootModificationUtil.addDependency(m4, m5, DependencyScope.COMPILE, true);
ModuleRootModificationUtil.addDependency(main, m3, DependencyScope.COMPILE, true);
addCode("module-info.java", """
module my.source.moduleB {
exports my.source.moduleB;
requires transitive my.source.moduleC;
}
""", M2);
addCode("module-info.java", """
module my.source.moduleE {
exports my.source.moduleE;
}
""", M3);
addCode("module-info.java", """
module my.source.moduleC {
exports my.source.moduleC;
requires transitive my.source.moduleD;
}
""", M4);
addCode("module-info.java", """
module my.source.moduleD {
exports my.source.moduleD;
}
""", M5);
JavaCodeStyleSettings javaSettings = JavaCodeStyleSettings.getInstance(getProject());
boolean preserveModuleImports = javaSettings.isPreserveModuleImports();
boolean deleteUnusedModuleImports = javaSettings.isDeleteUnusedModuleImports();
PackageEntryTable table = javaSettings.IMPORT_LAYOUT_TABLE;
int classOnDemand = javaSettings.CLASS_COUNT_TO_USE_IMPORT_ON_DEMAND;
int namesOnDemand = javaSettings.NAMES_COUNT_TO_USE_IMPORT_ON_DEMAND;
Disposer.register(getTestRootDisposable(), new Disposable() {
@Override
public void dispose() {
javaSettings.setDeleteUnusedModuleImports(deleteUnusedModuleImports);
javaSettings.setPreserveModuleImports(preserveModuleImports);
javaSettings.IMPORT_LAYOUT_TABLE = table;
javaSettings.CLASS_COUNT_TO_USE_IMPORT_ON_DEMAND = classOnDemand;
javaSettings.NAMES_COUNT_TO_USE_IMPORT_ON_DEMAND = namesOnDemand;
}
});
javaSettings.setDeleteUnusedModuleImports(false);
myFixture.enableInspections(new UnusedImportInspection());
}
public void testParentNotUsedChildUsed() {
IdeaTestUtil.withLevel(
getModule(), JavaFeature.PACKAGE_IMPORTS_SHADOW_MODULE_IMPORTS.getMinimumLevel(), () -> {
JavaCodeStyleSettings.getInstance(getProject()).setDeleteUnusedModuleImports(false);
addCode("my/source/moduleC/Sql.java", """
package my.source.moduleC;
public class Sql {}
""", M4);
doTest();
}
);
}
public void testParentNotUsedChildUsedDeleteUnused() {
IdeaTestUtil.withLevel(
getModule(), JavaFeature.PACKAGE_IMPORTS_SHADOW_MODULE_IMPORTS.getMinimumLevel(), () -> {
JavaCodeStyleSettings.getInstance(getProject()).setDeleteUnusedModuleImports(true);
addCode("my/source/moduleC/Sql.java", """
package my.source.moduleC;
public class Sql {}
""", M4);
doTest();
}
);
}
public void testParentUsedChildNotUsed() {
IdeaTestUtil.withLevel(
getModule(), JavaFeature.PACKAGE_IMPORTS_SHADOW_MODULE_IMPORTS.getMinimumLevel(), () -> {
JavaCodeStyleSettings.getInstance(getProject()).setDeleteUnusedModuleImports(false);
addCode("my/source/moduleB/Sql.java", """
package my.source.moduleB;
public class Sql {}
""", M2);
doTest();
}
);
}
public void testParentUsedChildNotUsedDeleteUnused() {
IdeaTestUtil.withLevel(
getModule(), JavaFeature.PACKAGE_IMPORTS_SHADOW_MODULE_IMPORTS.getMinimumLevel(), () -> {
JavaCodeStyleSettings.getInstance(getProject()).setDeleteUnusedModuleImports(true);
addCode("my/source/moduleB/Sql.java", """
package my.source.moduleB;
public class Sql {}
""", M2);
doTest();
}
);
}
public void testParentUsedChildUsed() {
IdeaTestUtil.withLevel(
getModule(), JavaFeature.PACKAGE_IMPORTS_SHADOW_MODULE_IMPORTS.getMinimumLevel(), () -> {
JavaCodeStyleSettings.getInstance(getProject()).setDeleteUnusedModuleImports(false);
addCode("my/source/moduleB/Sql.java", """
package my.source.moduleB;
public class Sql {}
""", M2);
addCode("my/source/moduleC/Transaction.java", """
package my.source.moduleC;
public class Transaction {}
""", M4);
doTest();
}
);
}
public void testParentUsedChildUsedDeleteUnused() {
IdeaTestUtil.withLevel(
getModule(), JavaFeature.PACKAGE_IMPORTS_SHADOW_MODULE_IMPORTS.getMinimumLevel(), () -> {
JavaCodeStyleSettings.getInstance(getProject()).setDeleteUnusedModuleImports(true);
addCode("my/source/moduleB/Sql.java", """
package my.source.moduleB;
public class Sql {}
""", M2);
addCode("my/source/moduleC/Transaction.java", """
package my.source.moduleC;
public class Transaction {}
""", M4);
doTest();
}
);
}
public void testParentUsedChildUsedGrandChildUsed() {
IdeaTestUtil.withLevel(
getModule(), JavaFeature.PACKAGE_IMPORTS_SHADOW_MODULE_IMPORTS.getMinimumLevel(), () -> {
JavaCodeStyleSettings.getInstance(getProject()).setDeleteUnusedModuleImports(false);
addCode("my/source/moduleB/Sql.java", """
package my.source.moduleB;
public class Sql {}
""", M2);
addCode("my/source/moduleC/Transaction.java", """
package my.source.moduleC;
public class Transaction {}
""", M4);
addCode("my/source/moduleD/Connection.java", """
package my.source.moduleD;
public class Connection {}
""", M5);
doTest();
}
);
}
public void testParentUsedChildUsedGrandChildUsedDeleteUnused() {
IdeaTestUtil.withLevel(
getModule(), JavaFeature.PACKAGE_IMPORTS_SHADOW_MODULE_IMPORTS.getMinimumLevel(), () -> {
JavaCodeStyleSettings.getInstance(getProject()).setDeleteUnusedModuleImports(true);
addCode("my/source/moduleB/Sql.java", """
package my.source.moduleB;
public class Sql {}
""", M2);
addCode("my/source/moduleC/Transaction.java", """
package my.source.moduleC;
public class Transaction {}
""", M4);
addCode("my/source/moduleD/Connection.java", """
package my.source.moduleD;
public class Connection {}
""", M5);
doTest();
}
);
}
public void testOneUsed() {
IdeaTestUtil.withLevel(
getModule(), JavaFeature.PACKAGE_IMPORTS_SHADOW_MODULE_IMPORTS.getMinimumLevel(), () -> {
JavaCodeStyleSettings.getInstance(getProject()).setDeleteUnusedModuleImports(false);
addCode("my/source/moduleB/Sql.java", """
package my.source.moduleB;
public class Sql {}
""", M2);
doTest();
}
);
}
public void testOneUsedDeleteUnused() {
IdeaTestUtil.withLevel(
getModule(), JavaFeature.PACKAGE_IMPORTS_SHADOW_MODULE_IMPORTS.getMinimumLevel(), () -> {
JavaCodeStyleSettings.getInstance(getProject()).setDeleteUnusedModuleImports(true);
addCode("my/source/moduleB/Sql.java", """
package my.source.moduleB;
public class Sql {}
""", M2);
doTest();
}
);
}
public void testNoOneUsed() {
IdeaTestUtil.withLevel(
getModule(), JavaFeature.PACKAGE_IMPORTS_SHADOW_MODULE_IMPORTS.getMinimumLevel(), () -> {
JavaCodeStyleSettings.getInstance(getProject()).setDeleteUnusedModuleImports(false);
doTest();
}
);
}
public void testNoOneUsedDeleteUnused() {
IdeaTestUtil.withLevel(
getModule(), JavaFeature.PACKAGE_IMPORTS_SHADOW_MODULE_IMPORTS.getMinimumLevel(), () -> {
JavaCodeStyleSettings.getInstance(getProject()).setDeleteUnusedModuleImports(true);
doTest();
}
);
}
public void testParentNotUsedChildNotUsed() {
IdeaTestUtil.withLevel(
getModule(), JavaFeature.PACKAGE_IMPORTS_SHADOW_MODULE_IMPORTS.getMinimumLevel(), () -> {
JavaCodeStyleSettings.getInstance(getProject()).setDeleteUnusedModuleImports(false);
doTest();
}
);
}
public void testParentUsedChildUsedParentCovered() {
IdeaTestUtil.withLevel(
getModule(), JavaFeature.PACKAGE_IMPORTS_SHADOW_MODULE_IMPORTS.getMinimumLevel(), () -> {
JavaCodeStyleSettings.getInstance(getProject()).setDeleteUnusedModuleImports(false);
addCode("my/source/moduleB/Sql.java", """
package my.source.moduleB;
public class Sql {}
""", M2);
addCode("my/source/moduleC/Transaction.java", """
package my.source.moduleC;
public class Transaction {}
""", M4);
doTest();
}
);
}
public void testParentUsedChildUsedParentCoveredDeleteUnused() {
IdeaTestUtil.withLevel(
getModule(), JavaFeature.PACKAGE_IMPORTS_SHADOW_MODULE_IMPORTS.getMinimumLevel(), () -> {
JavaCodeStyleSettings.getInstance(getProject()).setDeleteUnusedModuleImports(true);
addCode("my/source/moduleB/Sql.java", """
package my.source.moduleB;
public class Sql {}
""", M2);
addCode("my/source/moduleC/Transaction.java", """
package my.source.moduleC;
public class Transaction {}
""", M4);
doTest();
}
);
}
public void testParentUsedChildUsedChildCovered() {
IdeaTestUtil.withLevel(
getModule(), JavaFeature.PACKAGE_IMPORTS_SHADOW_MODULE_IMPORTS.getMinimumLevel(), () -> {
JavaCodeStyleSettings.getInstance(getProject()).setDeleteUnusedModuleImports(false);
addCode("my/source/moduleB/Sql.java", """
package my.source.moduleB;
public class Sql {}
""", M2);
addCode("my/source/moduleC/Transaction.java", """
package my.source.moduleC;
public class Transaction {}
""", M4);
doTest();
}
);
}
public void testParentUsedChildUsedChildCoveredDeleteUnused() {
IdeaTestUtil.withLevel(
getModule(), JavaFeature.PACKAGE_IMPORTS_SHADOW_MODULE_IMPORTS.getMinimumLevel(), () -> {
JavaCodeStyleSettings.getInstance(getProject()).setDeleteUnusedModuleImports(true);
addCode("my/source/moduleB/Sql.java", """
package my.source.moduleB;
public class Sql {}
""", M2);
addCode("my/source/moduleC/Transaction.java", """
package my.source.moduleC;
public class Transaction {}
""", M4);
doTest();
}
);
}
public void testParentUsedChildUsedChildCoveredParentCovered() {
IdeaTestUtil.withLevel(
getModule(), JavaFeature.PACKAGE_IMPORTS_SHADOW_MODULE_IMPORTS.getMinimumLevel(), () -> {
JavaCodeStyleSettings.getInstance(getProject()).setDeleteUnusedModuleImports(false);
addCode("my/source/moduleB/Sql.java", """
package my.source.moduleB;
public class Sql {}
""", M2);
addCode("my/source/moduleC/Transaction.java", """
package my.source.moduleC;
public class Transaction {}
""", M4);
doTest();
}
);
}
public void testParentUsedChildUsedChildCoveredParentCoveredDeleteUnused() {
IdeaTestUtil.withLevel(
getModule(), JavaFeature.PACKAGE_IMPORTS_SHADOW_MODULE_IMPORTS.getMinimumLevel(), () -> {
JavaCodeStyleSettings.getInstance(getProject()).setDeleteUnusedModuleImports(true);
addCode("my/source/moduleB/Sql.java", """
package my.source.moduleB;
public class Sql {}
""", M2);
addCode("my/source/moduleC/Transaction.java", """
package my.source.moduleC;
public class Transaction {}
""", M4);
doTest();
}
);
}
private void doTest() {
doTest(".java");
}
protected void doTest(@NotNull String extension) {
String fileName = getTestName(false) + extension;
PsiFile file = myFixture.configureByFile(fileName);
myFixture.testHighlighting(true , false, false);
WriteCommandAction.runWriteCommandAction(getProject(), () -> {
try {
JavaCodeStyleManager.getInstance(getProject()).optimizeImports(file);
PostprocessReformattingAspect.getInstance(getProject()).doPostponedFormatting();
PsiDocumentManager.getInstance(getProject()).commitAllDocuments();
myFixture.checkResultByFile(getTestName(false) + "_after" + extension);
PsiTestUtil.checkFileStructure(file);
}
catch (Exception e) {
LOG.error(e);
}
});
}
private void addCode(@NotNull String name, @NotNull @Language("JAVA") String text, @NotNull MultiModuleJava9ProjectDescriptor.ModuleDescriptor descriptor) {
addFile(name, text, descriptor);
}
}
@@ -1,18 +1,21 @@
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
// 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.java.psi.resolve;
import com.intellij.JavaTestUtil;
import com.intellij.java.testFramework.fixtures.LightJava9ModulesCodeInsightFixtureTestCase;
import com.intellij.java.testFramework.fixtures.MultiModuleJava9ProjectDescriptor.ModuleDescriptor;
import com.intellij.openapi.Disposable;
import com.intellij.openapi.command.WriteCommandAction;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.module.ModuleManager;
import com.intellij.openapi.roots.DependencyScope;
import com.intellij.openapi.roots.ModuleRootModificationUtil;
import com.intellij.openapi.util.Disposer;
import com.intellij.openapi.vfs.VfsUtil;
import com.intellij.pom.java.JavaFeature;
import com.intellij.psi.*;
import com.intellij.psi.codeStyle.JavaCodeStyleManager;
import com.intellij.psi.codeStyle.JavaCodeStyleSettings;
import com.intellij.psi.impl.source.PostprocessReformattingAspect;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.psi.util.PsiUtil;
@@ -43,6 +46,16 @@ public class ResolveModuleImportTest extends LightJava9ModulesCodeInsightFixture
getJarRootUrls("lib/moduleA-1.0-sources.jar"));
ModuleRootModificationUtil.addModuleLibrary(getModule(), "moduleB", getJarRootUrls("lib/moduleB-1.0.jar"),
getJarRootUrls("lib/moduleB-1.0-sources.jar"));
JavaCodeStyleSettings javaSettings = JavaCodeStyleSettings.getInstance(getProject());
boolean deleteUnusedModuleImports = javaSettings.isDeleteUnusedModuleImports();
Disposer.register(getTestRootDisposable(), new Disposable() {
@Override
public void dispose() {
javaSettings.setDeleteUnusedModuleImports(deleteUnusedModuleImports);
}
});
javaSettings.setDeleteUnusedModuleImports(false);
}
private List<String> getJarRootUrls(String path) {
@@ -382,6 +395,7 @@ public class ResolveModuleImportTest extends LightJava9ModulesCodeInsightFixture
}
public void testOptimizeImportWithSimilarNames() {
JavaCodeStyleSettings.getInstance(getProject()).setDeleteUnusedModuleImports(false);
addCode("module-info.java", """
module my.source.moduleB {
exports my.source.moduleB;
@@ -1,12 +1,15 @@
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package com.siyeh.ig.imports;
import com.intellij.analysis.AnalysisScope;
import com.intellij.codeInspection.ex.GlobalInspectionToolWrapper;
import com.intellij.codeInspection.ex.InspectionToolWrapper;
import com.intellij.codeInspection.unusedImport.UnusedImportInspection;
import com.intellij.openapi.Disposable;
import com.intellij.openapi.application.ex.PathManagerEx;
import com.intellij.openapi.util.Disposer;
import com.intellij.pom.java.JavaFeature;
import com.intellij.psi.codeStyle.JavaCodeStyleSettings;
import com.intellij.testFramework.IdeaTestUtil;
import com.intellij.testFramework.InspectionTestUtil;
import com.intellij.testFramework.InspectionsKt;
@@ -19,6 +22,21 @@ import java.io.File;
import java.util.Collections;
public class UnusedImportGlobalInspectionTest extends LightJavaCodeInsightFixtureTestCase {
@Override
public void setUp() throws Exception {
super.setUp();
JavaCodeStyleSettings javaSettings = JavaCodeStyleSettings.getInstance(getProject());
boolean deleteUnusedModuleImports = javaSettings.isDeleteUnusedModuleImports();
Disposer.register(getTestRootDisposable(), new Disposable() {
@Override
public void dispose() {
javaSettings.setDeleteUnusedModuleImports(deleteUnusedModuleImports);
}
});
javaSettings.setDeleteUnusedModuleImports(false);
}
@Override
protected String getTestDataPath() {
return PathManagerEx.getCommunityHomePath() + "/java/java-tests/testData/ig/com/siyeh/igtest/imports/globalInspection";
@@ -372,6 +390,7 @@ public class UnusedImportGlobalInspectionTest extends LightJavaCodeInsightFixtur
public void testRedundantImportModuleWithNotRedundantPackage() {
IdeaTestUtil.withLevel(getModule(), JavaFeature.PACKAGE_IMPORTS_SHADOW_MODULE_IMPORTS.getMinimumLevel(),
() -> {
JavaCodeStyleSettings.getInstance(getProject()).setDeleteUnusedModuleImports(true);
myFixture.addClass("""
package a.b;
@@ -391,6 +410,53 @@ public class UnusedImportGlobalInspectionTest extends LightJavaCodeInsightFixtur
});
}
public void testNotShowRedundantImportModuleWithNotRedundantPackage() {
IdeaTestUtil.withLevel(getModule(), JavaFeature.PACKAGE_IMPORTS_SHADOW_MODULE_IMPORTS.getMinimumLevel(),
() -> {
JavaCodeStyleSettings.getInstance(getProject()).setDeleteUnusedModuleImports(false);
myFixture.addClass("""
package a.b;
public final class List {
}
""");
doTest("""
import module java.base;
import a.b.*;
class Main {
public static void main(String[] args) {
List a;
}
}
""");
});
}
public void testDuplicatedRedundantImportModuleWithNotRedundantPackage() {
IdeaTestUtil.withLevel(getModule(), JavaFeature.PACKAGE_IMPORTS_SHADOW_MODULE_IMPORTS.getMinimumLevel(),
() -> {
JavaCodeStyleSettings.getInstance(getProject()).setDeleteUnusedModuleImports(false);
myFixture.addClass("""
package a.b;
public final class List {
}
""");
doTest("""
/*Unused import 'import module java.base;'*/ import module java.base;/**/
import module java.base;
import a.b.*;
class Main {
public static void main(String[] args) {
List a;
}
}
""");
});
}
public void testStaticMethodInInterface() {
myFixture.addClass("""
package org.example;
@@ -0,0 +1,625 @@
// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package com.siyeh.ig.imports;
import com.intellij.analysis.AnalysisScope;
import com.intellij.codeInspection.ex.GlobalInspectionToolWrapper;
import com.intellij.codeInspection.ex.InspectionToolWrapper;
import com.intellij.codeInspection.unusedImport.UnusedImportInspection;
import com.intellij.java.testFramework.fixtures.LightJava9ModulesCodeInsightFixtureTestCase;
import com.intellij.java.testFramework.fixtures.MultiModuleJava9ProjectDescriptor.ModuleDescriptor;
import com.intellij.openapi.Disposable;
import com.intellij.openapi.application.ex.PathManagerEx;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.module.ModuleManager;
import com.intellij.openapi.roots.DependencyScope;
import com.intellij.openapi.roots.ModuleRootModificationUtil;
import com.intellij.openapi.util.Disposer;
import com.intellij.pom.java.JavaFeature;
import com.intellij.psi.codeStyle.JavaCodeStyleSettings;
import com.intellij.testFramework.IdeaTestUtil;
import com.intellij.testFramework.InspectionTestUtil;
import com.intellij.testFramework.InspectionsKt;
import com.intellij.testFramework.fixtures.impl.GlobalInspectionContextForTests;
import org.intellij.lang.annotations.Language;
import org.jetbrains.annotations.NotNull;
import java.io.File;
import java.util.Collections;
import static com.intellij.java.testFramework.fixtures.MultiModuleJava9ProjectDescriptor.ModuleDescriptor.*;
public class UnusedImportGlobalWithModulesInspectionTest extends LightJava9ModulesCodeInsightFixtureTestCase {
@Override
protected void setUp() throws Exception {
super.setUp();
Module main = ModuleManager.getInstance(getProject()).findModuleByName(MAIN.moduleName);
Module m2 = ModuleManager.getInstance(getProject()).findModuleByName(M2.moduleName);
Module m3 = ModuleManager.getInstance(getProject()).findModuleByName(M3.moduleName);
Module m4 = ModuleManager.getInstance(getProject()).findModuleByName(M4.moduleName);
Module m5 = ModuleManager.getInstance(getProject()).findModuleByName(M5.moduleName);
//m2(B) -> m4(C) -> m5(D)
//m3(E)
ModuleRootModificationUtil.addDependency(m2, m4, DependencyScope.COMPILE, true);
ModuleRootModificationUtil.addDependency(m4, m5, DependencyScope.COMPILE, true);
ModuleRootModificationUtil.addDependency(m4, m5, DependencyScope.COMPILE, true);
ModuleRootModificationUtil.addDependency(main, m3, DependencyScope.COMPILE, true);
addCode("module-info.java", """
module my.source.moduleB {
exports my.source.moduleB;
requires transitive my.source.moduleC;
}
""", M2);
addCode("module-info.java", """
module my.source.moduleE {
exports my.source.moduleE;
}
""", M3);
addCode("module-info.java", """
module my.source.moduleC {
exports my.source.moduleC;
requires transitive my.source.moduleD;
}
""", M4);
addCode("module-info.java", """
module my.source.moduleD {
exports my.source.moduleD;
}
""", M5);
JavaCodeStyleSettings javaSettings = JavaCodeStyleSettings.getInstance(getProject());
boolean deleteUnusedModuleImports = javaSettings.isDeleteUnusedModuleImports();
Disposer.register(getTestRootDisposable(), new Disposable() {
@Override
public void dispose() {
javaSettings.setDeleteUnusedModuleImports(deleteUnusedModuleImports);
}
});
javaSettings.setDeleteUnusedModuleImports(false);
}
public void testParentNotUsedChildUsed() {
IdeaTestUtil.withLevel(
getModule(), JavaFeature.PACKAGE_IMPORTS_SHADOW_MODULE_IMPORTS.getMinimumLevel(), () -> {
JavaCodeStyleSettings.getInstance(getProject()).setDeleteUnusedModuleImports(false);
addCode("my/source/moduleC/Sql.java", """
package my.source.moduleC;
public class Sql {}
""", M4);
doTest("""
import module my.source.moduleB;
import module my.source.moduleC;/*unused*/
import module my.source.moduleE;
public final class Main {
public static void main(String[] args) {
new Sql();
}
}
""");
}
);
}
public void testParentNotUsedChildUsedDeleteUnused() {
IdeaTestUtil.withLevel(
getModule(), JavaFeature.PACKAGE_IMPORTS_SHADOW_MODULE_IMPORTS.getMinimumLevel(), () -> {
JavaCodeStyleSettings.getInstance(getProject()).setDeleteUnusedModuleImports(true);
addCode("my/source/moduleC/Sql.java", """
package my.source.moduleC;
public class Sql {}
""", M4);
doTest("""
import module my.source.moduleB;
import module my.source.moduleC;/*unused*/
import module my.source.moduleE;/*unused*/
public final class Main {
public static void main(String[] args) {
new Sql();
}
}
""");
}
);
}
public void testParentUsedChildNotUsed() {
IdeaTestUtil.withLevel(
getModule(), JavaFeature.PACKAGE_IMPORTS_SHADOW_MODULE_IMPORTS.getMinimumLevel(), () -> {
JavaCodeStyleSettings.getInstance(getProject()).setDeleteUnusedModuleImports(false);
addCode("my/source/moduleB/Sql.java", """
package my.source.moduleB;
public class Sql {}
""", M2);
doTest("""
import module my.source.moduleB;
import module my.source.moduleC;/*unused*/
import module my.source.moduleE;
public final class Main {
public static void main(String[] args) {
new Sql();
}
}
""");
}
);
}
public void testParentUsedChildNotUsedDeleteUnused() {
IdeaTestUtil.withLevel(
getModule(), JavaFeature.PACKAGE_IMPORTS_SHADOW_MODULE_IMPORTS.getMinimumLevel(), () -> {
JavaCodeStyleSettings.getInstance(getProject()).setDeleteUnusedModuleImports(true);
addCode("my/source/moduleB/Sql.java", """
package my.source.moduleB;
public class Sql {}
""", M2);
doTest("""
import module my.source.moduleB;
import module my.source.moduleC;/*unused*/
import module my.source.moduleE;/*unused*/
public final class Main {
public static void main(String[] args) {
new Sql();
}
}
""");
}
);
}
public void testParentUsedChildUsed() {
IdeaTestUtil.withLevel(
getModule(), JavaFeature.PACKAGE_IMPORTS_SHADOW_MODULE_IMPORTS.getMinimumLevel(), () -> {
JavaCodeStyleSettings.getInstance(getProject()).setDeleteUnusedModuleImports(false);
addCode("my/source/moduleB/Sql.java", """
package my.source.moduleB;
public class Sql {}
""", M2);
addCode("my/source/moduleC/Transaction.java", """
package my.source.moduleC;
public class Transaction {}
""", M4);
doTest("""
import module my.source.moduleB;
import module my.source.moduleC;/*unused*/
import module my.source.moduleE;
public final class Main {
public static void main(String[] args) {
new Sql();
new Transaction();
}
}
""");
}
);
}
public void testParentUsedChildUsedDeleteUnused() {
IdeaTestUtil.withLevel(
getModule(), JavaFeature.PACKAGE_IMPORTS_SHADOW_MODULE_IMPORTS.getMinimumLevel(), () -> {
JavaCodeStyleSettings.getInstance(getProject()).setDeleteUnusedModuleImports(true);
addCode("my/source/moduleB/Sql.java", """
package my.source.moduleB;
public class Sql {}
""", M2);
addCode("my/source/moduleC/Transaction.java", """
package my.source.moduleC;
public class Transaction {}
""", M4);
doTest("""
import module my.source.moduleB;
import module my.source.moduleC;/*unused*/
import module my.source.moduleE;/*unused*/
public final class Main {
public static void main(String[] args) {
new Sql();
new Transaction();
}
}
""");
}
);
}
public void testParentUsedChildUsedGrandChildUsed() {
IdeaTestUtil.withLevel(
getModule(), JavaFeature.PACKAGE_IMPORTS_SHADOW_MODULE_IMPORTS.getMinimumLevel(), () -> {
JavaCodeStyleSettings.getInstance(getProject()).setDeleteUnusedModuleImports(false);
addCode("my/source/moduleB/Sql.java", """
package my.source.moduleB;
public class Sql {}
""", M2);
addCode("my/source/moduleC/Transaction.java", """
package my.source.moduleC;
public class Transaction {}
""", M4);
addCode("my/source/moduleD/Connection.java", """
package my.source.moduleD;
public class Connection {}
""", M5);
doTest("""
import module my.source.moduleB;
import module my.source.moduleC;/*unused*/
import module my.source.moduleD;/*unused*/
import module my.source.moduleE;
public final class Main {
public static void main(String[] args) {
new Sql();
new Transaction();
new Connection();
}
}
""");
}
);
}
public void testParentUsedChildUsedGrandChildUsedDeleteUnused() {
IdeaTestUtil.withLevel(
getModule(), JavaFeature.PACKAGE_IMPORTS_SHADOW_MODULE_IMPORTS.getMinimumLevel(), () -> {
JavaCodeStyleSettings.getInstance(getProject()).setDeleteUnusedModuleImports(true);
addCode("my/source/moduleB/Sql.java", """
package my.source.moduleB;
public class Sql {}
""", M2);
addCode("my/source/moduleC/Transaction.java", """
package my.source.moduleC;
public class Transaction {}
""", M4);
addCode("my/source/moduleD/Connection.java", """
package my.source.moduleD;
public class Connection {}
""", M5);
doTest("""
import module my.source.moduleB;
import module my.source.moduleC;/*unused*/
import module my.source.moduleD;/*unused*/
import module my.source.moduleE;/*unused*/
public final class Main {
public static void main(String[] args) {
new Sql();
new Transaction();
new Connection();
}
}
""");
}
);
}
public void testOneUsed() {
IdeaTestUtil.withLevel(
getModule(), JavaFeature.PACKAGE_IMPORTS_SHADOW_MODULE_IMPORTS.getMinimumLevel(), () -> {
JavaCodeStyleSettings.getInstance(getProject()).setDeleteUnusedModuleImports(false);
addCode("my/source/moduleB/Sql.java", """
package my.source.moduleB;
public class Sql {}
""", M2);
doTest("""
import module my.source.moduleB;
import module my.source.moduleE;
public final class Main {
public static void main(String[] args) {
new Sql();
}
}
""");
}
);
}
public void testOneUsedDeleteUnused() {
IdeaTestUtil.withLevel(
getModule(), JavaFeature.PACKAGE_IMPORTS_SHADOW_MODULE_IMPORTS.getMinimumLevel(), () -> {
JavaCodeStyleSettings.getInstance(getProject()).setDeleteUnusedModuleImports(true);
addCode("my/source/moduleB/Sql.java", """
package my.source.moduleB;
public class Sql {}
""", M2);
doTest("""
import module my.source.moduleB;
import module my.source.moduleE;/*unused*/
public final class Main {
public static void main(String[] args) {
new Sql();
}
}
""");
}
);
}
public void testNoOneUsed() {
IdeaTestUtil.withLevel(
getModule(), JavaFeature.PACKAGE_IMPORTS_SHADOW_MODULE_IMPORTS.getMinimumLevel(), () -> {
JavaCodeStyleSettings.getInstance(getProject()).setDeleteUnusedModuleImports(false);
doTest("""
import module my.source.moduleB;
import module my.source.moduleE;
public final class Main {
public static void main(String[] args) {
}
}
""");
}
);
}
public void testNoOneUsedDeleteUnused() {
IdeaTestUtil.withLevel(
getModule(), JavaFeature.PACKAGE_IMPORTS_SHADOW_MODULE_IMPORTS.getMinimumLevel(), () -> {
JavaCodeStyleSettings.getInstance(getProject()).setDeleteUnusedModuleImports(true);
doTest("""
import module my.source.moduleB;/*unused*/
import module my.source.moduleE;/*unused*/
public final class Main {
public static void main(String[] args) {
}
}
""");
}
);
}
public void testParentNotUsedChildNotUsed() {
IdeaTestUtil.withLevel(
getModule(), JavaFeature.PACKAGE_IMPORTS_SHADOW_MODULE_IMPORTS.getMinimumLevel(), () -> {
JavaCodeStyleSettings.getInstance(getProject()).setDeleteUnusedModuleImports(false);
doTest("""
import module my.source.moduleB;
import module my.source.moduleC;/*unused*/
import module my.source.moduleE;
public final class Main {
public static void main(String[] args) {
}
}
""");
}
);
}
public void testParentNotUsedChildNotUsedDeleteUnused() {
IdeaTestUtil.withLevel(
getModule(), JavaFeature.PACKAGE_IMPORTS_SHADOW_MODULE_IMPORTS.getMinimumLevel(), () -> {
JavaCodeStyleSettings.getInstance(getProject()).setDeleteUnusedModuleImports(true);
doTest("""
import module my.source.moduleB;/*unused*/
import module my.source.moduleC;/*unused*/
import module my.source.moduleE;/*unused*/
public final class Main {
public static void main(String[] args) {
}
}
""");
}
);
}
public void testParentUsedChildUsedParentCovered() {
IdeaTestUtil.withLevel(
getModule(), JavaFeature.PACKAGE_IMPORTS_SHADOW_MODULE_IMPORTS.getMinimumLevel(), () -> {
JavaCodeStyleSettings.getInstance(getProject()).setDeleteUnusedModuleImports(false);
addCode("my/source/moduleB/Sql.java", """
package my.source.moduleB;
public class Sql {}
""", M2);
addCode("my/source/moduleC/Transaction.java", """
package my.source.moduleC;
public class Transaction {}
""", M4);
doTest("""
import module my.source.moduleB;
import module my.source.moduleC;/*unused*/
import module my.source.moduleE;
import my.source.moduleB.*;/*unused*/
public final class Main {
public static void main(String[] args) {
new Sql();
new Transaction();
}
}
""");
}
);
}
public void testParentUsedChildUsedParentCoveredDeleteUnused() {
IdeaTestUtil.withLevel(
getModule(), JavaFeature.PACKAGE_IMPORTS_SHADOW_MODULE_IMPORTS.getMinimumLevel(), () -> {
JavaCodeStyleSettings.getInstance(getProject()).setDeleteUnusedModuleImports(true);
addCode("my/source/moduleB/Sql.java", """
package my.source.moduleB;
public class Sql {}
""", M2);
addCode("my/source/moduleC/Transaction.java", """
package my.source.moduleC;
public class Transaction {}
""", M4);
doTest("""
import module my.source.moduleB;
import module my.source.moduleC;/*unused*/
import module my.source.moduleE;/*unused*/
import my.source.moduleB.*;/*unused*/
public final class Main {
public static void main(String[] args) {
new Sql();
new Transaction();
}
}
""");
}
);
}
public void testParentUsedChildUsedChildCovered() {
IdeaTestUtil.withLevel(
getModule(), JavaFeature.PACKAGE_IMPORTS_SHADOW_MODULE_IMPORTS.getMinimumLevel(), () -> {
JavaCodeStyleSettings.getInstance(getProject()).setDeleteUnusedModuleImports(false);
addCode("my/source/moduleB/Sql.java", """
package my.source.moduleB;
public class Sql {}
""", M2);
addCode("my/source/moduleC/Transaction.java", """
package my.source.moduleC;
public class Transaction {}
""", M4);
doTest("""
import module my.source.moduleB;
import module my.source.moduleC;/*unused*/
import module my.source.moduleE;
import my.source.moduleC.*;/*unused*/
public final class Main {
public static void main(String[] args) {
new Sql();
new Transaction();
}
}
""");
}
);
}
public void testParentUsedChildUsedChildCoveredDeleteUnused() {
IdeaTestUtil.withLevel(
getModule(), JavaFeature.PACKAGE_IMPORTS_SHADOW_MODULE_IMPORTS.getMinimumLevel(), () -> {
JavaCodeStyleSettings.getInstance(getProject()).setDeleteUnusedModuleImports(true);
addCode("my/source/moduleB/Sql.java", """
package my.source.moduleB;
public class Sql {}
""", M2);
addCode("my/source/moduleC/Transaction.java", """
package my.source.moduleC;
public class Transaction {}
""", M4);
doTest("""
import module my.source.moduleB;
import module my.source.moduleC;/*unused*/
import module my.source.moduleE;/*unused*/
import my.source.moduleC.*;/*unused*/
public final class Main {
public static void main(String[] args) {
new Sql();
new Transaction();
}
}
""");
}
);
}
public void testParentUsedChildUsedChildCoveredParentCovered() {
IdeaTestUtil.withLevel(
getModule(), JavaFeature.PACKAGE_IMPORTS_SHADOW_MODULE_IMPORTS.getMinimumLevel(), () -> {
JavaCodeStyleSettings.getInstance(getProject()).setDeleteUnusedModuleImports(false);
addCode("my/source/moduleB/Sql.java", """
package my.source.moduleB;
public class Sql {}
""", M2);
addCode("my/source/moduleC/Transaction.java", """
package my.source.moduleC;
public class Transaction {}
""", M4);
doTest("""
import module my.source.moduleB;
import module my.source.moduleC;/*unused*/
import module my.source.moduleE;
import my.source.moduleB.*;/*unused*/
import my.source.moduleC.*;/*unused*/
public final class Main {
public static void main(String[] args) {
new Sql();
new Transaction();
}
}
""");
}
);
}
public void testParentUsedChildUsedChildCoveredParentCoveredDeleteUnused() {
IdeaTestUtil.withLevel(
getModule(), JavaFeature.PACKAGE_IMPORTS_SHADOW_MODULE_IMPORTS.getMinimumLevel(), () -> {
JavaCodeStyleSettings.getInstance(getProject()).setDeleteUnusedModuleImports(true);
addCode("my/source/moduleB/Sql.java", """
package my.source.moduleB;
public class Sql {}
""", M2);
addCode("my/source/moduleC/Transaction.java", """
package my.source.moduleC;
public class Transaction {}
""", M4);
doTest("""
import module my.source.moduleB;
import module my.source.moduleC;/*unused*/
import module my.source.moduleE;/*unused*/
import my.source.moduleB.*;/*unused*/
import my.source.moduleC.*;/*unused*/
public final class Main {
public static void main(String[] args) {
new Sql();
new Transaction();
}
}
""");
}
);
}
@Override
protected String getTestDataPath() {
return PathManagerEx.getCommunityHomePath() + "/java/java-tests/testData/ig/com/siyeh/igtest/imports/globalInspectionWithModules";
}
private void doTest(@Language("JAVA") @NotNull String classText) {
myFixture.addClass(classText);
doTest();
}
private void doTest() {
GlobalInspectionToolWrapper toolWrapper = new GlobalInspectionToolWrapper(new UnusedImportInspection());
AnalysisScope scope = new AnalysisScope(myFixture.getProject());
GlobalInspectionContextForTests globalContext =
InspectionsKt.createGlobalContextForTool(scope, getProject(), Collections.<InspectionToolWrapper<?, ?>>singletonList(toolWrapper));
InspectionTestUtil.runTool(toolWrapper, scope, globalContext);
InspectionTestUtil.compareToolResults(globalContext, toolWrapper, false, new File(getTestDataPath(), getTestName(false)).getPath());
}
private void addCode(@NotNull String name, @NotNull @Language("JAVA") String text, @NotNull ModuleDescriptor descriptor) {
addFile(name, text, descriptor);
}
}