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,15 @@ 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 ()) {
103+ // TODO: try (and check null inbetween)
104+ // aPackage.getJavaProject().getProject();
98105 IResource packageResource = aPackage .getResource ();
99106 if (packageResource != null ) {
100- return JavaResolutionFactory .createExportPackageProposal (packageResource .getProject (), aPackage , JavaResolutionFactory .TYPE_JAVA_COMPLETION , 100 );
107+ IProject project = packageResource .getProject ();
108+ var change = JavaResolutionFactory .createExportPackageChange (project , aPackage );
109+ return JavaResolutionFactory .createJavaCompletionProposal (change , 100 );
101110 }
102111 }
103112 return null ;
@@ -114,13 +123,16 @@ public Object addRequireBundleModification(IProject project, ExportPackageDescri
114123 * Adds a require bundle proposal. Subclasses should implement the
115124 * actual adding to the collection.
116125 */
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 );
126+ public IJavaCompletionProposal addRequireBundleModification (IProject project , ExportPackageDescription desc ,
127+ int relevance , CompilationUnit cu , String qualifiedTypeToImport ) {
128+ BundleDescription exporter = desc .getExporter ();
129+ if (exporter == null ) {
130+ return null ;
131+ }
132+ var change = JavaResolutionFactory .createRequireBundleChange (project , exporter , cu , qualifiedTypeToImport );
133+ return JavaResolutionFactory .createJavaCompletionProposal (change , relevance );
121134 }
122135
123-
124136 /**
125137 * Adds a search repositories proposal. Subclasses should implement the actual adding to the collection.
126138 */
@@ -201,38 +213,31 @@ public void run(IProgressMonitor monitor) {
201213 }
202214 return ;
203215 }
204-
205- Iterator <Entry <String , ExportPackageDescription >> validPackagesIter = validPackages .entrySet ().iterator ();
206- Set <ExportPackageDescription > visiblePkgs = null ;
216+ // getting visible packages is not very efficient -> do it only once
217+ Set <ExportPackageDescription > visiblePackages = !validPackages .isEmpty () ? getVisiblePackages () : null ;
207218 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 ();
219+ for (var validPackagesIter = validPackages .entrySet ().iterator (); validPackagesIter .hasNext ()
220+ && (allowMultipleFixes || !fCollector .isDone ());) {
221+ var entry = validPackagesIter .next ();
222+ String qualifiedType = entry .getKey ();
223+ ExportPackageDescription currentPackage = entry .getValue ();
215224 // if package is already visible, skip over
216- if (visiblePkgs .contains (currentPackage )) {
225+ if (visiblePackages .contains (currentPackage )) {
217226 continue ;
218227 }
219228 // if currentPackage will resolve class and is valid, pass it to collector
220- fCollector .addResolutionModification (fProject , currentPackage , fCompilationUnit , currentEntry . getKey () );
229+ fCollector .addResolutionModification (fProject , currentPackage , fCompilationUnit , qualifiedType );
221230 }
222-
223231 // additionally add require bundle proposals
224232 Set <String > bundleNames = getCurrentBundleNames ();
225- for (validPackagesIter = validPackages .entrySet ().iterator (); validPackagesIter .hasNext ();) {
226- Entry <String , ExportPackageDescription > currentEntry = validPackagesIter .next ();
227- ExportPackageDescription currentPackage = currentEntry .getValue ();
233+ validPackages .forEach ((key , currentPackage ) -> {
228234 BundleDescription desc = currentPackage .getExporter ();
229235 // Ignore already required bundles and duplicate proposals (currently we do not consider version constraints)
230236 if (desc != null && !bundleNames .contains (desc .getName ())) {
231- fCollector .addRequireBundleModification (fProject , currentPackage , 3 , fCompilationUnit ,
232- currentEntry .getKey ());
237+ fCollector .addRequireBundleModification (fProject , currentPackage , 3 , fCompilationUnit , key );
233238 bundleNames .add (desc .getName ());
234239 }
235- }
240+ });
236241 }
237242 }
238243
@@ -251,7 +256,8 @@ private Map<String, ExportPackageDescription> getValidPackages(String typeName,
251256 if (importPkgs != null ) {
252257 if (packageName != null ) {
253258 if (!isImportedPackage (packageName , importPkgs )) {
254- validPackages = getValidPackages (packageName , qualifiedTypeToImport );
259+ List <ExportPackageDescription > packages = getValidPackages (packageName );
260+ validPackages = !packages .isEmpty () ? Map .of (qualifiedTypeToImport , packages .getLast ()) : Map .of ();
255261 }
256262 subMonitor .split (1 );
257263 } else {
@@ -279,18 +285,10 @@ private Map<String, ExportPackageDescription> findValidPackagesContainingSimpleT
279285 ImportPackageSpecification [] importPkgs , Set <IPackageFragment > packagesToExport , IProgressMonitor monitor ) {
280286 SubMonitor subMonitor = SubMonitor .convert (monitor );
281287
282- IPluginModelBase [] activeModels = PluginRegistry .getActiveModels ();
283- Set <IJavaProject > javaProjects = new LinkedHashSet <>(activeModels .length * 2 );
288+ Set <IJavaProject > javaProjects = Arrays .stream (PluginRegistry .getWorkspaceModels ())
289+ .map (IPluginModelBase ::getUnderlyingResource ).map (IResource ::getProject ).map (JavaCore ::create )
290+ .filter (IJavaProject ::exists ).collect (Collectors .toCollection (LinkedHashSet ::new ));
284291
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- }
294292 final IJavaProject currentJavaProject = JavaCore .create (fProject );
295293 javaProjects .remove (currentJavaProject ); // no need to search in current project itself
296294
@@ -328,10 +326,10 @@ public void acceptSearchMatch(SearchMatch aMatch) throws CoreException {
328326
329327 if (!packages .isEmpty ()) {
330328 // transform to ExportPackageDescriptions
331- Map < String , ExportPackageDescription > exportDescriptions = new HashMap <>( packages . size () );
329+ State state = PDECore . getDefault (). getModelManager (). getState (). getState ( );
332330
333331 // 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 ();
332+ ExportPackageDescription [] systemPackages = state .getSystemPackages ();
335333 for (ExportPackageDescription systemPackage : systemPackages ) {
336334 packages .remove (systemPackage .getName ());
337335 }
@@ -341,7 +339,8 @@ public void acceptSearchMatch(SearchMatch aMatch) throws CoreException {
341339 }
342340
343341 // finally create the list of ExportPackageDescriptions
344- ExportPackageDescription [] knownPackages = PDECore .getDefault ().getModelManager ().getState ().getState ().getExportedPackages ();
342+ Map <String , ExportPackageDescription > exportDescriptions = new HashMap <>(packages .size ());
343+ ExportPackageDescription [] knownPackages = state .getExportedPackages ();
345344 for (ExportPackageDescription knownPackage : knownPackages ) {
346345 if (packages .containsKey (knownPackage .getName ())) {
347346 exportDescriptions .put (qualifiedTypeNames .get (knownPackage .getName ()), knownPackage );
@@ -371,39 +370,26 @@ private boolean isImportedPackage(String packageName, ImportPackageSpecification
371370 return false ;
372371 }
373372
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- }
373+ private static List <ExportPackageDescription > getValidPackages (String packageName ) {
374+ State state = PDECore .getDefault ().getModelManager ().getState ().getState ();
375+ List <ExportPackageDescription > validPackages = Arrays .stream (state .getExportedPackages ())
376+ .filter (p -> packageName .equals (p .getName ())).toList ();
382377 // remove system packages if they happen to be included. Adding a system package won't resolve anything, since package package already comes from JRE
383378 if (!validPackages .isEmpty ()) {
384- knownPackages = PDECore . getDefault (). getModelManager (). getState (). getState () .getSystemPackages ();
385- for ( ExportPackageDescription knownPackage : knownPackages ) {
386- validPackages . remove ( knownPackage . getName () );
379+ ExportPackageDescription [] systemPackages = state .getSystemPackages ();
380+ if ( Arrays . stream ( systemPackages ). map ( ExportPackageDescription :: getName ). anyMatch ( packageName :: equals ) ) {
381+ return List . of ( );
387382 }
388383 }
389- Map <String , ExportPackageDescription > packages = new HashMap <>();
390- for (ExportPackageDescription exportPackageDescription : validPackages .values ()) {
391- packages .put (qualifiedTypeToImport , exportPackageDescription );
392- }
393- return packages ;
384+ return validPackages ;
394385 }
395386
396387 private Set <ExportPackageDescription > getVisiblePackages () {
397388 IPluginModelBase base = PluginRegistry .findModel (fProject );
398389 if (base != null ) {
399390 BundleDescription desc = base .getBundleDescription ();
400-
401391 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 ;
392+ return Set .of (helper .getVisiblePackages (desc ));
407393 }
408394 return Collections .emptySet ();
409395 }
0 commit comments