diff --git a/org.eclipse.jdt.core.manipulation/.settings/.api_filters b/org.eclipse.jdt.core.manipulation/.settings/.api_filters
index ece44acdf99..4363135a0f3 100644
--- a/org.eclipse.jdt.core.manipulation/.settings/.api_filters
+++ b/org.eclipse.jdt.core.manipulation/.settings/.api_filters
@@ -8,6 +8,22 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/org.eclipse.jdt.core.manipulation/common/org/eclipse/jdt/core/manipulation/OrganizeImportsOperation.java b/org.eclipse.jdt.core.manipulation/common/org/eclipse/jdt/core/manipulation/OrganizeImportsOperation.java
index a237a8f8f30..4a60c61d7d4 100644
--- a/org.eclipse.jdt.core.manipulation/common/org/eclipse/jdt/core/manipulation/OrganizeImportsOperation.java
+++ b/org.eclipse.jdt.core.manipulation/common/org/eclipse/jdt/core/manipulation/OrganizeImportsOperation.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2000, 2024 IBM Corporation and others.
+ * Copyright (c) 2000, 2025 IBM Corporation and others.
*
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
@@ -42,14 +42,20 @@
import org.eclipse.jdt.core.IPackageFragment;
import org.eclipse.jdt.core.IPackageFragmentRoot;
import org.eclipse.jdt.core.ISourceRange;
+import org.eclipse.jdt.core.IType;
+import org.eclipse.jdt.core.JavaCore;
import org.eclipse.jdt.core.JavaModelException;
import org.eclipse.jdt.core.Signature;
import org.eclipse.jdt.core.SourceRange;
import org.eclipse.jdt.core.compiler.IProblem;
+import org.eclipse.jdt.core.dom.AST;
import org.eclipse.jdt.core.dom.ASTNode;
+import org.eclipse.jdt.core.dom.ASTParser;
import org.eclipse.jdt.core.dom.AbstractTypeDeclaration;
import org.eclipse.jdt.core.dom.CompilationUnit;
import org.eclipse.jdt.core.dom.IBinding;
+import org.eclipse.jdt.core.dom.IModuleBinding;
+import org.eclipse.jdt.core.dom.IPackageBinding;
import org.eclipse.jdt.core.dom.ITypeBinding;
import org.eclipse.jdt.core.dom.ImportDeclaration;
import org.eclipse.jdt.core.dom.MethodInvocation;
@@ -72,7 +78,9 @@
import org.eclipse.jdt.internal.core.manipulation.util.Strings;
import org.eclipse.jdt.internal.corext.dom.ASTNodes;
import org.eclipse.jdt.internal.corext.dom.Bindings;
+import org.eclipse.jdt.internal.corext.dom.IASTSharedValues;
import org.eclipse.jdt.internal.corext.dom.ScopeAnalyzer;
+import org.eclipse.jdt.internal.corext.refactoring.util.RefactoringASTParser;
import org.eclipse.jdt.internal.corext.util.JavaModelUtil;
import org.eclipse.jdt.internal.corext.util.JdtFlags;
import org.eclipse.jdt.internal.corext.util.StaticImportFavoritesCompletionInvoker;
@@ -220,6 +228,7 @@ public void addInfo(TypeNameMatch info) {
private Set fOldSingleImports;
private Set fOldDemandImports;
+ private Map> fOldModuleImports;
private Set fImplicitImports;
@@ -235,13 +244,16 @@ public void addInfo(TypeNameMatch info) {
private Map fUnresolvedTypes;
private Set fImportsAdded;
+ private Set fModuleImportsAdded;
private TypeNameMatch[][] fOpenChoices;
private SourceRange[] fSourceRanges;
- public TypeReferenceProcessor(Set oldSingleImports, Set oldDemandImports, CompilationUnit root, ImportRewrite impStructure, boolean ignoreLowerCaseNames, UnresolvableImportMatcher unresolvableImportMatcher) {
+ public TypeReferenceProcessor(Set oldSingleImports, Set oldDemandImports, Map> oldModuleImports,
+ CompilationUnit root, ImportRewrite impStructure, boolean ignoreLowerCaseNames, UnresolvableImportMatcher unresolvableImportMatcher) {
fOldSingleImports= oldSingleImports;
fOldDemandImports= oldDemandImports;
+ fOldModuleImports= oldModuleImports;
fImpStructure= impStructure;
fDoIgnoreLowerCaseNames= ignoreLowerCaseNames;
fUnresolvableImportMatcher= unresolvableImportMatcher;
@@ -253,11 +265,46 @@ public TypeReferenceProcessor(Set oldSingleImports, Set oldDeman
fImplicitImports.add("java.lang"); //$NON-NLS-1$
fImplicitImports.add(cu.getParent().getElementName());
+ if (root.getAST().apiLevel() >= AST.JLS24) {
+ try {
+ IType[] types= cu.getAllTypes();
+ if (types.length > 0 && types[0].isImplicitlyDeclared()) {
+ ASTParser parser = ASTParser.newParser(IASTSharedValues.SHARED_AST_LEVEL);
+ Map compilerOptions= RefactoringASTParser.getCompilerOptions(cu);
+ if (root.getAST().isPreviewEnabled()) {
+ compilerOptions.put(JavaCore.COMPILER_PB_ENABLE_PREVIEW_FEATURES, JavaCore.ENABLED);
+ JavaCore.setComplianceOptions(Integer.toString(root.getAST().apiLevel()), compilerOptions);
+ }
+ parser.setCompilerOptions(compilerOptions);
+ parser.setEnvironment(null, null, null, true);
+ parser.setUnitName("A.java"); //$NON-NLS-1$
+ parser.setKind(ASTParser.K_COMPILATION_UNIT);
+ parser.setSource("import module java.base; class A { BigDecimal a; }".toCharArray()); //$NON-NLS-1$
+ parser.setResolveBindings(true);
+ CompilationUnit astRoot = (CompilationUnit) parser.createAST(null);
+ List importDecls= astRoot.imports();
+ if (!importDecls.isEmpty()) {
+ ImportDeclaration importDecl= importDecls.get(0);
+ if (importDecl.resolveBinding() instanceof IModuleBinding moduleBinding) {
+ IPackageBinding[] packageBindings= moduleBinding.getExportedPackages();
+ for (IPackageBinding packageBinding : packageBindings) {
+ fImplicitImports.add(packageBinding.getName());
+ }
+ }
+ }
+ }
+ } catch (JavaModelException e) {
+ // ignore
+ }
+ }
+
+
fAnalyzer= new ScopeAnalyzer(root);
fCurrPackage= (IPackageFragment) cu.getParent();
fImportsAdded= new HashSet<>();
+ fModuleImportsAdded= new HashSet<>();
fUnresolvedTypes= new HashMap<>();
}
@@ -323,6 +370,27 @@ public void add(SimpleName ref) {
}
typeBinding= typeBinding.getTypeDeclaration();
if (!typeBinding.isRecovered()) {
+ String qualifiedTypeName= typeBinding.getQualifiedName();
+ if (qualifiedTypeName.indexOf('.') > 0) {
+ String qualifier= qualifiedTypeName.substring(0, qualifiedTypeName.lastIndexOf('.'));
+ if (moduleImportsContains(qualifier)) {
+ for (Entry> entry : fOldModuleImports.entrySet()) {
+ if (entry.getValue().contains(qualifier)) {
+ fImportsAdded.add(typeName);
+ if (fModuleImportsAdded.contains(entry.getKey())) {
+ return;
+ }
+ fImpStructure.addModuleImport(entry.getKey(), new ArrayList<>(entry.getValue()));
+ fModuleImportsAdded.add(entry.getKey());
+ break;
+ }
+ }
+ return;
+ }
+ if (fImplicitImports.contains(qualifier)) {
+ return;
+ }
+ }
if (needsImport(typeBinding, ref)) {
fImpStructure.addImport(typeBinding);
fImportsAdded.add(typeName);
@@ -408,7 +476,9 @@ private TypeNameMatch[] processTypeInfo(List typeRefsFound) {
return null;
} else if (nFound == 1) {
TypeNameMatch typeRef= typeRefsFound.get(0);
- fImpStructure.addImport(typeRef.getFullyQualifiedName());
+ if (!moduleImportsContains(typeRef.getTypeContainerName())) {
+ fImpStructure.addImport(typeRef.getFullyQualifiedName());
+ }
return null;
} else {
String typeToImport= null;
@@ -429,6 +499,8 @@ private TypeNameMatch[] processTypeInfo(List typeRefsFound) {
} else { // more than one import-on-demand
ambiguousImports= true;
}
+ } else if (moduleImportsContains(containerName)) {
+ return null; // we don't reimport
}
}
@@ -441,6 +513,15 @@ private TypeNameMatch[] processTypeInfo(List typeRefsFound) {
}
}
+ private boolean moduleImportsContains(String typeContainerName) {
+ for (Set packageNames : fOldModuleImports.values()) {
+ if (packageNames.contains(typeContainerName)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
private boolean isOfKind(TypeNameMatch curr, int typeKinds) {
int flags= curr.getModifiers();
if (Flags.isAnnotation(flags)) {
@@ -587,10 +668,11 @@ public TextEdit createTextEdit(IProgressMonitor m) throws CoreException, Operati
Set oldSingleImports= new HashSet<>();
Set oldDemandImports= new HashSet<>();
+ Map> oldModulePackages= new HashMap<>();
List typeReferences= new ArrayList<>();
List staticReferences= new ArrayList<>();
- if (!collectReferences(astRoot, typeReferences, staticReferences, oldSingleImports, oldDemandImports))
+ if (!collectReferences(astRoot, typeReferences, staticReferences, oldSingleImports, oldDemandImports, oldModulePackages))
return null;
subMonitor.split(1);
@@ -600,6 +682,7 @@ public TextEdit createTextEdit(IProgressMonitor m) throws CoreException, Operati
TypeReferenceProcessor processor= new TypeReferenceProcessor(
oldSingleImports,
oldDemandImports,
+ oldModulePackages,
astRoot,
importsRewrite,
fIgnoreLowerCaseNames,
@@ -650,6 +733,7 @@ private void determineImportDifferences(ImportRewrite importsStructure, Set importsAdded= new ArrayList<>(importsStructure.getCreatedImports().length + importsStructure.getCreatedStaticImports().length);
importsAdded.addAll(Arrays.asList(importsStructure.getCreatedImports()));
importsAdded.addAll(Arrays.asList(importsStructure.getCreatedStaticImports()));
+ importsAdded.addAll(Arrays.asList(importsStructure.getCreatedModuleImports()));
for (Object element : oldSingleImports.toArray()) {
String importName= (String) element;
@@ -734,7 +818,8 @@ private void addStaticImports(
// find type references in a compilation unit
- private boolean collectReferences(CompilationUnit astRoot, List typeReferences, List staticReferences, Set oldSingleImports, Set oldDemandImports) {
+ private boolean collectReferences(CompilationUnit astRoot, List typeReferences, List staticReferences, Set oldSingleImports,
+ Set oldDemandImports, Map> oldModuleImports) {
if (!fAllowSyntaxErrors) {
for (IProblem curr : astRoot.getProblems()) {
if (curr.isError() && (curr.getID() & IProblem.Syntax) != 0) {
@@ -746,7 +831,16 @@ private boolean collectReferences(CompilationUnit astRoot, List type
List imports= astRoot.imports();
for (ImportDeclaration curr : imports) {
String id= ASTResolving.getFullName(curr.getName());
- if (curr.isOnDemand()) {
+ if (Modifier.isModule(curr.getModifiers())) {
+ Set oldModulePackages= new HashSet<>();
+ oldModuleImports.put(id, oldModulePackages);
+ if (curr.resolveBinding() instanceof IModuleBinding binding) {
+ IPackageBinding[] packageBindings= binding.getExportedPackages();
+ for (IPackageBinding packageBinding : packageBindings) {
+ oldModulePackages.add(packageBinding.getName());
+ }
+ }
+ } else if (curr.isOnDemand()) {
oldDemandImports.add(id);
} else {
oldSingleImports.add(id);
diff --git a/org.eclipse.jdt.core.manipulation/core extension/org/eclipse/jdt/internal/corext/codemanipulation/ContextSensitiveImportRewriteContext.java b/org.eclipse.jdt.core.manipulation/core extension/org/eclipse/jdt/internal/corext/codemanipulation/ContextSensitiveImportRewriteContext.java
index efa3f1eab8f..68451acacd9 100644
--- a/org.eclipse.jdt.core.manipulation/core extension/org/eclipse/jdt/internal/corext/codemanipulation/ContextSensitiveImportRewriteContext.java
+++ b/org.eclipse.jdt.core.manipulation/core extension/org/eclipse/jdt/internal/corext/codemanipulation/ContextSensitiveImportRewriteContext.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2000, 2018 IBM Corporation and others.
+ * Copyright (c) 2000, 2025 IBM Corporation and others.
*
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
@@ -35,9 +35,9 @@
import org.eclipse.jdt.core.dom.NodeFinder;
import org.eclipse.jdt.core.dom.SimpleName;
import org.eclipse.jdt.core.dom.rewrite.ImportRewrite;
+import org.eclipse.jdt.core.dom.rewrite.ImportRewrite.ImportRewriteContext;
import org.eclipse.jdt.core.dom.rewrite.ImportRewrite.TypeLocation;
import org.eclipse.jdt.core.manipulation.ImportReferencesCollector;
-import org.eclipse.jdt.core.dom.rewrite.ImportRewrite.ImportRewriteContext;
import org.eclipse.jdt.internal.corext.dom.ScopeAnalyzer;
import org.eclipse.jdt.internal.corext.util.JavaModelUtil;
@@ -137,6 +137,15 @@ public int findInContext(String qualifier, String name, int kind) {
}
}
+ // check if qualifier matches a package provided by an import module statement
+ for (String moduleName : fImportRewrite.getAddedModuleImports()) {
+ for (String packageName : fImportRewrite.getAddedModuleExportedPackages(moduleName)) {
+ if (qualifier.equals(packageName)) {
+ return RES_NAME_FOUND;
+ }
+ }
+ }
+
String qualifiedName= JavaModelUtil.concatenateName(qualifier, name);
for (String addedImport : fImportRewrite.getAddedImports()) {
if (qualifiedName.equals(addedImport)) {
diff --git a/org.eclipse.jdt.ui.tests/test plugin/org/eclipse/jdt/testplugin/JavaProjectHelper.java b/org.eclipse.jdt.ui.tests/test plugin/org/eclipse/jdt/testplugin/JavaProjectHelper.java
index 862c8dcfb8d..7835140187d 100644
--- a/org.eclipse.jdt.ui.tests/test plugin/org/eclipse/jdt/testplugin/JavaProjectHelper.java
+++ b/org.eclipse.jdt.ui.tests/test plugin/org/eclipse/jdt/testplugin/JavaProjectHelper.java
@@ -109,6 +109,7 @@ public class JavaProjectHelper {
public static final IPath RT_STUBS21= new Path("testresources/rtstubs_21.jar");
public static final IPath RT_STUBS22= new Path("testresources/rtstubs_22.jar");
public static final IPath RT_STUBS23= new Path("testresources/rtstubs_23.jar");
+ public static final IPath RT_STUBS24= new Path("testresources/rtstubs_24.jar");
public static final IPath JUNIT_SRC_381= new Path("testresources/junit381-noUI-src.zip");
public static final String JUNIT_SRC_ENCODING= "ISO-8859-1";
@@ -400,6 +401,23 @@ public static void set23CompilerOptions(IJavaProject project, boolean enable_pre
project.setOptions(options);
}
+ /**
+ * Sets the compiler options to 24 for the given project.
+ *
+ * @param project the java project
+ * @param enable_preview_feature sets enable-preview compliance project option based on the
+ * value specified.
+ */
+ public static void set24CompilerOptions(IJavaProject project, boolean enable_preview_feature) {
+ Map options= project.getOptions(false);
+ set24_CompilerOptions(options);
+ if (enable_preview_feature) {
+ options.put(JavaCore.COMPILER_PB_ENABLE_PREVIEW_FEATURES, JavaCore.ENABLED);
+ options.put(JavaCore.COMPILER_PB_REPORT_PREVIEW_FEATURES, JavaCore.IGNORE);
+ }
+ project.setOptions(options);
+ }
+
/**
* Sets the compiler options to 9.
*
@@ -508,6 +526,15 @@ public static void set23_CompilerOptions(Map options) {
JavaCore.setComplianceOptions(JavaCore.VERSION_23, options);
}
+ /**
+ * Sets the compiler options to 24.
+ *
+ * @param options the compiler options to configure
+ */
+ public static void set24_CompilerOptions(Map options) {
+ JavaCore.setComplianceOptions(JavaCore.VERSION_24, options);
+ }
+
/**
* Sets the compiler options to 1.8
*
diff --git a/org.eclipse.jdt.ui.tests/testresources/rtstubs_24.jar b/org.eclipse.jdt.ui.tests/testresources/rtstubs_24.jar
new file mode 100644
index 00000000000..4f64dc92095
Binary files /dev/null and b/org.eclipse.jdt.ui.tests/testresources/rtstubs_24.jar differ
diff --git a/org.eclipse.jdt.ui.tests/ui/org/eclipse/jdt/ui/tests/core/CoreTestSuite.java b/org.eclipse.jdt.ui.tests/ui/org/eclipse/jdt/ui/tests/core/CoreTestSuite.java
index 35ae002d3df..cc4ce042129 100644
--- a/org.eclipse.jdt.ui.tests/ui/org/eclipse/jdt/ui/tests/core/CoreTestSuite.java
+++ b/org.eclipse.jdt.ui.tests/ui/org/eclipse/jdt/ui/tests/core/CoreTestSuite.java
@@ -37,6 +37,7 @@
HierarchicalASTVisitorTest.class,
ImportOrganizeTest.class,
ImportOrganizeTest1d8.class,
+ImportOrganizeTest24.class,
JavaElementLabelsTest.class,
JavaElementLabelsTest1d8.class,
BindingLabelsTest.class,
diff --git a/org.eclipse.jdt.ui.tests/ui/org/eclipse/jdt/ui/tests/core/ImportOrganizeTest24.java b/org.eclipse.jdt.ui.tests/ui/org/eclipse/jdt/ui/tests/core/ImportOrganizeTest24.java
new file mode 100644
index 00000000000..456fb1944c9
--- /dev/null
+++ b/org.eclipse.jdt.ui.tests/ui/org/eclipse/jdt/ui/tests/core/ImportOrganizeTest24.java
@@ -0,0 +1,273 @@
+/*******************************************************************************
+ * Copyright (c) 2025 IBM Corporation and others.
+ *
+ * This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.jdt.ui.tests.core;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+import java.util.HashMap;
+import java.util.Hashtable;
+import java.util.Map;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+
+import org.eclipse.jdt.testplugin.JavaProjectHelper;
+import org.eclipse.jdt.testplugin.TestOptions;
+
+import org.eclipse.core.runtime.preferences.IEclipsePreferences;
+
+import org.eclipse.core.resources.ProjectScope;
+
+import org.eclipse.jdt.core.Flags;
+import org.eclipse.jdt.core.ICompilationUnit;
+import org.eclipse.jdt.core.IImportDeclaration;
+import org.eclipse.jdt.core.IJavaProject;
+import org.eclipse.jdt.core.IPackageFragment;
+import org.eclipse.jdt.core.IPackageFragmentRoot;
+import org.eclipse.jdt.core.JavaCore;
+import org.eclipse.jdt.core.formatter.DefaultCodeFormatterConstants;
+import org.eclipse.jdt.core.manipulation.OrganizeImportsOperation;
+import org.eclipse.jdt.core.manipulation.OrganizeImportsOperation.IChooseImportQuery;
+import org.eclipse.jdt.core.search.TypeNameMatch;
+
+import org.eclipse.jdt.ui.JavaUI;
+import org.eclipse.jdt.ui.PreferenceConstants;
+import org.eclipse.jdt.ui.tests.core.rules.Java24ProjectTestSetup;
+
+public class ImportOrganizeTest24 extends CoreTests {
+ @Rule
+ public Java24ProjectTestSetup proj= new Java24ProjectTestSetup(true);
+
+ private IJavaProject fJProject1;
+
+ @Before
+ public void before() throws Exception {
+ fJProject1= proj.getProject();
+
+// fJProject1.setOption(JavaCore.COMPILER_PB_ENABLE_PREVIEW_FEATURES, JavaCore.ENABLED);
+// fJProject1.setOption(JavaCore.COMPILER_PB_REPORT_PREVIEW_FEATURES, JavaCore.IGNORE);
+
+ Hashtable options= TestOptions.getDefaultOptions();
+ options.put(DefaultCodeFormatterConstants.FORMATTER_NUMBER_OF_EMPTY_LINES_TO_PRESERVE, String.valueOf(99));
+ options.put(JavaCore.COMPILER_PB_ENABLE_PREVIEW_FEATURES, JavaCore.ENABLED);
+ options.put(JavaCore.COMPILER_PB_REPORT_PREVIEW_FEATURES, JavaCore.IGNORE);
+ options.put(JavaCore.COMPILER_SOURCE, JavaCore.VERSION_24);
+ options.put(JavaCore.COMPILER_COMPLIANCE, JavaCore.VERSION_24);
+ options.put(JavaCore.COMPILER_CODEGEN_TARGET_PLATFORM, JavaCore.VERSION_24);
+ JavaCore.setOptions(options);
+ }
+
+ @After
+ public void after() throws Exception {
+ setOrganizeImportSettings(null, 99, 99, fJProject1);
+ JavaProjectHelper.clear(fJProject1, proj.getDefaultClasspath());
+ }
+
+ protected IChooseImportQuery createQuery(final String name, final String[] choices, final int[] nEntries) {
+ return (openChoices, ranges) -> {
+ assertEquals(name + "-query-nchoices1", choices.length, openChoices.length);
+ assertEquals(name + "-query-nchoices2", nEntries.length, openChoices.length);
+ for (int i1= 0; i1 < nEntries.length; i1++) {
+ assertEquals(name + "-query-cnt" + i1, openChoices[i1].length, nEntries[i1]);
+ }
+ TypeNameMatch[] res= new TypeNameMatch[openChoices.length];
+ for (int i2= 0; i2 < openChoices.length; i2++) {
+ TypeNameMatch[] selection= openChoices[i2];
+ assertNotNull(name + "-query-setset" + i2, selection);
+ assertTrue(name + "-query-setlen" + i2, selection.length > 0);
+ TypeNameMatch found= null;
+ for (TypeNameMatch s : selection) {
+ if (s.getFullyQualifiedName().equals(choices[i2])) {
+ found= s;
+ }
+ }
+ assertNotNull(name + "-query-notfound" + i2, found);
+ res[i2]= found;
+ }
+ return res;
+ };
+ }
+
+ protected OrganizeImportsOperation createOperation(ICompilationUnit cu, String[] order, int threshold, boolean ignoreLowerCaseNames, boolean save, boolean allowSyntaxErrors, IChooseImportQuery chooseImportQuery) {
+ setOrganizeImportSettings(order, threshold, threshold, cu.getJavaProject());
+ return new OrganizeImportsOperation(cu, null, ignoreLowerCaseNames, save, allowSyntaxErrors, chooseImportQuery);
+ }
+
+ protected OrganizeImportsOperation createOperation(ICompilationUnit cu, String[] order, int threshold, boolean ignoreLowerCaseNames, boolean save, boolean allowSyntaxErrors, IChooseImportQuery chooseImportQuery, boolean restoreExistingImports) {
+ setOrganizeImportSettings(order, threshold, threshold, cu.getJavaProject());
+ return new OrganizeImportsOperation(cu, null, ignoreLowerCaseNames, save, allowSyntaxErrors, chooseImportQuery, restoreExistingImports);
+ }
+
+ protected void setOrganizeImportSettings(String[] order, int threshold, int staticThreshold, IJavaProject project) {
+ IEclipsePreferences scope= new ProjectScope(project.getProject()).getNode(JavaUI.ID_PLUGIN);
+ if (order == null) {
+ scope.remove(PreferenceConstants.ORGIMPORTS_IMPORTORDER);
+ scope.remove(PreferenceConstants.ORGIMPORTS_ONDEMANDTHRESHOLD);
+ } else {
+ StringBuilder buf= new StringBuilder();
+ for (String o : order) {
+ buf.append(o);
+ buf.append(';');
+ }
+ scope.put(PreferenceConstants.ORGIMPORTS_IMPORTORDER, buf.toString());
+ scope.put(PreferenceConstants.ORGIMPORTS_ONDEMANDTHRESHOLD, String.valueOf(threshold));
+ scope.put(PreferenceConstants.ORGIMPORTS_STATIC_ONDEMANDTHRESHOLD, String.valueOf(staticThreshold));
+ }
+ }
+
+ protected void assertImports(ICompilationUnit cu, String[] imports) throws Exception {
+ IImportDeclaration[] desc= cu.getImports();
+ assertEquals(cu.getElementName() + "-count", imports.length, desc.length);
+ for (int i= 0; i < imports.length; i++) {
+ String elementName= desc[i].getElementName();
+ if (elementName.endsWith(".*") && Flags.isModule(desc[i].getFlags())) {
+ elementName= elementName.substring(0, elementName.length() - 2);
+ }
+ assertEquals(cu.getElementName() + "-cmpentries" + i, imports[i], elementName);
+ }
+ }
+
+ @Test
+ public void testSimpleBaseUse() throws Exception {
+ IPackageFragmentRoot sourceFolder= JavaProjectHelper.addSourceContainer(fJProject1, "src");
+
+ IPackageFragment pack1= sourceFolder.createPackageFragment("pack1", false, null);
+ String str= """
+ package pack1;
+ import module java.base;
+ class E {
+ List a;
+ }
+ """;
+ ICompilationUnit cu= pack1.createCompilationUnit("E.java", str, false, null);
+ Map options= new HashMap<>();
+ options.put(JavaCore.COMPILER_SOURCE, JavaCore.VERSION_24);
+ options.put(JavaCore.COMPILER_COMPLIANCE, JavaCore.VERSION_24);
+ options.put(JavaCore.COMPILER_PB_ENABLE_PREVIEW_FEATURES, JavaCore.ENABLED);
+ cu.setOptions(options);
+
+ String[] order= new String[0];
+ IChooseImportQuery query= createQuery("E", new String[] {}, new int[] {});
+
+ OrganizeImportsOperation op= createOperation(cu, order, 99, false, true, true, query);
+ op.run(null);
+
+ assertImports(cu, new String[] {
+ "java.base"
+ });
+ }
+
+ @Test
+ public void testUnneededImportFromBase() throws Exception {
+ IPackageFragmentRoot sourceFolder= JavaProjectHelper.addSourceContainer(fJProject1, "src");
+
+ IPackageFragment pack1= sourceFolder.createPackageFragment("pack1", false, null);
+ String str= """
+ package pack1;
+ import java.util.List;
+ import module java.base;
+ class E {
+ List a;
+ }
+ """;
+ ICompilationUnit cu= pack1.createCompilationUnit("E.java", str, false, null);
+ Map options= new HashMap<>();
+ options.put(JavaCore.COMPILER_SOURCE, JavaCore.VERSION_24);
+ options.put(JavaCore.COMPILER_COMPLIANCE, JavaCore.VERSION_24);
+ options.put(JavaCore.COMPILER_PB_ENABLE_PREVIEW_FEATURES, JavaCore.ENABLED);
+ cu.setOptions(options);
+
+ String[] order= new String[0];
+ IChooseImportQuery query= createQuery("E", new String[] {}, new int[] {});
+
+ OrganizeImportsOperation op= createOperation(cu, order, 99, false, true, true, query);
+ op.run(null);
+
+ assertImports(cu, new String[] {
+ "java.base"
+ });
+ }
+
+ @Test
+ public void testNeededImportOutsideBase() throws Exception {
+ IPackageFragmentRoot sourceFolder= JavaProjectHelper.addSourceContainer(fJProject1, "src");
+
+ IPackageFragment pack2= sourceFolder.createPackageFragment("pack2", false, null);
+ String str2= """
+ package pack2;
+ public class List {
+ }
+ """;
+ pack2.createCompilationUnit("List.java", str2, false, null);
+
+ IPackageFragment pack1= sourceFolder.createPackageFragment("pack1", false, null);
+ String str= """
+ package pack1;
+ import pack2.List;
+ import module java.base;
+ class E {
+ List a;
+ }
+ """;
+ ICompilationUnit cu= pack1.createCompilationUnit("E.java", str, false, null);
+ Map options= new HashMap<>();
+ options.put(JavaCore.COMPILER_SOURCE, JavaCore.VERSION_24);
+ options.put(JavaCore.COMPILER_COMPLIANCE, JavaCore.VERSION_24);
+ options.put(JavaCore.COMPILER_PB_ENABLE_PREVIEW_FEATURES, JavaCore.ENABLED);
+ cu.setOptions(options);
+
+ String[] order= new String[0];
+ IChooseImportQuery query= createQuery("E", new String[] {}, new int[] {});
+
+ OrganizeImportsOperation op= createOperation(cu, order, 99, false, true, true, query);
+ op.run(null);
+
+ assertImports(cu, new String[] {
+ "java.base",
+ "pack2.List",
+ });
+ }
+
+ @Test
+ public void testImplicitBase() throws Exception {
+ IPackageFragmentRoot sourceFolder= JavaProjectHelper.addSourceContainer(fJProject1, "src");
+
+ IPackageFragment pack1= sourceFolder.createPackageFragment("pack1", false, null);
+ String str= """
+ void main() {
+ List a;
+ }
+ """;
+ ICompilationUnit cu= pack1.createCompilationUnit("E.java", str, false, null);
+ Map options= new HashMap<>();
+ options.put(JavaCore.COMPILER_SOURCE, JavaCore.VERSION_24);
+ options.put(JavaCore.COMPILER_COMPLIANCE, JavaCore.VERSION_24);
+ options.put(JavaCore.COMPILER_PB_ENABLE_PREVIEW_FEATURES, JavaCore.ENABLED);
+ cu.setOptions(options);
+
+ String[] order= new String[0];
+ IChooseImportQuery query= createQuery("E", new String[] {}, new int[] {});
+
+ OrganizeImportsOperation op= createOperation(cu, order, 99, false, true, true, query);
+ op.run(null);
+
+ assertImports(cu, new String[] {
+ });
+ }
+
+}
diff --git a/org.eclipse.jdt.ui.tests/ui/org/eclipse/jdt/ui/tests/core/rules/Java23ProjectTestSetup.java b/org.eclipse.jdt.ui.tests/ui/org/eclipse/jdt/ui/tests/core/rules/Java23ProjectTestSetup.java
index 19ac112be75..daa255e8ba0 100644
--- a/org.eclipse.jdt.ui.tests/ui/org/eclipse/jdt/ui/tests/core/rules/Java23ProjectTestSetup.java
+++ b/org.eclipse.jdt.ui.tests/ui/org/eclipse/jdt/ui/tests/core/rules/Java23ProjectTestSetup.java
@@ -45,7 +45,7 @@ public IJavaProject getProject() {
@Override
public IClasspathEntry[] getDefaultClasspath() throws CoreException {
- IPath[] rtJarPath= JavaProjectHelper.findRtJar(JavaProjectHelper.RT_STUBS17);
+ IPath[] rtJarPath= JavaProjectHelper.findRtJar(JavaProjectHelper.RT_STUBS23);
IClasspathAttribute[] extraAttributes= { JavaCore.newClasspathAttribute(IClasspathAttribute.MODULE, Boolean.TRUE.toString()) };
return new IClasspathEntry[] { JavaCore.newLibraryEntry(rtJarPath[0], rtJarPath[1], rtJarPath[2], ClasspathEntry.NO_ACCESS_RULES, extraAttributes, true) };
}
diff --git a/org.eclipse.jdt.ui.tests/ui/org/eclipse/jdt/ui/tests/core/rules/Java24ProjectTestSetup.java b/org.eclipse.jdt.ui.tests/ui/org/eclipse/jdt/ui/tests/core/rules/Java24ProjectTestSetup.java
new file mode 100644
index 00000000000..9b54674ecce
--- /dev/null
+++ b/org.eclipse.jdt.ui.tests/ui/org/eclipse/jdt/ui/tests/core/rules/Java24ProjectTestSetup.java
@@ -0,0 +1,76 @@
+/*******************************************************************************
+ * Copyright (c) 2025 GK Software SE and others.
+ *
+ * This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * Stephan Herrmann - Initial API and implementation
+ *******************************************************************************/
+package org.eclipse.jdt.ui.tests.core.rules;
+
+import org.eclipse.jdt.testplugin.JavaProjectHelper;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IPath;
+
+import org.eclipse.core.resources.IProject;
+import org.eclipse.core.resources.ResourcesPlugin;
+
+import org.eclipse.jdt.core.IClasspathAttribute;
+import org.eclipse.jdt.core.IClasspathEntry;
+import org.eclipse.jdt.core.IJavaProject;
+import org.eclipse.jdt.core.JavaCore;
+
+import org.eclipse.jdt.internal.core.ClasspathEntry;
+
+/** Variant derived from Java17ProjectTestSetup */
+public class Java24ProjectTestSetup extends ProjectTestSetup {
+
+ public static final String PROJECT_NAME24= "TestSetupProject24";
+
+ private final String projectName;
+
+ private final boolean enable_preview_feature;
+
+ @Override
+ public IJavaProject getProject() {
+ IProject project= ResourcesPlugin.getWorkspace().getRoot().getProject(projectName);
+ return JavaCore.create(project);
+ }
+
+ @Override
+ public IClasspathEntry[] getDefaultClasspath() throws CoreException {
+ IPath[] rtJarPath= JavaProjectHelper.findRtJar(JavaProjectHelper.RT_STUBS24);
+ IClasspathAttribute[] extraAttributes= { JavaCore.newClasspathAttribute(IClasspathAttribute.MODULE, Boolean.TRUE.toString()) };
+ return new IClasspathEntry[] { JavaCore.newLibraryEntry(rtJarPath[0], rtJarPath[1], rtJarPath[2], ClasspathEntry.NO_ACCESS_RULES, extraAttributes, true) };
+ }
+
+ public Java24ProjectTestSetup( boolean enable_preview_feature) {
+ this.enable_preview_feature= enable_preview_feature;
+ projectName= PROJECT_NAME24;
+ }
+
+ public Java24ProjectTestSetup( String projectName, boolean enable_preview_feature) {
+ this.enable_preview_feature= enable_preview_feature;
+ this.projectName= projectName;
+ }
+
+ @Override
+ protected boolean projectExists() {
+ return getProject().exists();
+ }
+
+ @Override
+ protected IJavaProject createAndInitializeProject() throws CoreException {
+ IJavaProject javaProject= JavaProjectHelper.createJavaProject(projectName, "bin");
+ javaProject.setRawClasspath(getDefaultClasspath(), null);
+ JavaProjectHelper.set24CompilerOptions(javaProject, enable_preview_feature);
+ return javaProject;
+ }
+
+}