public static void checkGenericMethodCallTypeArguments()

in nullaway/src/main/java/com/uber/nullaway/generics/GenericsChecks.java [160:215]


  public static void checkGenericMethodCallTypeArguments(
      Tree tree, VisitorState state, NullAway analysis, Config config, Handler handler) {
    List<? extends Tree> typeArguments;
    switch (tree.getKind()) {
      case METHOD_INVOCATION:
        typeArguments = ((MethodInvocationTree) tree).getTypeArguments();
        break;
      case NEW_CLASS:
        typeArguments = ((NewClassTree) tree).getTypeArguments();
        break;
      default:
        throw new RuntimeException("Unexpected tree kind: " + tree.getKind());
    }
    if (typeArguments.isEmpty()) {
      return;
    }
    // get Nullable annotated type arguments
    Map<Integer, Tree> nullableTypeArguments = new HashMap<>();
    for (int i = 0; i < typeArguments.size(); i++) {
      Tree curTypeArg = typeArguments.get(i);
      if (curTypeArg instanceof AnnotatedTypeTree) {
        AnnotatedTypeTree annotatedType = (AnnotatedTypeTree) curTypeArg;
        for (AnnotationTree annotation : annotatedType.getAnnotations()) {
          Type annotationType = ASTHelpers.getType(annotation);
          if (annotationType != null
              && Nullness.isNullableAnnotation(annotationType.toString(), config)) {
            nullableTypeArguments.put(i, curTypeArg);
            break;
          }
        }
      }
    }
    Symbol.MethodSymbol methodSymbol =
        castToNonNull((Symbol.MethodSymbol) ASTHelpers.getSymbol(tree));

    // check if type variables are allowed to be Nullable
    Type baseType = methodSymbol.asType();
    List<Type> baseTypeVariables = baseType.getTypeArguments();
    for (int i = 0; i < baseTypeVariables.size(); i++) {
      if (nullableTypeArguments.containsKey(i)) {
        Type typeVariable = baseTypeVariables.get(i);
        Type upperBound = typeVariable.getUpperBound();
        com.sun.tools.javac.util.List<Attribute.TypeCompound> annotationMirrors =
            upperBound.getAnnotationMirrors();
        boolean hasNullableAnnotation =
            Nullness.hasNullableAnnotation(annotationMirrors.stream(), config)
                || handler.onOverrideTypeParameterUpperBound(baseType.tsym.toString(), i);
        // if type variable's upper bound does not have @Nullable annotation then the instantiation
        // is invalid
        if (!hasNullableAnnotation) {
          reportInvalidTypeArgumentError(
              nullableTypeArguments.get(i), methodSymbol, typeVariable, state, analysis);
        }
      }
    }
  }