in nullaway/src/main/java/com/uber/nullaway/generics/GenericsChecks.java [1557:1655]
public void compareGenericTypeParameterNullabilityForCall(
Symbol.MethodSymbol methodSymbol, Tree tree, VisitorState state) {
Config config = analysis.getConfig();
if (!config.isJSpecifyMode()) {
return;
}
Type invokedMethodType = methodSymbol.type;
Type enclosingType = null;
if (tree instanceof NewClassTree newClassTree) {
if (hasInferredClassTypeArguments(newClassTree)) {
TreePath currentPath = state.getPath();
if (currentPath != null && ASTHelpers.stripParentheses(currentPath.getLeaf()) == tree) {
TreePath parentPath = currentPath.getParentPath();
if (parentPath != null) {
enclosingType = getDiamondTypeFromParentContext(newClassTree, state, parentPath);
}
}
}
}
if (enclosingType == null) {
enclosingType = getEnclosingTypeForCallExpression(methodSymbol, tree, null, state, false);
}
if (enclosingType != null) {
invokedMethodType =
TypeSubstitutionUtils.memberType(state.getTypes(), enclosingType, methodSymbol, config);
}
// substitute type arguments for generic methods with explicit type arguments
if (tree instanceof MethodInvocationTree && invokedMethodType instanceof Type.ForAll) {
invokedMethodType =
substituteTypeArgsInGenericMethodType(
tree, (Type.ForAll) invokedMethodType, null, state, false);
}
Type.MethodType finalMethodType =
handler.onOverrideMethodType(methodSymbol, invokedMethodType.asMethodType(), state);
new InvocationArguments(tree, finalMethodType)
.forEach(
(currentActualParam, argPos, formalParameter, unused) -> {
if (formalParameter.isRaw()) {
// bail out of any checking involving raw types for now
return;
}
if (currentActualParam instanceof MemberReferenceTree memberReferenceTree) {
// the type of the method reference tree provided by javac may not capture
// nullability of nested types. So, do explicit type checks based on the return and
// parameter types of the referenced method
GenericsUtils.processMethodRefTypeRelations(
this,
formalParameter,
memberReferenceTree,
state,
(subtype, supertype, relationKind) -> {
if (!subtypeParameterNullability(supertype, subtype, state)) {
if (relationKind == MethodRefTypeRelationKind.RETURN) {
reportInvalidMethodReferenceReturnTypeError(
memberReferenceTree, supertype, subtype, state);
} else {
reportInvalidMethodReferenceParameterTypeError(
memberReferenceTree, subtype, supertype, state);
}
}
});
return;
}
Type actualParameterType = null;
if (currentActualParam instanceof LambdaExpressionTree) {
maybeStorePolyExpressionTypeFromTarget(currentActualParam, formalParameter);
}
Type inferredPolyType = inferredPolyExpressionTypes.get(currentActualParam);
if (inferredPolyType != null) {
actualParameterType = inferredPolyType;
} else {
TreePath pathToActualParam = new TreePath(state.getPath(), currentActualParam);
actualParameterType =
getTreeType(currentActualParam, state.withPath(pathToActualParam));
}
if (actualParameterType != null) {
if (isGenericCallNeedingInference(currentActualParam)) {
// infer the type of the method call based on the assignment context
// and the formal parameter type
actualParameterType =
inferGenericMethodCallType(
state,
(MethodInvocationTree) currentActualParam,
null,
formalParameter,
false,
false);
}
if (!subtypeParameterNullability(formalParameter, actualParameterType, state)) {
reportInvalidParametersNullabilityError(
formalParameter, actualParameterType, currentActualParam, state);
}
}
});
}