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; + } + +}