private void handleEnhancedForOverKeySet()

in nullaway/src/main/java/com/uber/nullaway/dataflow/AccessPathNullnessPropagation.java [563:613]


  private void handleEnhancedForOverKeySet(
      LocalVariableNode lhs,
      Node rhs,
      TransferInput<Nullness, NullnessStore> input,
      ReadableUpdates updates) {
    if (isEnhancedForIteratorVariable(lhs)) {
      // Based on the structure of Checker Framework CFGs, rhs must be a call of the form
      // e.iterator().  We check if e is a call to keySet() on a Map, and if so, propagate
      // NONNULL for an access path for e.get(iteratorContents(lhs))
      MethodInvocationNode rhsInv = (MethodInvocationNode) rhs;
      Node mapNode = getMapNodeForKeySetIteratorCall(rhsInv);
      if (mapNode != null) {
        AccessPath mapWithIteratorContentsKey =
            AccessPath.mapWithIteratorContentsKey(mapNode, lhs, apContext);
        if (mapWithIteratorContentsKey != null) {
          // put sanity check here to minimize perf impact
          if (!isCallToMethod(rhsInv, SET_TYPE_SUPPLIER, "iterator")) {
            throw new VerifyException(
                "expected call to iterator(), instead saw "
                    + state.getSourceForNode(rhsInv.getTree()));
          }
          updates.set(mapWithIteratorContentsKey, NONNULL);
        }
      }
    } else if (rhs instanceof MethodInvocationNode) {
      // Check for an assignment lhs = iter#numX.next().  From the structure of Checker Framework
      // CFGs, we know that if iter#numX is the receiver of a call on the rhs of an assignment, it
      // must be a call to next().
      MethodInvocationNode methodInv = (MethodInvocationNode) rhs;
      Node receiver = methodInv.getTarget().getReceiver();
      if (receiver instanceof LocalVariableNode
          && isEnhancedForIteratorVariable((LocalVariableNode) receiver)) {
        // See if we are tracking an access path e.get(iteratorContents(receiver)).  If so, since
        // lhs is being assigned from the iterator contents, propagate NONNULL for an access path
        // e.get(lhs)
        AccessPath mapGetPath =
            input
                .getRegularStore()
                .getMapGetIteratorContentsAccessPath((LocalVariableNode) receiver);
        if (mapGetPath != null) {
          // put sanity check here to minimize perf impact
          if (!isCallToMethod(methodInv, ITERATOR_TYPE_SUPPLIER, "next")) {
            throw new VerifyException(
                "expected call to next(), instead saw "
                    + state.getSourceForNode(methodInv.getTree()));
          }
          updates.set(AccessPath.replaceMapKey(mapGetPath, AccessPath.fromLocal(lhs)), NONNULL);
        }
      }
    }
  }