swc_ecma_transforms_base/rename/
analyer_and_collector.rs1use std::hash::Hash;
2
3use rustc_hash::FxHashSet;
4use swc_atoms::Atom;
5use swc_common::{Mark, SyntaxContext};
6use swc_ecma_ast::*;
7use swc_ecma_utils::{ident::IdentLike, stack_size::maybe_grow_default};
8use swc_ecma_visit::{noop_visit_type, Visit, VisitWith};
9
10use super::{analyzer::scope::Scope, Analyzer};
11
12struct IdCollector {
13 ids: FxHashSet<Id>,
14 stopped: bool,
15}
16
17impl IdCollector {
18 fn handle_ident(&mut self, n: &Ident) {
19 if !self.stopped && n.ctxt != SyntaxContext::empty() {
20 self.ids.insert(n.to_id());
21 }
22 }
23}
24
25struct CustomBindingCollector<I>
26where
27 I: IdentLike + Eq + Hash + Send + Sync,
28{
29 bindings: FxHashSet<I>,
30 preserved: FxHashSet<I>,
31 is_pat_decl: bool,
32
33 pub top_level_for_eval: Option<SyntaxContext>,
35}
36
37impl<I> CustomBindingCollector<I>
38where
39 I: IdentLike + Eq + Hash + Send + Sync,
40{
41 fn add(&mut self, i: &Ident) {
42 if let Some(top_level_ctxt) = self.top_level_for_eval {
43 if i.ctxt == top_level_ctxt {
44 self.preserved.insert(I::from_ident(i));
45 return;
46 }
47 }
48
49 self.bindings.insert(I::from_ident(i));
50 }
51
52 fn handle_assign_pat_prop(&mut self, node: &AssignPatProp) {
53 if self.is_pat_decl {
54 self.add(&Ident::from(&node.key));
55 }
56 }
57
58 fn handle_binding_ident(&mut self, node: &BindingIdent) {
59 if self.is_pat_decl {
60 self.add(&Ident::from(node));
61 }
62 }
63
64 fn handle_class_expr(&mut self, node: &ClassExpr) {
65 if let Some(id) = &node.ident {
66 self.add(id);
67 }
68 }
69
70 fn handle_fn_expr(&mut self, node: &FnExpr) {
71 if let Some(id) = &node.ident {
72 self.add(id);
73 }
74 }
75}
76
77pub(super) struct AnalyzerAndCollector {
78 analyzer: Analyzer,
79 id_collector: IdCollector,
80 decl_collector: CustomBindingCollector<Id>,
81}
82
83impl Visit for AnalyzerAndCollector {
84 noop_visit_type!();
85
86 fn visit_arrow_expr(&mut self, node: &ArrowExpr) {
87 let old_decl_collector_is_pat_decl = self.decl_collector.is_pat_decl;
88 self.decl_collector.is_pat_decl = true;
89
90 let old_analyzer = self.analyzer.enter_fn_scope();
91 let old_analyzer_is_pat_decl = self.analyzer.is_pat_decl;
92 self.analyzer.is_pat_decl = true;
93
94 node.params.visit_with(self);
95
96 self.analyzer.is_pat_decl = false;
99
100 match node.body.as_ref() {
101 BlockStmtOrExpr::BlockStmt(n) => n.visit_children_with(self),
102 BlockStmtOrExpr::Expr(n) => n.visit_with(self),
103 #[cfg(swc_ast_unknown)]
104 _ => (),
105 }
106
107 self.analyzer.is_pat_decl = old_analyzer_is_pat_decl;
108 self.analyzer.exit_scope(old_analyzer);
109
110 self.decl_collector.is_pat_decl = old_decl_collector_is_pat_decl;
111 }
112
113 fn visit_assign_target(&mut self, node: &AssignTarget) {
114 let old_analyzer_is_pat_decl = self.analyzer.is_pat_decl;
115 self.analyzer.is_pat_decl = false;
116
117 node.visit_children_with(self);
118
119 self.analyzer.is_pat_decl = old_analyzer_is_pat_decl;
120 }
121
122 fn visit_assign_pat_prop(&mut self, node: &AssignPatProp) {
123 node.visit_children_with(self);
124
125 self.decl_collector.handle_assign_pat_prop(node);
126 }
127
128 fn visit_binding_ident(&mut self, node: &BindingIdent) {
129 node.visit_children_with(self);
130
131 self.decl_collector.handle_binding_ident(node);
132 self.analyzer.handle_binding_ident(node);
133 }
134
135 fn visit_block_stmt(&mut self, node: &BlockStmt) {
136 let old_analyzer = self.analyzer.enter_block_scope();
137
138 node.visit_children_with(self);
139
140 self.analyzer.exit_scope(old_analyzer);
141 }
142
143 fn visit_bin_expr(&mut self, node: &BinExpr) {
144 maybe_grow_default(|| node.visit_children_with(self));
145 }
146
147 fn visit_catch_clause(&mut self, node: &CatchClause) {
148 let old_decl_collector_is_pat_decl = self.decl_collector.is_pat_decl;
149
150 let old_analyzer = self.analyzer.enter_block_scope();
151 let old_analyzer_is_pat_decl = self.analyzer.is_pat_decl;
152 let old_analyzer_in_catch_params = self.analyzer.in_catch_params;
153
154 self.decl_collector.is_pat_decl = false;
155 self.analyzer.in_catch_params = false;
156 self.analyzer.is_pat_decl = false;
157
158 node.body.visit_children_with(self);
159
160 self.decl_collector.is_pat_decl = true;
161 self.analyzer.is_pat_decl = true;
162 self.analyzer.in_catch_params = true;
163
164 node.param.visit_with(self);
165
166 self.decl_collector.is_pat_decl = old_decl_collector_is_pat_decl;
167
168 self.analyzer.in_catch_params = old_analyzer_in_catch_params;
169 self.analyzer.is_pat_decl = old_analyzer_is_pat_decl;
170 self.analyzer.exit_scope(old_analyzer);
171 }
172
173 fn visit_class_decl(&mut self, node: &ClassDecl) {
174 self.analyzer.handle_class_decl(node);
175
176 node.visit_children_with(self);
177
178 self.decl_collector.add(&node.ident);
179 }
180
181 fn visit_class_expr(&mut self, node: &ClassExpr) {
182 let old_analyzer = self.analyzer.enter_block_scope();
183
184 self.analyzer.handle_class_expr(node);
185
186 node.visit_children_with(self);
187
188 self.decl_collector.handle_class_expr(node);
189
190 self.analyzer.exit_scope(old_analyzer);
191 }
192
193 fn visit_class_method(&mut self, node: &ClassMethod) {
194 node.key.visit_with(self);
195
196 let old_analyzer = self.analyzer.enter_fn_scope();
197
198 node.function.decorators.visit_with(self);
199 node.function.params.visit_with(self);
200 if let Some(body) = &node.function.body {
201 body.visit_children_with(self);
202 }
203
204 self.analyzer.exit_scope(old_analyzer);
205 }
206
207 fn visit_constructor(&mut self, node: &Constructor) {
208 let old_analyzer = self.analyzer.enter_fn_scope();
209 node.key.visit_with(self);
210 node.params.visit_with(self);
211 if let Some(body) = &node.body {
212 body.visit_children_with(self);
213 }
214
215 self.analyzer.exit_scope(old_analyzer);
216 }
217
218 fn visit_default_decl(&mut self, node: &DefaultDecl) {
219 match node {
220 DefaultDecl::Class(c) => {
221 self.analyzer.handle_class_expr(c);
222 self.decl_collector.handle_class_expr(c);
223
224 let old_analyzer = self.analyzer.enter_fn_scope();
225 c.visit_children_with(self);
226 self.analyzer.exit_scope(old_analyzer);
227 }
228 DefaultDecl::Fn(f) => {
229 self.analyzer.handle_fn_expr(f);
230
231 f.visit_with(self);
232 }
233 DefaultDecl::TsInterfaceDecl(_) => {}
234 #[cfg(swc_ast_unknown)]
235 _ => {}
236 }
237 }
238
239 fn visit_export_named_specifier(&mut self, n: &ExportNamedSpecifier) {
240 let old_id_collector_stopped = self.id_collector.stopped;
241 self.id_collector.stopped = true;
242
243 self.analyzer.handle_export_named_specifier(n);
244
245 n.visit_children_with(self);
246
247 self.id_collector.stopped = old_id_collector_stopped;
248 }
249
250 fn visit_expr(&mut self, node: &Expr) {
251 let old_decl_collector_is_pat_decl = self.decl_collector.is_pat_decl;
252 self.decl_collector.is_pat_decl = false;
253
254 let old_analyzer_is_pat_decl = self.analyzer.is_pat_decl;
255 self.analyzer.is_pat_decl = false;
256
257 self.analyzer.handle_expr(node);
258
259 node.visit_children_with(self);
260
261 self.analyzer.is_pat_decl = old_analyzer_is_pat_decl;
262 self.decl_collector.is_pat_decl = old_decl_collector_is_pat_decl;
263 }
264
265 fn visit_fn_decl(&mut self, node: &FnDecl) {
266 let has_rest = node
271 .function
272 .params
273 .iter()
274 .any(|p| p.pat.is_rest() || p.pat.is_assign());
275 let need_skip_analyzer_record =
276 self.analyzer.is_first_node && self.analyzer.skip_first_fn_or_class_decl;
277 self.analyzer.is_first_node = false;
278
279 if !need_skip_analyzer_record {
280 self.analyzer.add_decl(node.ident.to_id(), true);
281
282 if has_rest {
283 self.analyzer.add_usage(node.ident.to_id());
284 }
285 }
286
287 node.ident.visit_with(self);
288
289 let old_analyzer = self.analyzer.enter_fn_scope();
290
291 if !need_skip_analyzer_record && has_rest {
292 self.analyzer.add_usage(node.ident.to_id());
294 }
295
296 node.function.decorators.visit_with(self);
297 node.function.params.visit_with(self);
298 if let Some(body) = &node.function.body {
299 body.visit_children_with(self);
300 }
301
302 self.analyzer.exit_scope(old_analyzer);
303 self.decl_collector.add(&node.ident);
304 }
305
306 fn visit_fn_expr(&mut self, node: &FnExpr) {
307 if let Some(id) = &node.ident {
308 let old_analyzer0 = self.analyzer.enter_fn_scope();
309 self.analyzer.add_decl(id.to_id(), true);
310 let old_analyzer1 = self.analyzer.enter_fn_scope();
311 if node
316 .function
317 .params
318 .iter()
319 .any(|p| p.pat.is_rest() || p.pat.is_assign())
320 {
321 self.analyzer.add_usage(id.to_id());
322 }
323 node.function.decorators.visit_with(self);
324 node.function.params.visit_with(self);
325 if let Some(body) = &node.function.body {
326 body.visit_children_with(self);
327 }
328 self.analyzer.exit_scope(old_analyzer1);
329 self.analyzer.exit_scope(old_analyzer0);
330 } else {
331 node.visit_children_with(self)
332 }
333
334 self.decl_collector.handle_fn_expr(node);
335 }
336
337 fn visit_for_in_stmt(&mut self, node: &ForInStmt) {
338 let old_analyzer0 = self.analyzer.enter_block_scope();
339 node.left.visit_with(self);
340 node.right.visit_with(self);
341 let old_analyzer1 = self.analyzer.enter_block_scope();
342 match node.body.as_ref() {
343 Stmt::Block(n) => n.visit_children_with(self),
344 _ => node.body.visit_with(self),
345 }
346 self.analyzer.exit_scope(old_analyzer1);
347 self.analyzer.exit_scope(old_analyzer0);
348 }
349
350 fn visit_for_of_stmt(&mut self, node: &ForOfStmt) {
351 let old_analyzer0 = self.analyzer.enter_block_scope();
352 node.left.visit_with(self);
353 node.right.visit_with(self);
354 let old_analyzer1 = self.analyzer.enter_block_scope();
355 match node.body.as_ref() {
356 Stmt::Block(n) => n.visit_children_with(self),
357 _ => node.body.visit_with(self),
358 }
359 self.analyzer.exit_scope(old_analyzer1);
360 self.analyzer.exit_scope(old_analyzer0);
361 }
362
363 fn visit_for_stmt(&mut self, node: &ForStmt) {
364 let old_analyzer0 = self.analyzer.enter_block_scope();
365 node.init.visit_with(self);
366 node.test.visit_with(self);
367 node.update.visit_with(self);
368 let old_analyzer1 = self.analyzer.enter_block_scope();
369 match node.body.as_ref() {
370 Stmt::Block(n) => n.visit_children_with(self),
371 _ => node.body.visit_with(self),
372 }
373 self.analyzer.exit_scope(old_analyzer1);
374 self.analyzer.exit_scope(old_analyzer0);
375 }
376
377 fn visit_function(&mut self, node: &Function) {
378 let old_analyzer = self.analyzer.enter_fn_scope();
379
380 node.decorators.visit_with(self);
381 node.params.visit_with(self);
382 if let Some(body) = &node.body {
383 body.visit_children_with(self);
384 }
385
386 self.analyzer.exit_scope(old_analyzer);
387 }
388
389 fn visit_import_default_specifier(&mut self, node: &ImportDefaultSpecifier) {
390 node.visit_children_with(self);
391
392 self.analyzer.add_decl(node.local.to_id(), true);
393 self.decl_collector.add(&node.local);
394 }
395
396 fn visit_import_named_specifier(&mut self, node: &ImportNamedSpecifier) {
397 node.visit_children_with(self);
398
399 self.analyzer.add_decl(node.local.to_id(), true);
400 self.decl_collector.add(&node.local);
401 }
402
403 fn visit_import_star_as_specifier(&mut self, node: &ImportStarAsSpecifier) {
404 node.visit_children_with(self);
405
406 self.analyzer.add_decl(node.local.to_id(), true);
407 self.decl_collector.add(&node.local);
408 }
409
410 fn visit_param(&mut self, node: &Param) {
411 let old_decl_collector_is_pat_decl = self.decl_collector.is_pat_decl;
412 self.decl_collector.is_pat_decl = true;
413
414 let old_analyzer_is_pat_decl = self.analyzer.is_pat_decl;
415 let old_analyzer_need_hoist = self.analyzer.var_belong_to_fn_scope;
416
417 self.analyzer.var_belong_to_fn_scope = !self.analyzer.in_catch_params;
420 self.analyzer.is_pat_decl = false;
421 node.decorators.visit_with(self);
422
423 self.analyzer.is_pat_decl = true;
424 node.pat.visit_with(self);
425
426 self.analyzer.var_belong_to_fn_scope = old_analyzer_need_hoist;
427 self.analyzer.is_pat_decl = old_analyzer_is_pat_decl;
428 self.decl_collector.is_pat_decl = old_decl_collector_is_pat_decl;
429 }
430
431 fn visit_prop(&mut self, node: &Prop) {
432 node.visit_children_with(self);
433 self.analyzer.handle_prop(node);
434 }
435
436 fn visit_static_block(&mut self, node: &StaticBlock) {
437 let old_analyzer = self.analyzer.enter_fn_scope();
438
439 node.body.visit_children_with(self);
440
441 self.analyzer.exit_scope(old_analyzer);
442 }
443
444 fn visit_stmt(&mut self, node: &Stmt) {
445 self.analyzer.is_first_node = false;
446 node.visit_children_with(self);
447 }
448
449 fn visit_ts_param_prop(&mut self, p: &TsParamProp) {
450 let old_decl_collector_is_pat_decl = self.decl_collector.is_pat_decl;
451 self.decl_collector.is_pat_decl = true;
452
453 p.visit_children_with(self);
454
455 self.decl_collector.is_pat_decl = old_decl_collector_is_pat_decl;
456 }
457
458 fn visit_var_decl(&mut self, node: &VarDecl) {
459 let old_analyzer_need_hoisted = self.analyzer.var_belong_to_fn_scope;
460 self.analyzer.var_belong_to_fn_scope = node.kind == VarDeclKind::Var;
461
462 node.visit_children_with(self);
463
464 self.analyzer.var_belong_to_fn_scope = old_analyzer_need_hoisted;
465 }
466
467 fn visit_var_declarator(&mut self, node: &VarDeclarator) {
468 let old_decl_collector_is_pat_decl = self.decl_collector.is_pat_decl;
469 self.decl_collector.is_pat_decl = true;
470
471 let old_analyzer_is_pat_decl = self.analyzer.is_pat_decl;
472 self.analyzer.is_pat_decl = true;
473
474 node.name.visit_with(self);
475
476 self.decl_collector.is_pat_decl = false;
477 self.analyzer.is_pat_decl = false;
478
479 node.init.visit_with(self);
480
481 self.analyzer.is_pat_decl = old_analyzer_is_pat_decl;
482 self.decl_collector.is_pat_decl = old_decl_collector_is_pat_decl;
483 }
484
485 fn visit_super_prop(&mut self, node: &SuperProp) {
486 let old_id_collector_stopped = self.id_collector.stopped;
487 if node.is_ident() {
488 self.id_collector.stopped = true;
489 }
490
491 node.visit_children_with(self);
492
493 if node.is_ident() {
494 self.id_collector.stopped = old_id_collector_stopped;
495 }
496 }
497
498 fn visit_export_default_specifier(&mut self, n: &ExportDefaultSpecifier) {
499 let old_id_collector_stopped = self.id_collector.stopped;
500 self.id_collector.stopped = true;
501
502 n.visit_children_with(self);
503
504 self.id_collector.stopped = old_id_collector_stopped;
505 }
506
507 fn visit_export_namespace_specifier(&mut self, n: &ExportNamespaceSpecifier) {
508 let old_id_collector_stopped = self.id_collector.stopped;
509 self.id_collector.stopped = true;
510
511 n.visit_children_with(self);
512
513 self.id_collector.stopped = old_id_collector_stopped;
514 }
515
516 fn visit_ident(&mut self, id: &Ident) {
517 self.id_collector.handle_ident(id);
518 }
519
520 fn visit_named_export(&mut self, node: &NamedExport) {
521 let old_id_collector_stopped = self.id_collector.stopped;
522 if node.src.is_some() {
523 self.id_collector.stopped = true;
524 }
525
526 node.visit_children_with(self);
527
528 if node.src.is_some() {
529 self.id_collector.stopped = old_id_collector_stopped;
530 }
531 }
532}
533
534pub(super) fn analyzer_and_collect_unresolved<N>(
535 n: &N,
536 has_eval: bool,
537 top_level_mark: Mark,
538 skip_first_fn_or_class_decl: bool,
539) -> (Scope, FxHashSet<Atom>)
540where
541 N: VisitWith<AnalyzerAndCollector>,
542{
543 let analyzer = Analyzer::new(has_eval, top_level_mark, skip_first_fn_or_class_decl);
544 let id_collector = IdCollector {
545 ids: Default::default(),
546 stopped: false,
547 };
548 let decl_collector = CustomBindingCollector {
549 bindings: Default::default(),
550 preserved: Default::default(),
551 is_pat_decl: false,
552 top_level_for_eval: has_eval
553 .then_some(top_level_mark)
554 .map(|m| SyntaxContext::empty().apply_mark(m)),
555 };
556
557 let mut v = AnalyzerAndCollector {
558 analyzer,
559 id_collector,
560 decl_collector,
561 };
562
563 n.visit_with(&mut v);
564
565 let (usages, decls, preserved) = (
566 v.id_collector.ids,
567 v.decl_collector.bindings,
568 v.decl_collector.preserved,
569 );
570
571 let unresolved = usages
572 .into_iter()
573 .filter(|used_id| !decls.contains(used_id))
574 .map(|v| v.0)
575 .chain(preserved.into_iter().map(|v| v.0))
576 .collect::<FxHashSet<_>>();
577
578 (v.analyzer.scope, unresolved)
579}