private MethodInferenceResult runInferenceForCall()

in nullaway/src/main/java/com/uber/nullaway/generics/GenericsChecks.java [882:963]


  private MethodInferenceResult runInferenceForCall(
      VisitorState state,
      @Nullable TreePath path,
      MethodInvocationTree invocationTree,
      @Nullable Type typeFromAssignmentContext,
      boolean assignedToLocal,
      boolean calledFromDataflow) {
    Symbol.MethodSymbol methodSymbol = ASTHelpers.getSymbol(invocationTree);
    ConstraintSolver solver = makeSolver(state, analysis);
    // allInvocations tracks the top-level invocations and any nested invocations that also
    // require inference
    Set<MethodInvocationTree> allInvocations = new LinkedHashSet<>();
    allInvocations.add(invocationTree);
    Map<Element, ConstraintSolver.InferredNullability> typeVarNullability;
    try {
      generateConstraintsForCall(
          state,
          path,
          typeFromAssignmentContext,
          assignedToLocal,
          solver,
          methodSymbol,
          invocationTree,
          allInvocations);
      typeVarNullability = new HashMap<>(solver.solve());
      // The solver only computes a solution for variables that appear in constraints. For
      // unconstrained variables, treat them as NONNULL, consistent with solver behavior for
      // unconstrained variables that do appear in the constraint graph.
      for (int i = 0; i < methodSymbol.getTypeParameters().size(); i++) {
        Symbol.TypeVariableSymbol typeVar = methodSymbol.getTypeParameters().get(i);
        typeVarNullability.putIfAbsent(typeVar, ConstraintSolver.InferredNullability.NONNULL);
      }

      // Store inferred types for lambda arguments
      new InvocationArguments(invocationTree, methodSymbol.type.asMethodType())
          .forEach(
              (argument, argPos, formalParamType, unused) -> {
                if (argument instanceof LambdaExpressionTree
                    || argument instanceof MemberReferenceTree) {
                  Type polyExprTreeType = ASTHelpers.getType(argument);
                  if (polyExprTreeType != null) {
                    Type typeWithInferredNullability =
                        TypeSubstitutionUtils.updateTypeWithInferredNullability(
                            polyExprTreeType, formalParamType, typeVarNullability, state, config);
                    inferredPolyExpressionTypes.put(argument, typeWithInferredNullability);
                  }
                }
              });

      InferenceSuccess successResult = new InferenceSuccess(typeVarNullability);
      // don't cache result if we were called from dataflow, since the result may rely on dataflow
      // facts that do not reflect the fixed point
      if (!calledFromDataflow) {
        for (MethodInvocationTree invTree : allInvocations) {
          inferredTypeVarNullabilityForGenericCalls.put(invTree, successResult);
        }
      }
      return successResult;
    } catch (UnsatisfiableConstraintsException e) {
      if (config.warnOnGenericInferenceFailure()) {
        ErrorBuilder errorBuilder = analysis.getErrorBuilder();
        ErrorMessage errorMessage =
            new ErrorMessage(
                ErrorMessage.MessageTypes.GENERIC_INFERENCE_FAILURE,
                String.format(
                    "Failed to infer type argument nullability for call %s: %s",
                    state.getSourceForNode(invocationTree), e.getMessage()));
        state.reportMatch(
            errorBuilder.createErrorDescription(
                errorMessage, analysis.buildDescription(invocationTree), state, null));
      }
      InferenceFailure failureResult = new InferenceFailure(e.getMessage());
      // don't cache result if we were called from dataflow, since the result may rely on dataflow
      // facts that do not reflect the fixed point
      if (!calledFromDataflow) {
        for (MethodInvocationTree invTree : allInvocations) {
          inferredTypeVarNullabilityForGenericCalls.put(invTree, failureResult);
        }
      }
      return failureResult;
    }
  }