diff --git a/src/com/google/javascript/jscomp/NameAnalyzer.java b/src/com/google/javascript/jscomp/NameAnalyzer.java index 9c4a51ed375..ff378873533 100644 --- a/src/com/google/javascript/jscomp/NameAnalyzer.java +++ b/src/com/google/javascript/jscomp/NameAnalyzer.java @@ -26,6 +26,7 @@ import com.google.common.collect.Iterables; import com.google.common.collect.LinkedListMultimap; import com.google.common.collect.ListMultimap; +import com.google.common.collect.Ordering; import com.google.common.io.Files; import com.google.javascript.jscomp.CodingConvention.SubclassRelationship; import com.google.javascript.jscomp.GatherSideEffectSubexpressionsCallback.GetReplacementSideEffectSubexpressions; @@ -37,7 +38,6 @@ import com.google.javascript.jscomp.graph.LinkedDirectedGraph; import com.google.javascript.rhino.IR; import com.google.javascript.rhino.Node; - import java.io.File; import java.io.IOException; import java.util.ArrayDeque; @@ -50,7 +50,6 @@ import java.util.List; import java.util.Map; import java.util.Set; -import java.util.TreeMap; /** * This pass identifies all global names, simple (e.g. a) or @@ -88,7 +87,7 @@ final class NameAnalyzer implements CompilerPass { private final AbstractCompiler compiler; /** Map of all JS names found */ - private final Map allNames = new TreeMap<>(); + private final Map allNames = new HashMap<>(); /** Reference dependency graph */ private LinkedDirectedGraph referenceGraph = @@ -204,6 +203,7 @@ private static class NameInformation { /** Whether this is a call that only affects the class definition */ boolean onlyAffectsClassDef = false; + @Override public String toString() { return "NameInformation:" + name; } @@ -1280,7 +1280,8 @@ String getHtmlReport() { sb.append(""); sb.append("ALL NAMES
    \n"); - for (JsName node : allNames.values()) { + // Sort before generating to ensure a consistent stable order + for (JsName node : Ordering.natural().sortedCopy(allNames.values())) { sb.append("
  • ").append(nameAnchor(node.name)).append("
      "); if (!node.prototypeNames.isEmpty()) { sb.append("
    • PROTOTYPES: "); @@ -1353,7 +1354,7 @@ private static String nameAnchor(String name) { */ private JsName getName(String name, boolean canCreate) { if (canCreate) { - createName(name); + return createName(name); } return allNames.get(name); } @@ -1364,13 +1365,14 @@ private JsName getName(String name, boolean canCreate) { * * @param name A fully qualified name */ - private void createName(String name) { + private JsName createName(String name) { JsName jsn = allNames.get(name); if (jsn == null) { jsn = new JsName(); jsn.name = name; allNames.put(name, jsn); } + return jsn; } /** @@ -1450,7 +1452,7 @@ private DiGraphNode getGraphNode(JsName name) { private void referenceParentNames() { // Duplicate set of nodes to process so we don't modify set we are // currently iterating over - Set allNamesCopy = new HashSet<>(allNames.values()); + JsName[] allNamesCopy = allNames.values().toArray(new JsName[0]); for (JsName name : allNamesCopy) { String curName = name.name; diff --git a/src/com/google/javascript/jscomp/graph/LinkedDirectedGraph.java b/src/com/google/javascript/jscomp/graph/LinkedDirectedGraph.java index dac34a3b008..946d86ac5a1 100644 --- a/src/com/google/javascript/jscomp/graph/LinkedDirectedGraph.java +++ b/src/com/google/javascript/jscomp/graph/LinkedDirectedGraph.java @@ -237,12 +237,26 @@ public boolean isConnectedInDirection( DiGraphNode dNode2) { // Verify the nodes. List> outEdges = dNode1.getOutEdges(); - int len = outEdges.size(); - for (int i = 0; i < len; i++) { - DiGraphEdge outEdge = outEdges.get(i); - if (outEdge.getDestination() == dNode2 - && edgeMatcher.apply(outEdge.getValue())) { - return true; + int outEdgesLen = outEdges.size(); + List> inEdges = dNode2.getInEdges(); + int inEdgesLen = inEdges.size(); + // It is possible that there is a large assymmetry between the nodes, so pick the direction + // to search based on the shorter list since the edge lists should be symmetric. + if (outEdgesLen < inEdgesLen) { + for (int i = 0; i < outEdgesLen; i++) { + DiGraphEdge outEdge = outEdges.get(i); + if (outEdge.getDestination() == dNode2 + && edgeMatcher.apply(outEdge.getValue())) { + return true; + } + } + } else { + for (int i = 0; i < inEdgesLen; i++) { + DiGraphEdge inEdge = inEdges.get(i); + if (inEdge.getSource() == dNode1 + && edgeMatcher.apply(inEdge.getValue())) { + return true; + } } } @@ -253,14 +267,7 @@ private boolean isConnectedInDirection(N n1, Predicate edgeMatcher, N n2) { // Verify the nodes. DiGraphNode dNode1 = getNodeOrFail(n1); DiGraphNode dNode2 = getNodeOrFail(n2); - for (DiGraphEdge outEdge : dNode1.getOutEdges()) { - if (outEdge.getDestination() == dNode2 - && edgeMatcher.apply(outEdge.getValue())) { - return true; - } - } - - return false; + return isConnectedInDirection(dNode1, edgeMatcher, dNode2); } @Override