From cd9a60ab8fef80056cb7194dfd2292fca7240e81 Mon Sep 17 00:00:00 2001 From: Mikhail Pyltsin Date: Thu, 19 Dec 2024 13:31:51 +0100 Subject: [PATCH] IJ-CR-151305 [java-import] IDEA-364508 support optimize imports - use layout table (cherry picked from commit 6862419acc2beb72f87cca6b93612f9afe81f698) GitOrigin-RevId: af86c63fa16f760ad3fd0b66fc9f86f7a21de7c7 --- .../psi/codeStyle/JavaCodeStyleSettings.java | 25 ++------ .../options/ImportLayoutPanel.java | 37 +++-------- .../options/JavaCodeStyleImportsPanel.java | 14 ----- .../JavaPackageEntryTableAccessor.java | 18 +++++- .../impl/source/codeStyle/ImportHelper.java | 61 +++++++++++++------ .../testData/codeStyle/jsonExport.json | 3 +- .../ImportModuleFirstWithSpace.java | 4 +- .../ImportModuleFirstWithSpace_after.java | 4 +- .../ImportModuleInTheMiddleWithoutSpace.java | 17 ++++++ ...tModuleInTheMiddleWithoutSpace_after.java} | 6 +- ...java => ImportModuleLastWithoutSpace.java} | 4 +- .../ImportModuleLastWithoutSpace_after.java | 16 +++++ ...OnDemandConflictWithSamePackage_after.java | 1 + .../ImportModuleOverOtherImports.java | 4 +- .../ImportModuleOverOtherImports_after.java | 4 +- .../daemon/impl/ImportHelperTest.java | 1 + .../daemon/LightOptimizeImportsTest.java | 5 +- .../intention/AddImportActionTest.java | 5 +- .../java/psi/OptimizeImportsTest.java | 50 ++++++++++++--- .../resources/messages/JavaBundle.properties | 2 - .../code-style-api/api-dump-experimental.txt | 2 + .../intellij/psi/codeStyle/PackageEntry.java | 11 +++- .../psi/codeStyle/PackageEntryTable.java | 15 ++++- .../EclipseCodeStylePropertiesImporter.java | 3 +- 24 files changed, 196 insertions(+), 116 deletions(-) create mode 100644 java/java-tests/testData/psi/optimizeImports/ImportModuleInTheMiddleWithoutSpace.java rename java/java-tests/testData/psi/optimizeImports/{ImportModuleFirstWithoutSpace_after.java => ImportModuleInTheMiddleWithoutSpace_after.java} (84%) rename java/java-tests/testData/psi/optimizeImports/{ImportModuleFirstWithoutSpace.java => ImportModuleLastWithoutSpace.java} (86%) create mode 100644 java/java-tests/testData/psi/optimizeImports/ImportModuleLastWithoutSpace_after.java diff --git a/java/java-frontback-impl/src/com/intellij/psi/codeStyle/JavaCodeStyleSettings.java b/java/java-frontback-impl/src/com/intellij/psi/codeStyle/JavaCodeStyleSettings.java index fd4d1e6b6775..76719fce00c4 100644 --- a/java/java-frontback-impl/src/com/intellij/psi/codeStyle/JavaCodeStyleSettings.java +++ b/java/java-frontback-impl/src/com/intellij/psi/codeStyle/JavaCodeStyleSettings.java @@ -10,6 +10,7 @@ import com.intellij.openapi.util.WriteExternalException; import com.intellij.psi.PsiFile; import com.intellij.psi.PsiModifier; import com.intellij.psi.codeStyle.CommonCodeStyleSettings.WrapConstant; +import com.intellij.util.containers.ContainerUtil; import org.jdom.Element; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.TestOnly; @@ -171,8 +172,6 @@ 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; @@ -298,27 +297,10 @@ 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; @@ -394,6 +376,7 @@ public class JavaCodeStyleSettings extends CustomCodeStyleSettings implements Im private void initImportsByDefault() { PACKAGES_TO_USE_IMPORT_ON_DEMAND.addEntry(new PackageEntry(false, "java.awt", false)); PACKAGES_TO_USE_IMPORT_ON_DEMAND.addEntry(new PackageEntry(false,"javax.swing", false)); + IMPORT_LAYOUT_TABLE.addEntry(PackageEntry.ALL_MODULE_IMPORTS); IMPORT_LAYOUT_TABLE.addEntry(PackageEntry.ALL_OTHER_IMPORTS_ENTRY); IMPORT_LAYOUT_TABLE.addEntry(PackageEntry.BLANK_LINE_ENTRY); IMPORT_LAYOUT_TABLE.addEntry(new PackageEntry(false, "javax", true)); @@ -470,6 +453,10 @@ public class JavaCodeStyleSettings extends CustomCodeStyleSettings implements Im readExternalCollection(parentElement, myDoNotImportInner, DO_NOT_IMPORT_INNER, DO_NOT_IMPORT_INNER_ITEM); myOldVersion = myVersion = CustomCodeStyleSettingsUtils.readVersion(parentElement.getChild(getTagName())); myIsInitialized = true; + PackageEntry[] entries = IMPORT_LAYOUT_TABLE.getEntries(); + if (!ContainerUtil.exists(entries, entry -> entry == PackageEntry.ALL_MODULE_IMPORTS)) { + IMPORT_LAYOUT_TABLE.setEntryAt(PackageEntry.ALL_MODULE_IMPORTS, 0); + } } @Override diff --git a/java/java-impl/src/com/intellij/application/options/ImportLayoutPanel.java b/java/java-impl/src/com/intellij/application/options/ImportLayoutPanel.java index 16351ce8a7bc..aa5547f556ef 100644 --- a/java/java-impl/src/com/intellij/application/options/ImportLayoutPanel.java +++ b/java/java-impl/src/com/intellij/application/options/ImportLayoutPanel.java @@ -40,8 +40,6 @@ 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(); @@ -63,16 +61,6 @@ public abstract class ImportLayoutPanel extends JPanel { return myCbLayoutOnDemandImportsFromSamePackageFirst; } - @Nullable - public JBCheckBox getCbModuleImportFirst() { - return myCbModuleImportFirst; - } - - @Nullable - public JBCheckBox getCbSpaceBetweenModuleAndOther() { - return myCbSpaceBetweenModuleAndOther; - } - public ImportLayoutPanel(boolean showLayoutOnDemandImportFromSamePackageFirstCheckbox, boolean supportModuleImport) { super(new BorderLayout()); @@ -119,7 +107,10 @@ public abstract class ImportLayoutPanel extends JPanel { .setRemoveActionUpdater(e -> { int selectedImport = myImportLayoutTable.getSelectedRow(); PackageEntry entry = selectedImport < 0 ? null : myImportLayoutList.getEntryAt(selectedImport); - return entry != null && entry != PackageEntry.ALL_OTHER_STATIC_IMPORTS_ENTRY && entry != PackageEntry.ALL_OTHER_IMPORTS_ENTRY; + return entry != null && + entry != PackageEntry.ALL_OTHER_STATIC_IMPORTS_ENTRY && + entry != PackageEntry.ALL_OTHER_IMPORTS_ENTRY && + entry != PackageEntry.ALL_MODULE_IMPORTS; }) .setButtonComparator(JavaBundle.message("button.add"), IdeBundle.message("action.remove"), @@ -133,13 +124,8 @@ public abstract class ImportLayoutPanel extends JPanel { ? 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, additionalCheckBoxes, importLayoutPanel); @@ -198,7 +184,9 @@ public abstract class ImportLayoutPanel extends JPanel { return; } PackageEntry entry = myImportLayoutList.getEntryAt(selected); - if (entry == PackageEntry.ALL_OTHER_STATIC_IMPORTS_ENTRY || entry == PackageEntry.ALL_OTHER_IMPORTS_ENTRY) { + if (entry == PackageEntry.ALL_OTHER_STATIC_IMPORTS_ENTRY || + entry == PackageEntry.ALL_OTHER_IMPORTS_ENTRY || + entry == PackageEntry.ALL_MODULE_IMPORTS) { return; } TableUtil.stopEditing(myImportLayoutTable); @@ -253,14 +241,6 @@ 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"), @@ -396,6 +376,9 @@ public abstract class ImportLayoutPanel extends JPanel { if (entry == PackageEntry.ALL_OTHER_IMPORTS_ENTRY || entry == PackageEntry.ALL_OTHER_STATIC_IMPORTS_ENTRY) { append(JavaBundle.message("import.layout.panel.all.other.imports"), SimpleTextAttributes.REGULAR_ATTRIBUTES); } + else if (entry == PackageEntry.ALL_MODULE_IMPORTS) { + append(JavaBundle.message("import.layout.panel.module.imports"), SimpleTextAttributes.REGULAR_ATTRIBUTES); + } else { append(entry.getPackageName() + ".*", SimpleTextAttributes.REGULAR_ATTRIBUTES); } diff --git a/java/java-impl/src/com/intellij/application/options/JavaCodeStyleImportsPanel.java b/java/java-impl/src/com/intellij/application/options/JavaCodeStyleImportsPanel.java index 6590cbb3e35c..d34d27f70995 100644 --- a/java/java-impl/src/com/intellij/application/options/JavaCodeStyleImportsPanel.java +++ b/java/java-impl/src/com/intellij/application/options/JavaCodeStyleImportsPanel.java @@ -63,8 +63,6 @@ class JavaCodeStyleImportsPanel extends CodeStyleImportsPanelBase { if(cbPreserveModuleImports!=null) javaSettings.setPreserveModuleImports(cbPreserveModuleImports.isSelected()); javaSettings.setDoNotImportInner(getInnerClassesNames()); javaSettings.setLayoutOnDemandImportFromSamePackageFirst(myImportLayoutPanel.isLayoutOnDemandImportsFromSamePackageFirst()); - javaSettings.setModuleImportFirst(myImportLayoutPanel.isModuleImportFirst()); - javaSettings.setSpaceBetweenModuleAndOtherImports(myImportLayoutPanel.isSpaceBetweenModuleAndOther()); } @Override @@ -81,12 +79,6 @@ class JavaCodeStyleImportsPanel extends CodeStyleImportsPanelBase { 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 @@ -101,12 +93,6 @@ class JavaCodeStyleImportsPanel extends CodeStyleImportsPanelBase { 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; } diff --git a/java/java-impl/src/com/intellij/psi/codeStyle/JavaPackageEntryTableAccessor.java b/java/java-impl/src/com/intellij/psi/codeStyle/JavaPackageEntryTableAccessor.java index c2a980a86cdb..afecb38af624 100644 --- a/java/java-impl/src/com/intellij/psi/codeStyle/JavaPackageEntryTableAccessor.java +++ b/java/java-impl/src/com/intellij/psi/codeStyle/JavaPackageEntryTableAccessor.java @@ -15,6 +15,7 @@ public class JavaPackageEntryTableAccessor extends ValueListPropertyAccessor o.name())) .collect(Collectors.toList()); - List resultList = sortItemsAccordingToSettings(imports, mySettings); - + SortedImportItems items = sortItemsWithModulesAccordingToSettings(imports, mySettings); + List resultList = items.imports(); Map classesOrPackagesToImportOnDemand = new HashMap<>(); List previousModuleStatements = collectModuleImports(file, mySettings); Map moduleStatementMap = collectNamesImportedByModules(file, previousModuleStatements, resultList); @@ -130,7 +130,6 @@ public final class ImportHelper { try { boolean onDemandFirst = mySettings.isLayoutOnDemandImportFromSamePackageFirst(); - boolean moduleImportFirst = mySettings.isModuleImportFirst(); StringBuilder text = buildImportListText(resultList, classesOrPackagesToImportOnDemand.keySet(), @@ -138,7 +137,7 @@ public final class ImportHelper { checker, moduleStatementMap, onDemandFirst, - moduleImportFirst); + items.moduleIndex()); for (PsiElement nonImport : nonImports) { text.append("\n").append(nonImport.getText()); } @@ -239,17 +238,31 @@ public final class ImportHelper { }); } - public static @NotNull List sortItemsAccordingToSettings(@NotNull List imports, @NotNull JavaCodeStyleSettings settings) { + private record SortedImportItems(@NotNull List imports, int moduleIndex) { } + + public static @NotNull List sortItemsAccordingToSettings(@NotNull List imports, + @NotNull JavaCodeStyleSettings settings) { + return sortItemsWithModulesAccordingToSettings(imports, settings).imports; + } + + private static @NotNull ImportHelper.SortedImportItems sortItemsWithModulesAccordingToSettings(@NotNull List imports, + @NotNull JavaCodeStyleSettings settings) { int[] entryForName = ArrayUtil.newIntArray(imports.size()); PackageEntry[] entries = settings.IMPORT_LAYOUT_TABLE.getEntries(); + int moduleEntryIndex = findEntryIndex("", false, true, entries); for (int i = 0; i < imports.size(); i++) { Import anImport = imports.get(i); entryForName[i] = findEntryIndex(StringUtil.getPackageName(anImport.name()), - settings.LAYOUT_STATIC_IMPORTS_SEPARATELY && anImport.isStatic(), entries); + settings.LAYOUT_STATIC_IMPORTS_SEPARATELY && anImport.isStatic(), false, entries); } List resultList = new ArrayList<>(imports.size()); + int moduleIndex = 0; for (int i = 0; i < entries.length; i++) { + if (i == moduleEntryIndex) { + moduleIndex = resultList.size(); + continue; + } for (int j = 0; j < imports.size(); j++) { if (entryForName[j] == i) { resultList.add(imports.get(j)); @@ -260,7 +273,7 @@ public final class ImportHelper { for (Import name : imports) { if (name != null) resultList.add(name); } - return resultList; + return new SortedImportItems(resultList, moduleIndex); } private static @NotNull Set findSingleImports(@NotNull PsiJavaFile file, @@ -465,13 +478,17 @@ public final class ImportHelper { @NotNull ImportUtils.ImplicitImportChecker implicitImportContext, @NotNull Map moduleStatementMap, boolean onDemandImportsFirst, - boolean moduleImportFirst) { + int moduleIndex) { Set importedPackagesOrClasses = new HashSet<>(); @NonNls StringBuilder buffer = new StringBuilder(); Set usedModuleImports = new HashSet<>(); - - for (Import importedName : imports) { + int indexModuleString = -1; + for (int i = 0; i < imports.size(); i++) { + if (i == moduleIndex) { + indexModuleString = buffer.length(); + } + Import importedName = imports.get(i); String name = importedName.name(); boolean isStatic = importedName.isStatic(); String packageOrClassName = StringUtil.getPackageName(name); @@ -505,8 +522,8 @@ public final class ImportHelper { } if (!moduleStatements.isEmpty()) { - if (moduleImportFirst) { - buffer.insert(0, moduleStatements); + if (indexModuleString != -1) { + buffer.insert(indexModuleString, moduleStatements); } else { buffer.append(moduleStatements); @@ -879,12 +896,6 @@ 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; @@ -922,7 +933,7 @@ public final class ImportHelper { return table.contains(packageName); } - private static int findEntryIndex(@NotNull String packageName, boolean isStatic, PackageEntry @NotNull [] entries) { + private static int findEntryIndex(@NotNull String packageName, boolean isStatic, boolean isModule, PackageEntry @NotNull [] entries) { PackageEntry bestEntry = null; int bestEntryIndex = -1; int allOtherStaticIndex = -1; @@ -939,6 +950,10 @@ public final class ImportHelper { bestEntry = entry; bestEntryIndex = i; } + if (isModule && entry == PackageEntry.ALL_MODULE_IMPORTS) { + bestEntry = entry; + bestEntryIndex = i; + } } if (bestEntryIndex == -1 && isStatic && allOtherStaticIndex == -1 && allOtherIndex != -1) { // if no layout for static imports specified, put them among all others @@ -949,11 +964,17 @@ public final class ImportHelper { int findEntryIndex(@NotNull PsiImportStatementBase statement) { PsiJavaCodeReferenceElement ref = statement.getImportReference(); + if (statement instanceof PsiImportModuleStatement) { + return findEntryIndex("", + mySettings.LAYOUT_STATIC_IMPORTS_SEPARATELY && statement instanceof PsiImportStaticStatement, + true, + mySettings.IMPORT_LAYOUT_TABLE.getEntries()); + } 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, + false, mySettings.IMPORT_LAYOUT_TABLE.getEntries()); } diff --git a/java/java-tests/testData/codeStyle/jsonExport.json b/java/java-tests/testData/codeStyle/jsonExport.json index 1ce86b7773b5..afa1acedf22a 100644 --- a/java/java-tests/testData/codeStyle/jsonExport.json +++ b/java/java-tests/testData/codeStyle/jsonExport.json @@ -106,6 +106,7 @@ "generate_use_type_annotation_before_type": true, "if_brace_force": "never", "imports_layout": [ + "@*", "*", "|", "javax.**", @@ -147,7 +148,6 @@ "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, @@ -224,7 +224,6 @@ "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, diff --git a/java/java-tests/testData/psi/optimizeImports/ImportModuleFirstWithSpace.java b/java/java-tests/testData/psi/optimizeImports/ImportModuleFirstWithSpace.java index 03ad21744177..08fb54bfe477 100644 --- a/java/java-tests/testData/psi/optimizeImports/ImportModuleFirstWithSpace.java +++ b/java/java-tests/testData/psi/optimizeImports/ImportModuleFirstWithSpace.java @@ -3,8 +3,8 @@ package main; import module java.base; import aaa.AAA; -import aaa.CCC; -import aaa.BBB; +import ccc.CCC; +import bbb.BBB; import java.util.ArrayList; diff --git a/java/java-tests/testData/psi/optimizeImports/ImportModuleFirstWithSpace_after.java b/java/java-tests/testData/psi/optimizeImports/ImportModuleFirstWithSpace_after.java index 12cbc470698d..3526ea4115eb 100644 --- a/java/java-tests/testData/psi/optimizeImports/ImportModuleFirstWithSpace_after.java +++ b/java/java-tests/testData/psi/optimizeImports/ImportModuleFirstWithSpace_after.java @@ -3,8 +3,8 @@ package main; import module java.base; import aaa.AAA; -import aaa.BBB; -import aaa.CCC; +import bbb.BBB; +import ccc.CCC; public class Main { void usage() { diff --git a/java/java-tests/testData/psi/optimizeImports/ImportModuleInTheMiddleWithoutSpace.java b/java/java-tests/testData/psi/optimizeImports/ImportModuleInTheMiddleWithoutSpace.java new file mode 100644 index 000000000000..dedeffeee209 --- /dev/null +++ b/java/java-tests/testData/psi/optimizeImports/ImportModuleInTheMiddleWithoutSpace.java @@ -0,0 +1,17 @@ +package main; + +import aaa.AAA; +import bbb.BBB; +import ccc.CCC; + +import module java.base; + +public class Main { + void usage() { + new ArrayList<>(); + new AAA(); + new BBB(); + new CCC(); + x(); + } +} diff --git a/java/java-tests/testData/psi/optimizeImports/ImportModuleFirstWithoutSpace_after.java b/java/java-tests/testData/psi/optimizeImports/ImportModuleInTheMiddleWithoutSpace_after.java similarity index 84% rename from java/java-tests/testData/psi/optimizeImports/ImportModuleFirstWithoutSpace_after.java rename to java/java-tests/testData/psi/optimizeImports/ImportModuleInTheMiddleWithoutSpace_after.java index ceb2998ada8f..3c022b1d85b3 100644 --- a/java/java-tests/testData/psi/optimizeImports/ImportModuleFirstWithoutSpace_after.java +++ b/java/java-tests/testData/psi/optimizeImports/ImportModuleInTheMiddleWithoutSpace_after.java @@ -1,9 +1,9 @@ package main; -import module java.base; import aaa.AAA; -import aaa.BBB; -import aaa.CCC; +import module java.base; +import bbb.BBB; +import ccc.CCC; public class Main { void usage() { diff --git a/java/java-tests/testData/psi/optimizeImports/ImportModuleFirstWithoutSpace.java b/java/java-tests/testData/psi/optimizeImports/ImportModuleLastWithoutSpace.java similarity index 86% rename from java/java-tests/testData/psi/optimizeImports/ImportModuleFirstWithoutSpace.java rename to java/java-tests/testData/psi/optimizeImports/ImportModuleLastWithoutSpace.java index 03ad21744177..08fb54bfe477 100644 --- a/java/java-tests/testData/psi/optimizeImports/ImportModuleFirstWithoutSpace.java +++ b/java/java-tests/testData/psi/optimizeImports/ImportModuleLastWithoutSpace.java @@ -3,8 +3,8 @@ package main; import module java.base; import aaa.AAA; -import aaa.CCC; -import aaa.BBB; +import ccc.CCC; +import bbb.BBB; import java.util.ArrayList; diff --git a/java/java-tests/testData/psi/optimizeImports/ImportModuleLastWithoutSpace_after.java b/java/java-tests/testData/psi/optimizeImports/ImportModuleLastWithoutSpace_after.java new file mode 100644 index 000000000000..f3fdf9ddf69f --- /dev/null +++ b/java/java-tests/testData/psi/optimizeImports/ImportModuleLastWithoutSpace_after.java @@ -0,0 +1,16 @@ +package main; + +import aaa.AAA; +import bbb.BBB; +import ccc.CCC; +import module java.base; + +public class Main { + void usage() { + new ArrayList<>(); + new AAA(); + new BBB(); + new CCC(); + x(); + } +} diff --git a/java/java-tests/testData/psi/optimizeImports/ImportModuleOnDemandConflictWithSamePackage_after.java b/java/java-tests/testData/psi/optimizeImports/ImportModuleOnDemandConflictWithSamePackage_after.java index a8da24a8ffb4..a5bc4811ad96 100644 --- a/java/java-tests/testData/psi/optimizeImports/ImportModuleOnDemandConflictWithSamePackage_after.java +++ b/java/java-tests/testData/psi/optimizeImports/ImportModuleOnDemandConflictWithSamePackage_after.java @@ -1,6 +1,7 @@ package aaa; import module java.base; + import java.util.List; public class Main { diff --git a/java/java-tests/testData/psi/optimizeImports/ImportModuleOverOtherImports.java b/java/java-tests/testData/psi/optimizeImports/ImportModuleOverOtherImports.java index 3b6813200ac2..fc15f77ef7fc 100644 --- a/java/java-tests/testData/psi/optimizeImports/ImportModuleOverOtherImports.java +++ b/java/java-tests/testData/psi/optimizeImports/ImportModuleOverOtherImports.java @@ -5,8 +5,8 @@ import module java.base; import java.util.List; import java.util.*; import aaa.AAA; -import aaa.CCC; -import aaa.BBB; +import ccc.CCC; +import bbb.BBB; import java.util.ArrayList; diff --git a/java/java-tests/testData/psi/optimizeImports/ImportModuleOverOtherImports_after.java b/java/java-tests/testData/psi/optimizeImports/ImportModuleOverOtherImports_after.java index 9e6bb3aabb33..42cb9c5c4879 100644 --- a/java/java-tests/testData/psi/optimizeImports/ImportModuleOverOtherImports_after.java +++ b/java/java-tests/testData/psi/optimizeImports/ImportModuleOverOtherImports_after.java @@ -2,8 +2,8 @@ package main; import module java.base; import aaa.AAA; -import aaa.BBB; -import aaa.CCC; +import bbb.BBB; +import ccc.CCC; public class Main { void usage() { diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/daemon/impl/ImportHelperTest.java b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/impl/ImportHelperTest.java index 671ecfbdd49c..fc2822402490 100644 --- a/java/java-tests/testSrc/com/intellij/codeInsight/daemon/impl/ImportHelperTest.java +++ b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/impl/ImportHelperTest.java @@ -203,6 +203,7 @@ public class ImportHelperTest extends LightDaemonAnalyzerTestCase { JavaCodeStyleSettings javaSettings = JavaCodeStyleSettings.getInstance(getProject()); javaSettings.LAYOUT_STATIC_IMPORTS_SEPARATELY = true; PackageEntryTable table = new PackageEntryTable(); + table.addEntry(PackageEntry.ALL_MODULE_IMPORTS); table.addEntry(PackageEntry.ALL_OTHER_IMPORTS_ENTRY); table.addEntry(PackageEntry.BLANK_LINE_ENTRY); table.addEntry(new PackageEntry(false, "javax", true)); diff --git a/java/java-tests/testSrc/com/intellij/java/codeInsight/daemon/LightOptimizeImportsTest.java b/java/java-tests/testSrc/com/intellij/java/codeInsight/daemon/LightOptimizeImportsTest.java index 7ca420c5beb0..b041c01ad1f3 100644 --- a/java/java-tests/testSrc/com/intellij/java/codeInsight/daemon/LightOptimizeImportsTest.java +++ b/java/java-tests/testSrc/com/intellij/java/codeInsight/daemon/LightOptimizeImportsTest.java @@ -84,6 +84,8 @@ public class LightOptimizeImportsTest extends LightJavaCodeInsightFixtureTestCas JavaCodeStyleSettings javaSettings = JavaCodeStyleSettings.getInstance(getProject()); javaSettings.LAYOUT_STATIC_IMPORTS_SEPARATELY = false; javaSettings.IMPORT_LAYOUT_TABLE = new PackageEntryTable(); + javaSettings.IMPORT_LAYOUT_TABLE.addEntry(PackageEntry.ALL_MODULE_IMPORTS); + javaSettings.IMPORT_LAYOUT_TABLE.addEntry(PackageEntry.BLANK_LINE_ENTRY); javaSettings.IMPORT_LAYOUT_TABLE.addEntry(PackageEntry.ALL_OTHER_IMPORTS_ENTRY); javaSettings.IMPORT_LAYOUT_TABLE.addEntry(PackageEntry.BLANK_LINE_ENTRY); javaSettings.IMPORT_LAYOUT_TABLE.addEntry(new PackageEntry(false, "aaa", true)); @@ -135,7 +137,8 @@ public class LightOptimizeImportsTest extends LightJavaCodeInsightFixtureTestCas myFixture.configureByText(JavaFileType.INSTANCE, text); JavaCodeStyleSettings javaSettings = JavaCodeStyleSettings.getInstance(getProject()); - javaSettings.IMPORT_LAYOUT_TABLE.insertEntryAt(new PackageEntry(false, "bbb", false), 1); + //1 is module import + javaSettings.IMPORT_LAYOUT_TABLE.insertEntryAt(new PackageEntry(false, "bbb", false), 1 + 1); WriteCommandAction.runWriteCommandAction(getProject(), () -> JavaCodeStyleManager.getInstance(getProject()).optimizeImports(getFile())); @Language("JAVA") String result = """ diff --git a/java/java-tests/testSrc/com/intellij/java/codeInsight/intention/AddImportActionTest.java b/java/java-tests/testSrc/com/intellij/java/codeInsight/intention/AddImportActionTest.java index 0626bc0b0a8c..6368436b42d8 100644 --- a/java/java-tests/testSrc/com/intellij/java/codeInsight/intention/AddImportActionTest.java +++ b/java/java-tests/testSrc/com/intellij/java/codeInsight/intention/AddImportActionTest.java @@ -1108,8 +1108,8 @@ public class AddImportActionTest extends LightJavaCodeInsightFixtureTestCase { myFixture.addClass("package a; public class List {}"); myFixture.configureByText("Test.java", """ - import a.*; import module java.base; + import a.*; class Test{ void main(){ java.util.List x; @@ -1119,8 +1119,9 @@ public class AddImportActionTest extends LightJavaCodeInsightFixtureTestCase { reimportClass(); myFixture.checkResult(""" - import a.*; import module java.base; + import a.*; + import java.util.List; class Test{ diff --git a/java/java-tests/testSrc/com/intellij/java/psi/OptimizeImportsTest.java b/java/java-tests/testSrc/com/intellij/java/psi/OptimizeImportsTest.java index 647c466f8512..89f8a8b6286c 100644 --- a/java/java-tests/testSrc/com/intellij/java/psi/OptimizeImportsTest.java +++ b/java/java-tests/testSrc/com/intellij/java/psi/OptimizeImportsTest.java @@ -60,14 +60,12 @@ public class OptimizeImportsTest extends OptimizeImportsTestCase { super.setUp(); JavaCodeStyleSettings javaSettings = JavaCodeStyleSettings.getInstance(getProject()); boolean preserveModuleImports = javaSettings.isPreserveModuleImports(); - boolean moduleImportFirst = javaSettings.isModuleImportFirst(); - boolean spaceBetweenModuleAndOtherImports = javaSettings.isSpaceBetweenModuleAndOtherImports(); + PackageEntryTable table = javaSettings.IMPORT_LAYOUT_TABLE; Disposer.register(getTestRootDisposable(), new Disposable() { @Override public void dispose() { javaSettings.setPreserveModuleImports(preserveModuleImports); - javaSettings.setModuleImportFirst(moduleImportFirst); - javaSettings.setSpaceBetweenModuleAndOtherImports(spaceBetweenModuleAndOtherImports); + javaSettings.IMPORT_LAYOUT_TABLE = table; } }); myFixture.enableInspections(new UnusedDeclarationInspection()); @@ -514,6 +512,7 @@ public class OptimizeImportsTest extends OptimizeImportsTestCase { settings -> { JavaCodeStyleSettings javaSettings = settings.getCustomSettings(JavaCodeStyleSettings.class); javaSettings.IMPORT_LAYOUT_TABLE = new PackageEntryTable(); + javaSettings.IMPORT_LAYOUT_TABLE.addEntry(PackageEntry.ALL_MODULE_IMPORTS); javaSettings.IMPORT_LAYOUT_TABLE.addEntry(PackageEntry.ALL_OTHER_STATIC_IMPORTS_ENTRY); javaSettings.IMPORT_LAYOUT_TABLE.addEntry(PackageEntry.BLANK_LINE_ENTRY); javaSettings.IMPORT_LAYOUT_TABLE.addEntry(PackageEntry.ALL_OTHER_IMPORTS_ENTRY); @@ -541,15 +540,42 @@ public class OptimizeImportsTest extends OptimizeImportsTestCase { } - public void testImportModuleFirstWithoutSpace() { + public void testImportModuleLastWithoutSpace() { 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.IMPORT_LAYOUT_TABLE = new PackageEntryTable(); + javaSettings.IMPORT_LAYOUT_TABLE.addEntry(PackageEntry.ALL_OTHER_STATIC_IMPORTS_ENTRY); + javaSettings.IMPORT_LAYOUT_TABLE.addEntry(PackageEntry.BLANK_LINE_ENTRY); + javaSettings.IMPORT_LAYOUT_TABLE.addEntry(PackageEntry.ALL_OTHER_IMPORTS_ENTRY); + javaSettings.IMPORT_LAYOUT_TABLE.addEntry(PackageEntry.ALL_MODULE_IMPORTS); + + javaSettings.setPreserveModuleImports(true); + doTest(); + }); + } + + public void testImportModuleInTheMiddleWithoutSpace() { + 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.IMPORT_LAYOUT_TABLE = new PackageEntryTable(); + + javaSettings.IMPORT_LAYOUT_TABLE.addEntry(new PackageEntry(false, "aaa", false)); + javaSettings.IMPORT_LAYOUT_TABLE.addEntry(PackageEntry.ALL_MODULE_IMPORTS); + javaSettings.IMPORT_LAYOUT_TABLE.addEntry(new PackageEntry(false, "bbb", false)); + javaSettings.IMPORT_LAYOUT_TABLE.addEntry(PackageEntry.ALL_OTHER_IMPORTS_ENTRY); + + javaSettings.setPreserveModuleImports(true); - javaSettings.setModuleImportFirst(true); - javaSettings.setSpaceBetweenModuleAndOtherImports(false); doTest(); }); } @@ -561,8 +587,14 @@ public class OptimizeImportsTest extends OptimizeImportsTestCase { myFixture.addClass("package aaa; public class CCC {}"); JavaCodeStyleSettings javaSettings = JavaCodeStyleSettings.getInstance(getProject()); javaSettings.setPreserveModuleImports(true); - javaSettings.setModuleImportFirst(true); - javaSettings.setSpaceBetweenModuleAndOtherImports(true); + + javaSettings.IMPORT_LAYOUT_TABLE = new PackageEntryTable(); + javaSettings.IMPORT_LAYOUT_TABLE.addEntry(PackageEntry.ALL_MODULE_IMPORTS); + javaSettings.IMPORT_LAYOUT_TABLE.addEntry(PackageEntry.BLANK_LINE_ENTRY); + javaSettings.IMPORT_LAYOUT_TABLE.addEntry(PackageEntry.ALL_OTHER_STATIC_IMPORTS_ENTRY); + javaSettings.IMPORT_LAYOUT_TABLE.addEntry(PackageEntry.BLANK_LINE_ENTRY); + javaSettings.IMPORT_LAYOUT_TABLE.addEntry(PackageEntry.ALL_OTHER_IMPORTS_ENTRY); + doTest(); }); } diff --git a/java/openapi/resources/messages/JavaBundle.properties b/java/openapi/resources/messages/JavaBundle.properties index 059f89484047..6840ec4ce560 100644 --- a/java/openapi/resources/messages/JavaBundle.properties +++ b/java/openapi/resources/messages/JavaBundle.properties @@ -366,8 +366,6 @@ 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 diff --git a/platform/code-style-api/api-dump-experimental.txt b/platform/code-style-api/api-dump-experimental.txt index b611e5e57cb3..354168381910 100644 --- a/platform/code-style-api/api-dump-experimental.txt +++ b/platform/code-style-api/api-dump-experimental.txt @@ -26,6 +26,8 @@ c:com.intellij.openapi.editor.EditorModificationUtilEx - a:indent(com.intellij.psi.PsiFile,I):java.lang.String - s:indentLine(com.intellij.psi.PsiFile,I):java.lang.String - s:useExternalFormatter(com.intellij.psi.PsiFile):Z +c:com.intellij.psi.codeStyle.PackageEntry +- *sf:ALL_MODULE_IMPORTS:com.intellij.psi.codeStyle.PackageEntry *:com.intellij.psi.codeStyle.modifier.CodeStyleSettingsModifier - sf:EP_NAME:com.intellij.openapi.extensions.ExtensionPointName - getDisablingFunction(com.intellij.openapi.project.Project):java.util.function.Consumer diff --git a/platform/code-style-api/src/com/intellij/psi/codeStyle/PackageEntry.java b/platform/code-style-api/src/com/intellij/psi/codeStyle/PackageEntry.java index 84344f959ad8..ac93b4369a56 100755 --- a/platform/code-style-api/src/com/intellij/psi/codeStyle/PackageEntry.java +++ b/platform/code-style-api/src/com/intellij/psi/codeStyle/PackageEntry.java @@ -3,6 +3,7 @@ package com.intellij.psi.codeStyle; import com.intellij.openapi.util.NlsSafe; import com.intellij.openapi.util.text.StringUtil; +import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -74,8 +75,16 @@ public class PackageEntry { } }; + @ApiStatus.Experimental + public static final PackageEntry ALL_MODULE_IMPORTS = new PackageEntry(false, "", true){ + @Override + public boolean matchesPackageName(String packageName) { + return false; + } + }; + public boolean isSpecial() { - return this == BLANK_LINE_ENTRY || this == ALL_OTHER_IMPORTS_ENTRY || this == ALL_OTHER_STATIC_IMPORTS_ENTRY; + return this == BLANK_LINE_ENTRY || this == ALL_OTHER_IMPORTS_ENTRY || this == ALL_OTHER_STATIC_IMPORTS_ENTRY || this == ALL_MODULE_IMPORTS; } public boolean isBetterMatchForPackageThan(@Nullable PackageEntry entry, @NotNull String packageName, boolean isStatic) { diff --git a/platform/code-style-api/src/com/intellij/psi/codeStyle/PackageEntryTable.java b/platform/code-style-api/src/com/intellij/psi/codeStyle/PackageEntryTable.java index fd62d50ebf97..00ea1db8053a 100755 --- a/platform/code-style-api/src/com/intellij/psi/codeStyle/PackageEntryTable.java +++ b/platform/code-style-api/src/com/intellij/psi/codeStyle/PackageEntryTable.java @@ -110,13 +110,19 @@ public class PackageEntryTable implements JDOMExternalizable, Cloneable { if ("package".equals(name)) { String packageName = e.getAttributeValue("name"); boolean isStatic = Boolean.parseBoolean(e.getAttributeValue("static")); + boolean isModule = Boolean.parseBoolean(e.getAttributeValue("module")); boolean withSubpackages = Boolean.parseBoolean(e.getAttributeValue("withSubpackages")); if (packageName == null) { throw new InvalidDataException(); } PackageEntry entry; if (packageName.isEmpty()) { - entry = isStatic ? PackageEntry.ALL_OTHER_STATIC_IMPORTS_ENTRY : PackageEntry.ALL_OTHER_IMPORTS_ENTRY; + if (isModule) { + entry = PackageEntry.ALL_MODULE_IMPORTS; + } + else { + entry = isStatic ? PackageEntry.ALL_OTHER_STATIC_IMPORTS_ENTRY : PackageEntry.ALL_OTHER_IMPORTS_ENTRY; + } } else { entry = new PackageEntry(isStatic, packageName, withSubpackages); @@ -142,9 +148,14 @@ public class PackageEntryTable implements JDOMExternalizable, Cloneable { @NonNls Element element = new Element("package"); parentNode.addContent(element); String packageName = entry.getPackageName(); - element.setAttribute("name", entry == PackageEntry.ALL_OTHER_IMPORTS_ENTRY || entry == PackageEntry.ALL_OTHER_STATIC_IMPORTS_ENTRY ? "": packageName); + element.setAttribute("name", entry == PackageEntry.ALL_OTHER_IMPORTS_ENTRY || + entry == PackageEntry.ALL_OTHER_STATIC_IMPORTS_ENTRY || + entry == PackageEntry.ALL_MODULE_IMPORTS ? "": packageName); element.setAttribute("withSubpackages", entry.isWithSubpackages() ? "true" : "false"); element.setAttribute("static", entry.isStatic() ? "true" : "false"); + if (entry == PackageEntry.ALL_MODULE_IMPORTS) { + element.setAttribute("module", "true"); + } } } } diff --git a/plugins/eclipse/src/org/jetbrains/idea/eclipse/importer/EclipseCodeStylePropertiesImporter.java b/plugins/eclipse/src/org/jetbrains/idea/eclipse/importer/EclipseCodeStylePropertiesImporter.java index 16d616e6635c..5c2042b1a25d 100644 --- a/plugins/eclipse/src/org/jetbrains/idea/eclipse/importer/EclipseCodeStylePropertiesImporter.java +++ b/plugins/eclipse/src/org/jetbrains/idea/eclipse/importer/EclipseCodeStylePropertiesImporter.java @@ -33,8 +33,6 @@ 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()); } @@ -42,6 +40,7 @@ public class EclipseCodeStylePropertiesImporter implements EclipseFormatterOptio String oderOfImportsValue = uiPreferences.getProperty(OPTION_IMPORT_ORDER); if (oderOfImportsValue != null) { PackageEntryTable importLayoutTable = new PackageEntryTable(); + importLayoutTable.addEntry(PackageEntry.ALL_OTHER_IMPORTS_ENTRY); importLayoutTable.addEntry(PackageEntry.ALL_OTHER_STATIC_IMPORTS_ENTRY); String[] chunks = oderOfImportsValue.split(";"); for (String importString : chunks) {