swc_ecma_transforms_base/rename/analyzer/
mod.rs1use swc_common::Mark;
2use swc_ecma_ast::*;
3
4use self::scope::{Scope, ScopeKind};
5
6mod reverse_map;
7pub(super) mod scope;
8
9#[derive(Debug, Default)]
10pub(super) struct Analyzer {
11 pub(super) has_eval: bool,
14 pub(super) top_level_mark: Mark,
16
17 pub(super) is_pat_decl: bool,
18 pub(super) var_belong_to_fn_scope: bool,
19 pub(super) in_catch_params: bool,
20 pub(super) scope: Scope,
21 pub(super) hoisted_vars: Vec<Id>,
25
26 pub(super) skip_first_fn_or_class_decl: bool,
27 pub(super) is_first_node: bool,
28}
29
30impl Analyzer {
31 pub(super) fn new(
32 has_eval: bool,
33 top_level_mark: Mark,
34 skip_first_fn_or_class_decl: bool,
35 ) -> Self {
36 Self {
37 has_eval,
38 top_level_mark,
39 skip_first_fn_or_class_decl,
40 is_first_node: true,
41 hoisted_vars: Vec::with_capacity(32),
42 ..Default::default()
43 }
44 }
45
46 pub(super) fn add_decl(&mut self, id: Id, belong_to_fn_scope: bool) {
47 if belong_to_fn_scope {
48 match self.scope.kind {
49 ScopeKind::Fn => {
50 self.scope.add_decl(&id, self.has_eval, self.top_level_mark);
51 }
52 ScopeKind::Block => self.hoisted_vars.push(id),
53 }
54 } else {
55 self.scope.add_decl(&id, self.has_eval, self.top_level_mark);
56 }
57 }
58
59 fn reserve_decl(&mut self, len: usize, belong_to_fn_scope: bool) {
60 if belong_to_fn_scope {
61 match self.scope.kind {
62 ScopeKind::Fn => {
63 self.scope.reserve_decl(len);
64 }
65 ScopeKind::Block => {
66 self.hoisted_vars.reserve(len);
67 }
68 }
69 } else {
70 self.scope.reserve_decl(len);
71 }
72 }
73
74 pub(super) fn add_usage(&mut self, id: Id) {
75 self.scope.add_usage(id);
76 }
77
78 fn reserve_usage(&mut self, len: usize) {
79 self.scope.reserve_usage(len);
80 }
81
82 fn enter_scope(&mut self, kind: ScopeKind) -> Self {
83 let mut analyer = Analyzer {
84 has_eval: self.has_eval,
85 top_level_mark: self.top_level_mark,
86 is_pat_decl: self.is_pat_decl,
87 var_belong_to_fn_scope: false,
88 in_catch_params: false,
89 scope: Scope {
90 kind,
91 ..Default::default()
92 },
93 skip_first_fn_or_class_decl: false,
94 is_first_node: false,
95 hoisted_vars: Default::default(),
96 };
97 std::mem::swap(self, &mut analyer);
98 analyer }
100
101 pub(super) fn enter_fn_scope(&mut self) -> Self {
102 self.enter_scope(ScopeKind::Fn)
103 }
104
105 pub(super) fn enter_block_scope(&mut self) -> Self {
106 self.enter_scope(ScopeKind::Block)
107 }
108
109 pub(super) fn exit_scope(&mut self, mut v: Self) {
110 std::mem::swap(self, &mut v);
111 if !v.hoisted_vars.is_empty() {
112 debug_assert!(matches!(v.scope.kind, ScopeKind::Block));
113 self.reserve_usage(v.hoisted_vars.len());
114 v.hoisted_vars.clone().into_iter().for_each(|id| {
115 v.add_usage(id);
119 });
120 match self.scope.kind {
121 ScopeKind::Fn => {
122 self.reserve_decl(v.hoisted_vars.len(), true);
123 v.hoisted_vars
124 .into_iter()
125 .for_each(|id| self.add_decl(id, true));
126 }
127 ScopeKind::Block => {
128 self.hoisted_vars.extend(v.hoisted_vars);
129 }
130 }
131 }
132 self.scope.children.push(v.scope);
133 }
134
135 pub(super) fn handle_binding_ident(&mut self, node: &BindingIdent) {
136 if self.is_pat_decl {
137 self.add_decl(node.to_id(), self.var_belong_to_fn_scope)
138 } else {
139 self.add_usage(node.to_id())
140 }
141 }
142
143 pub(super) fn handle_class_decl(&mut self, node: &ClassDecl) {
144 if self.is_first_node && self.skip_first_fn_or_class_decl {
145 self.is_first_node = false;
146 return;
147 }
148 self.is_first_node = false;
149 self.add_decl(node.ident.to_id(), false);
150 }
151
152 pub(super) fn handle_class_expr(&mut self, node: &ClassExpr) {
153 if let Some(id) = &node.ident {
154 self.add_decl(id.to_id(), false);
155 }
156 }
157
158 pub(super) fn handle_fn_expr(&mut self, node: &FnExpr) {
159 if let Some(id) = &node.ident {
160 self.add_decl(id.to_id(), true);
161 }
162 }
163
164 pub(super) fn handle_export_named_specifier(&mut self, n: &ExportNamedSpecifier) {
165 match &n.orig {
166 ModuleExportName::Ident(orig) => {
167 self.add_usage(orig.to_id());
168 }
169 ModuleExportName::Str(..) => {}
170 #[cfg(swc_ast_unknown)]
171 _ => {}
172 };
173 }
174
175 pub(super) fn handle_expr(&mut self, e: &Expr) {
176 if let Expr::Ident(i) = e {
177 self.add_usage(i.to_id());
178 }
179 }
180
181 pub(super) fn handle_prop(&mut self, node: &Prop) {
182 if let Prop::Shorthand(i) = node {
183 self.add_usage(i.to_id());
184 }
185 }
186}