public void findNamedFunctions(NodeTraversal t, Node n, Node parent) {
      if (!NodeUtil.isStatement(n)) {
        // There aren't any interesting functions here.
        return;
      }

      switch (n.getType()) {
          // Functions expressions in the form of:
          //   var fooFn = function(x) { return ... }
        case Token.VAR:
          Preconditions.checkState(n.hasOneChild());
          Node nameNode = n.getFirstChild();
          if (nameNode.isName()
              && nameNode.hasChildren()
              && nameNode.getFirstChild().isFunction()) {
            maybeAddFunction(new FunctionVar(n), t.getModule());
          }
          break;

          // Named functions
          // function Foo(x) { return ... }
        case Token.FUNCTION:
          Preconditions.checkState(NodeUtil.isStatementBlock(parent) || parent.isLabel());
          if (!NodeUtil.isFunctionExpression(n)) {
            Function fn = new NamedFunction(n);
            maybeAddFunction(fn, t.getModule());
          }
          break;
      }
    }
  private void addStatement(GenerateNodeContext context, Node stmt) {
    CodingConvention convention = compiler.getCodingConvention();

    Node n = context.getNode();
    Node exprRoot = n;
    while (!NodeUtil.isStatementBlock(exprRoot.getParent())) {
      exprRoot = exprRoot.getParent();
    }

    // It's important that any class-building calls (goog.inherits)
    // come right after the class definition, so move the export after that.
    while (true) {
      Node next = exprRoot.getNext();
      if (next != null
          && NodeUtil.isExprCall(next)
          && convention.getClassesDefinedByCall(next.getFirstChild()) != null) {
        exprRoot = next;
      } else {
        break;
      }
    }

    Node block = exprRoot.getParent();
    block.addChildAfter(stmt, exprRoot);
  }
 /**
  * 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;
 }
  /**
   * If we haven't found a return value yet, try to look at the "return" statements in the function.
   */
  FunctionTypeBuilder inferReturnStatementsAsLastResort(@Nullable Node functionBlock) {
    if (functionBlock == null || compiler.getInput(sourceName).isExtern()) {
      return this;
    }
    Preconditions.checkArgument(functionBlock.getType() == Token.BLOCK);
    if (returnType == null) {
      boolean hasNonEmptyReturns = false;
      List<Node> worklist = Lists.newArrayList(functionBlock);
      while (!worklist.isEmpty()) {
        Node current = worklist.remove(worklist.size() - 1);
        int cType = current.getType();
        if (cType == Token.RETURN && current.getFirstChild() != null || cType == Token.THROW) {
          hasNonEmptyReturns = true;
          break;
        } else if (NodeUtil.isStatementBlock(current) || NodeUtil.isControlStructure(current)) {
          for (Node child = current.getFirstChild(); child != null; child = child.getNext()) {
            worklist.add(child);
          }
        }
      }

      if (!hasNonEmptyReturns) {
        returnType = typeRegistry.getNativeType(VOID_TYPE);
        returnTypeInferred = true;
      }
    }
    return this;
  }
  Node tryFuseStatementsAggressively(Node n) {
    if (!NodeUtil.isStatementBlock(n)) {
      return n;
    }

    Node cur = n.getFirstChild();
    while (cur != null) {
      if (!cur.isExprResult()) {
        cur = cur.getNext();
        continue;
      }
      Node next = cur.getNext();
      while (next != null && next.isExprResult()) {
        next = next.getNext();
      }
      if (cur.getNext() != next) {
        cur = fuseIntoOneStatement(n, cur, next);
        reportCodeChange();
      }
      if (cur.isExprResult() && next != null && isFusableControlStatement(next)) {
        fuseExpressionIntoControlFlowStatement(cur, next);
        reportCodeChange();
        next = next.getNext();
      }
      cur = next;
    }

    return n;
  }
  /** Scans and gather variables declarations under a Node */
  private void scanVars(Node n, Node parent) {
    switch (n.getType()) {
      case Token.VAR:
        // Declare all variables. e.g. var x = 1, y, z;
        for (Node child = n.getFirstChild(); child != null; ) {
          Node next = child.getNext();
          Preconditions.checkState(child.getType() == Token.NAME);

          String name = child.getString();
          declareVar(name, child, n, parent, null, n);
          child = next;
        }
        return;

      case Token.FUNCTION:
        if (NodeUtil.isFunctionExpression(n)) {
          return;
        }

        String fnName = n.getFirstChild().getString();
        if (fnName.isEmpty()) {
          // This is invalid, but allow it so the checks can catch it.
          return;
        }
        declareVar(fnName, n.getFirstChild(), n, parent, null, n);
        return; // should not examine function's children

      case Token.CATCH:
        Preconditions.checkState(n.getChildCount() == 2);
        Preconditions.checkState(n.getFirstChild().getType() == Token.NAME);
        // the first child is the catch var and the third child
        // is the code block

        final Node var = n.getFirstChild();
        final Node block = var.getNext();

        declareVar(var.getString(), var, n, parent, null, n);
        scanVars(block, n);
        return; // only one child to scan

      case Token.SCRIPT:
        sourceName = (String) n.getProp(Node.SOURCENAME_PROP);
        break;
    }

    // Variables can only occur in statement-level nodes, so
    // we only need to traverse children in a couple special cases.
    if (NodeUtil.isControlStructure(n) || NodeUtil.isStatementBlock(n)) {
      for (Node child = n.getFirstChild(); child != null; ) {
        Node next = child.getNext();
        scanVars(child, n);
        child = next;
      }
    }
  }
  /** Collapse VARs and EXPR_RESULT node into FOR loop initializers where possible. */
  private void maybeCollapseIntoForStatements(Node n, Node parent) {
    // Only SCRIPT, BLOCK, and LABELs can have FORs that can be collapsed into.
    // LABELs are not supported here.
    if (parent == null || !NodeUtil.isStatementBlock(parent)) {
      return;
    }

    // Is the current node something that can be in a for loop initializer?
    if (!NodeUtil.isExpressionNode(n) && !NodeUtil.isVar(n)) {
      return;
    }

    // Is the next statement a valid FOR?
    Node nextSibling = n.getNext();
    if (nextSibling != null
        && nextSibling.getType() == Token.FOR
        && !NodeUtil.isForIn(nextSibling)
        && nextSibling.getFirstChild().getType() == Token.EMPTY) {

      // Does the current node contain an in operator?  If so, embedding
      // the expression in a for loop can cause some Javascript parsers (such
      // as the Playstation 3's browser based on Access's NetFront
      // browser) to fail to parse the code.
      // See bug 1778863 for details.
      if (NodeUtil.containsType(n, Token.IN)) {
        return;
      }

      // Move the current node into the FOR loop initializer.
      Node forNode = nextSibling;
      Node oldInitializer = forNode.getFirstChild();
      parent.removeChild(n);

      Node newInitializer;
      if (NodeUtil.isVar(n)) {
        newInitializer = n;
      } else {
        // Extract the expression from EXPR_RESULT node.
        Preconditions.checkState(n.hasOneChild());
        newInitializer = n.getFirstChild();
        n.removeChild(newInitializer);
      }

      forNode.replaceChild(oldInitializer, newInitializer);

      compiler.reportCodeChange();
    }
  }
  /**
   * Inline a function which fulfills the requirements of canInlineReferenceAsStatementBlock into
   * the call site, replacing the parent expression.
   */
  private Node inlineFunction(Node callNode, Node fnNode, String fnName) {
    Node parent = callNode.getParent();
    Node grandParent = parent.getParent();

    // TODO(johnlenz): Consider storing the callSite classification in the
    // reference object and passing it in here.
    CallSiteType callSiteType = classifyCallSite(callNode);
    Preconditions.checkArgument(callSiteType != CallSiteType.UNSUPPORTED);

    // Store the name for the result. This will be used to
    // replace "return expr" statements with "resultName = expr"
    // to replace
    String resultName = null;
    boolean needsDefaultReturnResult = true;
    switch (callSiteType) {
      case SIMPLE_ASSIGNMENT:
        resultName = parent.getFirstChild().getString();
        break;

      case VAR_DECL_SIMPLE_ASSIGNMENT:
        resultName = parent.getString();
        break;

      case SIMPLE_CALL:
        resultName = null; // "foo()" doesn't need a result.
        needsDefaultReturnResult = false;
        break;

      case EXPRESSION:
        resultName = getUniqueResultName();
        needsDefaultReturnResult = false; // The intermediary result already
        // has the default value.
        break;

      case DECOMPOSABLE_EXPRESSION:
        throw new IllegalStateException(
            "Decomposable expressions must decomposed before inlining.");

      default:
        throw new IllegalStateException("Unexpected call site type.");
    }

    boolean isCallInLoop = NodeUtil.isWithinLoop(callNode);

    FunctionToBlockMutator mutator = new FunctionToBlockMutator(compiler, this.safeNameIdSupplier);

    Node newBlock =
        mutator.mutate(
            fnName, fnNode, callNode, resultName, needsDefaultReturnResult, isCallInLoop);

    // TODO(nicksantos): Create a common mutation function that
    // can replace either a VAR name assignment, assignment expression or
    // a EXPR_RESULT.
    Node greatGrandParent = grandParent.getParent();
    switch (callSiteType) {
      case VAR_DECL_SIMPLE_ASSIGNMENT:
        // Remove the call from the name node.
        parent.removeChild(parent.getFirstChild());
        Preconditions.checkState(parent.getFirstChild() == null);
        // Add the call, after the VAR.
        greatGrandParent.addChildAfter(newBlock, grandParent);
        break;

      case SIMPLE_ASSIGNMENT:
        // The assignment is now part of the inline function so
        // replace it completely.
        Preconditions.checkState(NodeUtil.isExpressionNode(grandParent));
        greatGrandParent.replaceChild(grandParent, newBlock);
        break;

      case SIMPLE_CALL:
        // If nothing is looking at the result just replace the call.
        Preconditions.checkState(NodeUtil.isExpressionNode(parent));
        grandParent.replaceChild(parent, newBlock);
        break;

      case EXPRESSION:
        // TODO(johnlenz): Maybe change this so that movable and decomposable
        // expressions are handled the same way: The call is moved and
        // then handled by one the three basic cases, rather than
        // introducing a new case.
        Node injectionPoint = ExpressionDecomposer.findInjectionPoint(callNode);
        Preconditions.checkNotNull(injectionPoint);
        Node injectionPointParent = injectionPoint.getParent();
        Preconditions.checkNotNull(injectionPointParent);
        Preconditions.checkState(NodeUtil.isStatementBlock(injectionPointParent));

        // Declare the intermediate result name.
        newBlock.addChildrenToFront(
            NodeUtil.newVarNode(resultName, null).copyInformationFromForTree(callNode));
        // Inline the function before the selected injection point (before
        // the call).
        injectionPointParent.addChildBefore(newBlock, injectionPoint);
        // Replace the call site with a reference to the intermediate
        // result name.
        parent.replaceChild(callNode, Node.newString(Token.NAME, resultName));
        break;

      default:
        throw new IllegalStateException("Unexpected call site type.");
    }

    return newBlock;
  }
 @Override
 public final boolean shouldTraverse(NodeTraversal nodeTraversal, Node n, Node parent) {
   return parent == null
       || NodeUtil.isControlStructure(parent)
       || NodeUtil.isStatementBlock(parent);
 }