1717import net .sourceforge .pmd .lang .java .symbols .JTypeDeclSymbol ;
1818import net .sourceforge .pmd .lang .java .symbols .JTypeParameterSymbol ;
1919import net .sourceforge .pmd .lang .java .symbols .internal .UnresolvedClassStore ;
20+ import net .sourceforge .pmd .util .OptionalBool ;
2021
2122/**
2223 * Public utilities to test the type of nodes.
@@ -106,8 +107,10 @@ public static boolean isA(final @NonNull String canonicalName, final @Nullable T
106107 AssertionUtil .requireParamNotNull ("canonicalName" , (Object ) canonicalName );
107108 if (node == null ) {
108109 return false ;
109- } else if (isExactlyA (canonicalName , node )) {
110- return true ;
110+ }
111+ OptionalBool exactMatch = isExactlyAOrAnon (canonicalName , node );
112+ if (exactMatch != OptionalBool .NO ) {
113+ return exactMatch == OptionalBool .YES ; // otherwise anon, and we return false
111114 }
112115
113116 JTypeMirror thisType = node .getTypeMirror ();
@@ -125,13 +128,19 @@ public static boolean isA(final @NonNull String canonicalName, final @Nullable T
125128 TypeSystem ts = thisType .getTypeSystem ();
126129 UnresolvedClassStore unresolvedStore = InternalApiBridge .getProcessor (node ).getUnresolvedStore ();
127130 @ Nullable JTypeMirror otherType = TypesFromReflection .loadType (ts , canonicalName , unresolvedStore );
128- if (otherType == null ) {
131+ if (otherType == null
132+ || otherType .isClassOrInterface () && ((JClassType ) otherType ).getSymbol ().isAnonymousClass ()) {
129133 return false ; // we know isExactlyA(canonicalName, node); returned false
130134 }
131135
132136 return thisType .isSubtypeOf (otherType );
133137 }
134138
139+ private static boolean isAnonymous (JTypeMirror type ) {
140+ JTypeDeclSymbol symbol = type .getSymbol ();
141+ return symbol instanceof JClassSymbol && ((JClassSymbol ) symbol ).isAnonymousClass ();
142+ }
143+
135144 private static boolean isAnnotationSuperType (String clazzName ) {
136145 // then, the supertype may only be Object, j.l.Annotation
137146 // this is used e.g. by the typeIs function in XPath
@@ -210,25 +219,31 @@ private static boolean isExactlyA(@NonNull Class<?> klass, @Nullable JTypeDeclSy
210219 * @throws NullPointerException if the class name parameter is null
211220 */
212221 public static boolean isExactlyA (@ NonNull String canonicalName , final @ Nullable TypeNode node ) {
222+ return isExactlyAOrAnon (canonicalName , node ) == OptionalBool .YES ;
223+ }
224+
225+ private static OptionalBool isExactlyAOrAnon (@ NonNull String canonicalName , final @ Nullable TypeNode node ) {
213226 AssertionUtil .requireParamNotNull ("canonicalName" , canonicalName );
214227 if (node == null ) {
215- return false ;
228+ return OptionalBool . NO ;
216229 }
217230
218231 JTypeDeclSymbol sym = node .getTypeMirror ().getSymbol ();
219232 if (sym == null || sym instanceof JTypeParameterSymbol ) {
220- return false ;
233+ return OptionalBool . NO ;
221234 }
222235
223236 canonicalName = StringUtils .deleteWhitespace (canonicalName );
224237
225238 JClassSymbol klass = (JClassSymbol ) sym ;
226239 String canonical = klass .getCanonicalName ();
227- return canonical != null && canonical .equals (canonicalName );
240+ if (canonical == null ) {
241+ return OptionalBool .UNKNOWN ; // anonymous
242+ }
243+ return OptionalBool .definitely (canonical .equals (canonicalName ));
228244 }
229245
230246
231-
232247 private static boolean hasNoSubtypes (Class <?> clazz ) {
233248 // Neither final nor an annotation. Enums & records have ACC_FINAL
234249 // Note: arrays have ACC_FINAL, but have subtypes by covariance
0 commit comments