public void onMatchMethodReference()

in nullaway/src/main/java/com/uber/nullaway/handlers/StreamNullabilityPropagator.java [459:508]


  public void onMatchMethodReference(
      MemberReferenceTree tree, MethodAnalysisContext methodAnalysisContext) {
    VisitorState state = methodAnalysisContext.state();
    MapOrCollectMethodToFilterInstanceRecord callInstanceRecord =
        mapOrCollectRecordToFilterMap.get(tree);
    if (callInstanceRecord != null && ((JCTree.JCMemberReference) tree).kind.isUnbound()) {
      // Unbound method reference, check if we know the corresponding path to be NonNull from the
      // previous filter.
      Tree filterTree = callInstanceRecord.getFilter();
      if (!(filterTree instanceof MethodTree || filterTree instanceof LambdaExpressionTree)) {
        throw new IllegalStateException(
            "unexpected filterTree type "
                + filterTree.getClass()
                + " "
                + state.getSourceForNode(filterTree));
      }
      NullnessStore filterNullnessStore = filterToNSMap.get(filterTree);
      if (filterNullnessStore == null) {
        throw new IllegalStateException(
            "null filterNullStore for tree " + state.getSourceForNode(filterTree));
      }
      for (AccessPath ap : filterNullnessStore.getAccessPathsWithValue(Nullness.NONNULL)) {
        // Find the access path corresponding to the current unbound method reference after binding
        ImmutableList<AccessPathElement> elements = ap.getElements();
        if (elements.size() == 1) {
          // We only care for single method call chains (e.g. this.foo(), not this.f.bar())
          Element element = elements.get(0).getJavaElement();
          if (!element.getKind().equals(ElementKind.METHOD)) {
            // We are only looking for method APs
            continue;
          }
          if (!element
              .getSimpleName()
              .equals(methodAnalysisContext.methodSymbol().getSimpleName())) {
            // Check for the name match
            continue;
          }
          if (((ExecutableElement) element).getParameters().size() != 0) {
            // Methods that take parameters might have return values that don't depend only on this
            // and the AP
            continue;
          }
          // We found our method, and it was non-null when called inside the filter, so we mark the
          // return of the
          // method reference as non-null here
          methodAnalysisContext.analysis().setComputedNullness(tree, Nullness.NONNULL);
        }
      }
    }
  }