8282 */
8383public class UnusedDetector {
8484
85- public static class UnusedDescription {
86- public final Element unusedElement ;
87- public final TreePath unusedElementPath ;
88- public final boolean packagePrivate ;
89- public final UnusedReason reason ;
90-
91- public UnusedDescription (Element unusedElement , TreePath unusedElementPath , boolean packagePrivate , UnusedReason reason ) {
92- this .unusedElement = unusedElement ;
93- this .unusedElementPath = unusedElementPath ;
94- this .packagePrivate = packagePrivate ;
95- this .reason = reason ;
96- }
97-
98- }
85+ public record UnusedDescription (Element unusedElement , TreePath unusedElementPath , boolean packagePrivate , UnusedReason reason ) {}
86+
87+ private static final Object RESULTS_KEY = new Object ();
88+ private static final Object CLASS_INDEX_KEY = new Object ();
9989
10090 public enum UnusedReason {
10191 NOT_WRITTEN_READ ("neither read or written to" ),
@@ -111,7 +101,8 @@ private UnusedReason(String text) {
111101 }
112102
113103 public static List <UnusedDescription > findUnused (CompilationInfo info , Callable <Boolean > cancel ) {
114- List <UnusedDescription > cached = (List <UnusedDescription >) info .getCachedValue (UnusedDetector .class );
104+ @ SuppressWarnings ("unchecked" )
105+ List <UnusedDescription > cached = (List <UnusedDescription >) info .getCachedValue (RESULTS_KEY );
115106 if (cached != null ) {
116107 return cached ;
117108 }
@@ -181,7 +172,7 @@ public static List<UnusedDescription> findUnused(CompilationInfo info, Callable<
181172 }
182173 }
183174
184- info .putCachedValue (UnusedDetector . class , result , CompilationInfo .CacheClearPolicy .ON_CHANGE );
175+ info .putCachedValue (RESULTS_KEY , result , CompilationInfo .CacheClearPolicy .ON_CHANGE );
185176
186177 return result ;
187178 }
@@ -361,28 +352,17 @@ public boolean isDependencies() {
361352 default :
362353 return true ;
363354 }
364- ElementHandle eh = ElementHandle .create (el );
365- Project prj = FileOwnerQuery .getOwner (info .getFileObject ());
366- ClasspathInfo cpInfo ;
367- if (prj != null ) {
368- SourceGroup [] sourceGroups = ProjectUtils .getSources (prj ).getSourceGroups (JavaProjectConstants .SOURCES_TYPE_JAVA );
369- FileObject [] roots = new FileObject [sourceGroups .length ];
370- for (int i = 0 ; i < sourceGroups .length ; i ++) {
371- SourceGroup sourceGroup = sourceGroups [i ];
372- roots [i ] = sourceGroup .getRootFolder ();
373- }
374- cpInfo = ClasspathInfo .create (ClassPath .EMPTY , ClassPath .EMPTY , ClassPathSupport .createClassPath (roots ));
375- } else {
376- cpInfo = info .getClasspathInfo ();
377- }
378- Set <FileObject > res = cpInfo .getClassIndex ().getResources (ElementHandle .create (typeElement ), searchKinds , scope );
355+ FileObject fileObject = info .getFileObject ();
356+ ClassIndex classIndex = getCachedClassIndex (fileObject , info );
357+ Set <FileObject > res = classIndex .getResources (ElementHandle .create (typeElement ), searchKinds , scope );
379358 if (res != null ) {
359+ ElementHandle <Element > eh = ElementHandle .create (el );
380360 for (FileObject fo : res ) {
381361 try {
382362 if (Boolean .TRUE .equals (cancel .call ())) {
383363 return false ;
384364 }
385- if (fo != info . getFileObject () ) {
365+ if (fo != fileObject ) {
386366 JavaSource js = JavaSource .forFileObject (fo );
387367 if (js == null ) {
388368 return false ;
@@ -397,6 +377,7 @@ public Void scan(Tree tree, Element p) {
397377 Element element = cc .getTrees ().getElement (new TreePath (getCurrentPath (), tree ));
398378 if (element != null && eh .signatureEquals (element )) {
399379 found .set (true );
380+ return null ;
400381 }
401382 super .scan (tree , p );
402383 }
@@ -417,6 +398,29 @@ public Void scan(Tree tree, Element p) {
417398 return false ;
418399 }
419400
401+ // obtaining the ClassIndex can be expensive, this is usually called multiple times per search
402+ private static ClassIndex getCachedClassIndex (FileObject fileObject , CompilationInfo info ) {
403+ ClassIndex classIndex = (ClassIndex ) info .getCachedValue (CLASS_INDEX_KEY );
404+ if (classIndex == null ) {
405+ ClasspathInfo cpInfo ;
406+ Project prj = FileOwnerQuery .getOwner (fileObject );
407+ if (prj != null ) {
408+ SourceGroup [] sourceGroups = ProjectUtils .getSources (prj ).getSourceGroups (JavaProjectConstants .SOURCES_TYPE_JAVA );
409+ FileObject [] roots = new FileObject [sourceGroups .length ];
410+ for (int i = 0 ; i < sourceGroups .length ; i ++) {
411+ SourceGroup sourceGroup = sourceGroups [i ];
412+ roots [i ] = sourceGroup .getRootFolder ();
413+ }
414+ cpInfo = ClasspathInfo .create (ClassPath .EMPTY , ClassPath .EMPTY , ClassPathSupport .createClassPath (roots ));
415+ } else {
416+ cpInfo = info .getClasspathInfo ();
417+ }
418+ classIndex = cpInfo .getClassIndex ();
419+ info .putCachedValue (CLASS_INDEX_KEY , classIndex , CompilationInfo .CacheClearPolicy .ON_CHANGE );
420+ }
421+ return classIndex ;
422+ }
423+
420424 private static List <UsedDetector > collectUsedDetectors (CompilationInfo info ) {
421425 List <UsedDetector > detectors = new ArrayList <>();
422426 for (UsedDetector .Factory factory : Lookup .getDefault ().lookupAll (UsedDetector .Factory .class )) {
@@ -661,7 +665,7 @@ public Void visitLiteral(LiteralTree node, Void p) {
661665 @ Override
662666 public Void visitMethodInvocation (MethodInvocationTree node , Void p ) {
663667 Element invoked = info .getTrees ().getElement (new TreePath (getCurrentPath (), node .getMethodSelect ()));
664- if (invoked != null && invoked .getEnclosingElement () == methodHandlesLookup && node .getArguments ().size () > 0 ) {
668+ if (invoked != null && invoked .getEnclosingElement () == methodHandlesLookup && ! node .getArguments ().isEmpty () ) {
665669 ExpressionTree clazz = node .getArguments ().get (0 );
666670 Element lookupType = null ;
667671 if (clazz .getKind () == Kind .MEMBER_SELECT ) {
@@ -678,16 +682,12 @@ public Void visitMethodInvocation(MethodInvocationTree node, Void p) {
678682 }
679683 }
680684 switch (invoked .getSimpleName ().toString ()) {
681- case "findStatic" : case "findVirtual" : case "findSpecial" :
685+ case "findStatic" , "findVirtual" , "findSpecial" ->
682686 type2LookedUpMethods .computeIfAbsent (lookupType , t -> new HashSet <>()).add (lookupName );
683- break ;
684- case "findConstructor" :
687+ case "findConstructor" ->
685688 type2LookedUpMethods .computeIfAbsent (lookupType , t -> new HashSet <>()).add ("<init>" );
686- break ;
687- case "findGetter" : case "findSetter" : case "findStaticGetter" :
688- case "findStaticSetter" : case "findStaticVarHandle" : case "findVarHandle" :
689+ case "findGetter" , "findSetter" , "findStaticGetter" , "findStaticSetter" , "findStaticVarHandle" , "findVarHandle" ->
689690 type2LookedUpFields .computeIfAbsent (lookupType , t -> new HashSet <>()).add (lookupName );
690- break ;
691691 }
692692 }
693693 return super .visitMethodInvocation (node , p );
0 commit comments