swc_ecma_transforms_base/rename/
mod.rs1#![allow(unused_imports)]
2
3use std::{borrow::Cow, collections::hash_map::Entry};
4
5use rustc_hash::{FxHashMap, FxHashSet};
6use swc_atoms::Atom;
7use swc_ecma_ast::*;
8use swc_ecma_utils::stack_size::maybe_grow_default;
9use swc_ecma_visit::{
10 noop_visit_mut_type, visit_mut_pass, Fold, VisitMut, VisitMutWith, VisitWith,
11};
12
13#[cfg(feature = "concurrent-renamer")]
14use self::renamer_concurrent::{Send, Sync};
15#[cfg(not(feature = "concurrent-renamer"))]
16use self::renamer_single::{Send, Sync};
17use self::{
18 analyzer::Analyzer,
19 collector::{collect_decls, CustomBindingCollector, IdCollector},
20 eval::contains_eval,
21 ops::Operator,
22};
23use crate::hygiene::Config;
24
25mod analyzer;
26mod collector;
27mod eval;
28mod ops;
29
30pub trait Renamer: Send + Sync {
31 const RESET_N: bool;
33
34 const MANGLE: bool;
36
37 fn preserved_ids_for_module(&mut self, _: &Module) -> FxHashSet<Id> {
38 Default::default()
39 }
40
41 fn preserved_ids_for_script(&mut self, _: &Script) -> FxHashSet<Id> {
42 Default::default()
43 }
44
45 fn get_cached(&self) -> Option<Cow<RenameMap>> {
46 None
47 }
48
49 fn store_cache(&mut self, _update: &RenameMap) {}
50
51 fn new_name_for(&self, orig: &Id, n: &mut usize) -> Atom;
53}
54
55pub type RenameMap = FxHashMap<Id, Atom>;
56
57pub fn rename(map: &RenameMap) -> impl '_ + Pass + VisitMut {
58 rename_with_config(map, Default::default())
59}
60
61pub fn rename_with_config(map: &RenameMap, config: Config) -> impl '_ + Pass + VisitMut {
62 visit_mut_pass(Operator {
63 rename: map,
64 config,
65 extra: Default::default(),
66 })
67}
68
69pub fn remap(map: &FxHashMap<Id, Id>, config: Config) -> impl '_ + Pass + VisitMut {
70 visit_mut_pass(Operator {
71 rename: map,
72 config,
73 extra: Default::default(),
74 })
75}
76
77pub fn renamer<R>(config: Config, renamer: R) -> impl Pass + VisitMut
78where
79 R: Renamer,
80{
81 visit_mut_pass(RenamePass {
82 config,
83 renamer,
84 preserved: Default::default(),
85 unresolved: Default::default(),
86 previous_cache: Default::default(),
87 total_map: None,
88 })
89}
90
91#[derive(Debug, Default)]
92struct RenamePass<R>
93where
94 R: Renamer,
95{
96 config: Config,
97 renamer: R,
98
99 preserved: FxHashSet<Id>,
100 unresolved: FxHashSet<Atom>,
101
102 previous_cache: RenameMap,
103
104 total_map: Option<RenameMap>,
108}
109
110impl<R> RenamePass<R>
111where
112 R: Renamer,
113{
114 fn get_unresolved<N>(&self, n: &N, has_eval: bool) -> FxHashSet<Atom>
115 where
116 N: VisitWith<IdCollector> + VisitWith<CustomBindingCollector<Id>>,
117 {
118 let usages = {
119 let mut v = IdCollector {
120 ids: Default::default(),
121 };
122 n.visit_with(&mut v);
123 v.ids
124 };
125 let (decls, preserved) = collect_decls(
126 n,
127 if has_eval {
128 Some(self.config.top_level_mark)
129 } else {
130 None
131 },
132 );
133 usages
134 .into_iter()
135 .filter(|used_id| !decls.contains(used_id))
136 .map(|v| v.0)
137 .chain(preserved.into_iter().map(|v| v.0))
138 .collect()
139 }
140
141 fn get_map<N>(&mut self, node: &N, skip_one: bool, top_level: bool, has_eval: bool) -> RenameMap
142 where
143 N: VisitWith<IdCollector> + VisitWith<CustomBindingCollector<Id>>,
144 N: VisitWith<Analyzer>,
145 {
146 let mut scope = {
147 let mut v = Analyzer {
148 has_eval,
149 top_level_mark: self.config.top_level_mark,
150
151 ..Default::default()
152 };
153 if skip_one {
154 node.visit_children_with(&mut v);
155 } else {
156 node.visit_with(&mut v);
157 }
158 v.scope
159 };
160 scope.prepare_renaming();
161
162 let mut map = RenameMap::default();
163
164 let mut unresolved = if !top_level {
165 let mut unresolved = self.unresolved.clone();
166 unresolved.extend(self.get_unresolved(node, has_eval));
167 Cow::Owned(unresolved)
168 } else {
169 Cow::Borrowed(&self.unresolved)
170 };
171
172 if !self.preserved.is_empty() {
173 unresolved
174 .to_mut()
175 .extend(self.preserved.iter().map(|v| v.0.clone()));
176 }
177
178 if !self.config.preserved_symbols.is_empty() {
179 unresolved
180 .to_mut()
181 .extend(self.config.preserved_symbols.iter().cloned());
182 }
183
184 if R::MANGLE {
185 let cost = scope.rename_cost();
186 scope.rename_in_mangle_mode(
187 &self.renamer,
188 &mut map,
189 &self.previous_cache,
190 &Default::default(),
191 &self.preserved,
192 &unresolved,
193 cost > 1024,
194 );
195 } else {
196 scope.rename_in_normal_mode(
197 &self.renamer,
198 &mut map,
199 &self.previous_cache,
200 &mut Default::default(),
201 &self.preserved,
202 &unresolved,
203 );
204 }
205
206 if let Some(total_map) = &mut self.total_map {
207 total_map.reserve(map.len());
208
209 for (k, v) in &map {
210 match total_map.entry(k.clone()) {
211 Entry::Occupied(old) => {
212 unreachable!(
213 "{} is already renamed to {}, but it's renamed as {}",
214 k.0,
215 old.get(),
216 v
217 );
218 }
219 Entry::Vacant(e) => {
220 e.insert(v.clone());
221 }
222 }
223 }
224 }
225
226 map
227 }
228
229 fn load_cache(&mut self) {
230 if let Some(cache) = self.renamer.get_cached() {
231 self.previous_cache = cache.into_owned();
232 self.total_map = Some(Default::default());
233 }
234 }
235}
236
237macro_rules! unit {
241 ($name:ident, $T:ty) => {
242 fn $name(&mut self, n: &mut $T) {
244 if !self.config.ignore_eval && contains_eval(n, true) {
245 n.visit_mut_children_with(self);
246 } else {
247 let map = self.get_map(n, false, false, false);
248
249 if !map.is_empty() {
250 n.visit_mut_with(&mut rename_with_config(&map, self.config.clone()));
251 }
252 }
253 }
254 };
255 ($name:ident, $T:ty, true) => {
256 fn $name(&mut self, n: &mut $T) {
258 if !self.config.ignore_eval && contains_eval(n, true) {
259 n.visit_mut_children_with(self);
260 } else {
261 let map = self.get_map(n, true, false, false);
262
263 if !map.is_empty() {
264 n.visit_mut_with(&mut rename_with_config(&map, self.config.clone()));
265 }
266 }
267 }
268 };
269}
270
271impl<R> VisitMut for RenamePass<R>
272where
273 R: Renamer,
274{
275 noop_visit_mut_type!();
276
277 unit!(visit_mut_arrow_expr, ArrowExpr);
278
279 unit!(visit_mut_setter_prop, SetterProp);
280
281 unit!(visit_mut_getter_prop, GetterProp);
282
283 unit!(visit_mut_constructor, Constructor);
284
285 unit!(visit_mut_fn_expr, FnExpr);
286
287 unit!(visit_mut_method_prop, MethodProp);
288
289 unit!(visit_mut_class_method, ClassMethod);
290
291 unit!(visit_mut_private_method, PrivateMethod);
292
293 fn visit_mut_fn_decl(&mut self, n: &mut FnDecl) {
294 if !self.config.ignore_eval && contains_eval(n, true) {
295 n.visit_mut_children_with(self);
296 } else {
297 let id = n.ident.to_id();
298 let inserted = self.preserved.insert(id.clone());
299 let map = self.get_map(n, true, false, false);
300
301 if inserted {
302 self.preserved.remove(&id);
303 }
304
305 if !map.is_empty() {
306 n.visit_mut_with(&mut rename_with_config(&map, self.config.clone()));
307 }
308 }
309 }
310
311 fn visit_mut_class_decl(&mut self, n: &mut ClassDecl) {
312 if !self.config.ignore_eval && contains_eval(n, true) {
313 n.visit_mut_children_with(self);
314 } else {
315 let id = n.ident.to_id();
316 let inserted = self.preserved.insert(id.clone());
317 let map = self.get_map(n, true, false, false);
318
319 if inserted {
320 self.preserved.remove(&id);
321 }
322
323 if !map.is_empty() {
324 n.visit_mut_with(&mut rename_with_config(&map, self.config.clone()));
325 }
326 }
327 }
328
329 fn visit_mut_default_decl(&mut self, n: &mut DefaultDecl) {
330 match n {
331 DefaultDecl::Class(n) => {
332 n.visit_mut_children_with(self);
333 }
334 DefaultDecl::Fn(n) => {
335 n.visit_mut_children_with(self);
336 }
337 DefaultDecl::TsInterfaceDecl(n) => {
338 n.visit_mut_children_with(self);
339 }
340 }
341 }
342
343 fn visit_mut_expr(&mut self, n: &mut Expr) {
344 maybe_grow_default(|| n.visit_mut_children_with(self));
345 }
346
347 fn visit_mut_module(&mut self, m: &mut Module) {
348 self.load_cache();
349
350 self.preserved = self.renamer.preserved_ids_for_module(m);
351
352 let has_eval = !self.config.ignore_eval && contains_eval(m, true);
353
354 self.unresolved = self.get_unresolved(m, has_eval);
355
356 let map = self.get_map(m, false, true, has_eval);
357
358 if has_eval {
380 m.visit_mut_children_with(self);
381 }
382
383 if !map.is_empty() {
384 m.visit_mut_with(&mut rename_with_config(&map, self.config.clone()));
385 }
386
387 if let Some(total_map) = &self.total_map {
388 self.renamer.store_cache(total_map);
389 }
390 }
391
392 fn visit_mut_script(&mut self, m: &mut Script) {
393 self.load_cache();
394
395 self.preserved = self.renamer.preserved_ids_for_script(m);
396
397 let has_eval = !self.config.ignore_eval && contains_eval(m, true);
398
399 self.unresolved = self.get_unresolved(m, has_eval);
400
401 let map = self.get_map(m, false, true, has_eval);
402
403 if has_eval {
404 m.visit_mut_children_with(self);
405 }
406
407 if !map.is_empty() {
408 m.visit_mut_with(&mut rename_with_config(&map, self.config.clone()));
409 }
410
411 if let Some(total_map) = &self.total_map {
412 self.renamer.store_cache(total_map);
413 }
414 }
415}
416
417#[cfg(feature = "concurrent-renamer")]
418mod renamer_concurrent {
419 pub use std::marker::{Send, Sync};
420}
421
422#[cfg(not(feature = "concurrent-renamer"))]
423mod renamer_single {
424 pub trait Send {}
426 pub trait Sync {}
428
429 impl<T> Send for T where T: ?Sized {}
430 impl<T> Sync for T where T: ?Sized {}
431}