5151import java .util .List ;
5252import java .util .Map ;
5353import java .util .Set ;
54+ import java .util .function .BiPredicate ;
5455import java .util .stream .Collectors ;
5556import java .util .stream .Stream ;
5657import javax .lang .model .element .AnnotationMirror ;
@@ -328,13 +329,13 @@ private static Stream<Attribute.TypeCompound> getTypeUseAnnotations(
328329 return rawTypeAttributes .filter (
329330 (t ) ->
330331 t .position .type .equals (TargetType .METHOD_RETURN )
331- && isDirectTypeUseAnnotation (t , symbol , config ));
332+ && (! onlyDirect || isDirectTypeUseAnnotation (t , symbol , config ) ));
332333 } else {
333334 // filter for annotations directly on the type
334335 return rawTypeAttributes .filter (
335336 t ->
336337 targetTypeMatches (symbol , t .position )
337- && (!onlyDirect || NullabilityUtil . isDirectTypeUseAnnotation (t , symbol , config )));
338+ && (!onlyDirect || isDirectTypeUseAnnotation (t , symbol , config )));
338339 }
339340 }
340341
@@ -540,22 +541,11 @@ public static <T> T castToNonNull(@Nullable T obj) {
540541 * otherwise
541542 */
542543 public static boolean isArrayElementNullable (Symbol arraySymbol , Config config ) {
543- for (Attribute .TypeCompound t : arraySymbol .getRawTypeAttributes ()) {
544- for (TypeAnnotationPosition .TypePathEntry entry : t .position .location ) {
545- if (entry .tag == TypeAnnotationPosition .TypePathEntryKind .ARRAY ) {
546- if (Nullness .isNullableAnnotation (t .type .toString (), config )) {
547- return true ;
548- }
549- }
550- }
551- }
552- // For varargs symbols we also consider the elements to be @Nullable if there is a @Nullable
553- // declaration annotation on the parameter
554- // NOTE this flag check does not work for the varargs parameter of a method defined in bytecodes
555- if ((arraySymbol .flags () & Flags .VARARGS ) != 0 ) {
556- return Nullness .hasNullableDeclarationAnnotation (arraySymbol , config );
557- }
558- return false ;
544+ return checkArrayElementAnnotations (
545+ arraySymbol ,
546+ config ,
547+ Nullness ::isNullableAnnotation ,
548+ Nullness ::hasNullableDeclarationAnnotation );
559549 }
560550
561551 /**
@@ -582,12 +572,50 @@ public static boolean nullableVarargsElementsForSourceOrBytecode(
582572 * otherwise
583573 */
584574 public static boolean isArrayElementNonNull (Symbol arraySymbol , Config config ) {
575+ return checkArrayElementAnnotations (
576+ arraySymbol ,
577+ config ,
578+ Nullness ::isNonNullAnnotation ,
579+ Nullness ::hasNonNullDeclarationAnnotation );
580+ }
581+
582+ /**
583+ * Checks if the given varargs symbol has a {@code @NonNull} annotation for its elements. Works
584+ * for both source and bytecode.
585+ *
586+ * @param varargsSymbol the symbol of the varargs parameter
587+ * @param config NullAway configuration
588+ * @return true if the varargs symbol has a {@code @NonNull} annotation for its elements, false
589+ * otherwise
590+ */
591+ public static boolean nonnullVarargsElementsForSourceOrBytecode (
592+ Symbol varargsSymbol , Config config ) {
593+ return isArrayElementNonNull (varargsSymbol , config )
594+ || Nullness .hasNonNullDeclarationAnnotation (varargsSymbol , config );
595+ }
596+
597+ /**
598+ * Checks if the annotations on the elements of some array symbol satisfy some predicate.
599+ *
600+ * @param arraySymbol the array symbol
601+ * @param config NullAway configuration
602+ * @param typeUseCheck the predicate to check the type-use annotations
603+ * @param declarationCheck the predicate to check the declaration annotations (applied only to
604+ * varargs symbols)
605+ * @return true if the annotations on the elements of the array symbol satisfy the given
606+ * predicates, false otherwise
607+ */
608+ private static boolean checkArrayElementAnnotations (
609+ Symbol arraySymbol ,
610+ Config config ,
611+ BiPredicate <String , Config > typeUseCheck ,
612+ BiPredicate <Symbol , Config > declarationCheck ) {
585613 if (getTypeUseAnnotations (arraySymbol , config , /* onlyDirect= */ false )
586614 .anyMatch (
587615 t -> {
588616 for (TypeAnnotationPosition .TypePathEntry entry : t .position .location ) {
589617 if (entry .tag == TypeAnnotationPosition .TypePathEntryKind .ARRAY ) {
590- if (Nullness . isNonNullAnnotation (t .type .toString (), config )) {
618+ if (typeUseCheck . test (t .type .toString (), config )) {
591619 return true ;
592620 }
593621 }
@@ -596,30 +624,14 @@ public static boolean isArrayElementNonNull(Symbol arraySymbol, Config config) {
596624 })) {
597625 return true ;
598626 }
599- // For varargs symbols we also consider the elements to be @NonNull if there is a @NonNull
600- // declaration annotation on the parameter
627+ // For varargs symbols we also check for declaration annotations on the parameter
601628 // NOTE this flag check does not work for the varargs parameter of a method defined in bytecodes
602629 if ((arraySymbol .flags () & Flags .VARARGS ) != 0 ) {
603- return Nullness . hasNonNullDeclarationAnnotation (arraySymbol , config );
630+ return declarationCheck . test (arraySymbol , config );
604631 }
605632 return false ;
606633 }
607634
608- /**
609- * Checks if the given varargs symbol has a {@code @NonNull} annotation for its elements. Works
610- * for both source and bytecode.
611- *
612- * @param varargsSymbol the symbol of the varargs parameter
613- * @param config NullAway configuration
614- * @return true if the varargs symbol has a {@code @NonNull} annotation for its elements, false
615- * otherwise
616- */
617- public static boolean nonnullVarargsElementsForSourceOrBytecode (
618- Symbol varargsSymbol , Config config ) {
619- return isArrayElementNonNull (varargsSymbol , config )
620- || Nullness .hasNonNullDeclarationAnnotation (varargsSymbol , config );
621- }
622-
623635 /**
624636 * Does the given symbol have a JetBrains @NotNull declaration annotation? Useful for workarounds
625637 * in light of https://github.com/uber/NullAway/issues/720
0 commit comments