[java-import] IDEA-364508 support optimize imports

- new options are added
- changes for optimize imports

(cherry picked from commit 82b0223f9e7e2972d13ab182ea651cdccd28a5d3)

GitOrigin-RevId: 99f0276e1d9464f75f5bbce91ad09727582d208b
This commit is contained in:
Mikhail Pyltsin
2024-12-09 19:11:04 +01:00
committed by intellij-monorepo-bot
parent dc032bf4a7
commit 46bfa503aa
33 changed files with 693 additions and 40 deletions

View File

@@ -171,6 +171,9 @@ public class JavaCodeStyleSettings extends CustomCodeStyleSettings implements Im
// Imports
public boolean LAYOUT_STATIC_IMPORTS_SEPARATELY = true;
public boolean LAYOUT_ON_DEMAND_IMPORT_FROM_SAME_PACKAGE_FIRST = true;
public boolean MODULE_IMPORT_FIRST = true;
public boolean SPACE_BETWEEN_MODULE_AND_OTHER_IMPORTS = false;
public boolean PRESERVE_MODULE_IMPORTS = true;
public boolean USE_FQ_CLASS_NAMES;
public boolean USE_SINGLE_CLASS_IMPORTS = true;
public boolean INSERT_INNER_CLASS_IMPORTS;
@@ -295,10 +298,27 @@ public class JavaCodeStyleSettings extends CustomCodeStyleSettings implements Im
return LAYOUT_ON_DEMAND_IMPORT_FROM_SAME_PACKAGE_FIRST;
}
public boolean isModuleImportFirst() {
return MODULE_IMPORT_FIRST;
}
public boolean isSpaceBetweenModuleAndOtherImports() {
return SPACE_BETWEEN_MODULE_AND_OTHER_IMPORTS;
}
public void setLayoutOnDemandImportFromSamePackageFirst(boolean value) {
this.LAYOUT_ON_DEMAND_IMPORT_FROM_SAME_PACKAGE_FIRST = value;
}
public void setModuleImportFirst(boolean value) {
this.MODULE_IMPORT_FIRST = value;
}
public void setSpaceBetweenModuleAndOtherImports(boolean value) {
SPACE_BETWEEN_MODULE_AND_OTHER_IMPORTS = value;
}
@Override
public int getNamesCountToUseImportOnDemand() {
return NAMES_COUNT_TO_USE_IMPORT_ON_DEMAND;
@@ -338,6 +358,14 @@ public class JavaCodeStyleSettings extends CustomCodeStyleSettings implements Im
return USE_SINGLE_CLASS_IMPORTS;
}
public boolean isPreserveModuleImports() {
return PRESERVE_MODULE_IMPORTS;
}
public void setPreserveModuleImports(boolean value) {
PRESERVE_MODULE_IMPORTS = value;
}
@Override
public void setUseSingleClassImports(boolean value) {
USE_SINGLE_CLASS_IMPORTS = value;

View File

@@ -21,7 +21,7 @@ public abstract class CodeStyleImportsPanelBase extends JPanel {
protected final ImportLayoutPanel myImportLayoutPanel;
public CodeStyleImportsPanelBase() {
myImportLayoutPanel = new ImportLayoutPanel(isShowLayoutOnDemandImportFromSamePackageFirstCheckbox()) {
myImportLayoutPanel = new ImportLayoutPanel(isShowLayoutOnDemandImportFromSamePackageFirstCheckbox(), isSupportModule()) {
@Override
public void refresh() {
refreshTable(myPackageTable, myPackageList);
@@ -139,4 +139,8 @@ public abstract class CodeStyleImportsPanelBase extends JPanel {
protected boolean isShowLayoutOnDemandImportFromSamePackageFirstCheckbox() {
return false;
}
protected boolean isSupportModule() {
return false;
}
}

View File

@@ -30,6 +30,8 @@ import javax.swing.table.TableCellEditor;
import javax.swing.table.TableColumn;
import javax.swing.table.TableModel;
import java.awt.*;
import java.util.ArrayList;
import java.util.List;
/**
* @author Max Medvedev
@@ -38,6 +40,8 @@ public abstract class ImportLayoutPanel extends JPanel {
private final JBCheckBox myCbLayoutStaticImportsSeparately =
new JBCheckBox(JavaBundle.message("import.layout.static.imports.separately"));
@Nullable private final JBCheckBox myCbLayoutOnDemandImportsFromSamePackageFirst;
@Nullable private final JBCheckBox myCbModuleImportFirst;
@Nullable private final JBCheckBox myCbSpaceBetweenModuleAndOther;
private final JBTable myImportLayoutTable;
private final PackageEntryTable myImportLayoutList = new PackageEntryTable();
@@ -59,7 +63,17 @@ public abstract class ImportLayoutPanel extends JPanel {
return myCbLayoutOnDemandImportsFromSamePackageFirst;
}
public ImportLayoutPanel(boolean showLayoutOnDemandImportFromSamePackageFirstCheckbox) {
@Nullable
public JBCheckBox getCbModuleImportFirst() {
return myCbModuleImportFirst;
}
@Nullable
public JBCheckBox getCbSpaceBetweenModuleAndOther() {
return myCbSpaceBetweenModuleAndOther;
}
public ImportLayoutPanel(boolean showLayoutOnDemandImportFromSamePackageFirstCheckbox, boolean supportModuleImport) {
super(new BorderLayout());
myCbLayoutStaticImportsSeparately.addItemListener(e -> {
@@ -118,8 +132,16 @@ public abstract class ImportLayoutPanel extends JPanel {
showLayoutOnDemandImportFromSamePackageFirstCheckbox
? new JBCheckBox(JavaBundle.message("import.layout.on.demand.import.from.same.package.first"))
: null;
myCbModuleImportFirst = supportModuleImport ? new JBCheckBox(JavaBundle.message("import.layout.module.import.first")) : null;
myCbSpaceBetweenModuleAndOther =
supportModuleImport ? new JBCheckBox(JavaBundle.message("import.layout.space.between.module.import.other")) : null;
List<@Nullable JBCheckBox> additionalCheckBoxes = new ArrayList<>();
additionalCheckBoxes.add(myCbLayoutOnDemandImportsFromSamePackageFirst);
additionalCheckBoxes.add(myCbModuleImportFirst);
additionalCheckBoxes.add(myCbSpaceBetweenModuleAndOther);
final ImportLayoutPanelUI UI = new ImportLayoutPanelUI(myCbLayoutStaticImportsSeparately,
myCbLayoutOnDemandImportsFromSamePackageFirst,
additionalCheckBoxes,
importLayoutPanel);
add(UI.getPanel(), BorderLayout.CENTER);
}
@@ -231,6 +253,14 @@ public abstract class ImportLayoutPanel extends JPanel {
return myCbLayoutOnDemandImportsFromSamePackageFirst != null && myCbLayoutOnDemandImportsFromSamePackageFirst.isSelected();
}
public boolean isModuleImportFirst() {
return myCbModuleImportFirst != null && myCbModuleImportFirst.isSelected();
}
public boolean isSpaceBetweenModuleAndOther() {
return myCbSpaceBetweenModuleAndOther != null && myCbSpaceBetweenModuleAndOther.isSelected();
}
public static JBTable createTableForPackageEntries(final PackageEntryTable packageTable, final ImportLayoutPanel panel) {
final String[] names = {
JavaBundle.message("listbox.import.package"),

View File

@@ -7,10 +7,12 @@ import com.intellij.ui.dsl.builder.Align
import com.intellij.ui.dsl.builder.panel
import javax.swing.JPanel
internal class ImportLayoutPanelUI(staticImportsCb: JBCheckBox, onDemandBeforeSingleClassCb: JBCheckBox?, importLayoutPanel: JPanel) {
internal class ImportLayoutPanelUI(staticImportsCb: JBCheckBox, additionalCheckBoxes: List<JBCheckBox?>, importLayoutPanel: JPanel) {
val panel = panel {
group(JavaBundle.message("title.import.layout")) {
if (onDemandBeforeSingleClassCb != null) row { cell(onDemandBeforeSingleClassCb) }
for (box in additionalCheckBoxes) {
if (box != null) row { cell(box) }
}
row { cell(staticImportsCb) }
row { cell(importLayoutPanel).align(Align.FILL) }.resizableRow()
}.resizableRow()

View File

@@ -11,6 +11,7 @@ import com.intellij.ui.table.TableView;
import com.intellij.util.ui.ColumnInfo;
import com.intellij.util.ui.ListTableModel;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import javax.swing.*;
import javax.swing.table.TableCellEditor;
@@ -19,6 +20,8 @@ import java.util.List;
class JavaCodeStyleImportsPanel extends CodeStyleImportsPanelBase {
private FullyQualifiedNamesInJavadocOptionProvider myFqnInJavadocOption;
@Nullable
private JCheckBox myCbPreserveModuleImports;
private ListTableModel<InnerClassItem> doNotInsertInnerListModel;
private static final ColumnInfo<?, ?>[] INNER_CLASS_COLUMNS = {
@@ -36,13 +39,17 @@ class JavaCodeStyleImportsPanel extends CodeStyleImportsPanelBase {
};
private TableView<InnerClassItem> mydoNotInsertInnerTable;
JavaCodeStyleImportsPanel() {
super();
}
@Override
protected CodeStyleImportsBaseUI createKotlinUI(JComponent packages, JComponent importLayout) {
createDoNotImportInnerList();
myCbPreserveModuleImports = new JBCheckBox(JavaBundle.message("checkbox.preserve.module.import"));
myFqnInJavadocOption = new FullyQualifiedNamesInJavadocOptionProvider();
JavaCodeStyleImportsUI result =
new JavaCodeStyleImportsUI(packages, importLayout, mydoNotInsertInnerTable, myFqnInJavadocOption.getPanel());
new JavaCodeStyleImportsUI(packages, importLayout, mydoNotInsertInnerTable, myCbPreserveModuleImports, myFqnInJavadocOption.getPanel());
result.init();
return result;
}
@@ -52,8 +59,12 @@ class JavaCodeStyleImportsPanel extends CodeStyleImportsPanelBase {
final JavaCodeStyleSettings javaSettings = getJavaSettings(settings);
applyLayoutSettings(javaSettings);
myFqnInJavadocOption.apply(settings);
JCheckBox cbPreserveModuleImports = myCbPreserveModuleImports;
if(cbPreserveModuleImports!=null) javaSettings.setPreserveModuleImports(cbPreserveModuleImports.isSelected());
javaSettings.setDoNotImportInner(getInnerClassesNames());
javaSettings.setLayoutOnDemandImportFromSamePackageFirst(myImportLayoutPanel.isLayoutOnDemandImportsFromSamePackageFirst());
javaSettings.setModuleImportFirst(myImportLayoutPanel.isModuleImportFirst());
javaSettings.setSpaceBetweenModuleAndOtherImports(myImportLayoutPanel.isSpaceBetweenModuleAndOther());
}
@Override
@@ -64,8 +75,18 @@ class JavaCodeStyleImportsPanel extends CodeStyleImportsPanelBase {
for (String name : javaSettings.getDoNotImportInner()) {
doNotInsertInnerListModel.addRow(new InnerClassItem(name));
}
JBCheckBox checkBox = myImportLayoutPanel.getCbLayoutOnDemandImportsFromSamePackageFirst();
if (checkBox != null) checkBox.setSelected(javaSettings.isLayoutOnDemandImportFromSamePackageFirst());
JCheckBox cbPreserveModuleImports = myCbPreserveModuleImports;
if (cbPreserveModuleImports != null) cbPreserveModuleImports.setSelected(javaSettings.isPreserveModuleImports());
JBCheckBox cbLayoutOnDemandImportsFromSamePackageFirst = myImportLayoutPanel.getCbLayoutOnDemandImportsFromSamePackageFirst();
if (cbLayoutOnDemandImportsFromSamePackageFirst != null) cbLayoutOnDemandImportsFromSamePackageFirst.setSelected(javaSettings.isLayoutOnDemandImportFromSamePackageFirst());
JBCheckBox cbModuleImportFirst = myImportLayoutPanel.getCbModuleImportFirst();
if (cbModuleImportFirst != null) cbModuleImportFirst.setSelected(javaSettings.isModuleImportFirst());
JBCheckBox cbSpaceBetweenModuleAndOther = myImportLayoutPanel.getCbSpaceBetweenModuleAndOther();
if (cbSpaceBetweenModuleAndOther != null) cbSpaceBetweenModuleAndOther.setSelected(javaSettings.isSpaceBetweenModuleAndOtherImports());
}
@Override
@@ -74,8 +95,18 @@ class JavaCodeStyleImportsPanel extends CodeStyleImportsPanelBase {
boolean isModified = isModifiedLayoutSettings(javaSettings);
isModified |= myFqnInJavadocOption.isModified(settings);
isModified |= !javaSettings.getDoNotImportInner().equals(getInnerClassesNames());
JBCheckBox checkBox = myImportLayoutPanel.getCbLayoutOnDemandImportsFromSamePackageFirst();
if (checkBox != null) isModified |= isModified(checkBox, javaSettings.isLayoutOnDemandImportFromSamePackageFirst());
JCheckBox cbPreserveModuleImports = myCbPreserveModuleImports;
if (cbPreserveModuleImports != null) isModified |= isModified(cbPreserveModuleImports, javaSettings.isPreserveModuleImports());
JBCheckBox cbLayoutOnDemandImportsFromSamePackageFirst = myImportLayoutPanel.getCbLayoutOnDemandImportsFromSamePackageFirst();
if (cbLayoutOnDemandImportsFromSamePackageFirst != null) isModified |= isModified(cbLayoutOnDemandImportsFromSamePackageFirst, javaSettings.isLayoutOnDemandImportFromSamePackageFirst());
JBCheckBox cbModuleImportFirst = myImportLayoutPanel.getCbModuleImportFirst();
if (cbModuleImportFirst != null) isModified |= isModified(cbModuleImportFirst, javaSettings.isModuleImportFirst());
JBCheckBox cbSpaceBetweenModuleAndOther = myImportLayoutPanel.getCbSpaceBetweenModuleAndOther();
if (cbSpaceBetweenModuleAndOther != null) isModified |= isModified(cbSpaceBetweenModuleAndOther, javaSettings.isSpaceBetweenModuleAndOtherImports());
return isModified;
}
@@ -107,6 +138,11 @@ class JavaCodeStyleImportsPanel extends CodeStyleImportsPanelBase {
return true;
}
@Override
protected boolean isSupportModule() {
return true;
}
private abstract static class MyColumnInfo extends ColumnInfo<InnerClassItem, String> {
MyColumnInfo(final @NlsContexts.ColumnName String name) {
super(name);

View File

@@ -12,10 +12,13 @@ import com.intellij.ui.dsl.builder.Panel
import com.intellij.ui.dsl.gridLayout.UnscaledGaps
import com.intellij.ui.table.TableView
import com.intellij.util.ui.JBDimension
import javax.swing.JCheckBox
import javax.swing.JComponent
internal class JavaCodeStyleImportsUI(packages: JComponent, importLayout: JComponent,
internal class JavaCodeStyleImportsUI(packages: JComponent,
importLayout: JComponent,
private val doNotInsertInnerTable: TableView<InnerClassItem>,
private val preserveModuleImports: JCheckBox,
private val fqnInJavadocOption: JComponent) : CodeStyleImportsBaseUI(packages, importLayout) {
override fun init() {
@@ -26,6 +29,11 @@ internal class JavaCodeStyleImportsUI(packages: JComponent, importLayout: JCompo
}
override fun Panel.fillCustomOptions() {
row {
cell(preserveModuleImports).applyToComponent {
isOpaque = false
}
}
indent {
row {
val decorator = ToolbarDecorator.createDecorator(doNotInsertInnerTable)

View File

@@ -221,7 +221,7 @@ public final class AddSingleMemberStaticImportAction extends PsiUpdateModCommand
if (existingImport == null && resolved instanceof PsiClass) {
((PsiImportHolder) file).importClass((PsiClass) resolved);
}
else if (existingImport == null || existingImport.isOnDemand() && resolvedClass != null && ImportHelper.hasConflictingOnDemandImport((PsiJavaFile)file, resolvedClass, referenceName)) {
else if (existingImport == null || existingImport.isOnDemand() && resolvedClass != null && ImportHelper.hasConflictingOnStaticDemandImport((PsiJavaFile)file, resolvedClass, referenceName)) {
PsiReferenceExpressionImpl.bindToElementViaStaticImport(resolvedClass, referenceName, ((PsiJavaFile)file).getImportList());
}

View File

@@ -101,7 +101,9 @@ public final class ImportHelper {
List<Import> resultList = sortItemsAccordingToSettings(imports, mySettings);
Map<String, Boolean> classesOrPackagesToImportOnDemand = new HashMap<>();
collectOnDemandImports(resultList, mySettings, classesOrPackagesToImportOnDemand);
List<PsiImportModuleStatement> previousModuleStatements = collectModuleImports(file, mySettings);
Map<String, PsiImportModuleStatement> moduleStatementMap = collectNamesImportedByModules(file, previousModuleStatements, resultList);
collectOnDemandImports(resultList, mySettings, classesOrPackagesToImportOnDemand, moduleStatementMap);
MultiMap<String, String> conflictingMemberNames = new MultiMap<>();
for (Import anImport : resultList) {
@@ -120,14 +122,23 @@ public final class ImportHelper {
}
ImportUtils.ImplicitImportChecker checker = ImportUtils.createImplicitImportChecker(file);
Set<String> classesToUseSingle = findSingleImports(file, resultList, classesOrPackagesToImportOnDemand.keySet(), checker);
Set<String> toReimport = calculateOnDemandImportConflicts(file, classesOrPackagesToImportOnDemand);
Set<String> classesToUseSingle = findSingleImports(file, resultList, classesOrPackagesToImportOnDemand.keySet(),
moduleStatementMap.keySet(), checker);
Set<String> toReimport = calculateOnDemandImportConflicts(file, classesOrPackagesToImportOnDemand, moduleStatementMap.values(),
moduleStatementMap.keySet());
classesToUseSingle.addAll(toReimport);
try {
boolean onDemandFirst = mySettings.isLayoutOnDemandImportFromSamePackageFirst();
boolean moduleImportFirst = mySettings.isModuleImportFirst();
StringBuilder text =
buildImportListText(resultList, classesOrPackagesToImportOnDemand.keySet(), classesToUseSingle, checker, onDemandFirst);
buildImportListText(resultList,
classesOrPackagesToImportOnDemand.keySet(),
classesToUseSingle,
checker,
moduleStatementMap,
onDemandFirst,
moduleImportFirst);
for (PsiElement nonImport : nonImports) {
text.append("\n").append(nonImport.getText());
}
@@ -149,12 +160,67 @@ public final class ImportHelper {
}
}
/**
* Collects the names of classes that are imported by modules specified implicitly in the given Java file and in import list.
*
* @param file the Java file for which imported class names are being collected.
* @param statements a list of import module statements that specify the modules from which classes are imported.
* @param list a list of import objects representing the imports from which class names need to be collected.
* @return a map of class names and used module imports.
*/
@NotNull
private static 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));
moduleImports.addAll(statements);
Map<String, PsiImportModuleStatement> usedClasses = new HashMap<>();
for (Import anImport : list) {
if (anImport.isStatic) continue;
String qualifiedName = anImport.name();
String referencePackageName = StringUtil.getPackageName(qualifiedName);
String referenceShortName = StringUtil.getShortName(qualifiedName);
if (referencePackageName.isEmpty() || referenceShortName.isEmpty()) continue;
for (PsiImportModuleStatement statement : moduleImports) {
PsiPackageAccessibilityStatement importedPackage = statement.findImportedPackage(referencePackageName);
if (importedPackage == null) continue;
PsiJavaCodeReferenceElement packageReference = importedPackage.getPackageReference();
if (packageReference == null) continue;
PsiElement resolved = packageReference.resolve();
if (!(resolved instanceof PsiPackage psiPackage)) continue;
if (!psiPackage.containsClassNamed(referenceShortName)) continue;
usedClasses.put(anImport.name, statement);
}
}
return usedClasses;
}
/**
* Collects the module import statements from the specified Java file, considering the code style settings, to insert in the new import list
*
* @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.
* @return a list of module import statements present in the Java file.
*/
@NotNull
private static List<PsiImportModuleStatement> collectModuleImports(@NotNull PsiJavaFile file, JavaCodeStyleSettings settings) {
if (!settings.isPreserveModuleImports()) return Collections.emptyList();
PsiImportList importList = file.getImportList();
if (importList == null) return Collections.emptyList();
return Arrays.asList(importList.getImportModuleStatements());
}
public static void collectOnDemandImports(@NotNull List<Import> resultList,
@NotNull JavaCodeStyleSettings settings,
@NotNull Map<String, Boolean> outClassesOrPackagesToImportOnDemand) {
@NotNull Map<String, Boolean> outClassesOrPackagesToImportOnDemand,
@NotNull Map<String, PsiImportModuleStatement> moduleStatementMap) {
Object2IntMap<String> packageToCountMap = new Object2IntOpenHashMap<>();
Object2IntMap <String> classToCountMap = new Object2IntOpenHashMap<>();
for (Import anImport : resultList) {
if (!anImport.isStatic() && moduleStatementMap.containsKey(anImport.name)) continue;
String packageOrClassName = StringUtil.getPackageName(anImport.name());
if (packageOrClassName.isEmpty()) continue;
Object2IntMap<String> map = anImport.isStatic() ? classToCountMap : packageToCountMap;
@@ -200,6 +266,7 @@ public final class ImportHelper {
private static @NotNull Set<String> findSingleImports(@NotNull PsiJavaFile file,
@NotNull Collection<Import> imports,
@NotNull Set<String> onDemandImports,
@NotNull Set<String> namesImportedByModuleStatements,
@NotNull ImportUtils.ImplicitImportChecker checker) {
GlobalSearchScope resolveScope = file.getResolveScope();
String thisPackageName = file.getPackageName();
@@ -213,7 +280,7 @@ public final class ImportHelper {
String prefix = StringUtil.getPackageName(name);
if (prefix.isEmpty()) continue;
boolean isImplicitlyImported = checker.isImplicitlyImported(name, anImport.isStatic());
if (!onDemandImports.contains(prefix) && !isImplicitlyImported) continue;
if (!onDemandImports.contains(prefix) && !isImplicitlyImported && !namesImportedByModuleStatements.contains(name)) continue;
String shortName = PsiNameHelper.getShortClassName(name);
String thisPackageClass = !thisPackageName.isEmpty() ? thisPackageName + "." + shortName : shortName;
@@ -280,11 +347,16 @@ public final class ImportHelper {
return false;
}
private static Set<String> calculateOnDemandImportConflicts(@NotNull PsiJavaFile file, @NotNull Map<String, Boolean> onDemandImports) {
private static Set<String> calculateOnDemandImportConflicts(@NotNull PsiJavaFile file,
@NotNull Map<String, Boolean> onDemandImports,
@NotNull Collection<PsiImportModuleStatement> usedModuleStatements,
@NotNull Set<String> namesImportedByModuleStatements) {
if (file instanceof PsiCompiledElement) return Collections.emptySet();
List<PsiImportStatementBase> implicitImports = ImportsUtil.getAllImplicitImports(file);
List<PsiImportModuleStatement> implicitModuleImports =
ContainerUtil.filterIsInstance(implicitImports, PsiImportModuleStatement.class);
List<PsiImportModuleStatement> moduleImports =
new ArrayList<>(ContainerUtil.filterIsInstance(implicitImports, PsiImportModuleStatement.class));
moduleImports.addAll(usedModuleStatements);
List<String> onDemands =
StreamEx.of(implicitImports)
.filter(implicit -> implicit.isOnDemand() &&
@@ -296,7 +368,7 @@ public final class ImportHelper {
onDemands.add(onDemand);
}
}
if (implicitModuleImports.isEmpty() && onDemands.size() < 2) return Collections.emptySet();
if (moduleImports.isEmpty() && onDemands.size() < 2) return Collections.emptySet();
// if we have classes x.A, x.B and there is an "import x.*" then classNames = {"x" -> ("A", "B")}
GlobalSearchScope resolveScope = file.getResolveScope();
@@ -339,7 +411,7 @@ public final class ImportHelper {
conflicts.addAll(intersection);
}
}
if (implicitModuleImports.isEmpty() && conflicts.isEmpty()) return Collections.emptySet();
if (moduleImports.isEmpty() && conflicts.isEmpty()) return Collections.emptySet();
Set<String> result = new HashSet<>();
String filePackageName = file.getPackageName();
@@ -360,14 +432,13 @@ public final class ImportHelper {
//conflict with packages
boolean hasConflict = conflicts.contains(psiClass.getName());
if (!hasConflict) {
//check conflict only with implicit module imports
//explicit module imports should be checked separately, right now it is not supported
//if it is already imported by on demands, there is no conflict with modules
if (!(PsiUtil.isAvailable(JavaFeature.PACKAGE_IMPORTS_SHADOW_MODULE_IMPORTS, file) &&
classNames.getOrDefault(referencePackageName, Collections.emptySet()).contains(referenceShortName))) {
hasConflict = !implicitModuleImports.isEmpty() &&
ImportUtils.hasOnDemandImportConflictWithImports(file, implicitModuleImports, qualifiedName, false, true);
classNames.getOrDefault(referencePackageName, Collections.emptySet()).contains(referenceShortName)) ||
//with PACKAGE_IMPORTS_SHADOW_MODULE_IMPORTS conflicts are possible only between modules, other types of imports should be more important
namesImportedByModuleStatements.contains(qualifiedName)) {
hasConflict = !moduleImports.isEmpty() &&
ImportUtils.hasOnDemandImportConflictWithImports(file, moduleImports, qualifiedName, false, true);
}
}
if (!hasConflict) return;
@@ -392,9 +463,14 @@ public final class ImportHelper {
@NotNull Set<String> packagesOrClassesToImportOnDemand,
@NotNull Set<String> namesToUseSingle,
@NotNull ImportUtils.ImplicitImportChecker implicitImportContext,
boolean onDemandImportsFirst) {
@NotNull Map<String, PsiImportModuleStatement> moduleStatementMap,
boolean onDemandImportsFirst,
boolean moduleImportFirst) {
Set<String> importedPackagesOrClasses = new HashSet<>();
@NonNls StringBuilder buffer = new StringBuilder();
Set<PsiImportModuleStatement> usedModuleImports = new HashSet<>();
for (Import importedName : imports) {
String name = importedName.name();
boolean isStatic = importedName.isStatic();
@@ -412,10 +488,31 @@ public final class ImportHelper {
appendImportStatement(name, isStatic, buffer);
}
}
else if (!implicitlyImported && !importedPackagesOrClasses.contains(packageOrClassName)) {
else if (!implicitlyImported && !importedPackagesOrClasses.contains(packageOrClassName) && !moduleStatementMap.containsKey(name)) {
appendImportStatement(name, isStatic, buffer);
}
else if (!implicitlyImported && !importedPackagesOrClasses.contains(packageOrClassName) && moduleStatementMap.containsKey(name)) {
usedModuleImports.add(moduleStatementMap.get(name));
}
}
StringBuilder moduleStatements = new StringBuilder();
for (String importModuleStatement : usedModuleImports.stream()
.map(m->m.getText())
.sorted(Comparator.naturalOrder())
.toList()) {
moduleStatements.append(importModuleStatement).append("\n");
}
if (!moduleStatements.isEmpty()) {
if (moduleImportFirst) {
buffer.insert(0, moduleStatements);
}
else {
buffer.append(moduleStatements);
}
}
return buffer;
}
@@ -782,6 +879,12 @@ public final class ImportHelper {
}
public int getEmptyLinesBetween(@NotNull PsiImportStatementBase statement1, @NotNull PsiImportStatementBase statement2) {
boolean spaceBetweenModuleAndOtherImports = mySettings.SPACE_BETWEEN_MODULE_AND_OTHER_IMPORTS;
boolean isModule1 = statement1 instanceof PsiImportModuleStatement;
boolean isModule2 = statement2 instanceof PsiImportModuleStatement;
if (((isModule1 && !isModule2) || (!(isModule1) && isModule2))) {
return spaceBetweenModuleAndOtherImports ? 1 : 0;
}
int index1 = findEntryIndex(statement1);
int index2 = findEntryIndex(statement2);
if (index1 == index2) return 0;
@@ -798,7 +901,8 @@ public final class ImportHelper {
//noinspection AssignmentToForLoopParameter
do {
space++;
} while (entries[++i] == PackageEntry.BLANK_LINE_ENTRY);
}
while (entries[++i] == PackageEntry.BLANK_LINE_ENTRY);
maxSpace = Math.max(maxSpace, space);
}
}
@@ -848,11 +952,12 @@ public final class ImportHelper {
if (ref == null) return -1;
String packageName = statement.isOnDemand() ? ref.getCanonicalText() : StringUtil.getPackageName(ref.getCanonicalText());
return findEntryIndex(packageName,
mySettings.LAYOUT_STATIC_IMPORTS_SEPARATELY && statement instanceof PsiImportStaticStatement,
mySettings.IMPORT_LAYOUT_TABLE.getEntries());
}
public static boolean hasConflictingOnDemandImport(@NotNull PsiJavaFile file, @NotNull PsiClass psiClass, @NotNull String referenceName) {
public static boolean hasConflictingOnStaticDemandImport(@NotNull PsiJavaFile file, @NotNull PsiClass psiClass, @NotNull String referenceName) {
Collection<Import> resultList = collectNamesToImport(file, new ArrayList<>());
String qualifiedName = psiClass.getQualifiedName();
for (Import anImport : resultList) {
@@ -875,7 +980,7 @@ public final class ImportHelper {
.collect(Collectors.toSet());
String newImport = StringUtil.getQualifiedName(qualifiedName, referenceName);
Set<String> singleImports = findSingleImports(file, Collections.singletonList(new Import(newImport, true)), onDemandImportedClasses,
ImportUtils.createImplicitImportChecker(file));
Collections.emptySet(), ImportUtils.createImplicitImportChecker(file));
return singleImports.contains(newImport);
}

View File

@@ -130,7 +130,7 @@ public class JavaCodeStyleManagerImpl extends JavaCodeStyleManager {
@Override
public boolean hasConflictingOnDemandImport(@NotNull PsiJavaFile file, @NotNull PsiClass psiClass, @NotNull String referenceName) {
return ImportHelper.hasConflictingOnDemandImport(file, psiClass, referenceName);
return ImportHelper.hasConflictingOnStaticDemandImport(file, psiClass, referenceName);
}
@Override

View File

@@ -147,6 +147,7 @@
"method_parameters_right_paren_on_new_line": false,
"method_parameters_wrap": "normal",
"modifier_list_wrap": false,
"module_import_first": true,
"multi_catch_types_wrap": "normal",
"names_count_to_use_import_on_demand": 3,
"new_line_after_lparen_in_annotation": false,
@@ -163,6 +164,7 @@
"place_assignment_sign_on_next_line": false,
"prefer_longer_names": true,
"prefer_parameters_wrap": false,
"preserve_module_imports": true,
"record_components_wrap": "normal",
"repeat_annotations": [
"com.jetbrains.First",
@@ -222,6 +224,7 @@
"space_before_while_keyword": true,
"space_before_while_left_brace": true,
"space_before_while_parentheses": true,
"space_between_module_and_other_imports": false,
"space_inside_one_line_enum_braces": false,
"space_within_empty_array_initializer_braces": false,
"space_within_empty_method_call_parentheses": false,

View File

@@ -0,0 +1,10 @@
import module my.source.moduleB;
import module my.source.moduleA;
import my.source.moduleA.*;
class ModuleImportWithPackageImport {
Imported module;
A a;
B b;
}

View File

@@ -0,0 +1,9 @@
import module my.source.moduleA;
import module my.source.moduleB;
import my.source.moduleA.Imported;
class ModuleImportWithPackageImport {
Imported module;
A a;
B b;
}

View File

@@ -1,5 +1,4 @@
import java.util.ArrayList;
import java.util.List;
import module java.base;
public class beforeSimpleModuleImport {
public static void main(String[] args) {

View File

@@ -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();
}
}

View File

@@ -0,0 +1,20 @@
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();
}
}

View File

@@ -0,0 +1,19 @@
package main;
import module java.base;
import aaa.*;
public class Main {
void usage() {
new ArrayList<>();
new AAA();
new BBB();
new CCC();
new DDD();
new EEE();
List a = null;
Date da =new Date();
}
}

View File

@@ -0,0 +1,18 @@
package main;
import module java.base;
import aaa.*;
public class Main {
void usage() {
new ArrayList<>();
new AAA();
new BBB();
new CCC();
new DDD();
new EEE();
List a = null;
Date da =new Date();
}
}

View File

@@ -0,0 +1,16 @@
package aaa;
import module java.base;
public class Main {
void usage() {
new ArrayList<>();
new AAA();
new BBB();
new CCC();
new DDD();
new EEE();
List a = null;
Date da =new Date();
}
}

View File

@@ -0,0 +1,16 @@
package aaa;
import module java.base;
public class Main {
void usage() {
new ArrayList<>();
new AAA();
new BBB();
new CCC();
new DDD();
new EEE();
List a = null;
Date da =new Date();
}
}

View File

@@ -0,0 +1,19 @@
package main;
import module java.base;
import aaa.AAA;
import aaa.CCC;
import aaa.BBB;
import java.util.ArrayList;
public class Main {
void usage() {
new ArrayList<>();
new AAA();
new BBB();
new CCC();
x();
}
}

View File

@@ -0,0 +1,17 @@
package main;
import module java.base;
import aaa.AAA;
import aaa.BBB;
import aaa.CCC;
public class Main {
void usage() {
new ArrayList<>();
new AAA();
new BBB();
new CCC();
x();
}
}

View File

@@ -0,0 +1,19 @@
package main;
import module java.base;
import aaa.AAA;
import aaa.CCC;
import aaa.BBB;
import java.util.ArrayList;
public class Main {
void usage() {
new ArrayList<>();
new AAA();
new BBB();
new CCC();
x();
}
}

View File

@@ -0,0 +1,16 @@
package main;
import module java.base;
import aaa.AAA;
import aaa.BBB;
import aaa.CCC;
public class Main {
void usage() {
new ArrayList<>();
new AAA();
new BBB();
new CCC();
x();
}
}

View File

@@ -0,0 +1,18 @@
package aaa;
import module java.base;
import java.util.List;
public class Main {
void usage() {
new ArrayList<>();
new AAA();
new BBB();
new CCC();
new DDD();
new EEE();
List a = null;
Date da =new Date();
}
}

View File

@@ -0,0 +1,17 @@
package aaa;
import module java.base;
import java.util.List;
public class Main {
void usage() {
new ArrayList<>();
new AAA();
new BBB();
new CCC();
new DDD();
new EEE();
List a = null;
Date da =new Date();
}
}

View File

@@ -0,0 +1,23 @@
package main;
import module java.base;
import java.util.List;
import java.util.*;
import aaa.AAA;
import aaa.CCC;
import aaa.BBB;
import java.util.ArrayList;
public class Main {
void usage() {
new ArrayList<>();
new AAA();
new BBB();
new CCC();
List<String> a = new ArrayList<>();
a.add("a");
Date da =new Date();
}
}

View File

@@ -0,0 +1,18 @@
package main;
import module java.base;
import aaa.AAA;
import aaa.BBB;
import aaa.CCC;
public class Main {
void usage() {
new ArrayList<>();
new AAA();
new BBB();
new CCC();
List<String> a = new ArrayList<>();
a.add("a");
Date da =new Date();
}
}

View File

@@ -1121,7 +1121,6 @@ public class AddImportActionTest extends LightJavaCodeInsightFixtureTestCase {
myFixture.checkResult("""
import a.*;
import module java.base;
import java.util.List;
class Test{

View File

@@ -17,10 +17,12 @@ import com.intellij.lang.LanguageImportStatements;
import com.intellij.lang.annotation.HighlightSeverity;
import com.intellij.lang.java.JavaImportOptimizer;
import com.intellij.lang.java.JavaLanguage;
import com.intellij.openapi.Disposable;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.application.ReadAction;
import com.intellij.openapi.application.ex.PathManagerEx;
import com.intellij.openapi.command.WriteCommandAction;
import com.intellij.openapi.util.Disposer;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.pom.java.JavaFeature;
import com.intellij.psi.PsiDocumentManager;
@@ -56,6 +58,18 @@ public class OptimizeImportsTest extends OptimizeImportsTestCase {
@Override
protected void setUp() throws Exception {
super.setUp();
JavaCodeStyleSettings javaSettings = JavaCodeStyleSettings.getInstance(getProject());
boolean preserveModuleImports = javaSettings.isPreserveModuleImports();
boolean moduleImportFirst = javaSettings.isModuleImportFirst();
boolean spaceBetweenModuleAndOtherImports = javaSettings.isSpaceBetweenModuleAndOtherImports();
Disposer.register(getTestRootDisposable(), new Disposable() {
@Override
public void dispose() {
javaSettings.setPreserveModuleImports(preserveModuleImports);
javaSettings.setModuleImportFirst(moduleImportFirst);
javaSettings.setSpaceBetweenModuleAndOtherImports(spaceBetweenModuleAndOtherImports);
}
});
myFixture.enableInspections(new UnusedDeclarationInspection());
}
@@ -526,6 +540,116 @@ public class OptimizeImportsTest extends OptimizeImportsTestCase {
});
}
public void testImportModuleFirstWithoutSpace() {
IdeaTestUtil.withLevel(getModule(), JavaFeature.PACKAGE_IMPORTS_SHADOW_MODULE_IMPORTS.getMinimumLevel(), () -> {
myFixture.addClass("package aaa; public class AAA {}");
myFixture.addClass("package bbb; public class BBB {}");
myFixture.addClass("package ccc; public class CCC {}");
JavaCodeStyleSettings javaSettings = JavaCodeStyleSettings.getInstance(getProject());
javaSettings.setPreserveModuleImports(true);
javaSettings.setModuleImportFirst(true);
javaSettings.setSpaceBetweenModuleAndOtherImports(false);
doTest();
});
}
public void testImportModuleFirstWithSpace() {
IdeaTestUtil.withLevel(getModule(), JavaFeature.PACKAGE_IMPORTS_SHADOW_MODULE_IMPORTS.getMinimumLevel(), () -> {
myFixture.addClass("package aaa; public class AAA {}");
myFixture.addClass("package aaa; public class BBB {}");
myFixture.addClass("package aaa; public class CCC {}");
JavaCodeStyleSettings javaSettings = JavaCodeStyleSettings.getInstance(getProject());
javaSettings.setPreserveModuleImports(true);
javaSettings.setModuleImportFirst(true);
javaSettings.setSpaceBetweenModuleAndOtherImports(true);
doTest();
});
}
public void testImportModuleOverOtherImports() {
IdeaTestUtil.withLevel(getModule(), JavaFeature.PACKAGE_IMPORTS_SHADOW_MODULE_IMPORTS.getMinimumLevel(), () -> {
myFixture.addClass("package aaa; public class AAA {}");
myFixture.addClass("package aaa; public class BBB {}");
myFixture.addClass("package aaa; public class CCC {}");
JavaCodeStyleSettings javaSettings = JavaCodeStyleSettings.getInstance(getProject());
javaSettings.setPreserveModuleImports(true);
doTest();
});
}
public void testImportModuleConflictWithPackage() {
IdeaTestUtil.withLevel(getModule(), JavaFeature.PACKAGE_IMPORTS_SHADOW_MODULE_IMPORTS.getMinimumLevel(), () -> {
myFixture.addClass("package aaa; public class AAA {}");
myFixture.addClass("package aaa; public class BBB {}");
myFixture.addClass("package aaa; public class CCC {}");
myFixture.addClass("package aaa; public class DDD {}");
myFixture.addClass("package aaa; public class EEE {}");
myFixture.addClass("package aaa; public class List {}");
JavaCodeStyleSettings javaSettings = JavaCodeStyleSettings.getInstance(getProject());
javaSettings.setPreserveModuleImports(true);
doTest();
});
}
public void testImportModuleConflictWithSamePackage() {
IdeaTestUtil.withLevel(getModule(), JavaFeature.PACKAGE_IMPORTS_SHADOW_MODULE_IMPORTS.getMinimumLevel(), () -> {
myFixture.addClass("package aaa; public class AAA {}");
myFixture.addClass("package aaa; public class BBB {}");
myFixture.addClass("package aaa; public class CCC {}");
myFixture.addClass("package aaa; public class DDD {}");
myFixture.addClass("package aaa; public class EEE {}");
myFixture.addClass("package aaa; public class List {}");
JavaCodeStyleSettings javaSettings = JavaCodeStyleSettings.getInstance(getProject());
javaSettings.setPreserveModuleImports(true);
doTest();
});
}
public void testImportModuleOnDemandConflictWithSamePackage() {
IdeaTestUtil.withLevel(getModule(), JavaFeature.PACKAGE_IMPORTS_SHADOW_MODULE_IMPORTS.getMinimumLevel(), () -> {
myFixture.addClass("package aaa; public class AAA {}");
myFixture.addClass("package aaa; public class BBB {}");
myFixture.addClass("package aaa; public class CCC {}");
myFixture.addClass("package aaa; public class DDD {}");
myFixture.addClass("package aaa; public class EEE {}");
myFixture.addClass("package aaa; public class List {}");
JavaCodeStyleSettings javaSettings = JavaCodeStyleSettings.getInstance(getProject());
javaSettings.setPreserveModuleImports(true);
doTest();
});
}
public void testDoNotInsertImportForClassVisibleByInheritanceWithModuleConflict() {
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();
}
private void doTest() {
doTest(".java");
}

View File

@@ -4,6 +4,7 @@ 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.command.WriteCommandAction;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.module.ModuleManager;
import com.intellij.openapi.roots.DependencyScope;
@@ -11,9 +12,12 @@ import com.intellij.openapi.roots.ModuleRootModificationUtil;
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.impl.source.PostprocessReformattingAspect;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.psi.util.PsiUtil;
import com.intellij.testFramework.IdeaTestUtil;
import com.intellij.testFramework.PsiTestUtil;
import org.intellij.lang.annotations.Language;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -319,6 +323,26 @@ public class ResolveModuleImportTest extends LightJava9ModulesCodeInsightFixture
});
}
public void testOptimizeImportWithModuleConflict() {
IdeaTestUtil.withLevel(getModule(), JavaFeature.PACKAGE_IMPORTS_SHADOW_MODULE_IMPORTS.getMinimumLevel(), ()->{
prepareAmbiguousModuleTests();
WriteCommandAction.runWriteCommandAction(getProject(), () -> {
String fileName = getTestName(false) + ".java";
try {
PsiFile file = myFixture.configureByFile(fileName);
JavaCodeStyleManager.getInstance(getProject()).optimizeImports(file);
PostprocessReformattingAspect.getInstance(getProject()).doPostponedFormatting();
PsiDocumentManager.getInstance(getProject()).commitAllDocuments();
myFixture.checkResultByFile(getTestName(false) + "_after" + ".java");
PsiTestUtil.checkFileStructure(file);
}
catch (Exception e) {
LOG.error(e);
}
});
});
}
public void testModuleImportWithDefaultPackageImport() {
IdeaTestUtil.withLevel(getModule(), JavaFeature.PACKAGE_IMPORTS_SHADOW_MODULE_IMPORTS.getMinimumLevel(), ()->{
addCode("module-info.java", """
@@ -367,6 +391,10 @@ public class ResolveModuleImportTest extends LightJava9ModulesCodeInsightFixture
package my.source.moduleB;
public class Imported {}
""", M2);
addCode("my/source/moduleB/B.java", """
package my.source.moduleB;
public class B {}
""", M2);
addCode("module-info.java", """
module my.source.moduleA {
exports my.source.moduleA;
@@ -376,6 +404,10 @@ public class ResolveModuleImportTest extends LightJava9ModulesCodeInsightFixture
package my.source.moduleA;
public class Imported {}
""", M4);
addCode("my/source/moduleA/A.java", """
package my.source.moduleA;
public class A {}
""", M4);
addCode("Test.java", """
""");
}

View File

@@ -116,6 +116,7 @@ checkbox.suppress.with.suppresswarnings=Suppress with @SuppressWarnings
checkbox.treat.get.k.null.the.same.as.containskey.k.may.change.semantics=Treat 'get(k) != null' the same as 'containsKey(k)' (may change semantics)
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.use.throws.rather.than.exception=Use @throws rather than @exception
checkbox.warn.if.only.foreach.replacement.is.available=Warn if only 'forEach' replacement is available
checkbox.warn.if.the.loop.is.trivial=Warn if the loop is trivial
@@ -365,6 +366,8 @@ ignore.imports.and.formatting=Ignore imports and formatting
illegal.name.validation.info=Illegal name: {0}
import.layout.static.imports.separately=Layout static imports separately
import.layout.on.demand.import.from.same.package.first=Place on-demand import before single-class imports from the same package
import.layout.module.import.first=Place module imports at the beginning of import table (otherwise at the end of import table)
import.layout.space.between.module.import.other=Put empty line between module imports and other imports
import.statically=Import statically
include.accessors=&Include Accessors
infer.nullity.progress=Post-processing results\u2026
@@ -1607,6 +1610,7 @@ import.layout.panel.up.button=Up
import.layout.panel.down.button=Down
import.layout.panel.blank.line.entry=<blank line>
import.layout.panel.all.other.imports=all other imports
import.layout.panel.module.imports=module imports
edit.contract.dialog.hint=<html>Please specify the contract text<p>Example: <code>_, null -> false</code><br><small>See intention action description for more details</small></html>
edit.contract.dialog.mutates.hint=Specify comma-separated elements that can be mutated<p>Example: <code>this,param1</code><p>Leave empty for unspecified side effects.
edit.range.dialog.message=Leave empty if unrestricted

View File

@@ -33,6 +33,8 @@ public class EclipseCodeStylePropertiesImporter implements EclipseFormatterOptio
importStarImportThresholds(uiPreferences, javaSettings);
javaSettings.LAYOUT_STATIC_IMPORTS_SEPARATELY = true;
javaSettings.LAYOUT_ON_DEMAND_IMPORT_FROM_SAME_PACKAGE_FIRST = true;
javaSettings.MODULE_IMPORT_FIRST = true;
javaSettings.SPACE_BETWEEN_MODULE_AND_OTHER_IMPORTS = false;
javaSettings.PACKAGES_TO_USE_IMPORT_ON_DEMAND.copyFrom(new PackageEntryTable());
}

View File

@@ -49,7 +49,7 @@ public final class JavaFxImportsOptimizer implements ImportOptimizer {
final JavaCodeStyleSettings settings = JavaCodeStyleSettings.getInstance(file);
final @NotNull List<ImportHelper.Import> sortedNames = ImportHelper.sortItemsAccordingToSettings(names, settings);
final Map<String, Boolean> onDemand = new HashMap<>();
ImportHelper.collectOnDemandImports(sortedNames, settings, onDemand);
ImportHelper.collectOnDemandImports(sortedNames, settings, onDemand, new HashMap<>());
for (String s : demandedForNested) {
onDemand.put(s, false);
}