Example #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;
  }
    /**
     * Rename or remove labels.
     *
     * @param node The label node.
     * @param parent The parent of the label node.
     */
    private void visitLabel(Node node, Node parent) {
      Node nameNode = node.getFirstChild();
      Preconditions.checkState(nameNode != null);
      String name = nameNode.getString();
      LabelInfo li = getLabelInfo(name);
      // This is a label...
      if (li.referenced || !removeUnused) {
        String newName = getNameForId(li.id);
        if (!name.equals(newName)) {
          // ... and it is used, give it the short name.
          nameNode.setString(newName);
          compiler.reportCodeChange();
        }
      } else {
        // ... and it is not referenced, just remove it.
        Node newChild = node.getLastChild();
        node.removeChild(newChild);
        parent.replaceChild(node, newChild);
        if (newChild.isBlock()) {
          NodeUtil.tryMergeBlock(newChild);
        }
        compiler.reportCodeChange();
      }

      // Remove the label from the current stack of labels.
      namespaceStack.peek().renameMap.remove(name);
    }
  /**
   * Duplicates the PolymerElement externs with a different element base class if needed. For
   * example, if the base class is HTMLInputElement, then a class PolymerInputElement will be added.
   * If the element does not extend a native HTML element, this method is a no-op.
   */
  private void appendPolymerElementExterns(final ClassDefinition cls) {
    if (!nativeExternsAdded.add(cls.nativeBaseElement)) {
      return;
    }

    Node block = IR.block();

    Node baseExterns = polymerElementExterns.cloneTree();
    String polymerElementType = getPolymerElementType(cls);
    baseExterns.getFirstChild().setString(polymerElementType);

    String elementType = tagNameMap.get(cls.nativeBaseElement);
    JSTypeExpression elementBaseType =
        new JSTypeExpression(new Node(Token.BANG, IR.string(elementType)), VIRTUAL_FILE);
    JSDocInfoBuilder baseDocs = JSDocInfoBuilder.copyFrom(baseExterns.getJSDocInfo());
    baseDocs.changeBaseType(elementBaseType);
    baseExterns.setJSDocInfo(baseDocs.build());
    block.addChildToBack(baseExterns);

    for (Node baseProp : polymerElementProps) {
      Node newProp = baseProp.cloneTree();
      Node newPropRootName =
          NodeUtil.getRootOfQualifiedName(newProp.getFirstChild().getFirstChild());
      newPropRootName.setString(polymerElementType);
      block.addChildToBack(newProp);
    }

    Node parent = polymerElementExterns.getParent();
    Node stmts = block.removeChildren();
    parent.addChildrenAfter(stmts, polymerElementExterns);

    compiler.reportCodeChange();
  }
    @Override
    public void visit(NodeTraversal t, Node n, Node parent) {
      if (!NodeUtil.isReferenceName(n)) {
        return;
      }

      Scope referencedIn = t.getScope();
      String oldName = n.getString();
      Scope current = referencedIn;
      boolean doRename = false;
      String newName = null;
      while (current != null) {
        Map<String, String> renamesAtCurrentLevel = renameMap.get(current.getRootNode());
        if (current.isDeclared(oldName, false)) {
          return;
        } else if (renamesAtCurrentLevel != null && renamesAtCurrentLevel.containsKey(oldName)) {
          doRename = true;
          newName = renamesAtCurrentLevel.get(oldName);
          break;
        } else {
          current = current.getParent();
        }
      }
      if (doRename) {
        n.setString(newName);
        t.getCompiler().reportCodeChange();
      }
    }
 private void fixJsdocType(Scope scope, Node node) {
   if (node.isString()) {
     Polyfill polyfill = polyfills.statics.get(node.getString());
     // Note: all classes are unqualified names, so we don't need to deal with dots
     if (polyfill != null
         && scope.getVar(node.getString()) == null
         && !languageOutIsAtLeast(polyfill.nativeVersion)) {
       node.setString(polyfill.rewrite);
     }
   }
   for (Node child = node.getFirstChild(); child != null; child = child.getNext()) {
     fixJsdocType(scope, child);
   }
 }
  /** Renames all properties with references on more than one type. */
  void renameProperties() {
    int propsRenamed = 0,
        propsSkipped = 0,
        instancesRenamed = 0,
        instancesSkipped = 0,
        singleTypeProps = 0;

    for (Property prop : properties.values()) {
      if (prop.shouldRename()) {
        Map<T, String> propNames = buildPropNames(prop.getTypes(), prop.name);

        ++propsRenamed;
        prop.expandTypesToSkip();
        UnionFind<T> types = prop.getTypes();
        for (Node node : prop.renameNodes) {
          T rootType = prop.rootTypes.get(node);
          if (prop.shouldRename(rootType)) {
            String newName = propNames.get(rootType);
            node.setString(newName);
            compiler.reportCodeChange();
            ++instancesRenamed;
          } else {
            ++instancesSkipped;
          }
        }
      } else {
        if (prop.skipRenaming) {
          ++propsSkipped;
        } else {
          ++singleTypeProps;
        }
      }
    }
    logger.info("Renamed " + instancesRenamed + " instances of " + propsRenamed + " properties.");
    logger.info(
        "Skipped renaming "
            + instancesSkipped
            + " invalidated "
            + "properties, "
            + propsSkipped
            + " instances of properties "
            + "that were skipped for specific types and "
            + singleTypeProps
            + " properties that were referenced from only one type.");
  }
 /**
  * Rename label references in breaks and continues.
  *
  * @param node The break or continue node.
  */
 private void visitBreakOrContinue(Node node) {
   Node nameNode = node.getFirstChild();
   if (nameNode != null) {
     // This is a named break or continue;
     String name = nameNode.getString();
     Preconditions.checkState(!name.isEmpty());
     LabelInfo li = getLabelInfo(name);
     if (li != null) {
       String newName = getNameForId(li.id);
       // Mark the label as referenced so it isn't removed.
       li.referenced = true;
       if (!name.equals(newName)) {
         // Give it the short name.
         nameNode.setString(newName);
         compiler.reportCodeChange();
       }
     }
   }
 }
  @Override
  public void visit(NodeTraversal t, Node n, Node parent) {
    // TODO(moz): Add support for renaming classes.
    if (!n.isLet() && !n.isConst() && !NodeUtil.isBlockScopedFunctionDeclaration(n)) {
      return;
    }

    Scope scope = t.getScope();
    Node nameNode = n.getFirstChild();
    if (!n.isFunction()
        && !nameNode.hasChildren()
        && (parent == null || !NodeUtil.isEnhancedFor(parent))) {
      nameNode.addChildToFront(IR.name("undefined").useSourceInfoIfMissingFrom(nameNode));
    }

    String oldName = nameNode.getString();
    if (n.isLet() || n.isConst()) {
      blockScopedDeclarations.add(n);
    }
    Scope hoistScope = scope.getClosestHoistScope();
    boolean doRename = false;
    if (scope != hoistScope) {
      doRename = hoistScope.isDeclared(oldName, true) || undeclaredNames.contains(oldName);
      String newName =
          doRename ? oldName + "$" + compiler.getUniqueNameIdSupplier().get() : oldName;
      Var oldVar = scope.getVar(oldName);
      scope.undeclare(oldVar);
      hoistScope.declare(newName, nameNode, oldVar.input);
      if (doRename) {
        nameNode.setString(newName);
        Node scopeRoot = scope.getRootNode();
        if (!renameMap.containsKey(scopeRoot)) {
          renameMap.put(scopeRoot, new HashMap<String, String>());
        }

        renameMap.get(scopeRoot).put(oldName, newName);
      }
    }
    if (doRename) {
      t.getCompiler().reportCodeChange();
    }
  }
Example #9
0
    @Override
    public void visit(NodeTraversal t, Node n, Node parent) {
      if (!n.isName()) {
        return;
      }

      String name = n.getString();

      // Ignore anonymous functions
      if (name.length() == 0) {
        return;
      }

      // Is this local or Global?
      // Bleeding functions should be treated as part of their outer
      // scope, because IE has bugs in how it handles bleeding
      // functions.
      Scope.Var var = t.getScope().getVar(name);
      boolean local =
          (var != null)
              && var.isLocal()
              && (!var.scope.getParent().isGlobal() || !var.isBleedingFunction());

      // Are we renaming global variables?
      if (!local && localRenamingOnly) {
        reservedNames.add(name);
        return;
      }

      // Are we renaming function expression names?
      if (preserveFunctionExpressionNames
          && var != null
          && NodeUtil.isFunctionExpression(var.getParentNode())) {
        reservedNames.add(name);
        return;
      }

      // Check if we can rename this.
      if (!okToRenameVar(name, local)) {
        if (local) {
          // Blindly de-uniquify for the Prototype library for issue 103.
          String newName = MakeDeclaredNamesUnique.ContextualRenameInverter.getOrginalName(name);
          if (!newName.equals(name)) {
            n.setString(newName);
          }
        }
        return;
      }

      if (isExternsPass_) {
        // Keep track of extern globals.
        if (!local) {
          externNames.add(name);
        }
        return;
      }

      if (pseudoNameMap != null) {
        recordPseudoName(n);
      }

      if (local) {
        // Local var: assign a new name
        String tempName = LOCAL_VAR_PREFIX + getLocalVarIndex(var);
        incCount(tempName);
        localNameNodes.add(n);
        n.setString(tempName);
      } else if (var != null) { // Not an extern
        // If it's global, increment global count
        incCount(name);
        globalNameNodes.add(n);
      }
    }