11/*******************************************************************************
2- * Copyright (c) 2008, 2019 IBM Corporation and others.
2+ * Copyright (c) 2008, 2025 IBM Corporation and others.
33 *
44 * This program and the accompanying materials
55 * are made available under the terms of the Eclipse Public License 2.0
1313 *******************************************************************************/
1414package org .eclipse .pde .internal .ui .correction .java ;
1515
16+ import java .util .Arrays ;
1617import java .util .Collections ;
1718import java .util .HashMap ;
1819import java .util .HashSet ;
19- import java .util .Iterator ;
2020import java .util .LinkedHashSet ;
21+ import java .util .List ;
2122import java .util .Map ;
22- import java .util .Map .Entry ;
2323import java .util .Set ;
24+ import java .util .stream .Collectors ;
2425
2526import org .eclipse .core .resources .IProject ;
2627import org .eclipse .core .resources .IResource ;
4142import org .eclipse .jdt .core .search .SearchParticipant ;
4243import org .eclipse .jdt .core .search .SearchPattern ;
4344import org .eclipse .jdt .core .search .SearchRequestor ;
45+ import org .eclipse .jdt .ui .text .java .IJavaCompletionProposal ;
4446import org .eclipse .jface .operation .IRunnableWithProgress ;
4547import org .eclipse .osgi .service .resolver .BundleDescription ;
4648import org .eclipse .osgi .service .resolver .BundleSpecification ;
4749import org .eclipse .osgi .service .resolver .ExportPackageDescription ;
4850import org .eclipse .osgi .service .resolver .ImportPackageSpecification ;
51+ import org .eclipse .osgi .service .resolver .State ;
4952import org .eclipse .osgi .service .resolver .StateHelper ;
5053import org .eclipse .pde .core .plugin .IPluginModelBase ;
5154import org .eclipse .pde .core .plugin .PluginRegistry ;
5962 */
6063public class FindClassResolutionsOperation implements IRunnableWithProgress {
6164
62- String fClassName = null ;
63- IProject fProject = null ;
64- AbstractClassResolutionCollector fCollector = null ;
65+ private String fClassName = null ;
66+ private IProject fProject = null ;
67+ private AbstractClassResolutionCollector fCollector = null ;
6568 private CompilationUnit fCompilationUnit ;
6669
6770 /**
@@ -78,7 +81,9 @@ public static abstract class AbstractClassResolutionCollector {
7881 * Import-Package. The proposals can be created with the help of the
7982 * JavaResolutionFactory
8083 */
81- abstract public void addResolutionModification (IProject project , ExportPackageDescription desc );
84+ public void addResolutionModification (IProject project , ExportPackageDescription desc ) {
85+ addResolutionModification (project , desc , null , "" ); //$NON-NLS-1$
86+ }
8287
8388 /**
8489 * This method is meant to be sub-classed. The subclass should decide if
@@ -93,11 +98,13 @@ abstract public void addResolutionModification(IProject project, ExportPackageDe
9398 * Adds an export package proposal. Subclasses should implement the
9499 * actual adding to the collection.
95100 */
96- public Object addExportPackageResolutionModification (IPackageFragment aPackage ) {
101+ public IJavaCompletionProposal addExportPackageResolutionModification (IPackageFragment aPackage ) {
97102 if (aPackage .exists ()) {
98103 IResource packageResource = aPackage .getResource ();
99104 if (packageResource != null ) {
100- return JavaResolutionFactory .createExportPackageProposal (packageResource .getProject (), aPackage , JavaResolutionFactory .TYPE_JAVA_COMPLETION , 100 );
105+ IProject project = packageResource .getProject ();
106+ var change = JavaResolutionFactory .createExportPackageChange (project , aPackage );
107+ return JavaResolutionFactory .createJavaCompletionProposal (change , 100 );
101108 }
102109 }
103110 return null ;
@@ -114,13 +121,16 @@ public Object addRequireBundleModification(IProject project, ExportPackageDescri
114121 * Adds a require bundle proposal. Subclasses should implement the
115122 * actual adding to the collection.
116123 */
117- public Object addRequireBundleModification (IProject project , ExportPackageDescription desc , int relevance ,
118- CompilationUnit cu , String qualifiedTypeToImport ) {
119- return JavaResolutionFactory .createRequireBundleProposal (project , desc ,
120- JavaResolutionFactory .TYPE_JAVA_COMPLETION , relevance , cu , qualifiedTypeToImport );
124+ public IJavaCompletionProposal addRequireBundleModification (IProject project , ExportPackageDescription desc ,
125+ int relevance , CompilationUnit cu , String qualifiedTypeToImport ) {
126+ BundleDescription exporter = desc .getExporter ();
127+ if (exporter == null ) {
128+ return null ;
129+ }
130+ var change = JavaResolutionFactory .createRequireBundleChange (project , exporter , cu , qualifiedTypeToImport );
131+ return JavaResolutionFactory .createJavaCompletionProposal (change , relevance );
121132 }
122133
123-
124134 /**
125135 * Adds a search repositories proposal. Subclasses should implement the actual adding to the collection.
126136 */
@@ -134,9 +144,6 @@ public Object addSearchRepositoriesModification(String packageName) {
134144 public boolean isDone () {
135145 return false ;
136146 }
137-
138-
139-
140147 }
141148
142149 /**
@@ -201,38 +208,31 @@ public void run(IProgressMonitor monitor) {
201208 }
202209 return ;
203210 }
204-
205- Iterator <Entry <String , ExportPackageDescription >> validPackagesIter = validPackages .entrySet ().iterator ();
206- Set <ExportPackageDescription > visiblePkgs = null ;
211+ // getting visible packages is not very efficient -> do it only once
212+ Set <ExportPackageDescription > visiblePackages = !validPackages .isEmpty () ? getVisiblePackages () : null ;
207213 boolean allowMultipleFixes = packageName == null ;
208- while (validPackagesIter .hasNext () && (allowMultipleFixes || !fCollector .isDone ())) {
209- // since getting visible packages is not very efficient, only do it once and cache result
210- if (visiblePkgs == null ) {
211- visiblePkgs = getVisiblePackages ();
212- }
213- Entry <String , ExportPackageDescription > currentEntry = validPackagesIter .next ();
214- ExportPackageDescription currentPackage = currentEntry .getValue ();
214+ for (var validPackagesIter = validPackages .entrySet ().iterator (); validPackagesIter .hasNext ()
215+ && (allowMultipleFixes || !fCollector .isDone ());) {
216+ var entry = validPackagesIter .next ();
217+ String qualifiedType = entry .getKey ();
218+ ExportPackageDescription currentPackage = entry .getValue ();
215219 // if package is already visible, skip over
216- if (visiblePkgs .contains (currentPackage )) {
220+ if (visiblePackages .contains (currentPackage )) {
217221 continue ;
218222 }
219223 // if currentPackage will resolve class and is valid, pass it to collector
220- fCollector .addResolutionModification (fProject , currentPackage , fCompilationUnit , currentEntry . getKey () );
224+ fCollector .addResolutionModification (fProject , currentPackage , fCompilationUnit , qualifiedType );
221225 }
222-
223226 // additionally add require bundle proposals
224227 Set <String > bundleNames = getCurrentBundleNames ();
225- for (validPackagesIter = validPackages .entrySet ().iterator (); validPackagesIter .hasNext ();) {
226- Entry <String , ExportPackageDescription > currentEntry = validPackagesIter .next ();
227- ExportPackageDescription currentPackage = currentEntry .getValue ();
228+ validPackages .forEach ((key , currentPackage ) -> {
228229 BundleDescription desc = currentPackage .getExporter ();
229230 // Ignore already required bundles and duplicate proposals (currently we do not consider version constraints)
230231 if (desc != null && !bundleNames .contains (desc .getName ())) {
231- fCollector .addRequireBundleModification (fProject , currentPackage , 3 , fCompilationUnit ,
232- currentEntry .getKey ());
232+ fCollector .addRequireBundleModification (fProject , currentPackage , 3 , fCompilationUnit , key );
233233 bundleNames .add (desc .getName ());
234234 }
235- }
235+ });
236236 }
237237 }
238238
@@ -251,7 +251,8 @@ private Map<String, ExportPackageDescription> getValidPackages(String typeName,
251251 if (importPkgs != null ) {
252252 if (packageName != null ) {
253253 if (!isImportedPackage (packageName , importPkgs )) {
254- validPackages = getValidPackages (packageName , qualifiedTypeToImport );
254+ List <ExportPackageDescription > packages = getValidPackages (packageName );
255+ validPackages = !packages .isEmpty () ? Map .of (qualifiedTypeToImport , packages .getLast ()) : Map .of ();
255256 }
256257 subMonitor .split (1 );
257258 } else {
@@ -279,18 +280,10 @@ private Map<String, ExportPackageDescription> findValidPackagesContainingSimpleT
279280 ImportPackageSpecification [] importPkgs , Set <IPackageFragment > packagesToExport , IProgressMonitor monitor ) {
280281 SubMonitor subMonitor = SubMonitor .convert (monitor );
281282
282- IPluginModelBase [] activeModels = PluginRegistry .getActiveModels ();
283- Set <IJavaProject > javaProjects = new LinkedHashSet <>(activeModels .length * 2 );
283+ Set <IJavaProject > javaProjects = Arrays .stream (PluginRegistry .getWorkspaceModels ())
284+ .map (IPluginModelBase ::getUnderlyingResource ).map (IResource ::getProject ).map (JavaCore ::create )
285+ .filter (IJavaProject ::exists ).collect (Collectors .toCollection (LinkedHashSet ::new ));
284286
285- for (IPluginModelBase model : activeModels ) {
286- IResource resource = model .getUnderlyingResource ();
287- if (resource != null && resource .isAccessible ()) {
288- IJavaProject javaProject = JavaCore .create (resource .getProject ());
289- if (javaProject .exists ()) {
290- javaProjects .add (javaProject );
291- }
292- }
293- }
294287 final IJavaProject currentJavaProject = JavaCore .create (fProject );
295288 javaProjects .remove (currentJavaProject ); // no need to search in current project itself
296289
@@ -328,10 +321,10 @@ public void acceptSearchMatch(SearchMatch aMatch) throws CoreException {
328321
329322 if (!packages .isEmpty ()) {
330323 // transform to ExportPackageDescriptions
331- Map < String , ExportPackageDescription > exportDescriptions = new HashMap <>( packages . size () );
324+ State state = PDECore . getDefault (). getModelManager (). getState (). getState ( );
332325
333326 // remove system packages if they happen to be included. Adding a system package won't resolve anything, since package package already comes from JRE
334- ExportPackageDescription [] systemPackages = PDECore . getDefault (). getModelManager (). getState (). getState () .getSystemPackages ();
327+ ExportPackageDescription [] systemPackages = state .getSystemPackages ();
335328 for (ExportPackageDescription systemPackage : systemPackages ) {
336329 packages .remove (systemPackage .getName ());
337330 }
@@ -341,7 +334,8 @@ public void acceptSearchMatch(SearchMatch aMatch) throws CoreException {
341334 }
342335
343336 // finally create the list of ExportPackageDescriptions
344- ExportPackageDescription [] knownPackages = PDECore .getDefault ().getModelManager ().getState ().getState ().getExportedPackages ();
337+ Map <String , ExportPackageDescription > exportDescriptions = new HashMap <>(packages .size ());
338+ ExportPackageDescription [] knownPackages = state .getExportedPackages ();
345339 for (ExportPackageDescription knownPackage : knownPackages ) {
346340 if (packages .containsKey (knownPackage .getName ())) {
347341 exportDescriptions .put (qualifiedTypeNames .get (knownPackage .getName ()), knownPackage );
@@ -371,39 +365,26 @@ private boolean isImportedPackage(String packageName, ImportPackageSpecification
371365 return false ;
372366 }
373367
374- private static Map <String , ExportPackageDescription > getValidPackages (String pkgName , String qualifiedTypeToImport ) {
375- ExportPackageDescription [] knownPackages = PDECore .getDefault ().getModelManager ().getState ().getState ().getExportedPackages ();
376- Map <String , ExportPackageDescription > validPackages = new HashMap <>();
377- for (ExportPackageDescription knownPackage : knownPackages ) {
378- if (knownPackage .getName ().equals (pkgName )) {
379- validPackages .put (knownPackage .getName (), knownPackage );
380- }
381- }
368+ private static List <ExportPackageDescription > getValidPackages (String packageName ) {
369+ State state = PDECore .getDefault ().getModelManager ().getState ().getState ();
370+ List <ExportPackageDescription > validPackages = Arrays .stream (state .getExportedPackages ())
371+ .filter (p -> packageName .equals (p .getName ())).toList ();
382372 // remove system packages if they happen to be included. Adding a system package won't resolve anything, since package package already comes from JRE
383373 if (!validPackages .isEmpty ()) {
384- knownPackages = PDECore . getDefault (). getModelManager (). getState (). getState () .getSystemPackages ();
385- for ( ExportPackageDescription knownPackage : knownPackages ) {
386- validPackages . remove ( knownPackage . getName () );
374+ ExportPackageDescription [] systemPackages = state .getSystemPackages ();
375+ if ( Arrays . stream ( systemPackages ). map ( ExportPackageDescription :: getName ). anyMatch ( packageName :: equals ) ) {
376+ return List . of ( );
387377 }
388378 }
389- Map <String , ExportPackageDescription > packages = new HashMap <>();
390- for (ExportPackageDescription exportPackageDescription : validPackages .values ()) {
391- packages .put (qualifiedTypeToImport , exportPackageDescription );
392- }
393- return packages ;
379+ return validPackages ;
394380 }
395381
396382 private Set <ExportPackageDescription > getVisiblePackages () {
397383 IPluginModelBase base = PluginRegistry .findModel (fProject );
398384 if (base != null ) {
399385 BundleDescription desc = base .getBundleDescription ();
400-
401386 StateHelper helper = BundleHelper .getPlatformAdmin ().getStateHelper ();
402- ExportPackageDescription [] visiblePkgs = helper .getVisiblePackages (desc );
403-
404- HashSet <ExportPackageDescription > set = new HashSet <>();
405- Collections .addAll (set , visiblePkgs );
406- return set ;
387+ return Set .of (helper .getVisiblePackages (desc ));
407388 }
408389 return Collections .emptySet ();
409390 }
0 commit comments