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 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 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 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 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 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}