/**
   * Collapses definitions of the collapsible properties of a global name. Recurs on subnames that
   * also represent JavaScript objects with collapsible properties.
   *
   * @param n A node representing a global name
   * @param alias The flattened name for {@code n}
   */
  private void collapseDeclarationOfNameAndDescendants(Name n, String alias) {
    boolean canCollapseChildNames = n.canCollapseUnannotatedChildNames();

    // Handle this name first so that nested object literals get unrolled.
    if (n.canCollapse()) {
      updateObjLitOrFunctionDeclaration(n, alias, canCollapseChildNames);
    }

    if (n.props == null) {
      return;
    }
    for (Name p : n.props) {
      // Recur first so that saved node ancestries are intact when needed.
      collapseDeclarationOfNameAndDescendants(p, appendPropForAlias(alias, p.getBaseName()));
      if (!p.inExterns
          && canCollapseChildNames
          && p.getDeclaration() != null
          && p.canCollapse()
          && p.getDeclaration().node != null
          && p.getDeclaration().node.getParent() != null
          && p.getDeclaration().node.getParent().isAssign()) {
        updateSimpleDeclaration(appendPropForAlias(alias, p.getBaseName()), p, p.getDeclaration());
      }
    }
  }
 /**
  * Adds global variable "stubs" for any properties of a global name that are only set in a local
  * scope or read but never set.
  *
  * @param n An object representing a global name (e.g. "a", "a.b.c")
  * @param alias The flattened name of the object whose properties we are adding stubs for (e.g.
  *     "a$b$c")
  * @param parent The node to which new global variables should be added as children
  * @param addAfter The child of after which new variables should be added
  * @return The number of variables added
  */
 private int addStubsForUndeclaredProperties(Name n, String alias, Node parent, Node addAfter) {
   Preconditions.checkState(n.canCollapseUnannotatedChildNames());
   Preconditions.checkArgument(NodeUtil.isStatementBlock(parent));
   Preconditions.checkNotNull(addAfter);
   if (n.props == null) {
     return 0;
   }
   int numStubs = 0;
   for (Name p : n.props) {
     if (p.needsToBeStubbed()) {
       String propAlias = appendPropForAlias(alias, p.getBaseName());
       Node nameNode = IR.name(propAlias);
       Node newVar = IR.var(nameNode).useSourceInfoIfMissingFromForTree(addAfter);
       parent.addChildAfter(newVar, addAfter);
       addAfter = newVar;
       numStubs++;
       compiler.reportCodeChange();
       // Determine if this is a constant var by checking the first
       // reference to it. Don't check the declaration, as it might be null.
       if (p.getRefs().get(0).node.getLastChild().getBooleanProp(Node.IS_CONSTANT_NAME)) {
         nameNode.putBooleanProp(Node.IS_CONSTANT_NAME, true);
       }
     }
   }
   return numStubs;
 }
  @Override
  public void process(Node externs, Node root) {
    GlobalNamespace namespace;
    namespace = new GlobalNamespace(compiler, root);

    if (inlineAliases) {
      inlineAliases(namespace);
    }
    nameMap = namespace.getNameIndex();
    globalNames = namespace.getNameForest();
    checkNamespaces();

    for (Name name : globalNames) {
      flattenReferencesToCollapsibleDescendantNames(name, name.getBaseName());
    }

    // We collapse property definitions after collapsing property references
    // because this step can alter the parse tree above property references,
    // invalidating the node ancestry stored with each reference.
    for (Name name : globalNames) {
      collapseDeclarationOfNameAndDescendants(name, name.getBaseName());
    }
  }
  /**
   * Flattens all references to collapsible properties of a global name except their initial
   * definitions. Recurs on subnames.
   *
   * @param n An object representing a global name
   * @param alias The flattened name for {@code n}
   */
  private void flattenReferencesToCollapsibleDescendantNames(Name n, String alias) {
    if (n.props == null || n.isCollapsingExplicitlyDenied()) {
      return;
    }

    for (Name p : n.props) {
      String propAlias = appendPropForAlias(alias, p.getBaseName());

      if (p.canCollapse()) {
        flattenReferencesTo(p, propAlias);
      } else if (p.isSimpleStubDeclaration() && !p.isCollapsingExplicitlyDenied()) {
        flattenSimpleStubDeclaration(p, propAlias);
      }

      flattenReferencesToCollapsibleDescendantNames(p, propAlias);
    }
  }