3939
4040import java .util .List ;
4141import java .util .Map ;
42+ import java .util .Queue ;
4243
4344import javax .lang .model .element .AnnotationMirror ;
4445import javax .lang .model .element .ExecutableElement ;
@@ -81,6 +82,14 @@ public class NullnessNoInitTransfer
8182 */
8283 protected final AnnotatedDeclaredType MAP_TYPE ;
8384
85+ /**
86+ * Java's Queue interface.
87+ *
88+ * <p>The qualifiers in this type don't matter -- it is not used as a fully-annotated
89+ * AnnotatedDeclaredType, but just passed to asSuper().
90+ */
91+ protected final AnnotatedDeclaredType QUEUE_TYPE ;
92+
8493 /** The type factory for the nullness analysis that was passed to the constructor. */
8594 protected final NullnessNoInitAnnotatedTypeFactory nullnessTypeFactory ;
8695
@@ -130,6 +139,14 @@ public NullnessNoInitTransfer(NullnessNoInitAnalysis analysis) {
130139 nullnessTypeFactory ,
131140 false );
132141
142+ QUEUE_TYPE =
143+ (AnnotatedDeclaredType )
144+ AnnotatedTypeMirror .createType (
145+ TypesUtils .typeFromClass (
146+ Queue .class , analysis .getTypes (), elements ),
147+ nullnessTypeFactory ,
148+ false );
149+
133150 nonNullAssumptionAfterInvocation =
134151 !analysis .getTypeFactory ()
135152 .getChecker ()
@@ -464,6 +481,40 @@ public TransferResult<NullnessNoInitValue, NullnessNoInitStore> visitMethodInvoc
464481 }
465482 }
466483
484+ // Handle Collection.isEmpty(), mark receiver as non-empty in the false branch
485+ if (nullnessTypeFactory .isCollectionIsEmpty (n )) {
486+ AnnotatedTypeMirror receiverType = nullnessTypeFactory .getReceiverType (n .getTree ());
487+ AnnotatedDeclaredType queueType =
488+ AnnotatedTypes .asSuper (nullnessTypeFactory , receiverType , QUEUE_TYPE );
489+ // Only track isEmpty status for Queues, for poll()
490+ if (queueType != null ) {
491+ JavaExpression receiverExpr = JavaExpression .fromNode (receiver );
492+ if (CFAbstractStore .canInsertJavaExpression (receiverExpr )) {
493+ NullnessNoInitStore thenStore = result .getThenStore ();
494+ NullnessNoInitStore elseStore = result .getElseStore ();
495+ elseStore .insertValue (receiverExpr , NONNULL );
496+ return new ConditionalTransferResult <>(
497+ result .getResultValue (), thenStore , elseStore );
498+ }
499+ }
500+ }
501+
502+ // Refine result to @NonNull if n is an invocation of Queue.poll(), the receiver is known to
503+ // be non-empty
504+ // and Queue element type is @NonNull
505+ if (nullnessTypeFactory .isQueuePoll (n )) {
506+ NullnessNoInitStore store = result .getRegularStore ();
507+ JavaExpression receiverExpr = JavaExpression .fromNode (receiver );
508+ NullnessNoInitValue receiverValue = store .getValue (receiverExpr );
509+ if (receiverValue != null && receiverValue .getAnnotations ().contains (NONNULL )) {
510+ AnnotatedTypeMirror receiverType = nullnessTypeFactory .getReceiverType (n .getTree ());
511+ if (!isElementTypeNullable (receiverType )) {
512+ makeNonNull (result , n );
513+ refineToNonNull (result );
514+ }
515+ }
516+ }
517+
467518 return result ;
468519 }
469520
@@ -485,6 +536,24 @@ private boolean isValueTypeNullable(AnnotatedTypeMirror mapOrSubtype) {
485536 return valueType .hasAnnotation (NULLABLE );
486537 }
487538
539+ /**
540+ * Returns true if queueType's element type (the E type argument to Queue) is @Nullable.
541+ *
542+ * @param queueOrSubtype the Queue type, or a subtype
543+ * @return true if queueType's element type is @Nullable
544+ */
545+ private boolean isElementTypeNullable (AnnotatedTypeMirror queueOrSubtype ) {
546+ AnnotatedDeclaredType queueType =
547+ AnnotatedTypes .asSuper (nullnessTypeFactory , queueOrSubtype , QUEUE_TYPE );
548+ int numTypeArguments = queueType .getTypeArguments ().size ();
549+ if (numTypeArguments != 1 ) {
550+ throw new TypeSystemError (
551+ "Wrong number %d of type arguments: %s" , numTypeArguments , queueType );
552+ }
553+ AnnotatedTypeMirror elementType = queueType .getTypeArguments ().get (0 );
554+ return elementType .hasAnnotation (NULLABLE );
555+ }
556+
488557 @ Override
489558 public TransferResult <NullnessNoInitValue , NullnessNoInitStore > visitReturn (
490559 ReturnNode n , TransferInput <NullnessNoInitValue , NullnessNoInitStore > in ) {
0 commit comments