/** 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);
  }
 @Override
 public Node getAstRoot(AbstractCompiler compiler) {
   Node root = ast.getAstRoot(compiler);
   // The root maybe null if the AST can not be created.
   if (root != null) {
     Preconditions.checkState(root.isScript());
     Preconditions.checkNotNull(root.getInputId());
   }
   return root;
 }
  /** Scans and gather variables declarations under a Node */
  private void scanVars(Node n) {
    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();
          declareVar(child);
          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(n.getFirstChild());
        return; // should not examine function's children

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

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

        declareVar(var);
        scanVars(block);
        return; // only one child to scan

      case Token.SCRIPT:
        inputId = n.getInputId();
        Preconditions.checkNotNull(inputId);
        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);
        child = next;
      }
    }
  }
 private void addInstaller(Node sourceNode, String function) {
   // Find the module
   InputId inputId = sourceNode.getInputId();
   CompilerInput input = inputId != null ? compiler.getInput(inputId) : null;
   JSModule module = input != null ? input.getModule() : null;
   InjectedInstaller injected = new InjectedInstaller(module, function);
   if (installers.add(injected)) {
     changed = true;
     Node installer = compiler.parseSyntheticCode(function).removeChildren();
     installer.useSourceInfoIfMissingFromForTree(sourceNode);
     Node enclosingScript = NodeUtil.getEnclosingScript(sourceNode);
     enclosingScript.addChildrenToFront(installer);
   }
 }
  /**
   * Updates the internal reference map based on the provided parameters. If {@code scriptRoot} is
   * not SCRIPT, it basically replaces the internal map with the new one, otherwise it replaces all
   * the information associated to the given script.
   *
   * @param refMapPatch The reference map result of a {@link ReferenceCollectingCallback} pass which
   *     might be collected from the whole AST or just a sub-tree associated to a SCRIPT node.
   * @param root AST sub-tree root on which reference collection was done.
   */
  void updateGlobalVarReferences(Map<Var, ReferenceCollection> refMapPatch, Node root) {
    if (refMap == null || !root.isScript()) {
      resetGlobalVarReferences(refMapPatch);
      return;
    }

    InputId inputId = root.getInputId();
    Preconditions.checkNotNull(inputId);
    // Note there are two assumptions here (i) the order of compiler inputs
    // has not changed and (ii) all references are in the order they appear
    // in AST (this is enforced in ReferenceCollectionCallback).
    removeScriptReferences(inputId);
    for (Entry<Var, ReferenceCollection> entry : refMapPatch.entrySet()) {
      Var var = entry.getKey();
      if (var.isGlobal()) {
        replaceReferences(var.getName(), inputId, entry.getValue());
      }
    }
  }
Example #6
0
  private void addThisVar(NodeTraversal t) {
    Scope scope = t.getScope();
    if (scope.isDeclared(THIS_VAR, false)) {
      return;
    }

    Node parent = t.getScopeRoot();
    if (parent.isFunction()) {
      // Add the new node at the beginning of the function body.
      parent = parent.getLastChild();
    }
    if (parent.isSyntheticBlock()) {
      // Add the new node inside the SCRIPT node instead of the
      // synthetic block that contains it.
      parent = parent.getFirstChild();
    }

    Node name = IR.name(THIS_VAR).srcref(parent);
    Node thisVar = IR.var(name, IR.thisNode().srcref(parent));
    thisVar.srcref(parent);
    parent.addChildToFront(thisVar);
    scope.declare(THIS_VAR, name, null, compiler.getInput(parent.getInputId()));
  }
  private void addVarDecls(NodeTraversal t, boolean addThis, boolean addArguments) {
    Scope scope = t.getScope();
    if (scope.isDeclared(THIS_VAR, false)) {
      addThis = false;
    }
    if (scope.isDeclared(ARGUMENTS_VAR, false)) {
      addArguments = false;
    }

    Node parent = t.getScopeRoot();
    if (parent.isFunction()) {
      // Add the new node at the beginning of the function body.
      parent = parent.getLastChild();
    }
    if (parent.isSyntheticBlock() && parent.getFirstChild().isScript()) {
      // Add the new node inside the SCRIPT node instead of the
      // synthetic block that contains it.
      parent = parent.getFirstChild();
    }

    CompilerInput input = compiler.getInput(parent.getInputId());
    if (addArguments) {
      Node name = IR.name(ARGUMENTS_VAR).srcref(parent);
      Node argumentsVar = IR.var(name, IR.name("arguments").srcref(parent));
      argumentsVar.srcref(parent);
      parent.addChildToFront(argumentsVar);
      scope.declare(ARGUMENTS_VAR, name, null, input);
    }
    if (addThis) {
      Node name = IR.name(THIS_VAR).srcref(parent);
      Node thisVar = IR.var(name, IR.thisNode().srcref(parent));
      thisVar.srcref(parent);
      parent.addChildToFront(thisVar);
      scope.declare(THIS_VAR, name, null, input);
    }
  }
Example #8
0
 private void validateHasInputId(Node n) {
   InputId inputId = n.getInputId();
   if (inputId == null) {
     violation("Missing 'input id' annotation.", n);
   }
 }