in nullaway/src/main/java/com/uber/nullaway/dataflow/AccessPathNullnessPropagation.java [997:1045]
private void setNullnessForMapCalls(
MethodInvocationNode node,
Symbol.MethodSymbol callee,
List<Node> arguments,
AccessPathNullnessPropagation.SubNodeValues inputs,
AccessPathNullnessPropagation.Updates thenUpdates,
AccessPathNullnessPropagation.Updates bothUpdates) {
if (AccessPath.isContainsKey(callee, state)) {
// make sure argument is a variable, and get its element
AccessPath getAccessPath = AccessPath.getForMapInvocation(node, state, apContext);
if (getAccessPath != null) {
// in the then branch, we want the get() call with the same argument to be non-null
// we assume that the declared target of the get() method will be in the same class
// as containsKey()
thenUpdates.set(getAccessPath, NONNULL);
}
} else if (AccessPath.isMapPut(callee, state)) {
AccessPath getAccessPath = AccessPath.getForMapInvocation(node, state, apContext);
if (getAccessPath != null) {
Nullness value = inputs.valueOfSubNode(arguments.get(1));
bothUpdates.set(getAccessPath, value);
}
} else if (AccessPath.isMapComputeIfAbsent(callee, state)) {
AccessPath getAccessPath = AccessPath.getForMapInvocation(node, state, apContext);
if (getAccessPath != null) {
// TODO: For now, Function<K, V> implies a @NonNull V. We need to revisit this once we
// support generics, but we do include a couple defensive tests below.
if (arguments.size() < 2) {
return;
}
Node funcNode = arguments.get(1);
if (!funcNode.getType().getKind().equals(TypeKind.DECLARED)) {
return;
}
Type.ClassType classType = (Type.ClassType) funcNode.getType();
if (classType.getTypeArguments().size() != 2) {
return;
}
Type functionReturnType = classType.getTypeArguments().get(1);
// Unfortunately, functionReturnType.tsym seems to elide annotation info, so we can't call
// the Nullness.* methods that deal with Symbol. We might have better APIs for this kind of
// check once we have real generics support.
if (!Nullness.hasNullableAnnotation(
functionReturnType.getAnnotationMirrors().stream(), config)) {
bothUpdates.set(getAccessPath, NONNULL);
}
}
}
}