/* * Copyright 2004 The Closure Compiler Authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.javascript.jscomp; import com.google.javascript.rhino.Node; import java.util.logging.Logger; /** * Gives anonymous function names. This makes it way easier to debug because * debuggers and stack traces use the function names. So if you have * * goog.string.htmlEscape = function(str) { * } * * It will become * * goog.string.htmlEscape = function $goog$string$htmlEscape$(str) { * } * */ class NameAnonymousFunctions implements CompilerPass { private static final Logger logger = Logger.getLogger( NameAnonymousFunctions.class.getName()); static final char DELIMITER = '$'; private final AbstractCompiler compiler; private int namedCount = 0; private int bytesUsed = 0; NameAnonymousFunctions(AbstractCompiler compiler) { this.compiler = compiler; } @Override public void process(Node externs, Node root) { AnonymousFunctionNamingCallback namingCallback = new AnonymousFunctionNamingCallback(new AnonymousFunctionNamer()); NodeTraversal.traverseEs6(compiler, root, namingCallback); logger.fine("Named " + namedCount + " anon functions using " + bytesUsed + " bytes"); } /** * Names anonymous functions. The function names don't have to be globally * unique or even locally unique. We make them somewhat unique because of a * bug in IE (and there may be other bugs we haven't found). See unit test for * more info. */ private class AnonymousFunctionNamer implements AnonymousFunctionNamingCallback.FunctionNamer { private final NodeNameExtractor nameExtractor; AnonymousFunctionNamer() { this.nameExtractor = new NodeNameExtractor(DELIMITER); } /** * Returns a likely not conflicting name to make IE happy. See unit test * for more info. */ private String getLikelyNonConflictingName(String name) { return DELIMITER + name + DELIMITER; } @Override public final String getName(Node node) { return nameExtractor.getName(node); } @Override public final void setFunctionName(String name, Node fnNode) { Node fnNameNode = fnNode.getFirstChild(); String uniqueName = getLikelyNonConflictingName(name); fnNameNode.setString(uniqueName); compiler.reportChangeToEnclosingScope(fnNameNode); namedCount++; bytesUsed += uniqueName.length(); } @Override public final String getCombinedName(String lhs, String rhs) { return lhs + DELIMITER + rhs; } } }