3232import org .eclipse .core .runtime .CoreException ;
3333import org .eclipse .core .runtime .IProgressMonitor ;
3434import org .eclipse .core .runtime .ProgressMonitorWrapper ;
35+ import org .eclipse .core .runtime .Status ;
3536import org .eclipse .core .runtime .SubMonitor ;
3637import org .eclipse .jdt .core .IJavaProject ;
38+ import org .eclipse .jdt .core .IPackageFragment ;
3739import org .eclipse .jdt .core .JavaCore ;
40+ import org .eclipse .jdt .core .JavaModelException ;
3841import org .eclipse .jdt .core .search .IJavaSearchConstants ;
3942import org .eclipse .jdt .core .search .IJavaSearchScope ;
4043import org .eclipse .jdt .core .search .SearchEngine ;
@@ -144,10 +147,10 @@ public void run(IProgressMonitor monitor) throws InvocationTargetException, Inte
144147 if (subMonitor .isCanceled ()) {
145148 return ;
146149 }
150+ removeSourceReferences (usedPlugins , usedPackages , subMonitor .split (10 ));
147151 minimizeDependencies (usedPlugins , usedPackages , subMonitor );
148152 removeBuddies ();
149153 removeReexported ();
150- removeSourceReferences (subMonitor .split (10 ));
151154 }
152155
153156 /**
@@ -158,8 +161,12 @@ public void run(IProgressMonitor monitor) throws InvocationTargetException, Inte
158161 * warnings. To prevent the user from getting a confusing project
159162 * error/warnings we retain them here even if not strictly required at
160163 * runtime.
164+ *
165+ * @param usedPackages
166+ * @param usedPlugins
161167 */
162- private void removeSourceReferences (IProgressMonitor monitor ) {
168+ private void removeSourceReferences (Map <String , IPluginImport > usedPlugins , List <ImportPackageObject > usedPackages ,
169+ IProgressMonitor monitor ) {
163170 if (fList .isEmpty ()) {
164171 return ;
165172 }
@@ -168,49 +175,66 @@ private void removeSourceReferences(IProgressMonitor monitor) {
168175 IJavaProject javaProject = JavaCore .create (project );
169176 SubMonitor convert = SubMonitor .convert (monitor , "Search Source References for unused requirements" , //$NON-NLS-1$
170177 fList .size ());
178+ SearchEngine engine = new SearchEngine ();
179+ IJavaSearchScope searchScope ;
180+ try {
181+ searchScope = PluginJavaSearchUtil .createSeachScope (javaProject );
182+ } catch (JavaModelException e ) {
183+ return ;
184+ }
185+ Requestor requestor = new Requestor (engine , searchScope );
171186 for (Iterator <Object > iterator = fList .iterator (); iterator .hasNext ();) {
172187 Object item = iterator .next ();
173188 if (item instanceof ImportPackageObject pkg ) {
174- if (isPackageReferenced (pkg , javaProject , convert .split (1 ))) {
189+ if (isPackageReferenced (pkg , requestor , convert .split (1 ))) {
190+ usedPackages .add (pkg );
191+ iterator .remove ();
192+ }
193+ } else if (item instanceof IPluginImport bundle ) {
194+ IPluginModelBase [] models = PluginJavaSearchUtil .getPluginImports (bundle );
195+ IPackageFragment [] packageFragments ;
196+ try {
197+ packageFragments = PluginJavaSearchUtil .collectPackageFragments (models , javaProject , true );
198+ } catch (JavaModelException e ) {
199+ // something is broken, so better assume it is used
200+ // here.
201+ iterator .remove ();
202+ continue ;
203+ }
204+ if (isBundleReferenced (packageFragments , requestor , convert .split (1 ))) {
205+ usedPlugins .put (bundle .getId (), bundle );
175206 iterator .remove ();
176207 }
177208 }
178209 }
179210 }
180211 }
181212
182- private boolean isPackageReferenced (ImportPackageObject pkg , IJavaProject javaProject , IProgressMonitor monitor ) {
213+ private boolean isBundleReferenced (IPackageFragment [] packageFragments , Requestor requestor ,
214+ IProgressMonitor monitor ) {
183215 try {
184- SearchEngine engine = new SearchEngine ();
185- IJavaSearchScope searchScope = PluginJavaSearchUtil .createSeachScope (javaProject );
186- Requestor requestor = new Requestor ();
187- String packageName = pkg .getName ();
188- SearchPattern pattern = SearchPattern .createPattern (packageName , IJavaSearchConstants .PACKAGE ,
189- IJavaSearchConstants .REFERENCES , SearchPattern .R_EXACT_MATCH );
190- if (pattern != null ) {
191- ProgressMonitorWrapper wrapper = new ProgressMonitorWrapper (monitor ) {
192-
193- @ Override
194- public boolean isCanceled () {
195- return monitor .isCanceled () || requestor .used ;
196- }
197-
198- @ Override
199- public void setCanceled (boolean b ) {
200- }
201- };
202- try {
203- engine .search (pattern , new SearchParticipant [] { SearchEngine .getDefaultSearchParticipant () },
204- searchScope , requestor , wrapper );
205- } catch (org .eclipse .core .runtime .OperationCanceledException e ) {
206- if (monitor .isCanceled ()) {
207- // the the user really canceled, rethrow it here,
208- // otherwise we just found a match!
209- throw e ;
216+ SubMonitor subMonitor = SubMonitor .convert (monitor , packageFragments .length );
217+ for (IPackageFragment fragment : packageFragments ) {
218+ if (fragment .hasChildren () && !fragment .isDefaultPackage ()) {
219+ SearchPattern pattern = SearchPattern .createPattern (fragment , IJavaSearchConstants .REFERENCES );
220+ if (requestor .search (pattern , subMonitor .split (1 ))) {
221+ return true ;
210222 }
211223 }
212- return requestor .used ;
213224 }
225+ return false ;
226+ } catch (CoreException e ) {
227+ }
228+ // If we can't be sure better assume it is used!
229+ return true ;
230+ }
231+
232+ private boolean isPackageReferenced (ImportPackageObject pkg , Requestor requestor , IProgressMonitor monitor ) {
233+ try {
234+ String packageName = pkg .getName ();
235+ SearchPattern pattern = SearchPattern .createPattern (packageName , IJavaSearchConstants .PACKAGE ,
236+ IJavaSearchConstants .REFERENCES , SearchPattern .R_EXACT_MATCH );
237+ return requestor .search (pattern , monitor );
214238 } catch (CoreException e ) {
215239 }
216240 // can't tell, so better be safe and assume it is used...
@@ -372,11 +396,50 @@ private void minimizeDependencies(Map<String, IPluginImport> usedPlugins, List<I
372396 }
373397
374398 private static class Requestor extends SearchRequestor {
375- volatile boolean used ;
399+ private volatile boolean used ;
400+ private SearchEngine engine ;
401+ private IJavaSearchScope searchScope ;
402+
403+ public Requestor (SearchEngine engine , IJavaSearchScope searchScope ) {
404+ this .engine = engine ;
405+ this .searchScope = searchScope ;
406+ }
407+
408+ public boolean search (SearchPattern pattern , IProgressMonitor monitor ) throws CoreException {
409+ used = false ;
410+ if (pattern == null ) {
411+ throw new CoreException (Status .error ("pattern is null" , new NullPointerException ())); //$NON-NLS-1$
412+ }
413+ try {
414+ engine .search (pattern , new SearchParticipant [] { SearchEngine .getDefaultSearchParticipant () },
415+ searchScope , this , getMonitor (monitor ));
416+ } catch (org .eclipse .core .runtime .OperationCanceledException e ) {
417+ if (monitor .isCanceled ()) {
418+ // the the user really canceled, rethrow it here,
419+ // otherwise we just found a match and canceled the search!
420+ throw e ;
421+ }
422+ }
423+ return used ;
424+ }
376425
377426 @ Override
378427 public void acceptSearchMatch (SearchMatch match ) {
379428 used = true ;
380429 }
430+
431+ public IProgressMonitor getMonitor (IProgressMonitor parent ) {
432+ return new ProgressMonitorWrapper (parent ) {
433+
434+ @ Override
435+ public boolean isCanceled () {
436+ return parent .isCanceled () || used ;
437+ }
438+
439+ @ Override
440+ public void setCanceled (boolean b ) {
441+ }
442+ };
443+ }
381444 }
382445}
0 commit comments