/** Traverses a function. */ private void traverseFunction(Node n, Node parent) { Preconditions.checkState(n.getChildCount() == 3); Preconditions.checkState(n.isFunction()); final Node fnName = n.getFirstChild(); boolean isFunctionExpression = (parent != null) && NodeUtil.isFunctionExpression(n); if (!isFunctionExpression) { // Functions declarations are in the scope containing the declaration. traverseBranch(fnName, n); } curNode = n; pushScope(n); if (isFunctionExpression) { // Function expression names are only accessible within the function // scope. traverseBranch(fnName, n); } final Node args = fnName.getNext(); final Node body = args.getNext(); // Args traverseBranch(args, n); // Body // ES6 "arrow" function may not have a block as a body. traverseBranch(body, n); popScope(); }
/** Traverses a parse tree recursively with a scope, starting at that scope's root. */ void traverseAtScope(Scope s) { Node n = s.getRootNode(); if (n.isFunction()) { // We need to do some extra magic to make sure that the scope doesn't // get re-created when we dive into the function. if (inputId == null) { inputId = NodeUtil.getInputId(n); } sourceName = getSourceName(n); curNode = n; pushScope(s); Node args = n.getFirstChild().getNext(); Node body = args.getNext(); traverseBranch(args, n); traverseBranch(body, n); popScope(); } else if (n.isBlock()) { if (inputId == null) { inputId = NodeUtil.getInputId(n); } sourceName = getSourceName(n); curNode = n; pushScope(s); traverseBranch(n, n.getParent()); popScope(); } else { Preconditions.checkState(s.isGlobal(), "Expected global scope. Got:", s); traverseWithScope(n, s); } }
/** * Traverses an inner node recursively with a refined scope. An inner node may be any node with a * non {@code null} parent (i.e. all nodes except the root). * * @param node the node to traverse * @param parent the node's parent, it may not be {@code null} * @param refinedScope the refined scope of the scope currently at the top of the scope stack or * in trivial cases that very scope or {@code null} */ protected void traverseInnerNode(Node node, Node parent, Scope refinedScope) { Preconditions.checkNotNull(parent); if (inputId == null) { inputId = NodeUtil.getInputId(node); } if (refinedScope != null && getScope() != refinedScope) { curNode = node; pushScope(refinedScope); traverseBranch(node, parent); popScope(); } else { traverseBranch(node, parent); } }
/** Traverses a non-function block. */ private void traverseBlockScope(Node n) { pushScope(n); for (Node child : n.children()) { traverseBranch(child, n); } popScope(); }
/** Traverses a branch. */ private void traverseBranch(Node n, Node parent) { int type = n.getType(); if (type == Token.SCRIPT) { inputId = n.getInputId(); sourceName = getSourceName(n); } curNode = n; if (!callback.shouldTraverse(this, n, parent)) { return; } if (type == Token.FUNCTION) { traverseFunction(n, parent); } else if (useBlockScope && NodeUtil.createsBlockScope(n)) { traverseBlockScope(n); } else { for (Node child = n.getFirstChild(); child != null; ) { // child could be replaced, in which case our child node // would no longer point to the true next Node next = child.getNext(); traverseBranch(child, n); child = next; } } curNode = n; callback.visit(this, n, parent); }
void traverseRoots(Node externs, Node root) { try { Node scopeRoot = externs.getParent(); Preconditions.checkState(scopeRoot != null); inputId = NodeUtil.getInputId(scopeRoot); sourceName = ""; curNode = scopeRoot; pushScope(scopeRoot); traverseBranch(externs, scopeRoot); Preconditions.checkState(root.getParent() == scopeRoot); traverseBranch(root, scopeRoot); popScope(); } catch (Exception unexpectedException) { throwUnexpectedException(unexpectedException); } }
/** * Traverse a function out-of-band of normal traversal. * * @param node The function node. * @param scope The scope the function is contained in. Does not fire enter/exit callback events * for this scope. */ public void traverseFunctionOutOfBand(Node node, Scope scope) { Preconditions.checkNotNull(scope); Preconditions.checkState(node.isFunction()); Preconditions.checkState(scope.getRootNode() != null); if (inputId == null) { inputId = NodeUtil.getInputId(node); } curNode = node.getParent(); pushScope(scope, true /* quietly */); traverseBranch(node, curNode); popScope(true /* quietly */); }
/** * Traverses a parse tree recursively with a scope, starting with the given root. This should only * be used in the global scope. Otherwise, use {@link #traverseAtScope}. */ void traverseWithScope(Node root, Scope s) { Preconditions.checkState(s.isGlobal()); try { inputId = null; sourceName = ""; curNode = root; pushScope(s); traverseBranch(root, null); popScope(); } catch (Exception unexpectedException) { throwUnexpectedException(unexpectedException); } }
/** Traverses a parse tree recursively. */ public void traverse(Node root) { try { inputId = NodeUtil.getInputId(root); sourceName = ""; curNode = root; pushScope(root); // null parent ensures that the shallow callbacks will traverse root traverseBranch(root, null); popScope(); } catch (Exception unexpectedException) { throwUnexpectedException(unexpectedException); } }