Skip to content

Commit c7d196e

Browse files
committed
Rename declarations and references in function bodies to avoid shadowing
names referenced in default parameters. ------------- Created by MOE: http://code.google.com/p/moe-java MOE_MIGRATED_REVID=70370026
1 parent f7b254d commit c7d196e

File tree

6 files changed

+409
-11
lines changed

6 files changed

+409
-11
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,138 @@
1+
/*
2+
* Copyright 2014 The Closure Compiler Authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package com.google.javascript.jscomp;
18+
19+
import com.google.common.collect.Lists;
20+
import com.google.javascript.jscomp.Es6ToEs3Converter.UniqueNameGenerator;
21+
import com.google.javascript.jscomp.NodeTraversal.AbstractPostOrderCallback;
22+
import com.google.javascript.jscomp.Scope.Var;
23+
import com.google.javascript.rhino.Node;
24+
25+
import java.util.HashMap;
26+
import java.util.HashSet;
27+
import java.util.Iterator;
28+
import java.util.Map;
29+
import java.util.Set;
30+
31+
/**
32+
* Renames declarations and references in function bodies to avoid shadowing
33+
* names referenced in default parameters.
34+
*
35+
* @author [email protected] (Michael Zhou)
36+
*/
37+
public class Es6HandleDefaultParameters extends AbstractPostOrderCallback
38+
implements HotSwapCompilerPass {
39+
40+
private final AbstractCompiler compiler;
41+
private final UniqueNameGenerator unique;
42+
43+
public Es6HandleDefaultParameters(AbstractCompiler compiler, UniqueNameGenerator unique) {
44+
this.compiler = compiler;
45+
this.unique = unique;
46+
}
47+
48+
@Override
49+
public void visit(NodeTraversal t, Node n, Node parent) {
50+
// Arrow functions without blocked body cannot have declarations in the body
51+
if (!n.isFunction() || !n.getLastChild().isBlock()) {
52+
return;
53+
}
54+
55+
Node paramList = n.getChildAtIndex(1);
56+
CollectReferences collector = new CollectReferences();
57+
for (Node child : paramList.children()) {
58+
if (child.isName() && child.hasChildren()) {
59+
NodeTraversal.traverse(compiler, child.getFirstChild(), collector);
60+
}
61+
}
62+
63+
Node block = paramList.getNext();
64+
Scope fBlockScope = new Es6SyntacticScopeCreator(compiler).createScope(block, null);
65+
Map<String, String> currFuncRenameMap = new HashMap<>();
66+
for (Iterator<Var> it = fBlockScope.getVars(); it.hasNext();) {
67+
Var var = it.next();
68+
String oldName = var.getName();
69+
if (collector.currFuncReferences.contains(oldName)
70+
&& !currFuncRenameMap.containsKey(oldName)) {
71+
currFuncRenameMap.put(oldName, unique.generate(oldName));
72+
}
73+
}
74+
new NodeTraversal(compiler,
75+
new RenameReferences(fBlockScope, currFuncRenameMap))
76+
.traverseInnerNode(block, block.getParent(), fBlockScope.getParent());
77+
}
78+
79+
@Override
80+
public void process(Node externs, Node root) {
81+
NodeTraversal.traverseRoots(compiler, Lists.newArrayList(externs, root), this);
82+
}
83+
84+
@Override
85+
public void hotSwapScript(Node scriptRoot, Node originalRoot) {
86+
NodeTraversal.traverse(compiler, scriptRoot, this);
87+
}
88+
89+
/**
90+
* Collects all references in a naive way.
91+
*/
92+
private class CollectReferences extends NodeTraversal.AbstractPostOrderCallback {
93+
94+
private final Set<String> currFuncReferences = new HashSet<>();
95+
96+
@Override
97+
public void visit(NodeTraversal t, Node n, Node parent) {
98+
if (!NodeUtil.isReferenceName(n)) {
99+
return;
100+
}
101+
currFuncReferences.add(n.getString());
102+
}
103+
}
104+
105+
/**
106+
* Renames declarations / references when necessary.
107+
*
108+
* TODO(moz): See if we can just use the one in Es6RewriteLetConst.
109+
*/
110+
private class RenameReferences extends AbstractPostOrderCallback {
111+
112+
private final Scope fBlockScope;
113+
private final Map<String, String> currParamListMap;
114+
115+
private RenameReferences(Scope scope, Map<String, String> map) {
116+
fBlockScope = scope;
117+
currParamListMap = map;
118+
}
119+
120+
@Override
121+
public void visit(NodeTraversal t, Node n, Node parent) {
122+
if (!NodeUtil.isReferenceName(n)) {
123+
return;
124+
}
125+
126+
Scope scope = t.getScope();
127+
String oldName = n.getString();
128+
if (scope.getRootNode() != fBlockScope.getRootNode()
129+
&& scope.isDeclared(oldName, false)) {
130+
return;
131+
}
132+
if (currParamListMap.containsKey(oldName)) {
133+
n.setString(currParamListMap.get(oldName));
134+
compiler.reportCodeChange();
135+
}
136+
}
137+
}
138+
}

src/com/google/javascript/jscomp/Es6RewriteLetConst.java

+7-8
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
import com.google.common.collect.LinkedHashMultimap;
2121
import com.google.common.collect.Lists;
2222
import com.google.common.collect.Multimap;
23+
import com.google.javascript.jscomp.Es6ToEs3Converter.UniqueNameGenerator;
2324
import com.google.javascript.jscomp.NodeTraversal.AbstractPostOrderCallback;
2425
import com.google.javascript.jscomp.Scope.Var;
2526
import com.google.javascript.rhino.IR;
@@ -43,16 +44,13 @@ public class Es6RewriteLetConst extends AbstractPostOrderCallback
4344
implements HotSwapCompilerPass {
4445

4546
private final AbstractCompiler compiler;
46-
private int uId;
4747
private final Map<Node, Map<String, String>> renameMap = new LinkedHashMap<>();
4848
private final Set<Node> letConsts = new HashSet<>();
49+
private final UniqueNameGenerator unique;
4950

50-
public Es6RewriteLetConst(AbstractCompiler compiler) {
51+
public Es6RewriteLetConst(AbstractCompiler compiler, UniqueNameGenerator unique) {
5152
this.compiler = compiler;
52-
}
53-
54-
private String newUniqueName(String name) {
55-
return name + "$" + uId++;
53+
this.unique = unique;
5654
}
5755

5856
@Override
@@ -76,7 +74,7 @@ public void visit(NodeTraversal t, Node n, Node parent) {
7674
boolean doRename = false;
7775
if (scope != hoistScope) {
7876
doRename = hoistScope.isDeclared(oldName, true);
79-
String newName = doRename ? newUniqueName(oldName) : oldName;
77+
String newName = doRename ? unique.generate(oldName) : oldName;
8078
Var oldVar = scope.getVar(oldName);
8179
scope.undeclare(oldVar);
8280
hoistScope.declare(newName, nameNode, null, oldVar.input);
@@ -228,7 +226,8 @@ public void visit(NodeTraversal t, Node n, Node parent) {
228226
functionHandledMap.put(function, name);
229227

230228
if (!loopObjectMap.containsKey(loopNode)) {
231-
loopObjectMap.put(loopNode, new LoopObject(newUniqueName(LOOP_OBJECT_NAME)));
229+
loopObjectMap.put(loopNode,
230+
new LoopObject(unique.generate(LOOP_OBJECT_NAME)));
232231
}
233232
LoopObject object = loopObjectMap.get(loopNode);
234233
object.vars.add(var);

src/com/google/javascript/jscomp/Es6ToEs3Converter.java

+14-2
Original file line numberDiff line numberDiff line change
@@ -82,20 +82,24 @@ public class Es6ToEs3Converter implements NodeTraversal.Callback, HotSwapCompile
8282

8383
private static final String MAKE_ITER = "$jscomp$make$iterator";
8484

85+
private final UniqueNameGenerator unique = new UniqueNameGenerator();
86+
8587
public Es6ToEs3Converter(AbstractCompiler compiler) {
8688
this.compiler = compiler;
8789
}
8890

8991
@Override
9092
public void process(Node externs, Node root) {
93+
new Es6HandleDefaultParameters(compiler, unique).process(externs, root);
9194
NodeTraversal.traverse(compiler, root, this);
92-
new Es6RewriteLetConst(compiler).process(externs, root);
95+
new Es6RewriteLetConst(compiler, unique).process(externs, root);
9396
}
9497

9598
@Override
9699
public void hotSwapScript(Node scriptRoot, Node originalRoot) {
100+
new Es6HandleDefaultParameters(compiler, unique).hotSwapScript(scriptRoot, originalRoot);
97101
NodeTraversal.traverse(compiler, scriptRoot, this);
98-
new Es6RewriteLetConst(compiler).hotSwapScript(scriptRoot, originalRoot);
102+
new Es6RewriteLetConst(compiler, unique).hotSwapScript(scriptRoot, originalRoot);
99103
}
100104

101105
/**
@@ -801,6 +805,14 @@ public void visit(NodeTraversal t, Node n, Node parent) {
801805

802806
}
803807

808+
static class UniqueNameGenerator {
809+
private int uId;
810+
811+
String generate(String name) {
812+
return name + "$" + uId++;
813+
}
814+
}
815+
804816
private void cannotConvert(Node n, String message) {
805817
compiler.report(JSError.make(n, CANNOT_CONVERT, message));
806818
}

0 commit comments

Comments
 (0)