in nullaway/src/main/java/com/uber/nullaway/NullAway.java [2038:2093]
private Description checkCastToNonNullTakesNullable(
Tree tree,
VisitorState state,
Symbol.MethodSymbol methodSymbol,
List<? extends ExpressionTree> actualParams) {
String qualifiedName =
ASTHelpers.enclosingClass(methodSymbol) + "." + methodSymbol.getSimpleName().toString();
Integer castToNonNullPosition;
if (qualifiedName.equals(config.getCastToNonNullMethod())
&& methodSymbol.getParameters().size() == 1) {
// castToNonNull method passed to CLI config, it acts as a cast-to-non-null on its first
// argument. Since this is a single argument method, we skip further querying of handlers.
castToNonNullPosition = 0;
} else {
castToNonNullPosition =
handler.castToNonNullArgumentPositionsForMethod(
actualParams, null, new MethodAnalysisContext(this, state, methodSymbol));
}
if (castToNonNullPosition != null) {
ExpressionTree actual = actualParams.get(castToNonNullPosition);
TreePath enclosingMethodOrLambda =
NullabilityUtil.findEnclosingMethodOrLambdaOrInitializer(state.getPath());
boolean isInitializer;
if (enclosingMethodOrLambda == null) {
throw new RuntimeException("no enclosing method, lambda or initializer!");
} else if (enclosingMethodOrLambda.getLeaf() instanceof LambdaExpressionTree) {
isInitializer = false;
} else if (enclosingMethodOrLambda.getLeaf() instanceof MethodTree) {
MethodTree enclosingMethod = (MethodTree) enclosingMethodOrLambda.getLeaf();
isInitializer = isInitializerMethod(state, ASTHelpers.getSymbol(enclosingMethod));
} else {
// Initializer block
isInitializer = true;
}
if (!isInitializer && !mayBeNullExpr(state, actual)) {
String message =
"passing known @NonNull parameter '"
+ state.getSourceForNode(actual)
+ "' to CastToNonNullMethod ("
+ qualifiedName
+ ") at position "
+ castToNonNullPosition
+ ". This method argument should only take values that NullAway considers @Nullable "
+ "at the invocation site, but which are known not to be null at runtime.";
return errorBuilder.createErrorDescription(
new ErrorMessage(MessageTypes.CAST_TO_NONNULL_ARG_NONNULL, message),
// The Tree passed as suggestTree is the expression being cast
// to avoid recomputing the arg index:
actual,
buildDescription(tree),
state,
null);
}
}
return Description.NO_MATCH;
}