public void onMatchMethodInvocation()

in nullaway/src/main/java/com/uber/nullaway/handlers/StreamNullabilityPropagator.java [210:273]


  public void onMatchMethodInvocation(
      NullAway analysis,
      MethodInvocationTree tree,
      VisitorState state,
      Symbol.MethodSymbol methodSymbol) {
    Type receiverType = ASTHelpers.getReceiverType(tree);
    for (StreamTypeRecord streamType : models) {
      if (streamType.matchesType(receiverType, state)) {
        // Build observable call chain
        buildObservableCallChain(tree);

        // Dispatch to code handling specific observer methods
        if (streamType.isFilterMethod(methodSymbol) && methodSymbol.getParameters().length() == 1) {
          ExpressionTree argTree = tree.getArguments().get(0);
          if (argTree instanceof NewClassTree) {
            ClassTree annonClassBody = ((NewClassTree) argTree).getClassBody();
            // Ensure that this `new A() ...` has a custom class body, otherwise, we skip for now.
            // In the future, we could look at the declared type and its inheritance chain, at least
            // for
            // filters.
            if (annonClassBody != null) {
              handleFilterAnonClass(streamType, tree, annonClassBody, state);
            }
          } else if (argTree instanceof LambdaExpressionTree) {
            LambdaExpressionTree lambdaTree = (LambdaExpressionTree) argTree;
            handleFilterLambda(streamType, tree, lambdaTree, state);
          }
        } else if (streamType.isMapMethod(methodSymbol)
            && methodSymbol.getParameters().length() == 1) {
          ExpressionTree argTree = tree.getArguments().get(0);
          if (argTree instanceof NewClassTree) {
            ClassTree annonClassBody = ((NewClassTree) argTree).getClassBody();
            // Ensure that this `new B() ...` has a custom class body, otherwise, we skip for now.
            if (annonClassBody != null) {
              MapLikeMethodRecord methodRecord = streamType.getMaplikeMethodRecord(methodSymbol);
              handleMapOrCollectAnonClassBody(
                  methodRecord,
                  annonClassBody,
                  t -> observableCallToInnerMethodOrLambda.put(tree, t));
            }
          } else if (argTree instanceof LambdaExpressionTree) {
            observableCallToInnerMethodOrLambda.put(tree, argTree);
          } else if (argTree instanceof MemberReferenceTree) {
            observableCallToInnerMethodOrLambda.put(tree, argTree);
          }
        } else {
          if (methodSymbol.getParameters().length() == 1) {
            // We can have multiple CollectLikeMethodRecords for a single collect method, reflecting
            // the different possible collector factory methods whose result may be passed to a
            // collect call.  At a single collect call site, at most one of these records will be
            // relevant. So, we loop through them all, but break out of the loop as soon as we find
            // one that matches.
            for (CollectLikeMethodRecord collectlikeMethodRecord :
                streamType.getCollectlikeMethodRecords(methodSymbol)) {
              boolean handled = handleCollectCall(tree, collectlikeMethodRecord);
              if (handled) {
                break;
              }
            }
          }
        }
      }
    }
  }