in nullaway/src/main/java/com/uber/nullaway/dataflow/CoreNullnessStoreInitializer.java [85:156]
private static NullnessStore lambdaInitialStore(
UnderlyingAST.CFGLambda underlyingAST,
List<LocalVariableNode> parameters,
Handler handler,
Context context,
Types types,
Config config,
CodeAnnotationInfo codeAnnotationInfo) {
// include nullness info for locals from enclosing environment
EnclosingEnvironmentNullness environmentNullness =
EnclosingEnvironmentNullness.instance(context);
NullnessStore environmentMapping =
Objects.requireNonNull(
environmentNullness.getEnvironmentMapping(underlyingAST.getLambdaTree()),
"no environment stored for lambda");
NullnessStore.Builder result = environmentMapping.toBuilder();
LambdaExpressionTree code = underlyingAST.getLambdaTree();
// need to check annotation for i'th parameter of functional interface declaration
Symbol.MethodSymbol fiMethodSymbol = NullabilityUtil.getFunctionalInterfaceMethod(code, types);
com.sun.tools.javac.util.List<Symbol.VarSymbol> fiMethodParameters =
fiMethodSymbol.getParameters();
// This obtains the types of the functional interface method parameters with preserved
// annotations in case of generic type arguments. Only used in JSpecify mode.
List<Type> overridenMethodParamTypeList =
TypeSubstitutionUtils.memberType(
types, castToNonNull(ASTHelpers.getType(code)), fiMethodSymbol, config)
.getParameterTypes();
// If fiArgumentPositionNullness[i] == null, parameter position i is unannotated
@Nullable Nullness[] fiArgumentPositionNullness = new Nullness[fiMethodParameters.size()];
boolean isFIAnnotated =
!codeAnnotationInfo.isSymbolUnannotated(fiMethodSymbol, config, handler);
if (isFIAnnotated) {
for (int i = 0; i < fiMethodParameters.size(); i++) {
if (Nullness.hasNullableAnnotation(fiMethodParameters.get(i), config)) {
// Get the Nullness if the Annotation is directly written with the parameter
fiArgumentPositionNullness[i] = NULLABLE;
} else if (config.isJSpecifyMode()
&& Nullness.hasNullableAnnotation(
overridenMethodParamTypeList.get(i).getAnnotationMirrors().stream(), config)) {
// Get the Nullness if the Annotation is indirectly applied through a generic type if we
// are in JSpecify mode
fiArgumentPositionNullness[i] = NULLABLE;
} else {
fiArgumentPositionNullness[i] = NONNULL;
}
}
}
fiArgumentPositionNullness =
handler.onOverrideMethodInvocationParametersNullability(
context, fiMethodSymbol, isFIAnnotated, fiArgumentPositionNullness);
for (int i = 0; i < parameters.size(); i++) {
LocalVariableNode param = parameters.get(i);
VariableTree variableTree = code.getParameters().get(i);
Element element = param.getElement();
Nullness assumed;
// we treat lambda parameters differently; they "inherit" the nullability of the
// corresponding functional interface parameter, unless they are explicitly annotated
if (Nullness.hasNullableAnnotation((Symbol) element, config)) {
assumed = NULLABLE;
} else if (!NullabilityUtil.lambdaParamIsImplicitlyTyped(variableTree)) {
// the parameter has a declared type with no @Nullable annotation
// treat as non-null
assumed = NONNULL;
} else {
assumed = fiArgumentPositionNullness[i] == null ? NONNULL : fiArgumentPositionNullness[i];
}
result.setInformation(AccessPath.fromLocal(param), assumed);
}
result = handler.onDataflowInitialStore(underlyingAST, parameters, result);
return result.build();
}