private Multimap<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 = 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();
  }
private Multimap < Tree , Element > computeTree2Init ( TreePath enclosingClassPath , VisitorState state ) { ClassTree enclosingClass = ( ClassTree ) enclosingClassPath . getLeaf ( ) ; ImmutableMultimap . Builder < Tree , Element > builder = ImmutableMultimap . builder ( ) ; Set < Element > initThusFar = new LinkedHashSet < > ( ) ; Set < MethodTree > constructors = new LinkedHashSet < > ( ) ; AccessPathNullnessAnalysis nullnessAnalysis = getNullnessAnalysis ( state ) ; for ( Tree memberTree : enclosingClass . getMembers ( ) ) { if ( memberTree instanceof VariableTree || memberTree instanceof BlockTree ) { builder . putAll ( memberTree , initThusFar ) ; } if ( memberTree instanceof BlockTree ) { BlockTree blockTree = ( BlockTree ) memberTree ; 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 ) ; } } } constructors . stream ( ) . forEach ( ( c ) -> builder . putAll ( c , initThusFar ) ) ; Symbol . ClassSymbol classSymbol = ASTHelpers . getSymbol ( enclosingClass ) ; FieldInitEntities entities = class2Entities . get ( classSymbol ) ; if ( entities . instanceInitializerMethods ( ) . size ( ) == 1 ) { MethodTree initMethod = entities . instanceInitializerMethods ( ) . iterator ( ) . next ( ) ; Set < Symbol > constructorUninitSymbols = class2ConstructorUninit . get ( classSymbol ) ; 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 ( ) ; builder . putAll ( staticInitMethod , initThusFar ) ; } return builder . build ( ) ; }
@param enclosingClassPath TreePath to class
@param state visitor state
@return a map from each initializer <em>i</em> to the fields known to be initialized before
<em>i</em> executes