swc_ecma_transforms_base/rename/
ops.rs

1use rustc_hash::FxHashMap;
2use swc_common::{
3    util::{move_map::MoveMap, take::Take},
4    Spanned, SyntaxContext, DUMMY_SP,
5};
6use swc_ecma_ast::*;
7use swc_ecma_utils::stack_size::maybe_grow_default;
8use swc_ecma_visit::{noop_visit_mut_type, VisitMut, VisitMutWith};
9
10use crate::{
11    hygiene::Config,
12    perf::{cpu_count, ParExplode, Parallel, ParallelExt},
13    rename::RenamedVariable,
14};
15
16pub(super) struct Operator<'a, V>
17where
18    V: RenamedVariable,
19{
20    pub rename: &'a FxHashMap<Id, V>,
21    pub config: Config,
22
23    pub extra: Vec<ModuleItem>,
24}
25
26impl<V> Operator<'_, V>
27where
28    V: RenamedVariable,
29{
30    fn keep_class_name(&mut self, ident: &mut Ident, class: &mut Class) -> Option<ClassExpr> {
31        if !self.config.keep_class_names {
32            return None;
33        }
34
35        let mut orig_name = ident.clone();
36        orig_name.ctxt = SyntaxContext::empty();
37
38        {
39            // Remove span hygiene of the class.
40            let mut rename = FxHashMap::<Id, V>::default();
41
42            rename.insert(ident.to_id(), V::new_private(ident.sym.clone()));
43
44            let mut operator = Operator {
45                rename: &rename,
46                config: self.config.clone(),
47                extra: Default::default(),
48            };
49
50            class.visit_mut_with(&mut operator);
51        }
52
53        let _ = self.rename_ident(ident);
54        class.visit_mut_with(self);
55
56        let class_expr = ClassExpr {
57            ident: Some(orig_name),
58            class: Box::new(class.take()),
59        };
60
61        Some(class_expr)
62    }
63}
64
65impl<V> Parallel for Operator<'_, V>
66where
67    V: RenamedVariable,
68{
69    fn create(&self) -> Self {
70        Self {
71            rename: self.rename,
72            config: self.config.clone(),
73            extra: Default::default(),
74        }
75    }
76
77    fn merge(&mut self, other: Self) {
78        self.extra.extend(other.extra);
79    }
80
81    fn after_module_items(&mut self, stmts: &mut Vec<ModuleItem>) {
82        stmts.append(&mut self.extra);
83    }
84}
85
86impl<V> ParExplode for Operator<'_, V>
87where
88    V: RenamedVariable,
89{
90    fn after_one_stmt(&mut self, _: &mut Vec<Stmt>) {}
91
92    fn after_one_module_item(&mut self, stmts: &mut Vec<ModuleItem>) {
93        stmts.append(&mut self.extra);
94    }
95}
96
97impl<V> VisitMut for Operator<'_, V>
98where
99    V: RenamedVariable,
100{
101    noop_visit_mut_type!();
102
103    /// Preserve key of properties.
104    fn visit_mut_assign_pat_prop(&mut self, p: &mut AssignPatProp) {
105        if let Some(value) = &mut p.value {
106            value.visit_mut_children_with(self);
107        }
108    }
109
110    fn visit_mut_class_expr(&mut self, n: &mut ClassExpr) {
111        if let Some(ident) = &mut n.ident {
112            if let Some(expr) = self.keep_class_name(ident, &mut n.class) {
113                *n = expr;
114                return;
115            }
116        }
117
118        n.ident.visit_mut_with(self);
119
120        n.class.visit_mut_with(self);
121    }
122
123    fn visit_mut_decl(&mut self, decl: &mut Decl) {
124        match decl {
125            Decl::Class(cls) if self.config.keep_class_names => {
126                let span = cls.class.span;
127
128                let expr = self.keep_class_name(&mut cls.ident, &mut cls.class);
129                if let Some(expr) = expr {
130                    let var = VarDeclarator {
131                        span,
132                        name: cls.ident.clone().into(),
133                        init: Some(expr.into()),
134                        definite: false,
135                    };
136                    *decl = VarDecl {
137                        span,
138                        kind: VarDeclKind::Let,
139                        decls: vec![var],
140                        ..Default::default()
141                    }
142                    .into();
143                    return;
144                }
145
146                return;
147            }
148            _ => {}
149        }
150
151        decl.visit_mut_children_with(self);
152    }
153
154    fn visit_mut_export_named_specifier(&mut self, s: &mut ExportNamedSpecifier) {
155        if s.exported.is_some() {
156            s.orig.visit_mut_with(self);
157            return;
158        }
159
160        let exported = s.orig.clone();
161
162        if let ModuleExportName::Ident(orig) = &mut s.orig {
163            if self.rename_ident(orig).is_ok() {
164                match &exported {
165                    ModuleExportName::Ident(exported) => {
166                        if orig.sym == exported.sym {
167                            return;
168                        }
169                    }
170                    ModuleExportName::Str(_) => {}
171                    #[cfg(swc_ast_unknown)]
172                    _ => {}
173                }
174
175                s.exported = Some(exported);
176            }
177        }
178    }
179
180    fn visit_mut_expr(&mut self, n: &mut Expr) {
181        maybe_grow_default(|| n.visit_mut_children_with(self))
182    }
183
184    fn visit_mut_expr_or_spreads(&mut self, n: &mut Vec<ExprOrSpread>) {
185        self.maybe_par(cpu_count() * 100, n, |v, n| {
186            n.visit_mut_with(v);
187        })
188    }
189
190    fn visit_mut_exprs(&mut self, n: &mut Vec<Box<Expr>>) {
191        self.maybe_par(cpu_count() * 100, n, |v, n| {
192            n.visit_mut_with(v);
193        })
194    }
195
196    fn visit_mut_ident(&mut self, ident: &mut Ident) {
197        match self.rename_ident(ident) {
198            Ok(i) | Err(i) => i,
199        }
200    }
201
202    fn visit_mut_import_named_specifier(&mut self, s: &mut ImportNamedSpecifier) {
203        if s.imported.is_some() {
204            s.local.visit_mut_with(self);
205            return;
206        }
207
208        let imported = s.local.clone();
209        let local = self.rename_ident(&mut s.local);
210
211        if local.is_ok() {
212            if s.local.sym == imported.sym {
213                return;
214            }
215
216            s.imported = Some(ModuleExportName::Ident(imported));
217        }
218    }
219
220    /// Preserve key of properties.
221    fn visit_mut_key_value_pat_prop(&mut self, p: &mut KeyValuePatProp) {
222        p.key.visit_mut_with(self);
223        p.value.visit_mut_with(self);
224    }
225
226    fn visit_mut_key_value_prop(&mut self, p: &mut KeyValueProp) {
227        p.key.visit_mut_with(self);
228        p.value.visit_mut_with(self);
229    }
230
231    fn visit_mut_member_expr(&mut self, expr: &mut MemberExpr) {
232        expr.span.visit_mut_with(self);
233        expr.obj.visit_mut_with(self);
234
235        if let MemberProp::Computed(c) = &mut expr.prop {
236            c.visit_mut_with(self)
237        }
238    }
239
240    fn visit_mut_module_item(&mut self, item: &mut ModuleItem) {
241        let span = item.span();
242
243        macro_rules! export {
244            ($orig:expr, $ident:expr) => {
245                self.extra
246                    .push(ModuleItem::ModuleDecl(ModuleDecl::ExportNamed(
247                        NamedExport {
248                            span,
249                            specifiers: vec![ExportSpecifier::Named(ExportNamedSpecifier {
250                                span: DUMMY_SP,
251                                orig: $ident,
252                                exported: Some($orig),
253                                is_type_only: false,
254                            })],
255                            src: None,
256                            type_only: false,
257                            with: None,
258                        },
259                    )));
260            };
261        }
262
263        match item {
264            ModuleItem::ModuleDecl(ModuleDecl::ExportDecl(ExportDecl {
265                span,
266                decl:
267                    Decl::Class(ClassDecl {
268                        ident,
269                        class,
270                        declare,
271                    }),
272            })) => {
273                let mut ident = ident.take();
274                let mut class = class.take();
275
276                class.visit_mut_with(self);
277                let orig_ident = ident.clone();
278                match self.rename_ident(&mut ident) {
279                    Ok(..) => {
280                        *item = ClassDecl {
281                            ident: ident.clone(),
282                            class: class.take(),
283                            declare: *declare,
284                        }
285                        .into();
286                        export!(
287                            ModuleExportName::Ident(orig_ident),
288                            ModuleExportName::Ident(ident.take())
289                        );
290                    }
291                    Err(..) => {
292                        *item = ExportDecl {
293                            span: *span,
294                            decl: ClassDecl {
295                                ident: ident.take(),
296                                class: class.take(),
297                                declare: *declare,
298                            }
299                            .into(),
300                        }
301                        .into()
302                    }
303                }
304            }
305            ModuleItem::ModuleDecl(ModuleDecl::ExportDecl(ExportDecl {
306                span,
307                decl:
308                    Decl::Fn(FnDecl {
309                        ident,
310                        function,
311                        declare,
312                    }),
313            })) => {
314                let mut ident = ident.take();
315                let mut function = function.take();
316
317                function.visit_mut_with(self);
318                let orig_ident = ident.clone();
319                match self.rename_ident(&mut ident) {
320                    Ok(..) => {
321                        *item = FnDecl {
322                            ident: ident.clone(),
323                            function,
324                            declare: *declare,
325                        }
326                        .into();
327                        export!(
328                            ModuleExportName::Ident(orig_ident),
329                            ModuleExportName::Ident(ident)
330                        );
331                    }
332                    Err(..) => {
333                        *item = ExportDecl {
334                            span: *span,
335                            decl: FnDecl {
336                                ident,
337                                function,
338                                declare: *declare,
339                            }
340                            .into(),
341                        }
342                        .into()
343                    }
344                }
345            }
346            ModuleItem::ModuleDecl(ModuleDecl::ExportDecl(ExportDecl {
347                decl: Decl::Var(var),
348                ..
349            })) => {
350                let decls = var.decls.take();
351
352                let mut renamed: Vec<ExportSpecifier> = Vec::new();
353                let decls = decls.move_map(|mut decl| {
354                    decl.name.visit_mut_with(&mut VarFolder {
355                        orig: self,
356                        renamed: &mut renamed,
357                    });
358                    decl.init.visit_mut_with(self);
359                    decl
360                });
361
362                if renamed.is_empty() {
363                    *item = ExportDecl {
364                        span,
365                        decl: VarDecl {
366                            decls,
367                            ..*var.take()
368                        }
369                        .into(),
370                    }
371                    .into();
372                    return;
373                }
374                *item = VarDecl {
375                    decls,
376                    ..*var.take()
377                }
378                .into();
379                self.extra.push(
380                    NamedExport {
381                        span,
382                        specifiers: renamed,
383                        src: None,
384                        type_only: false,
385                        with: None,
386                    }
387                    .into(),
388                );
389            }
390            _ => {
391                item.visit_mut_children_with(self);
392            }
393        }
394    }
395
396    fn visit_mut_module_items(&mut self, nodes: &mut Vec<ModuleItem>) {
397        use std::mem::take;
398
399        #[cfg(feature = "concurrent")]
400        if nodes.len() >= 8 * cpu_count() {
401            ::swc_common::GLOBALS.with(|globals| {
402                use par_iter::prelude::*;
403
404                let (visitor, new_nodes) = take(nodes)
405                    .into_par_iter()
406                    .map(|mut node| {
407                        ::swc_common::GLOBALS.set(globals, || {
408                            let mut visitor = Parallel::create(&*self);
409                            node.visit_mut_with(&mut visitor);
410
411                            let mut nodes = Vec::with_capacity(4);
412
413                            ParExplode::after_one_module_item(&mut visitor, &mut nodes);
414
415                            nodes.push(node);
416
417                            (visitor, nodes)
418                        })
419                    })
420                    .reduce(
421                        || (Parallel::create(&*self), Vec::new()),
422                        |mut a, b| {
423                            Parallel::merge(&mut a.0, b.0);
424
425                            a.1.extend(b.1);
426
427                            a
428                        },
429                    );
430
431                Parallel::merge(self, visitor);
432
433                {
434                    self.after_module_items(nodes);
435                }
436
437                *nodes = new_nodes;
438            });
439
440            return;
441        }
442
443        let mut buf = Vec::with_capacity(nodes.len());
444
445        for mut node in take(nodes) {
446            let mut visitor = Parallel::create(&*self);
447            node.visit_mut_with(&mut visitor);
448            buf.push(node);
449            visitor.after_one_module_item(&mut buf);
450        }
451
452        self.after_module_items(&mut buf);
453
454        *nodes = buf;
455    }
456
457    fn visit_mut_named_export(&mut self, e: &mut NamedExport) {
458        if e.src.is_some() {
459            return;
460        }
461
462        e.visit_mut_children_with(self);
463    }
464
465    fn visit_mut_object_pat_prop(&mut self, n: &mut ObjectPatProp) {
466        n.visit_mut_children_with(self);
467
468        if let ObjectPatProp::Assign(p) = n {
469            let mut renamed = Ident::from(&p.key);
470            if self.rename_ident(&mut renamed).is_ok() {
471                if renamed.sym == p.key.sym {
472                    return;
473                }
474
475                *n = KeyValuePatProp {
476                    key: PropName::Ident(p.key.take().into()),
477                    value: match p.value.take() {
478                        Some(default_expr) => AssignPat {
479                            span: p.span,
480                            left: renamed.into(),
481                            right: default_expr,
482                        }
483                        .into(),
484                        None => renamed.into(),
485                    },
486                }
487                .into();
488            }
489        }
490    }
491
492    fn visit_mut_opt_vec_expr_or_spreads(&mut self, n: &mut Vec<Option<ExprOrSpread>>) {
493        self.maybe_par(cpu_count() * 100, n, |v, n| {
494            n.visit_mut_with(v);
495        })
496    }
497
498    fn visit_mut_prop(&mut self, prop: &mut Prop) {
499        match prop {
500            Prop::Shorthand(i) => {
501                let mut renamed = i.clone();
502                if self.rename_ident(&mut renamed).is_ok() {
503                    if renamed.sym == i.sym {
504                        return;
505                    }
506
507                    *prop = Prop::KeyValue(KeyValueProp {
508                        key: PropName::Ident(IdentName {
509                            // clear mark
510                            span: i.span,
511                            sym: i.sym.clone(),
512                        }),
513                        value: renamed.into(),
514                    })
515                }
516            }
517            _ => prop.visit_mut_children_with(self),
518        }
519    }
520
521    fn visit_mut_prop_name(&mut self, n: &mut PropName) {
522        if let PropName::Computed(c) = n {
523            c.visit_mut_with(self)
524        }
525    }
526
527    fn visit_mut_class_members(&mut self, members: &mut Vec<ClassMember>) {
528        self.maybe_par(cpu_count(), members, |v, member| {
529            member.visit_mut_with(v);
530        });
531    }
532
533    fn visit_mut_prop_or_spreads(&mut self, n: &mut Vec<PropOrSpread>) {
534        self.maybe_par(cpu_count() * 100, n, |v, n| {
535            n.visit_mut_with(v);
536        })
537    }
538
539    fn visit_mut_stmts(&mut self, nodes: &mut Vec<Stmt>) {
540        use std::mem::take;
541
542        #[cfg(feature = "concurrent")]
543        if nodes.len() >= 100 * cpu_count() {
544            ::swc_common::GLOBALS.with(|globals| {
545                use par_iter::prelude::*;
546
547                let (visitor, new_nodes) = take(nodes)
548                    .into_par_iter()
549                    .map(|mut node| {
550                        ::swc_common::GLOBALS.set(globals, || {
551                            let mut visitor = Parallel::create(&*self);
552                            node.visit_mut_with(&mut visitor);
553
554                            let mut nodes = Vec::with_capacity(4);
555
556                            ParExplode::after_one_stmt(&mut visitor, &mut nodes);
557
558                            nodes.push(node);
559
560                            (visitor, nodes)
561                        })
562                    })
563                    .reduce(
564                        || (Parallel::create(&*self), Vec::new()),
565                        |mut a, b| {
566                            Parallel::merge(&mut a.0, b.0);
567
568                            a.1.extend(b.1);
569
570                            a
571                        },
572                    );
573
574                Parallel::merge(self, visitor);
575
576                {
577                    self.after_stmts(nodes);
578                }
579
580                *nodes = new_nodes;
581            });
582
583            return;
584        }
585
586        let mut buf = Vec::with_capacity(nodes.len());
587
588        for mut node in take(nodes) {
589            let mut visitor = Parallel::create(&*self);
590            node.visit_mut_with(&mut visitor);
591            buf.push(node);
592            visitor.after_one_stmt(&mut buf);
593        }
594
595        self.after_stmts(&mut buf);
596
597        *nodes = buf;
598    }
599
600    fn visit_mut_super_prop_expr(&mut self, expr: &mut SuperPropExpr) {
601        expr.span.visit_mut_with(self);
602        if let SuperProp::Computed(c) = &mut expr.prop {
603            c.visit_mut_with(self);
604        }
605    }
606
607    fn visit_mut_var_declarators(&mut self, n: &mut Vec<VarDeclarator>) {
608        self.maybe_par(cpu_count() * 100, n, |v, n| {
609            n.visit_mut_with(v);
610        })
611    }
612}
613
614struct VarFolder<'a, 'b, V>
615where
616    V: RenamedVariable,
617{
618    orig: &'a mut Operator<'b, V>,
619    renamed: &'a mut Vec<ExportSpecifier>,
620}
621
622impl<V> VisitMut for VarFolder<'_, '_, V>
623where
624    V: RenamedVariable,
625{
626    noop_visit_mut_type!();
627
628    #[inline]
629    fn visit_mut_expr(&mut self, _: &mut Expr) {}
630
631    #[inline]
632    fn visit_mut_simple_assign_target(&mut self, _: &mut SimpleAssignTarget) {}
633
634    fn visit_mut_ident(&mut self, i: &mut Ident) {
635        let orig = i.clone();
636        if self.orig.rename_ident(i).is_ok() {
637            self.renamed
638                .push(ExportSpecifier::Named(ExportNamedSpecifier {
639                    span: i.span,
640                    exported: Some(ModuleExportName::Ident(orig)),
641                    orig: ModuleExportName::Ident(i.clone()),
642                    is_type_only: false,
643                }));
644        }
645    }
646}
647
648impl<V> Operator<'_, V>
649where
650    V: RenamedVariable,
651{
652    /// Returns `Ok(renamed_ident)` if ident should be renamed.
653    fn rename_ident(&mut self, ident: &mut Ident) -> Result<(), ()> {
654        if let Some(new_id) = self.rename.get(&ident.to_id()) {
655            let new_sym = new_id.atom();
656
657            if ident.sym.eq(new_sym) {
658                return Err(());
659            }
660
661            ident.ctxt = new_id.ctxt();
662            ident.sym = new_sym.clone();
663            return Ok(());
664        }
665
666        Err(())
667    }
668}