Beispiel #1
0
  @Override
  public void process(Node externs, Node root) {
    assignmentLog = new StringBuilder();

    // Do variable reference counting.
    NodeTraversal.traverse(compiler, externs, new ProcessVars(true));
    NodeTraversal.traverse(compiler, root, new ProcessVars(false));

    // Make sure that new names don't overlap with extern names.
    reservedNames.addAll(externNames);

    // Rename vars, sorted by frequency of occurrence to minimize code size.
    SortedSet<Assignment> varsByFrequency = new TreeSet<Assignment>(FREQUENCY_COMPARATOR);
    varsByFrequency.addAll(assignments.values());

    if (shouldShadow) {
      new ShadowVariables(compiler, assignments, varsByFrequency, pseudoNameMap)
          .process(externs, root);
    }

    // First try to reuse names from an earlier compilation.
    if (prevUsedRenameMap != null) {
      reusePreviouslyUsedVariableMap();
    }

    // Assign names, sorted by descending frequency to minimize code size.
    assignNames(varsByFrequency);

    boolean changed = false;

    // Rename the globals!
    for (Node n : globalNameNodes) {
      String newName = getNewGlobalName(n);
      // Note: if newName is null, then oldName is an extern.
      if (newName != null) {
        n.setString(newName);
        changed = true;
      }
    }

    // Rename the locals!
    int count = 0;
    for (Node n : localNameNodes) {
      String newName = getNewLocalName(n);
      if (newName != null) {
        n.setString(newName);
        changed = true;
      }
      count++;
    }

    if (changed) {
      compiler.reportCodeChange();
    }

    // Lastly, write the name assignments to the debug log.
    compiler.addToDebugLog("JS var assignments:\n" + assignmentLog);
    assignmentLog = null;
  }
  /**
   * Removes any vars in the scope that were not referenced. Removes any assignments to those
   * variables as well.
   */
  private void removeUnreferencedVars() {
    CodingConvention convention = codingConvention;

    for (Iterator<Var> it = maybeUnreferenced.iterator(); it.hasNext(); ) {
      Var var = it.next();

      // Remove calls to inheritance-defining functions where the unreferenced
      // class is the subclass.
      for (Node exprCallNode : inheritsCalls.get(var)) {
        NodeUtil.removeChild(exprCallNode.getParent(), exprCallNode);
        compiler.reportCodeChange();
      }

      // Regardless of what happens to the original declaration,
      // we need to remove all assigns, because they may contain references
      // to other unreferenced variables.
      removeAllAssigns(var);

      compiler.addToDebugLog("Unreferenced var: " + var.name);
      Node nameNode = var.nameNode;
      Node toRemove = nameNode.getParent();
      Node parent = toRemove.getParent();

      Preconditions.checkState(
          toRemove.getType() == Token.VAR
              || toRemove.getType() == Token.FUNCTION
              || toRemove.getType() == Token.LP && parent.getType() == Token.FUNCTION,
          "We should only declare vars and functions and function args");

      if (toRemove.getType() == Token.LP && parent.getType() == Token.FUNCTION) {
        // Don't remove function arguments here. That's a special case
        // that's taken care of in removeUnreferencedFunctionArgs.
      } else if (NodeUtil.isFunctionExpression(toRemove)) {
        if (!preserveFunctionExpressionNames) {
          toRemove.getFirstChild().setString("");
          compiler.reportCodeChange();
        }
        // Don't remove bleeding functions.
      } else if (parent != null && parent.getType() == Token.FOR && parent.getChildCount() < 4) {
        // foreach iterations have 3 children. Leave them alone.
      } else if (toRemove.getType() == Token.VAR
          && nameNode.hasChildren()
          && NodeUtil.mayHaveSideEffects(nameNode.getFirstChild())) {
        // If this is a single var declaration, we can at least remove the
        // declaration itself and just leave the value, e.g.,
        // var a = foo(); => foo();
        if (toRemove.getChildCount() == 1) {
          parent.replaceChild(toRemove, new Node(Token.EXPR_RESULT, nameNode.removeFirstChild()));
          compiler.reportCodeChange();
        }
      } else if (toRemove.getType() == Token.VAR && toRemove.getChildCount() > 1) {
        // For var declarations with multiple names (i.e. var a, b, c),
        // only remove the unreferenced name
        toRemove.removeChild(nameNode);
        compiler.reportCodeChange();
      } else if (parent != null) {
        NodeUtil.removeChild(parent, toRemove);
        compiler.reportCodeChange();
      }
    }
  }