in nullaway/src/main/java/com/uber/nullaway/NullAway.java [1432:1487]
private ImmutableMultimap<Tree, Element> computeTree2Init(
TreePath enclosingClassPath, VisitorState state) {
ClassTree enclosingClass = (ClassTree) enclosingClassPath.getLeaf();
ImmutableMultimap.Builder<Tree, Element> builder = ImmutableMultimap.builder();
// NOTE: this set includes both instance and static fields
Set<Element> initThusFar = new LinkedHashSet<>();
Set<MethodTree> constructors = new LinkedHashSet<>();
AccessPathNullnessAnalysis nullnessAnalysis = getNullnessAnalysis(state);
// NOTE: we assume the members are returned in their syntactic order. This has held
// true in our testing
for (Tree memberTree : enclosingClass.getMembers()) {
if (memberTree instanceof VariableTree || memberTree instanceof BlockTree) {
// putAll does not keep a reference to initThusFar, so we don't need to make a copy here
builder.putAll(memberTree, initThusFar);
}
if (memberTree instanceof BlockTree) {
BlockTree blockTree = (BlockTree) memberTree;
// add whatever gets initialized here
TreePath memberPath = new TreePath(enclosingClassPath, memberTree);
if (blockTree.isStatic()) {
initThusFar.addAll(
nullnessAnalysis.getNonnullStaticFieldsAtExit(memberPath, state.context));
} else {
initThusFar.addAll(
nullnessAnalysis.getNonnullFieldsOfReceiverAtExit(memberPath, state.context));
}
}
if (memberTree instanceof MethodTree) {
MethodTree methodTree = (MethodTree) memberTree;
if (isConstructor(methodTree)) {
constructors.add(methodTree);
}
}
}
// all the initializer blocks have run before any code inside a constructor
constructors.stream().forEach((c) -> builder.putAll(c, initThusFar));
Symbol.ClassSymbol classSymbol = ASTHelpers.getSymbol(enclosingClass);
FieldInitEntities entities = castToNonNull(class2Entities.get(classSymbol));
if (entities.instanceInitializerMethods().size() == 1) {
MethodTree initMethod = entities.instanceInitializerMethods().iterator().next();
// collect the fields that may not be initialized by *some* constructor NC
Set<Symbol> constructorUninitSymbols = class2ConstructorUninit.get(classSymbol);
// fields initialized after constructors is initThusFar + (nonNullFields - constructorUninit)
Sets.SetView<Element> initAfterConstructors =
Sets.union(
initThusFar,
Sets.difference(entities.nonnullInstanceFields(), constructorUninitSymbols));
builder.putAll(initMethod, initAfterConstructors);
}
if (entities.staticInitializerMethods().size() == 1) {
MethodTree staticInitMethod = entities.staticInitializerMethods().iterator().next();
// constructors aren't relevant here; just use initThusFar
builder.putAll(staticInitMethod, initThusFar);
}
return builder.build();
}