diff --git a/checker/src/main/java/org/checkerframework/checker/nullness/NullnessNoInitAnnotatedTypeFactory.java b/checker/src/main/java/org/checkerframework/checker/nullness/NullnessNoInitAnnotatedTypeFactory.java index befbe2fb9937..2419e4366fda 100644 --- a/checker/src/main/java/org/checkerframework/checker/nullness/NullnessNoInitAnnotatedTypeFactory.java +++ b/checker/src/main/java/org/checkerframework/checker/nullness/NullnessNoInitAnnotatedTypeFactory.java @@ -113,6 +113,14 @@ public class NullnessNoInitAnnotatedTypeFactory private final ExecutableElement mapGet = TreeUtils.getMethod("java.util.Map", "get", 1, processingEnv); + /** The Collection.isEmpty method. */ + private final ExecutableElement collectionIsEmpty = + TreeUtils.getMethod("java.util.Collection", "isEmpty", 0, processingEnv); + + /** The Queue.poll method. */ + private final ExecutableElement queuePoll = + TreeUtils.getMethod("java.util.Queue", "poll", 0, processingEnv); + // List is in alphabetical order. If you update it, also update // ../../../../../../../../docs/manual/nullness-checker.tex // and make a pull request for variables NONNULL_ANNOTATIONS and BASE_COPYABLE_ANNOTATIONS in @@ -1072,4 +1080,24 @@ private AnnotationMirror ensuresNonNullAnno(String expression) { public boolean isMapGet(Node node) { return NodeUtils.isMethodInvocation(node, mapGet, getProcessingEnv()); } + + /** + * Returns true if {@code node} is an invocation of Collection.isEmpty. + * + * @param node a CFG node + * @return true if {@code node} is an invocation of Collection.isEmpty + */ + public boolean isCollectionIsEmpty(Node node) { + return NodeUtils.isMethodInvocation(node, collectionIsEmpty, getProcessingEnv()); + } + + /** + * Returns true if {@code node} is an invocation of Queue.poll. + * + * @param node a CFG node + * @return true if {@code node} is an invocation of Queue.poll + */ + public boolean isQueuePoll(Node node) { + return NodeUtils.isMethodInvocation(node, queuePoll, getProcessingEnv()); + } } diff --git a/checker/src/main/java/org/checkerframework/checker/nullness/NullnessNoInitStore.java b/checker/src/main/java/org/checkerframework/checker/nullness/NullnessNoInitStore.java index 27fccb002789..1b927056c38f 100644 --- a/checker/src/main/java/org/checkerframework/checker/nullness/NullnessNoInitStore.java +++ b/checker/src/main/java/org/checkerframework/checker/nullness/NullnessNoInitStore.java @@ -1,18 +1,29 @@ package org.checkerframework.checker.nullness; +import com.sun.source.tree.MethodInvocationTree; + import org.checkerframework.checker.initialization.InitializationAnnotatedTypeFactory; import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.checker.nullness.qual.Nullable; import org.checkerframework.checker.nullness.qual.PolyNull; +import org.checkerframework.dataflow.cfg.node.MethodInvocationNode; +import org.checkerframework.dataflow.cfg.node.Node; import org.checkerframework.dataflow.cfg.visualize.CFGVisualizer; import org.checkerframework.dataflow.expression.FieldAccess; +import org.checkerframework.dataflow.expression.JavaExpression; +import org.checkerframework.dataflow.util.PurityUtils; import org.checkerframework.framework.flow.CFAbstractAnalysis; import org.checkerframework.framework.flow.CFAbstractStore; import org.checkerframework.framework.qual.MonotonicQualifier; import org.checkerframework.framework.type.GenericAnnotatedTypeFactory; +import org.checkerframework.javacutil.TreeUtils; import java.util.HashMap; +import java.util.HashSet; import java.util.Map; +import java.util.Set; + +import javax.lang.model.element.ExecutableElement; /** * In addition to the base class behavior, tracks whether {@link PolyNull} is known to be {@link @@ -40,6 +51,9 @@ public class NullnessNoInitStore extends CFAbstractStore initializedFields; + /** Receivers that are currently known to be non-empty queues. */ + protected Set nonEmptyQueueReceivers; + /** * Create a NullnessStore. * @@ -53,6 +67,7 @@ public NullnessNoInitStore( super(analysis, sequentialSemantics); isPolyNullNonNull = false; isPolyNullNull = false; + nonEmptyQueueReceivers = new HashSet<>(); } /** @@ -67,6 +82,56 @@ public NullnessNoInitStore(NullnessNoInitStore s) { if (s.initializedFields != null) { initializedFields = s.initializedFields; } + nonEmptyQueueReceivers = new HashSet<>(s.nonEmptyQueueReceivers); + } + + /** + * Marks the receiver as a queue known to be non-empty. + * + * @param receiver a queue receiver expression + */ + public void markQueueAsNonEmpty(JavaExpression receiver) { + nonEmptyQueueReceivers.add(receiver); + } + + /** + * Returns true if the receiver is known to be a non-empty queue. + * + * @param receiver a queue receiver expression + * @return true if the receiver is known to be a non-empty queue + */ + public boolean isQueueNonEmpty(JavaExpression receiver) { + return nonEmptyQueueReceivers.contains(receiver); + } + + @Override + public void updateForAssignment(Node n, @Nullable NullnessNoInitValue val) { + super.updateForAssignment(n, val); + JavaExpression expr = JavaExpression.fromNode(n); + if (expr != null) { + nonEmptyQueueReceivers.removeIf( + receiver -> receiver.containsSyntacticEqualJavaExpression(expr)); + } + } + + @Override + public void updateForMethodCall( + MethodInvocationNode methodInvocationNode, + GenericAnnotatedTypeFactory + atypeFactory, + NullnessNoInitValue val) { + super.updateForMethodCall(methodInvocationNode, atypeFactory, val); + + // Conservatively invalidate all non-empty queue information for side-effecting method + // calls. + MethodInvocationTree tree = methodInvocationNode.getTree(); + ExecutableElement method = TreeUtils.elementFromUse(tree); + boolean hasSideEffect = + !(atypeFactory.isSideEffectFree(method) + || PurityUtils.isSideEffectFree(atypeFactory, method)); + if (hasSideEffect) { + nonEmptyQueueReceivers.clear(); + } } @Override @@ -118,6 +183,8 @@ public NullnessNoInitStore leastUpperBound(NullnessNoInitStore other) { NullnessNoInitStore lub = super.leastUpperBound(other); lub.isPolyNullNonNull = isPolyNullNonNull && other.isPolyNullNonNull; lub.isPolyNullNull = isPolyNullNull && other.isPolyNullNull; + lub.nonEmptyQueueReceivers = new HashSet<>(nonEmptyQueueReceivers); + lub.nonEmptyQueueReceivers.retainAll(other.nonEmptyQueueReceivers); return lub; } @@ -131,7 +198,8 @@ protected boolean supersetOf(CFAbstractStoreThe qualifiers in this type don't matter -- it is not used as a fully-annotated + * AnnotatedDeclaredType, but just passed to asSuper(). + */ + protected final AnnotatedDeclaredType QUEUE_TYPE; + /** The type factory for the nullness analysis that was passed to the constructor. */ protected final NullnessNoInitAnnotatedTypeFactory nullnessTypeFactory; @@ -130,6 +139,14 @@ public NullnessNoInitTransfer(NullnessNoInitAnalysis analysis) { nullnessTypeFactory, false); + QUEUE_TYPE = + (AnnotatedDeclaredType) + AnnotatedTypeMirror.createType( + TypesUtils.typeFromClass( + Queue.class, analysis.getTypes(), elements), + nullnessTypeFactory, + false); + nonNullAssumptionAfterInvocation = !analysis.getTypeFactory() .getChecker() @@ -411,6 +428,15 @@ public TransferResult visitThrow( @Override public TransferResult visitMethodInvocation( MethodInvocationNode n, TransferInput in) { + Node receiver = n.getTarget().getReceiver(); + JavaExpression receiverExpr = JavaExpression.fromNode(receiver); + // Capture queue non-emptiness fact before superclass mutates the store when handling side + // effects. + boolean isNonEmptyQueuePoll = + nullnessTypeFactory.isQueuePoll(n) + && receiverExpr != null + && in.getRegularStore().isQueueNonEmpty(receiverExpr); + TransferResult result = super.visitMethodInvocation(n, in); @@ -420,7 +446,6 @@ public TransferResult visitMethodInvoc boolean isMethodSideEffectFree = nullnessTypeFactory.isSideEffectFree(method) || PurityUtils.isSideEffectFree(nullnessTypeFactory, method); - Node receiver = n.getTarget().getReceiver(); if (nonNullAssumptionAfterInvocation || isMethodSideEffectFree || !JavaExpression.fromNode(receiver).isAssignableByOtherCode()) { @@ -464,6 +489,27 @@ public TransferResult visitMethodInvoc } } + // Handle Collection.isEmpty(): mark receiver as non-empty in the false branch. + if (nullnessTypeFactory.isCollectionIsEmpty(n)) { + if (receiverExpr != null) { + NullnessNoInitStore thenStore = result.getThenStore(); + NullnessNoInitStore elseStore = result.getElseStore(); + elseStore.markQueueAsNonEmpty(receiverExpr); + return new ConditionalTransferResult<>( + result.getResultValue(), thenStore, elseStore); + } + } + + // Refine result to @NonNull if n is an invocation of Queue.poll(), the receiver is known to + // be non-empty, and Queue element type is @NonNull + if (isNonEmptyQueuePoll) { + AnnotatedTypeMirror receiverType = nullnessTypeFactory.getReceiverType(n.getTree()); + if (!isElementTypeNullable(receiverType)) { + makeNonNull(result, n); + refineToNonNull(result); + } + } + return result; } @@ -485,6 +531,24 @@ private boolean isValueTypeNullable(AnnotatedTypeMirror mapOrSubtype) { return valueType.hasAnnotation(NULLABLE); } + /** + * Returns true if queueType's element type (the E type argument to Queue) is @Nullable. + * + * @param queueOrSubtype the Queue type, or a subtype + * @return true if queueType's element type is @Nullable + */ + private boolean isElementTypeNullable(AnnotatedTypeMirror queueOrSubtype) { + AnnotatedDeclaredType queueType = + AnnotatedTypes.asSuper(nullnessTypeFactory, queueOrSubtype, QUEUE_TYPE); + int numTypeArguments = queueType.getTypeArguments().size(); + if (numTypeArguments != 1) { + throw new TypeSystemError( + "Wrong number %d of type arguments: %s", numTypeArguments, queueType); + } + AnnotatedTypeMirror elementType = queueType.getTypeArguments().get(0); + return elementType.hasAnnotation(NULLABLE); + } + @Override public TransferResult visitReturn( ReturnNode n, TransferInput in) { diff --git a/checker/tests/nullness-extra/issue5174/Issue5174.out b/checker/tests/nullness-extra/issue5174/Issue5174.out index 81e50d518d05..624a47823a13 100644 --- a/checker/tests/nullness-extra/issue5174/Issue5174.out +++ b/checker/tests/nullness-extra/issue5174/Issue5174.out @@ -128,7 +128,8 @@ Before: InitializationStore#19( Before: NullnessNoInitStore#27( isPolyNullNonNull = false - isPolyNullNull = false) + isPolyNullNull = false + nonEmptyQueueReceivers = []) ~~~~~~~~~ @@ -136,7 +137,8 @@ Before: NullnessNoInitStore#27( Before: NullnessNoInitStore#27( isPolyNullNonNull = false - isPolyNullNull = false) + isPolyNullNull = false + nonEmptyQueueReceivers = []) ~~~~~~~~~ "" [ StringLiteral ] > NV{@NonNull, String, poly nn/n=f/f} (this).sf = "" [ Assignment ] > NV{@NonNull, String, poly nn/n=f/f} @@ -145,7 +147,8 @@ Before: NullnessNoInitStore#27( Before: NullnessNoInitStore#28( Issue5174Super.sf > NV{@NonNull, String, poly nn/n=f/f} isPolyNullNonNull = false - isPolyNullNull = false) + isPolyNullNull = false + nonEmptyQueueReceivers = []) ~~~~~~~~~ 7 -> 8 @@ -158,7 +161,8 @@ Before: NullnessNoInitStore#32( Issue5174Super.sf > NV{@NonNull, Object, poly nn/n=f/f} this.f > NV{, S, poly nn/n=f/f} isPolyNullNonNull = false - isPolyNullNull = false) + isPolyNullNull = false + nonEmptyQueueReceivers = []) ~~~~~~~~~ @@ -169,7 +173,8 @@ Before: NullnessNoInitStore#32( Issue5174Super.sf > NV{@NonNull, Object, poly nn/n=f/f} this.f > NV{, S, poly nn/n=f/f} isPolyNullNonNull = false - isPolyNullNull = false) + isPolyNullNull = false + nonEmptyQueueReceivers = []) ~~~~~~~~~ in [ LocalVariable ] > NV{, S, poly nn/n=f/f} return in [ Return ] > NV{@NonNull, boolean, poly nn/n=f/f} @@ -181,7 +186,8 @@ Before: NullnessNoInitStore#33( Issue5174Super.sf > NV{@NonNull, Object, poly nn/n=f/f} this.f > NV{, S, poly nn/n=f/f} isPolyNullNonNull = false - isPolyNullNull = false) + isPolyNullNull = false + nonEmptyQueueReceivers = []) ~~~~~~~~~ 13 -> 14 @@ -197,7 +203,8 @@ Before: NullnessNoInitStore#37( this > NV{@NonNull, Issue5174Super, poly nn/n=f/f} Issue5174Super.sf > NV{@NonNull, Object, poly nn/n=f/f} isPolyNullNonNull = false - isPolyNullNull = false) + isPolyNullNull = false + nonEmptyQueueReceivers = []) ~~~~~~~~~ @@ -207,7 +214,8 @@ Before: NullnessNoInitStore#37( this > NV{@NonNull, Issue5174Super, poly nn/n=f/f} Issue5174Super.sf > NV{@NonNull, Object, poly nn/n=f/f} isPolyNullNonNull = false - isPolyNullNull = false) + isPolyNullNull = false + nonEmptyQueueReceivers = []) ~~~~~~~~~ (this) [ ImplicitThis ] > NV{@NonNull, Issue5174Super, poly nn/n=f/f} (this). [ MethodAccess ] > NV{@NonNull, Issue5174Super, poly nn/n=f/f} @@ -218,7 +226,8 @@ Before: NullnessNoInitStore#38( this > NV{@NonNull, Issue5174Super, poly nn/n=f/f} Issue5174Super.sf > NV{@NonNull, Object, poly nn/n=f/f} isPolyNullNonNull = false - isPolyNullNull = false) + isPolyNullNull = false + nonEmptyQueueReceivers = []) ~~~~~~~~~ (this).() [ MethodInvocation ] > NV{@NonNull, Object, poly nn/n=f/f} @@ -229,7 +238,8 @@ Before: NullnessNoInitStore#39( Issue5174Super.sf > NV{@NonNull, Object, poly nn/n=f/f} this.() > NV{@NonNull, Object, poly nn/n=f/f} isPolyNullNonNull = false - isPolyNullNull = false) + isPolyNullNull = false + nonEmptyQueueReceivers = []) ~~~~~~~~~ expression statement super() [ ExpressionStatement ] this [ ExplicitThis ] > NV{@NonNull, Issue5174Super, poly nn/n=f/f} @@ -244,7 +254,8 @@ Before: NullnessNoInitStore#40( this > NV{@NonNull, Issue5174Super, poly nn/n=f/f} Issue5174Super.sf > NV{@NonNull, Object, poly nn/n=f/f} isPolyNullNonNull = false - isPolyNullNull = false) + isPolyNullNull = false + nonEmptyQueueReceivers = []) ~~~~~~~~~ @@ -255,7 +266,8 @@ Before: NullnessNoInitStore#43( Issue5174Super.sf > NV{@NonNull, Object, poly nn/n=f/f} this.f > NV{, S, poly nn/n=f/f} isPolyNullNonNull = false - isPolyNullNull = false) + isPolyNullNull = false + nonEmptyQueueReceivers = []) ~~~~~~~~~ 20 -> 21 @@ -1006,7 +1018,8 @@ Before: NullnessNoInitStore#275( f > NV{, T, poly nn/n=f/f} this > NV{@NonNull, Issue5174Sub, poly nn/n=f/f} isPolyNullNonNull = false - isPolyNullNull = false) + isPolyNullNull = false + nonEmptyQueueReceivers = []) ~~~~~~~~~ @@ -1015,7 +1028,8 @@ Before: NullnessNoInitStore#275( f > NV{, T, poly nn/n=f/f} this > NV{@NonNull, Issue5174Sub, poly nn/n=f/f} isPolyNullNonNull = false - isPolyNullNull = false) + isPolyNullNull = false + nonEmptyQueueReceivers = []) ~~~~~~~~~ (this) [ ImplicitThis ] > NV{@NonNull, Issue5174Sub, poly nn/n=f/f} (this). [ MethodAccess ] > NV{@NonNull, Issue5174Sub, poly nn/n=f/f} @@ -1026,7 +1040,8 @@ Before: NullnessNoInitStore#276( f > NV{, T, poly nn/n=f/f} this > NV{@NonNull, Issue5174Sub, poly nn/n=f/f} isPolyNullNonNull = false - isPolyNullNull = false) + isPolyNullNull = false + nonEmptyQueueReceivers = []) ~~~~~~~~~ (this).(f) [ MethodInvocation ] > NV{@NonNull, Issue5174Super, poly nn/n=f/f} @@ -1035,7 +1050,8 @@ Before: NullnessNoInitStore#277( f > NV{, T, poly nn/n=f/f} this > NV{@NonNull, Issue5174Sub, poly nn/n=f/f} isPolyNullNonNull = false - isPolyNullNull = false) + isPolyNullNull = false + nonEmptyQueueReceivers = []) ~~~~~~~~~ expression statement super(f) [ ExpressionStatement ] @@ -1044,7 +1060,8 @@ Before: NullnessNoInitStore#278( f > NV{, T, poly nn/n=f/f} this > NV{@NonNull, Issue5174Sub, poly nn/n=f/f} isPolyNullNonNull = false - isPolyNullNull = false) + isPolyNullNull = false + nonEmptyQueueReceivers = []) ~~~~~~~~~ @@ -1053,7 +1070,8 @@ Before: NullnessNoInitStore#281( f > NV{, T, poly nn/n=f/f} this > NV{@NonNull, Issue5174Sub, poly nn/n=f/f} isPolyNullNonNull = false - isPolyNullNull = false) + isPolyNullNull = false + nonEmptyQueueReceivers = []) ~~~~~~~~~ 27 -> 28 @@ -1068,7 +1086,8 @@ Before: NullnessNoInitStore#288( in > NV{, T, poly nn/n=f/f} this > NV{@NonNull, Issue5174Sub, poly nn/n=f/f} isPolyNullNonNull = false - isPolyNullNull = false) + isPolyNullNull = false + nonEmptyQueueReceivers = []) ~~~~~~~~~ @@ -1077,7 +1096,8 @@ Before: NullnessNoInitStore#288( in > NV{, T, poly nn/n=f/f} this > NV{@NonNull, Issue5174Sub, poly nn/n=f/f} isPolyNullNonNull = false - isPolyNullNull = false) + isPolyNullNull = false + nonEmptyQueueReceivers = []) ~~~~~~~~~ o [ VariableDeclaration ] (this) [ ImplicitThis ] > NV{@NonNull, Issue5174Sub, poly nn/n=f/f} @@ -1089,7 +1109,8 @@ Before: NullnessNoInitStore#289( in > NV{, T, poly nn/n=f/f} this > NV{@NonNull, Issue5174Sub, poly nn/n=f/f} isPolyNullNonNull = false - isPolyNullNull = false) + isPolyNullNull = false + nonEmptyQueueReceivers = []) ~~~~~~~~~ (this).methodInner(in) [ MethodInvocation ] > NV{, T, poly nn/n=f/f} @@ -1098,7 +1119,8 @@ Before: NullnessNoInitStore#290( in > NV{, T, poly nn/n=f/f} this > NV{@NonNull, Issue5174Sub, poly nn/n=f/f} isPolyNullNonNull = false - isPolyNullNull = false) + isPolyNullNull = false + nonEmptyQueueReceivers = []) ~~~~~~~~~ o = (this).methodInner(in) [ Assignment ] > NV{, T, poly nn/n=f/f} @@ -1107,7 +1129,8 @@ Before: NullnessNoInitStore#291( in > NV{, T, poly nn/n=f/f} this > NV{@NonNull, Issue5174Sub, poly nn/n=f/f} isPolyNullNonNull = false - isPolyNullNull = false) + isPolyNullNull = false + nonEmptyQueueReceivers = []) ~~~~~~~~~ @@ -1117,7 +1140,8 @@ Before: NullnessNoInitStore#294( o > NV{, T, poly nn/n=f/f} this > NV{@NonNull, Issue5174Sub, poly nn/n=f/f} isPolyNullNonNull = false - isPolyNullNull = false) + isPolyNullNull = false + nonEmptyQueueReceivers = []) ~~~~~~~~~ 34 -> 35 @@ -1132,7 +1156,8 @@ Before: NullnessNoInitStore#301( in > NV{, T, poly nn/n=f/f} this > NV{@NonNull, Issue5174Sub, poly nn/n=f/f} isPolyNullNonNull = false - isPolyNullNull = false) + isPolyNullNull = false + nonEmptyQueueReceivers = []) ~~~~~~~~~ @@ -1141,7 +1166,8 @@ Before: NullnessNoInitStore#301( in > NV{, T, poly nn/n=f/f} this > NV{@NonNull, Issue5174Sub, poly nn/n=f/f} isPolyNullNonNull = false - isPolyNullNull = false) + isPolyNullNull = false + nonEmptyQueueReceivers = []) ~~~~~~~~~ o [ VariableDeclaration ] this [ ExplicitThis ] > NV{@NonNull, Issue5174Sub, poly nn/n=f/f} @@ -1153,7 +1179,8 @@ Before: NullnessNoInitStore#302( in > NV{, T, poly nn/n=f/f} this > NV{@NonNull, Issue5174Sub, poly nn/n=f/f} isPolyNullNonNull = false - isPolyNullNull = false) + isPolyNullNull = false + nonEmptyQueueReceivers = []) ~~~~~~~~~ this.methodInner(in) [ MethodInvocation ] > NV{, T, poly nn/n=f/f} @@ -1162,7 +1189,8 @@ Before: NullnessNoInitStore#303( in > NV{, T, poly nn/n=f/f} this > NV{@NonNull, Issue5174Sub, poly nn/n=f/f} isPolyNullNonNull = false - isPolyNullNull = false) + isPolyNullNull = false + nonEmptyQueueReceivers = []) ~~~~~~~~~ o = this.methodInner(in) [ Assignment ] > NV{, T, poly nn/n=f/f} @@ -1171,7 +1199,8 @@ Before: NullnessNoInitStore#304( in > NV{, T, poly nn/n=f/f} this > NV{@NonNull, Issue5174Sub, poly nn/n=f/f} isPolyNullNonNull = false - isPolyNullNull = false) + isPolyNullNull = false + nonEmptyQueueReceivers = []) ~~~~~~~~~ @@ -1181,7 +1210,8 @@ Before: NullnessNoInitStore#307( o > NV{, T, poly nn/n=f/f} this > NV{@NonNull, Issue5174Sub, poly nn/n=f/f} isPolyNullNonNull = false - isPolyNullNull = false) + isPolyNullNull = false + nonEmptyQueueReceivers = []) ~~~~~~~~~ 41 -> 42 @@ -1191,7 +1221,8 @@ Before: NullnessNoInitStore#307( Before: NullnessNoInitStore#314( this > NV{@NonNull, Issue5174Sub, poly nn/n=f/f} isPolyNullNonNull = false - isPolyNullNull = false) + isPolyNullNull = false + nonEmptyQueueReceivers = []) ~~~~~~~~~ @@ -1199,7 +1230,8 @@ Before: NullnessNoInitStore#314( Before: NullnessNoInitStore#314( this > NV{@NonNull, Issue5174Sub, poly nn/n=f/f} isPolyNullNonNull = false - isPolyNullNull = false) + isPolyNullNull = false + nonEmptyQueueReceivers = []) ~~~~~~~~~ o [ VariableDeclaration ] (this) [ ImplicitThis ] > NV{@NonNull, Issue5174Sub, poly nn/n=f/f} @@ -1211,7 +1243,8 @@ Before: NullnessNoInitStore#315( o > NV{, T, poly nn/n=f/f} this > NV{@NonNull, Issue5174Sub, poly nn/n=f/f} isPolyNullNonNull = false - isPolyNullNull = false) + isPolyNullNull = false + nonEmptyQueueReceivers = []) ~~~~~~~~~ 46 -> 47 @@ -1221,7 +1254,8 @@ Before: NullnessNoInitStore#315( Before: NullnessNoInitStore#319( this > NV{@NonNull, Issue5174Sub, poly nn/n=f/f} isPolyNullNonNull = false - isPolyNullNull = false) + isPolyNullNull = false + nonEmptyQueueReceivers = []) ~~~~~~~~~ @@ -1229,7 +1263,8 @@ Before: NullnessNoInitStore#319( Before: NullnessNoInitStore#319( this > NV{@NonNull, Issue5174Sub, poly nn/n=f/f} isPolyNullNonNull = false - isPolyNullNull = false) + isPolyNullNull = false + nonEmptyQueueReceivers = []) ~~~~~~~~~ o [ VariableDeclaration ] this [ ExplicitThis ] > NV{@NonNull, Issue5174Sub, poly nn/n=f/f} @@ -1241,7 +1276,8 @@ Before: NullnessNoInitStore#320( o > NV{, T, poly nn/n=f/f} this > NV{@NonNull, Issue5174Sub, poly nn/n=f/f} isPolyNullNonNull = false - isPolyNullNull = false) + isPolyNullNull = false + nonEmptyQueueReceivers = []) ~~~~~~~~~ 51 -> 52 @@ -1269,7 +1305,8 @@ Before: NullnessNoInitStore#320( Before: NullnessNoInitStore#324( this > NV{@NonNull, Issue5174Sub, poly nn/n=f/f} isPolyNullNonNull = false - isPolyNullNull = false) + isPolyNullNull = false + nonEmptyQueueReceivers = []) ~~~~~~~~~ @@ -1277,7 +1314,8 @@ Before: NullnessNoInitStore#324( Before: NullnessNoInitStore#324( this > NV{@NonNull, Issue5174Sub, poly nn/n=f/f} isPolyNullNonNull = false - isPolyNullNull = false) + isPolyNullNull = false + nonEmptyQueueReceivers = []) ~~~~~~~~~ o [ VariableDeclaration ] o [ LocalVariable ] @@ -1286,7 +1324,8 @@ o [ LocalVariable ] Before: NullnessNoInitStore#325( this > NV{@NonNull, Issue5174Sub, poly nn/n=f/f} isPolyNullNonNull = false - isPolyNullNull = false) + isPolyNullNull = false + nonEmptyQueueReceivers = []) ~~~~~~~~~ Issue5174Super [ ClassName ] @@ -1294,7 +1333,8 @@ Issue5174Super [ ClassName ] Before: NullnessNoInitStore#326( this > NV{@NonNull, Issue5174Sub, poly nn/n=f/f} isPolyNullNonNull = false - isPolyNullNull = false) + isPolyNullNull = false + nonEmptyQueueReceivers = []) ~~~~~~~~~ Issue5174Super.sf [ FieldAccess ] > NV{@NonNull, Object, poly nn/n=f/f} o = Issue5174Super.sf [ Assignment ] > NV{@NonNull, Object, poly nn/n=f/f} @@ -1305,7 +1345,8 @@ o [ LocalVariable ] Before: NullnessNoInitStore#327( this > NV{@NonNull, Issue5174Sub, poly nn/n=f/f} isPolyNullNonNull = false - isPolyNullNull = false) + isPolyNullNull = false + nonEmptyQueueReceivers = []) ~~~~~~~~~ @@ -1314,7 +1355,8 @@ Before: NullnessNoInitStore#334( o > NV{@NonNull, Object, poly nn/n=f/f} this > NV{@NonNull, Issue5174Sub, poly nn/n=f/f} isPolyNullNonNull = false - isPolyNullNull = false) + isPolyNullNull = false + nonEmptyQueueReceivers = []) ~~~~~~~~~ Issue5174Sub [ ClassName ] > NV{@NonNull, Issue5174Sub, poly nn/n=f/f} @@ -1323,7 +1365,8 @@ Before: NullnessNoInitStore#335( o > NV{@NonNull, Object, poly nn/n=f/f} this > NV{@NonNull, Issue5174Sub, poly nn/n=f/f} isPolyNullNonNull = false - isPolyNullNull = false) + isPolyNullNull = false + nonEmptyQueueReceivers = []) ~~~~~~~~~ Issue5174Sub.sf [ FieldAccess ] > NV{@NonNull, Object, poly nn/n=f/f} o = Issue5174Sub.sf [ Assignment ] > NV{@NonNull, Object, poly nn/n=f/f} @@ -1335,7 +1378,8 @@ Before: NullnessNoInitStore#344( o > NV{@NonNull, Object, poly nn/n=f/f} this > NV{@NonNull, Issue5174Sub, poly nn/n=f/f} isPolyNullNonNull = false - isPolyNullNull = false) + isPolyNullNull = false + nonEmptyQueueReceivers = []) ~~~~~~~~~ Issue5174Super [ ClassName ] > NV{@NonNull, Issue5174Super, poly nn/n=f/f} @@ -1344,7 +1388,8 @@ Before: NullnessNoInitStore#345( o > NV{@NonNull, Object, poly nn/n=f/f} this > NV{@NonNull, Issue5174Sub, poly nn/n=f/f} isPolyNullNonNull = false - isPolyNullNull = false) + isPolyNullNull = false + nonEmptyQueueReceivers = []) ~~~~~~~~~ Issue5174Super.sf [ FieldAccess ] > NV{@NonNull, Object, poly nn/n=f/f} o = Issue5174Super.sf [ Assignment ] > NV{@NonNull, Object, poly nn/n=f/f} @@ -1355,7 +1400,8 @@ Before: NullnessNoInitStore#354( o > NV{@NonNull, Object, poly nn/n=f/f} this > NV{@NonNull, Issue5174Sub, poly nn/n=f/f} isPolyNullNonNull = false - isPolyNullNull = false) + isPolyNullNull = false + nonEmptyQueueReceivers = []) ~~~~~~~~~ 62 -> 63 @@ -1369,7 +1415,8 @@ Before: NullnessNoInitStore#354( Before: NullnessNoInitStore#365( this > NV{@NonNull, SubNested, poly nn/n=f/f} isPolyNullNonNull = false - isPolyNullNull = false) + isPolyNullNull = false + nonEmptyQueueReceivers = []) ~~~~~~~~~ @@ -1377,7 +1424,8 @@ Before: NullnessNoInitStore#365( Before: NullnessNoInitStore#365( this > NV{@NonNull, SubNested, poly nn/n=f/f} isPolyNullNonNull = false - isPolyNullNull = false) + isPolyNullNull = false + nonEmptyQueueReceivers = []) ~~~~~~~~~ (this) [ ImplicitThis ] > NV{@NonNull, SubNested, poly nn/n=f/f} (this). [ MethodAccess ] > NV{@NonNull, SubNested, poly nn/n=f/f} @@ -1386,7 +1434,8 @@ Before: NullnessNoInitStore#365( Before: NullnessNoInitStore#366( this > NV{@NonNull, SubNested, poly nn/n=f/f} isPolyNullNonNull = false - isPolyNullNull = false) + isPolyNullNull = false + nonEmptyQueueReceivers = []) ~~~~~~~~~ (this).() [ MethodInvocation ] > NV{@NonNull, Object, poly nn/n=f/f} @@ -1395,7 +1444,8 @@ Before: NullnessNoInitStore#367( this > NV{@NonNull, SubNested, poly nn/n=f/f} this.() > NV{@NonNull, Object, poly nn/n=f/f} isPolyNullNonNull = false - isPolyNullNull = false) + isPolyNullNull = false + nonEmptyQueueReceivers = []) ~~~~~~~~~ expression statement super() [ ExpressionStatement ] @@ -1403,7 +1453,8 @@ expression statement super() [ ExpressionStatement ] Before: NullnessNoInitStore#368( this > NV{@NonNull, SubNested, poly nn/n=f/f} isPolyNullNonNull = false - isPolyNullNull = false) + isPolyNullNull = false + nonEmptyQueueReceivers = []) ~~~~~~~~~ @@ -1412,7 +1463,8 @@ Before: NullnessNoInitStore#371( this > NV{@NonNull, SubNested, poly nn/n=f/f} this.() > NV{@NonNull, Object, poly nn/n=f/f} isPolyNullNonNull = false - isPolyNullNull = false) + isPolyNullNull = false + nonEmptyQueueReceivers = []) ~~~~~~~~~ 69 -> 70 @@ -1427,7 +1479,8 @@ Before: NullnessNoInitStore#378( in > NV{, T, poly nn/n=f/f} this > NV{@NonNull, SubNested, poly nn/n=f/f} isPolyNullNonNull = false - isPolyNullNull = false) + isPolyNullNull = false + nonEmptyQueueReceivers = []) ~~~~~~~~~ @@ -1436,7 +1489,8 @@ Before: NullnessNoInitStore#378( in > NV{, T, poly nn/n=f/f} this > NV{@NonNull, SubNested, poly nn/n=f/f} isPolyNullNonNull = false - isPolyNullNull = false) + isPolyNullNull = false + nonEmptyQueueReceivers = []) ~~~~~~~~~ o [ VariableDeclaration ] (this) [ ImplicitThis ] > NV{@NonNull, SubNested, poly nn/n=f/f} @@ -1448,7 +1502,8 @@ Before: NullnessNoInitStore#379( in > NV{, T, poly nn/n=f/f} this > NV{@NonNull, Issue5174Sub, poly nn/n=f/f} isPolyNullNonNull = false - isPolyNullNull = false) + isPolyNullNull = false + nonEmptyQueueReceivers = []) ~~~~~~~~~ (this).methodInner(in) [ MethodInvocation ] > NV{, T, poly nn/n=f/f} @@ -1457,7 +1512,8 @@ Before: NullnessNoInitStore#380( in > NV{, T, poly nn/n=f/f} this > NV{@NonNull, Issue5174Sub, poly nn/n=f/f} isPolyNullNonNull = false - isPolyNullNull = false) + isPolyNullNull = false + nonEmptyQueueReceivers = []) ~~~~~~~~~ o = (this).methodInner(in) [ Assignment ] > NV{, T, poly nn/n=f/f} @@ -1466,7 +1522,8 @@ Before: NullnessNoInitStore#381( in > NV{, T, poly nn/n=f/f} this > NV{@NonNull, Issue5174Sub, poly nn/n=f/f} isPolyNullNonNull = false - isPolyNullNull = false) + isPolyNullNull = false + nonEmptyQueueReceivers = []) ~~~~~~~~~ @@ -1476,7 +1533,8 @@ Before: NullnessNoInitStore#384( o > NV{, T, poly nn/n=f/f} this > NV{@NonNull, Issue5174Sub, poly nn/n=f/f} isPolyNullNonNull = false - isPolyNullNull = false) + isPolyNullNull = false + nonEmptyQueueReceivers = []) ~~~~~~~~~ 76 -> 77 @@ -1501,7 +1559,8 @@ Before: NullnessNoInitStore#391( in > NV{, T, poly nn/n=f/f} this > NV{@NonNull, SubNested, poly nn/n=f/f} isPolyNullNonNull = false - isPolyNullNull = false) + isPolyNullNull = false + nonEmptyQueueReceivers = []) ~~~~~~~~~ @@ -1510,7 +1569,8 @@ Before: NullnessNoInitStore#391( in > NV{, T, poly nn/n=f/f} this > NV{@NonNull, SubNested, poly nn/n=f/f} isPolyNullNonNull = false - isPolyNullNull = false) + isPolyNullNull = false + nonEmptyQueueReceivers = []) ~~~~~~~~~ o [ VariableDeclaration ] @@ -1519,7 +1579,8 @@ Before: NullnessNoInitStore#392( in > NV{, T, poly nn/n=f/f} this > NV{@NonNull, SubNested, poly nn/n=f/f} isPolyNullNonNull = false - isPolyNullNull = false) + isPolyNullNull = false + nonEmptyQueueReceivers = []) ~~~~~~~~~ Issue5174Sub [ ClassName ] > NV{@NonNull, Issue5174Sub, poly nn/n=f/f} @@ -1528,7 +1589,8 @@ Before: NullnessNoInitStore#393( in > NV{, T, poly nn/n=f/f} this > NV{@NonNull, SubNested, poly nn/n=f/f} isPolyNullNonNull = false - isPolyNullNull = false) + isPolyNullNull = false + nonEmptyQueueReceivers = []) ~~~~~~~~~ Issue5174Sub.this [ FieldAccess ] > NV{@NonNull, Issue5174Sub, poly nn/n=f/f} @@ -1537,7 +1599,8 @@ Before: NullnessNoInitStore#410( in > NV{, T, poly nn/n=f/f} this > NV{@NonNull, Object, poly nn/n=f/f} isPolyNullNonNull = false - isPolyNullNull = false) + isPolyNullNull = false + nonEmptyQueueReceivers = []) ~~~~~~~~~ @@ -1547,7 +1610,8 @@ Before: NullnessNoInitStore#401( this > NV{@NonNull, SubNested, poly nn/n=f/f} Issue5174Sub.class > NV{@NonNull, Issue5174Sub, poly nn/n=f/f} isPolyNullNonNull = false - isPolyNullNull = false) + isPolyNullNull = false + nonEmptyQueueReceivers = []) ~~~~~~~~~ Issue5174Sub.this.methodInner [ MethodAccess ] @@ -1557,7 +1621,8 @@ Before: NullnessNoInitStore#404( this > NV{@NonNull, Issue5174Sub, poly nn/n=f/f} Issue5174Sub.class > NV{@NonNull, Issue5174Sub, poly nn/n=f/f} isPolyNullNonNull = false - isPolyNullNull = false) + isPolyNullNull = false + nonEmptyQueueReceivers = []) ~~~~~~~~~ in [ LocalVariable ] > NV{, T, poly nn/n=f/f} @@ -1567,7 +1632,8 @@ Before: NullnessNoInitStore#407( this > NV{@NonNull, Issue5174Sub, poly nn/n=f/f} Issue5174Sub.class > NV{@NonNull, Issue5174Sub, poly nn/n=f/f} isPolyNullNonNull = false - isPolyNullNull = false) + isPolyNullNull = false + nonEmptyQueueReceivers = []) ~~~~~~~~~ Issue5174Sub.this.methodInner(in) [ MethodInvocation ] > NV{, T, poly nn/n=f/f} @@ -1577,7 +1643,8 @@ Before: NullnessNoInitStore#408( this > NV{@NonNull, Issue5174Sub, poly nn/n=f/f} Issue5174Sub.class > NV{@NonNull, Issue5174Sub, poly nn/n=f/f} isPolyNullNonNull = false - isPolyNullNull = false) + isPolyNullNull = false + nonEmptyQueueReceivers = []) ~~~~~~~~~ o = Issue5174Sub.this.methodInner(in) [ Assignment ] > NV{, T, poly nn/n=f/f} @@ -1588,7 +1655,8 @@ Before: NullnessNoInitStore#413( this > NV{@NonNull, Issue5174Sub, poly nn/n=f/f} Issue5174Sub.class > NV{@NonNull, Issue5174Sub, poly nn/n=f/f} isPolyNullNonNull = false - isPolyNullNull = false) + isPolyNullNull = false + nonEmptyQueueReceivers = []) ~~~~~~~~~ 89 -> 90 @@ -1598,7 +1666,8 @@ Before: NullnessNoInitStore#413( Before: NullnessNoInitStore#424( this > NV{@NonNull, SubNested, poly nn/n=f/f} isPolyNullNonNull = false - isPolyNullNull = false) + isPolyNullNull = false + nonEmptyQueueReceivers = []) ~~~~~~~~~ @@ -1606,7 +1675,8 @@ Before: NullnessNoInitStore#424( Before: NullnessNoInitStore#424( this > NV{@NonNull, SubNested, poly nn/n=f/f} isPolyNullNonNull = false - isPolyNullNull = false) + isPolyNullNull = false + nonEmptyQueueReceivers = []) ~~~~~~~~~ o [ VariableDeclaration ] (this) [ ImplicitThis ] > NV{@NonNull, SubNested, poly nn/n=f/f} @@ -1618,7 +1688,8 @@ Before: NullnessNoInitStore#425( o > NV{, T, poly nn/n=f/f} this > NV{@NonNull, Issue5174Sub, poly nn/n=f/f} isPolyNullNonNull = false - isPolyNullNull = false) + isPolyNullNull = false + nonEmptyQueueReceivers = []) ~~~~~~~~~ 94 -> 95 @@ -1638,7 +1709,8 @@ Before: NullnessNoInitStore#425( Before: NullnessNoInitStore#429( this > NV{@NonNull, SubNested, poly nn/n=f/f} isPolyNullNonNull = false - isPolyNullNull = false) + isPolyNullNull = false + nonEmptyQueueReceivers = []) ~~~~~~~~~ @@ -1646,7 +1718,8 @@ Before: NullnessNoInitStore#429( Before: NullnessNoInitStore#429( this > NV{@NonNull, SubNested, poly nn/n=f/f} isPolyNullNonNull = false - isPolyNullNull = false) + isPolyNullNull = false + nonEmptyQueueReceivers = []) ~~~~~~~~~ o [ VariableDeclaration ] @@ -1654,7 +1727,8 @@ o [ VariableDeclaration ] Before: NullnessNoInitStore#430( this > NV{@NonNull, SubNested, poly nn/n=f/f} isPolyNullNonNull = false - isPolyNullNull = false) + isPolyNullNull = false + nonEmptyQueueReceivers = []) ~~~~~~~~~ Issue5174Sub [ ClassName ] > NV{@NonNull, Issue5174Sub, poly nn/n=f/f} @@ -1662,7 +1736,8 @@ Issue5174Sub [ ClassName ] > NV{@NonNull, Issue5174Sub, poly nn/n=f/f} Before: NullnessNoInitStore#431( this > NV{@NonNull, SubNested, poly nn/n=f/f} isPolyNullNonNull = false - isPolyNullNull = false) + isPolyNullNull = false + nonEmptyQueueReceivers = []) ~~~~~~~~~ Issue5174Sub.this [ FieldAccess ] > NV{@NonNull, Issue5174Sub, poly nn/n=f/f} @@ -1670,7 +1745,8 @@ Issue5174Sub.this [ FieldAccess ] > NV{@NonNull, Issue5174Sub, poly nn/n=f/ Before: NullnessNoInitStore#432( this > NV{@NonNull, SubNested, poly nn/n=f/f} isPolyNullNonNull = false - isPolyNullNull = false) + isPolyNullNull = false + nonEmptyQueueReceivers = []) ~~~~~~~~~ @@ -1679,7 +1755,8 @@ Before: NullnessNoInitStore#439( this > NV{@NonNull, SubNested, poly nn/n=f/f} Issue5174Sub.class > NV{@NonNull, Issue5174Sub, poly nn/n=f/f} isPolyNullNonNull = false - isPolyNullNull = false) + isPolyNullNull = false + nonEmptyQueueReceivers = []) ~~~~~~~~~ Issue5174Sub.this.f [ FieldAccess ] > NV{, T, poly nn/n=f/f} @@ -1688,7 +1765,8 @@ Before: NullnessNoInitStore#442( this > NV{@NonNull, Issue5174Sub, poly nn/n=f/f} Issue5174Sub.class > NV{@NonNull, Issue5174Sub, poly nn/n=f/f} isPolyNullNonNull = false - isPolyNullNull = false) + isPolyNullNull = false + nonEmptyQueueReceivers = []) ~~~~~~~~~ o = Issue5174Sub.this.f [ Assignment ] > NV{, T, poly nn/n=f/f} @@ -1698,7 +1776,8 @@ Before: NullnessNoInitStore#445( this > NV{@NonNull, Issue5174Sub, poly nn/n=f/f} Issue5174Sub.class > NV{@NonNull, Issue5174Sub, poly nn/n=f/f} isPolyNullNonNull = false - isPolyNullNull = false) + isPolyNullNull = false + nonEmptyQueueReceivers = []) ~~~~~~~~~ 105 -> 106 @@ -1726,7 +1805,8 @@ Before: NullnessNoInitStore#445( Before: NullnessNoInitStore#454( this > NV{@NonNull, SubNested, poly nn/n=f/f} isPolyNullNonNull = false - isPolyNullNull = false) + isPolyNullNull = false + nonEmptyQueueReceivers = []) ~~~~~~~~~ @@ -1734,7 +1814,8 @@ Before: NullnessNoInitStore#454( Before: NullnessNoInitStore#454( this > NV{@NonNull, SubNested, poly nn/n=f/f} isPolyNullNonNull = false - isPolyNullNull = false) + isPolyNullNull = false + nonEmptyQueueReceivers = []) ~~~~~~~~~ o [ VariableDeclaration ] o [ LocalVariable ] @@ -1743,7 +1824,8 @@ o [ LocalVariable ] Before: NullnessNoInitStore#455( this > NV{@NonNull, SubNested, poly nn/n=f/f} isPolyNullNonNull = false - isPolyNullNull = false) + isPolyNullNull = false + nonEmptyQueueReceivers = []) ~~~~~~~~~ Issue5174Super [ ClassName ] @@ -1751,7 +1833,8 @@ Issue5174Super [ ClassName ] Before: NullnessNoInitStore#456( this > NV{@NonNull, SubNested, poly nn/n=f/f} isPolyNullNonNull = false - isPolyNullNull = false) + isPolyNullNull = false + nonEmptyQueueReceivers = []) ~~~~~~~~~ Issue5174Super.sf [ FieldAccess ] > NV{@NonNull, Object, poly nn/n=f/f} o = Issue5174Super.sf [ Assignment ] > NV{@NonNull, Object, poly nn/n=f/f} @@ -1762,7 +1845,8 @@ o [ LocalVariable ] Before: NullnessNoInitStore#457( this > NV{@NonNull, SubNested, poly nn/n=f/f} isPolyNullNonNull = false - isPolyNullNull = false) + isPolyNullNull = false + nonEmptyQueueReceivers = []) ~~~~~~~~~ @@ -1771,7 +1855,8 @@ Before: NullnessNoInitStore#464( o > NV{@NonNull, Object, poly nn/n=f/f} this > NV{@NonNull, SubNested, poly nn/n=f/f} isPolyNullNonNull = false - isPolyNullNull = false) + isPolyNullNull = false + nonEmptyQueueReceivers = []) ~~~~~~~~~ Issue5174Sub [ ClassName ] > NV{@NonNull, Issue5174Sub, poly nn/n=f/f} @@ -1780,7 +1865,8 @@ Before: NullnessNoInitStore#465( o > NV{@NonNull, Object, poly nn/n=f/f} this > NV{@NonNull, SubNested, poly nn/n=f/f} isPolyNullNonNull = false - isPolyNullNull = false) + isPolyNullNull = false + nonEmptyQueueReceivers = []) ~~~~~~~~~ Issue5174Sub.sf [ FieldAccess ] > NV{@NonNull, Object, poly nn/n=f/f} o = Issue5174Sub.sf [ Assignment ] > NV{@NonNull, Object, poly nn/n=f/f} @@ -1792,7 +1878,8 @@ Before: NullnessNoInitStore#474( o > NV{@NonNull, Object, poly nn/n=f/f} this > NV{@NonNull, SubNested, poly nn/n=f/f} isPolyNullNonNull = false - isPolyNullNull = false) + isPolyNullNull = false + nonEmptyQueueReceivers = []) ~~~~~~~~~ Issue5174Super [ ClassName ] > NV{@NonNull, Issue5174Super, poly nn/n=f/f} @@ -1801,7 +1888,8 @@ Before: NullnessNoInitStore#475( o > NV{@NonNull, Object, poly nn/n=f/f} this > NV{@NonNull, SubNested, poly nn/n=f/f} isPolyNullNonNull = false - isPolyNullNull = false) + isPolyNullNull = false + nonEmptyQueueReceivers = []) ~~~~~~~~~ Issue5174Super.sf [ FieldAccess ] > NV{@NonNull, Object, poly nn/n=f/f} o = Issue5174Super.sf [ Assignment ] > NV{@NonNull, Object, poly nn/n=f/f} @@ -1812,6 +1900,7 @@ Before: NullnessNoInitStore#484( o > NV{@NonNull, Object, poly nn/n=f/f} this > NV{@NonNull, SubNested, poly nn/n=f/f} isPolyNullNonNull = false - isPolyNullNull = false) + isPolyNullNull = false + nonEmptyQueueReceivers = []) ~~~~~~~~~ diff --git a/checker/tests/nullness/IsEmptyPoll.java b/checker/tests/nullness/IsEmptyPoll.java index 30f618aca32e..37e863f523c7 100644 --- a/checker/tests/nullness/IsEmptyPoll.java +++ b/checker/tests/nullness/IsEmptyPoll.java @@ -1,8 +1,6 @@ // Test case for Issue 399: // https://github.com/typetools/checker-framework/issues/399 -// @skip-test until the issue is fixed - import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.checker.nullness.qual.Nullable; @@ -17,6 +15,13 @@ void mNonNull(Queue q) { } } + void noSideEffectMethod(Queue q) { + while (!q.isEmpty()) { + q.size(); + @NonNull String firstNode = q.poll(); + } + } + void mNullable(Queue<@Nullable String> q) { while (!q.isEmpty()) { // :: error: (assignment.type.incompatible) @@ -28,4 +33,83 @@ void mNoCheck(Queue<@Nullable String> q) { // :: error: (assignment.type.incompatible) @NonNull String firstNode = q.poll(); } + + void secondPoll(Queue q) { + while (!q.isEmpty()) { + @NonNull String firstNode = q.poll(); + // :: error: (assignment.type.incompatible) + @NonNull String secondNode = q.poll(); + } + } + + void replaceQueue(Queue q1, Queue q2) { + while (!q1.isEmpty()) { + q1 = q2; + // :: error: (assignment.type.incompatible) + @NonNull String firstNode = q1.poll(); + } + } + + void removeBeforePoll(Queue q) { + while (!q.isEmpty()) { + q.remove(); + // :: error: (assignment.type.incompatible) + @NonNull String firstNode = q.poll(); + } + } + + void clearBeforePoll(Queue q) { + while (!q.isEmpty()) { + q.clear(); + // :: error: (assignment.type.incompatible) + @NonNull String firstNode = q.poll(); + } + } + + void conditionalClearBeforePoll(Queue q, boolean bool) { + while (!q.isEmpty()) { + if (bool) { + q.clear(); + } + // :: error: (assignment.type.incompatible) + @NonNull String firstNode = q.poll(); + } + } + + void aliasClearBeforePoll(Queue q) { + Queue a = q; + while (!q.isEmpty()) { + a.clear(); + // :: error: (assignment.type.incompatible) + @NonNull String firstNode = q.poll(); + } + } + + void potentiallyRelatedMutation(Queue q1, Queue q2) { + while (!q1.isEmpty()) { + q2.clear(); + // :: error: (assignment.type.incompatible) + @NonNull String firstNode = q1.poll(); + } + } + + void indexPoll(Queue[] arr, int i) { + while (!arr[i].isEmpty()) { + i++; + // :: error: (assignment.type.incompatible) + @NonNull String firstNode = arr[i].poll(); + } + } + + void clearViaArg(Queue q) { + q.clear(); + } + + void argMutate(Queue q) { + while (!q.isEmpty()) { + clearViaArg(q); + // :: error: (assignment.type.incompatible) + @NonNull String firstNode = q.poll(); + } + } } diff --git a/docs/CHANGELOG.md b/docs/CHANGELOG.md index e60707ca2db9..fe33cd927782 100644 --- a/docs/CHANGELOG.md +++ b/docs/CHANGELOG.md @@ -41,6 +41,8 @@ The Nullness Checker now recognizes references to private, final fields with zer The `ClassBound` annotation can now be used with anonymous types. +The Nullness Checker now refines `Queue.poll()` to `@NonNull` after a false `isEmpty()` check for queues with `@NonNull` element types. + **Implementation details:** `CFAbstractTranfer` now returns a `RegularTransferResult` when the visited method has non-boolean return type, instead of always returning a `ConditionalTransferResult`.