public void checkTypeParameterNullnessForAssignability()

in nullaway/src/main/java/com/uber/nullaway/generics/GenericsChecks.java [424:482]


  public void checkTypeParameterNullnessForAssignability(
      Tree tree, NullAway analysis, VisitorState state) {
    Config config = analysis.getConfig();
    if (!config.isJSpecifyMode()) {
      return;
    }
    Type lhsType = getTreeType(tree, config);
    if (lhsType == null) {
      return;
    }
    Tree rhsTree;
    if (tree instanceof VariableTree) {
      VariableTree varTree = (VariableTree) tree;
      rhsTree = varTree.getInitializer();
    } else {
      AssignmentTree assignmentTree = (AssignmentTree) tree;
      rhsTree = assignmentTree.getExpression();
    }
    // rhsTree can be null for a VariableTree.  Also, we don't need to do a check
    // if rhsTree is the null literal
    if (rhsTree == null || rhsTree.getKind().equals(Tree.Kind.NULL_LITERAL)) {
      return;
    }
    Type rhsType = getTreeType(rhsTree, config);

    if (rhsTree instanceof MethodInvocationTree) {
      MethodInvocationTree methodInvocationTree = (MethodInvocationTree) rhsTree;
      Symbol.MethodSymbol methodSymbol = ASTHelpers.getSymbol(methodInvocationTree);
      if (methodSymbol.type instanceof Type.ForAll
          && methodInvocationTree.getTypeArguments().isEmpty()) {
        // generic method call with no explicit generic arguments
        // update inferred type arguments based on the assignment context
        boolean invokedMethodIsNullUnmarked =
            CodeAnnotationInfo.instance(state.context)
                .isSymbolUnannotated(methodSymbol, config, analysis.getHandler());
        InferGenericMethodSubstitutionViaAssignmentContextVisitor inferVisitor =
            new InferGenericMethodSubstitutionViaAssignmentContextVisitor(
                state, config, invokedMethodIsNullUnmarked);
        Type returnType = methodSymbol.getReturnType();
        returnType.accept(inferVisitor, lhsType);

        Map<TypeVariable, Type> substitution = inferVisitor.getInferredSubstitution();
        inferredSubstitutionsForGenericMethodCalls.put(methodInvocationTree, substitution);
        if (rhsType != null) {
          // update rhsType with inferred substitution
          rhsType =
              substituteInferredTypesForTypeVariables(
                  state, methodSymbol.getReturnType(), substitution, config);
        }
      }
    }

    if (rhsType != null) {
      boolean isAssignmentValid = subtypeParameterNullability(lhsType, rhsType, state, config);
      if (!isAssignmentValid) {
        reportInvalidAssignmentInstantiationError(tree, lhsType, rhsType, state, analysis);
      }
    }
  }