private void updateGlobalNameDeclarationAtAssignNode(
      Name n, String alias, boolean canCollapseChildNames) {
    // NOTE: It's important that we don't add additional nodes
    // (e.g. a var node before the exprstmt) because the exprstmt might be
    // the child of an if statement that's not inside a block).

    // All qualified names - even for variables that are initially declared as LETS and CONSTS -
    // are being declared as VAR statements, but this is not incorrect because
    // we are only collapsing for global names.
    Ref ref = n.getDeclaration();
    Node rvalue = ref.getNode().getNext();
    if (ref.getTwin() != null) {
      updateTwinnedDeclaration(alias, ref.name, ref);
      return;
    }
    Node varNode = new Node(Token.VAR);
    Node varParent = ref.getNode().getAncestor(3);
    Node grandparent = ref.getNode().getAncestor(2);
    boolean isObjLit = rvalue.isObjectLit();
    boolean insertedVarNode = false;

    if (isObjLit && canEliminate(n)) {
      // Eliminate the object literal altogether.
      varParent.replaceChild(grandparent, varNode);
      n.updateRefNode(ref, null);
      insertedVarNode = true;
      compiler.reportChangeToEnclosingScope(varNode);
    } else if (!n.isSimpleName()) {
      // Create a VAR node to declare the name.
      if (rvalue.isFunction()) {
        checkForHosedThisReferences(rvalue, n.getJSDocInfo(), n);
      }

      compiler.reportChangeToEnclosingScope(rvalue);
      ref.getNode().getParent().removeChild(rvalue);

      Node nameNode =
          NodeUtil.newName(compiler, alias, ref.getNode().getAncestor(2), n.getFullName());

      JSDocInfo info = NodeUtil.getBestJSDocInfo(ref.getNode().getParent());
      if (ref.getNode().getLastChild().getBooleanProp(Node.IS_CONSTANT_NAME)
          || (info != null && info.isConstant())) {
        nameNode.putBooleanProp(Node.IS_CONSTANT_NAME, true);
      }

      if (info != null) {
        varNode.setJSDocInfo(info);
      }
      varNode.addChildToBack(nameNode);
      nameNode.addChildToFront(rvalue);
      varParent.replaceChild(grandparent, varNode);

      // Update the node ancestry stored in the reference.
      n.updateRefNode(ref, nameNode);
      insertedVarNode = true;
      compiler.reportChangeToEnclosingScope(varNode);
    }

    if (canCollapseChildNames) {
      if (isObjLit) {
        declareVariablesForObjLitValues(
            n, alias, rvalue, varNode, varNode.getPrevious(), varParent);
      }

      addStubsForUndeclaredProperties(n, alias, varParent, varNode);
    }

    if (insertedVarNode) {
      if (!varNode.hasChildren()) {
        varParent.removeChild(varNode);
      }
    }
  }
private void updateGlobalNameDeclarationAtAssignNode ( Name n , String alias , boolean canCollapseChildNames ) { Ref ref = n . getDeclaration ( ) ; Node rvalue = ref . getNode ( ) . getNext ( ) ; if ( ref . getTwin ( ) != null ) { updateTwinnedDeclaration ( alias , ref . name , ref ) ; return ; } Node varNode = new Node ( Token . VAR ) ; Node varParent = ref . getNode ( ) . getAncestor ( 3 ) ; Node grandparent = ref . getNode ( ) . getAncestor ( 2 ) ; boolean isObjLit = rvalue . isObjectLit ( ) ; boolean insertedVarNode = false ; if ( isObjLit && canEliminate ( n ) ) { varParent . replaceChild ( grandparent , varNode ) ; n . updateRefNode ( ref , null ) ; insertedVarNode = true ; compiler . reportChangeToEnclosingScope ( varNode ) ; } else if ( ! n . isSimpleName ( ) ) { if ( rvalue . isFunction ( ) ) { checkForHosedThisReferences ( rvalue , n . getJSDocInfo ( ) , n ) ; } compiler . reportChangeToEnclosingScope ( rvalue ) ; ref . getNode ( ) . getParent ( ) . removeChild ( rvalue ) ; Node nameNode = NodeUtil . newName ( compiler , alias , ref . getNode ( ) . getAncestor ( 2 ) , n . getFullName ( ) ) ; JSDocInfo info = NodeUtil . getBestJSDocInfo ( ref . getNode ( ) . getParent ( ) ) ; if ( ref . getNode ( ) . getLastChild ( ) . getBooleanProp ( Node . IS_CONSTANT_NAME ) || ( info != null && info . isConstant ( ) ) ) { nameNode . putBooleanProp ( Node . IS_CONSTANT_NAME , true ) ; } if ( info != null ) { varNode . setJSDocInfo ( info ) ; } varNode . addChildToBack ( nameNode ) ; nameNode . addChildToFront ( rvalue ) ; varParent . replaceChild ( grandparent , varNode ) ; n . updateRefNode ( ref , nameNode ) ; insertedVarNode = true ; compiler . reportChangeToEnclosingScope ( varNode ) ; } if ( canCollapseChildNames ) { if ( isObjLit ) { declareVariablesForObjLitValues ( n , alias , rvalue , varNode , varNode . getPrevious ( ) , varParent ) ; } addStubsForUndeclaredProperties ( n , alias , varParent , varNode ) ; } if ( insertedVarNode ) { if ( ! varNode . hasChildren ( ) ) { varParent . removeChild ( varNode ) ; } } }
Updates the first initialization (a.k.a "declaration") of a global name
that occurs at an ASSIGN node. See comment for
{@link #updateGlobalNameDeclaration}.

@param n An object representing a global name (e.g. "a", "a.b.c")
@param alias The flattened name for {@code n} (e.g. "a", "a$b$c")