private NullnessStore lambdaInitialStore()

in nullaway/src/main/java/com/uber/nullaway/dataflow/CoreNullnessStoreInitializer.java [93:180]


  private NullnessStore lambdaInitialStore(
      UnderlyingAST.CFGLambda underlyingAST,
      List<LocalVariableNode> parameters,
      Handler handler,
      Context context,
      Types types,
      Config config,
      CodeAnnotationInfo codeAnnotationInfo) {
    // include nullness info for locals from enclosing environment
    EnclosingEnvironmentNullness environmentNullness =
        EnclosingEnvironmentNullness.instance(context);
    NullnessStore environmentMapping =
        Objects.requireNonNull(
            environmentNullness.getEnvironmentMapping(underlyingAST.getLambdaTree()),
            "no environment stored for lambda");
    NullnessStore.Builder result = environmentMapping.toBuilder();
    LambdaExpressionTree code = underlyingAST.getLambdaTree();
    // need to check annotation for i'th parameter of functional interface declaration
    Symbol.MethodSymbol fiMethodSymbol = NullabilityUtil.getFunctionalInterfaceMethod(code, types);
    com.sun.tools.javac.util.List<Symbol.VarSymbol> fiMethodParameters =
        fiMethodSymbol.getParameters();

    /*
     * A potential concern here is that this method might return null because we haven't inferred the type
     * of the lambda yet.
     * However, this is not an issue due to the standard AST traversal order used by Error Prone.
     * We currently only infer lambda types when they are passed as a parameter to a generic method.
     * The checker is guaranteed to visit the enclosing generic method call (e.g., {@code wrap(s -> ...)})
     * and perform type inference for it *before* it descends into the lambda's body to begin dataflow
     * analysis. By the time this method is called during the setup for the lambda's analysis, the
     * inferred type for the lambda argument will have already been computed and stored.
     */
    Type lambdaType = castToNonNull(ASTHelpers.getType(code));
    Type inferredType = genericsChecks.getInferredPolyExpressionType(code);
    if (inferredType != null) {
      lambdaType = inferredType;
    }

    // This obtains the types of the functional interface method parameters with preserved
    // annotations in case of generic type arguments.  Only used in JSpecify mode.
    List<Type> overridenMethodParamTypeList =
        TypeSubstitutionUtils.memberType(types, lambdaType, fiMethodSymbol, config)
            .getParameterTypes();
    MethodParameterNullness fiArgumentNullness = MethodParameterNullness.create(fiMethodSymbol);
    boolean isFIAnnotated =
        !codeAnnotationInfo.isSymbolUnannotated(fiMethodSymbol, config, handler);
    if (isFIAnnotated) {
      for (int i = 0; i < fiMethodParameters.size(); i++) {
        if (Nullness.hasNullableAnnotation(fiMethodParameters.get(i), config)) {
          // Get the Nullness if the Annotation is directly written with the parameter
          fiArgumentNullness.setParameterNullness(i, NULLABLE);
        } else if (config.isJSpecifyMode()
            && Nullness.hasNullableAnnotation(
                overridenMethodParamTypeList.get(i).getAnnotationMirrors().stream(), config)) {
          // Get the Nullness if the Annotation is indirectly applied through a generic type if we
          // are in JSpecify mode
          fiArgumentNullness.setParameterNullness(i, NULLABLE);
        } else {
          fiArgumentNullness.setParameterNullness(i, NONNULL);
        }
      }
    }
    fiArgumentNullness =
        handler.onOverrideMethodInvocationParametersNullability(
            context, fiMethodSymbol, isFIAnnotated, fiArgumentNullness);

    for (int i = 0; i < parameters.size(); i++) {
      LocalVariableNode param = parameters.get(i);
      VariableTree variableTree = code.getParameters().get(i);
      Element element = param.getElement();
      Nullness assumed;
      // we treat lambda parameters differently; they "inherit" the nullability of the
      // corresponding functional interface parameter, unless they are explicitly annotated
      if (Nullness.hasNullableAnnotation((Symbol) element, config)) {
        assumed = NULLABLE;
      } else if (!NullabilityUtil.lambdaParamIsImplicitlyTyped(variableTree)) {
        // the parameter has a declared type with no @Nullable annotation
        // treat as non-null
        assumed = NONNULL;
      } else {
        Nullness fiParameterNullness = fiArgumentNullness.getParameterNullness(i);
        assumed = fiParameterNullness == null ? NONNULL : fiParameterNullness;
      }
      result.setInformation(AccessPath.fromLocal(param), assumed);
    }
    result = handler.onDataflowInitialStore(underlyingAST, parameters, result);
    return result.build();
  }