swc_ecma_compat_es2015/
function_name.rs1use swc_common::{util::take::Take, DUMMY_SP};
2use swc_ecma_ast::*;
3use swc_ecma_transforms_base::perf::Parallel;
4use swc_ecma_utils::{private_ident, IdentUsageFinder};
5use swc_ecma_visit::{noop_visit_mut_type, visit_mut_pass, VisitMut, VisitMutWith};
6use swc_trace_macro::swc_trace;
7
8pub fn function_name() -> impl Pass {
26 visit_mut_pass(FnName)
27}
28
29#[derive(Clone, Copy)]
30struct FnName;
31
32impl Parallel for FnName {
33 fn create(&self) -> Self {
34 *self
35 }
36
37 fn merge(&mut self, _: Self) {}
38}
39
40struct Rename {
41 name: Option<Ident>,
42}
43
44fn prepare(i: Ident) -> Ident {
46 if i.is_reserved() || i.is_reserved_in_strict_mode(true) || i.is_reserved_in_strict_bind() {
47 return private_ident!(i.span, format!("_{}", i.sym));
48 }
49
50 private_ident!(i.span, i.sym)
51}
52
53#[swc_trace]
54impl VisitMut for FnName {
55 noop_visit_mut_type!(fail);
56
57 fn visit_mut_assign_expr(&mut self, expr: &mut AssignExpr) {
58 expr.visit_mut_children_with(self);
59
60 if expr.op != op!("=") {
61 return;
62 }
63
64 if let Some(ident) = expr.left.as_ident_mut() {
65 let mut folder = Rename {
66 name: Some(Ident::from(&*ident)),
67 };
68
69 expr.right.visit_mut_with(&mut folder);
70 }
71 }
72
73 fn visit_mut_key_value_prop(&mut self, p: &mut KeyValueProp) {
74 p.visit_mut_children_with(self);
75
76 if let Expr::Fn(expr @ FnExpr { ident: None, .. }) = &mut *p.value {
77 p.value = if let PropName::Ident(ref i) = p.key {
79 FnExpr {
80 ident: Some(prepare(i.clone().into())),
81 ..expr.take()
82 }
83 .into()
84 } else {
85 expr.take().into()
86 };
87 };
88 }
89
90 fn visit_mut_var_declarator(&mut self, decl: &mut VarDeclarator) {
91 decl.visit_mut_children_with(self);
92
93 if let Pat::Ident(ref mut ident) = decl.name {
94 let mut folder = Rename {
95 name: Some(prepare(Ident::from(&*ident))),
96 };
97 decl.init.visit_mut_with(&mut folder);
98 }
99 }
100}
101
102macro_rules! impl_for {
103 ($name:ident, $T:tt) => {
104 fn $name(&mut self, node: &mut $T) {
105 match node.ident {
106 Some(..) => return,
107 None => {
108 let name = match self.name.take() {
110 None => {
111 node.ident = None;
112 return;
113 }
114 Some(name) => name,
115 };
116 if IdentUsageFinder::find(&name.to_id(), &*node) {
119 node.ident = None;
121 } else {
122 node.ident = Some(private_ident!(DUMMY_SP, name.sym));
123 }
124 }
125 }
126 }
127 };
128}
129
130macro_rules! noop {
131 ($name:ident, $T:tt) => {
132 fn $name(&mut self, _: &mut $T) {}
134 };
135}
136
137impl VisitMut for Rename {
138 noop_visit_mut_type!(fail);
139
140 impl_for!(visit_mut_fn_expr, FnExpr);
141
142 impl_for!(visit_mut_class_expr, ClassExpr);
143
144 noop!(visit_mut_object_lit, ObjectLit);
145
146 noop!(visit_mut_array_lit, ArrayLit);
147
148 noop!(visit_mut_call_expr, CallExpr);
149
150 noop!(visit_mut_new_expr, NewExpr);
151
152 noop!(visit_mut_bin_expr, BinExpr);
153
154 noop!(visit_mut_unary_expr, UnaryExpr);
155}