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
+ }
0 commit comments