1use std::collections::HashMap;
7use std::collections::HashSet;
8
9use indexmap::IndexMap;
10use react_compiler_ast::scope::*;
11use swc_ecma_ast::*;
12use swc_ecma_visit::Visit;
13use swc_ecma_visit::VisitWith;
14
15fn str_value_to_string(s: &Str) -> String {
19 s.value.to_atom_lossy().to_string()
20}
21
22pub fn build_scope_info(module: &Module) -> ScopeInfo {
28 let mut collector = ScopeCollector::new();
30 collector.visit_module(module);
31
32 let ref_node_id_to_binding = {
38 let mut resolver = ReferenceResolver::new(&collector);
39 resolver.visit_module(module);
40
41 for binding in &collector.bindings {
43 if let Some(start) = binding.declaration_start {
44 resolver
45 .reference_to_binding
46 .entry(start)
47 .or_insert(binding.id);
48 }
49 }
50
51 for (start, binding_id) in &collector.redeclaration_refs {
54 resolver.reference_to_binding.insert(*start, *binding_id);
55 }
56
57 resolver.reference_to_binding
58 };
59
60 let node_id_to_scope = collector.node_to_scope.clone();
61
62 ScopeInfo {
63 scopes: collector.scopes,
64 bindings: collector.bindings,
65 node_to_scope: collector.node_to_scope,
66 node_to_scope_end: collector.node_to_scope_end,
67 reference_to_binding: indexmap::IndexMap::new(),
68 ref_node_id_to_binding,
69 node_id_to_scope,
70 program_scope: ScopeId(0),
71 }
72}
73
74struct ScopeCollector {
77 scopes: Vec<ScopeData>,
78 bindings: Vec<BindingData>,
79 node_to_scope: HashMap<u32, ScopeId>,
80 node_to_scope_end: HashMap<u32, u32>,
81 scope_stack: Vec<ScopeId>,
83 function_body_spans: HashSet<u32>,
86 redeclaration_refs: HashMap<u32, BindingId>,
91}
92
93impl ScopeCollector {
94 fn new() -> Self {
95 Self {
96 scopes: Vec::new(),
97 bindings: Vec::new(),
98 node_to_scope: HashMap::new(),
99 node_to_scope_end: HashMap::new(),
100 scope_stack: Vec::new(),
101 function_body_spans: HashSet::new(),
102 redeclaration_refs: HashMap::new(),
103 }
104 }
105
106 fn current_scope(&self) -> ScopeId {
107 *self.scope_stack.last().expect("scope stack is empty")
108 }
109
110 fn push_scope(&mut self, kind: ScopeKind, node_start: u32, node_end: u32) -> ScopeId {
111 let id = ScopeId(self.scopes.len() as u32);
112 let parent = self.scope_stack.last().copied();
113 self.scopes.push(ScopeData {
114 id,
115 parent,
116 kind,
117 bindings: HashMap::new(),
118 });
119 self.node_to_scope.insert(node_start, id);
120 if node_end > node_start {
121 self.node_to_scope_end.insert(node_start, node_end);
122 }
123 self.scope_stack.push(id);
124 id
125 }
126
127 fn pop_scope(&mut self) {
128 self.scope_stack.pop();
129 }
130
131 fn enclosing_function_scope(&self) -> ScopeId {
133 for &scope_id in self.scope_stack.iter().rev() {
134 let scope = &self.scopes[scope_id.0 as usize];
135 match scope.kind {
136 ScopeKind::Function | ScopeKind::Program => return scope_id,
137 _ => {}
138 }
139 }
140 ScopeId(0)
141 }
142
143 fn add_binding(
144 &mut self,
145 name: String,
146 kind: BindingKind,
147 scope: ScopeId,
148 declaration_type: String,
149 declaration_start: Option<u32>,
150 import: Option<ImportBindingData>,
151 ) -> BindingId {
152 let id = BindingId(self.bindings.len() as u32);
153 self.bindings.push(BindingData {
154 id,
155 name: name.clone(),
156 kind,
157 scope,
158 declaration_type,
159 declaration_start,
160 declaration_node_id: declaration_start,
161 import,
162 });
163 self.scopes[scope.0 as usize].bindings.insert(name, id);
164 id
165 }
166
167 fn collect_pat_bindings(
169 &mut self,
170 pat: &Pat,
171 kind: BindingKind,
172 scope: ScopeId,
173 declaration_type: &str,
174 ) {
175 match pat {
176 Pat::Ident(binding_ident) => {
177 let name = binding_ident.id.sym.to_string();
178 let start = binding_ident.id.span.lo.0;
179 self.add_binding(
180 name,
181 kind,
182 scope,
183 declaration_type.to_string(),
184 Some(start),
185 None,
186 );
187 }
188 Pat::Array(arr) => {
189 for elem in &arr.elems {
190 if let Some(p) = elem {
191 self.collect_pat_bindings(p, kind.clone(), scope, declaration_type);
192 }
193 }
194 }
195 Pat::Object(obj) => {
196 for prop in &obj.props {
197 match prop {
198 ObjectPatProp::KeyValue(kv) => {
199 self.collect_pat_bindings(
200 &kv.value,
201 kind.clone(),
202 scope,
203 declaration_type,
204 );
205 }
206 ObjectPatProp::Assign(assign) => {
207 let name = assign.key.sym.to_string();
208 let start = assign.key.span.lo.0;
209 self.add_binding(
210 name,
211 kind.clone(),
212 scope,
213 declaration_type.to_string(),
214 Some(start),
215 None,
216 );
217 }
218 ObjectPatProp::Rest(rest) => {
219 self.collect_pat_bindings(
220 &rest.arg,
221 kind.clone(),
222 scope,
223 declaration_type,
224 );
225 }
226 }
227 }
228 }
229 Pat::Rest(rest) => {
230 self.collect_pat_bindings(&rest.arg, kind, scope, declaration_type);
231 }
232 Pat::Assign(assign) => {
233 self.collect_pat_bindings(&assign.left, kind, scope, declaration_type);
234 }
235 Pat::Expr(_) | Pat::Invalid(_) => {}
236 }
237 }
238
239 fn visit_function_inner(&mut self, function: &Function) {
242 let func_start = function.span.lo.0;
243 self.push_scope(ScopeKind::Function, func_start, function.span.hi.0);
244
245 for param in &function.params {
246 self.collect_pat_bindings(
247 ¶m.pat,
248 BindingKind::Param,
249 self.current_scope(),
250 "FormalParameter",
251 );
252 }
253
254 if let Some(body) = &function.body {
255 self.function_body_spans.insert(body.span.lo.0);
256 body.visit_with(self);
257 }
258
259 self.pop_scope();
260 }
261}
262
263impl Visit for ScopeCollector {
264 fn visit_module(&mut self, module: &Module) {
265 self.push_scope(ScopeKind::Program, module.span.lo.0, module.span.hi.0);
266 module.visit_children_with(self);
267 self.pop_scope();
268 }
269
270 fn visit_import_decl(&mut self, import: &ImportDecl) {
271 let source = str_value_to_string(&import.src);
272 let program_scope = ScopeId(0);
273
274 for spec in &import.specifiers {
275 match spec {
276 ImportSpecifier::Named(named) => {
277 let local_name = named.local.sym.to_string();
278 let start = named.local.span.lo.0;
279 let imported_name = match &named.imported {
280 Some(ModuleExportName::Ident(ident)) => Some(ident.sym.to_string()),
281 Some(ModuleExportName::Str(s)) => Some(str_value_to_string(s)),
282 None => Some(local_name.clone()),
283 };
284 self.add_binding(
285 local_name,
286 BindingKind::Module,
287 program_scope,
288 "ImportSpecifier".to_string(),
289 Some(start),
290 Some(ImportBindingData {
291 source: source.clone(),
292 kind: ImportBindingKind::Named,
293 imported: imported_name,
294 }),
295 );
296 }
297 ImportSpecifier::Default(default) => {
298 let local_name = default.local.sym.to_string();
299 let start = default.local.span.lo.0;
300 self.add_binding(
301 local_name,
302 BindingKind::Module,
303 program_scope,
304 "ImportDefaultSpecifier".to_string(),
305 Some(start),
306 Some(ImportBindingData {
307 source: source.clone(),
308 kind: ImportBindingKind::Default,
309 imported: None,
310 }),
311 );
312 }
313 ImportSpecifier::Namespace(ns) => {
314 let local_name = ns.local.sym.to_string();
315 let start = ns.local.span.lo.0;
316 self.add_binding(
317 local_name,
318 BindingKind::Module,
319 program_scope,
320 "ImportNamespaceSpecifier".to_string(),
321 Some(start),
322 Some(ImportBindingData {
323 source: source.clone(),
324 kind: ImportBindingKind::Namespace,
325 imported: None,
326 }),
327 );
328 }
329 }
330 }
331 }
332
333 fn visit_var_decl(&mut self, var_decl: &VarDecl) {
334 let (kind, declaration_type) = match var_decl.kind {
335 VarDeclKind::Var => (BindingKind::Var, "VariableDeclarator"),
336 VarDeclKind::Let => (BindingKind::Let, "VariableDeclarator"),
337 VarDeclKind::Const => (BindingKind::Const, "VariableDeclarator"),
338 };
339
340 let target_scope = match var_decl.kind {
341 VarDeclKind::Var => self.enclosing_function_scope(),
342 VarDeclKind::Let | VarDeclKind::Const => self.current_scope(),
343 };
344
345 for declarator in &var_decl.decls {
346 self.collect_pat_bindings(
347 &declarator.name,
348 kind.clone(),
349 target_scope,
350 declaration_type,
351 );
352 if let Some(init) = &declarator.init {
354 init.visit_with(self);
355 }
356 }
357 }
358
359 fn visit_fn_decl(&mut self, fn_decl: &FnDecl) {
360 let hoist_scope = self.enclosing_function_scope();
362 let name = fn_decl.ident.sym.to_string();
363 let start = fn_decl.ident.span.lo.0;
364 if let Some(&existing_id) =
365 self.scopes[hoist_scope.0 as usize].bindings.get(&name)
366 {
367 self.redeclaration_refs.insert(start, existing_id);
368 } else {
369 self.add_binding(
370 name,
371 BindingKind::Hoisted,
372 hoist_scope,
373 "FunctionDeclaration".to_string(),
374 Some(start),
375 None,
376 );
377 }
378
379 self.visit_function_inner(&fn_decl.function);
380 }
381
382 fn visit_export_default_decl(&mut self, decl: &ExportDefaultDecl) {
383 match &decl.decl {
387 DefaultDecl::Fn(fn_expr) => {
388 if let Some(ident) = &fn_expr.ident {
389 let hoist_scope = self.enclosing_function_scope();
390 let name = ident.sym.to_string();
391 let start = ident.span.lo.0;
392 self.add_binding(
393 name,
394 BindingKind::Hoisted,
395 hoist_scope,
396 "FunctionDeclaration".to_string(),
397 Some(start),
398 None,
399 );
400 }
401 self.visit_function_inner(&fn_expr.function);
402 }
403 DefaultDecl::Class(class_expr) => {
404 if let Some(ident) = &class_expr.ident {
405 let name = ident.sym.to_string();
406 let start = ident.span.lo.0;
407 self.add_binding(
408 name,
409 BindingKind::Local,
410 self.current_scope(),
411 "ClassDeclaration".to_string(),
412 Some(start),
413 None,
414 );
415 }
416 self.push_scope(
417 ScopeKind::Class,
418 class_expr.class.span.lo.0,
419 class_expr.class.span.hi.0,
420 );
421 class_expr.class.visit_children_with(self);
422 self.pop_scope();
423 }
424 DefaultDecl::TsInterfaceDecl(d) => {
425 d.visit_with(self);
426 }
427 }
428 }
429
430 fn visit_fn_expr(&mut self, fn_expr: &FnExpr) {
431 let func_start = fn_expr.function.span.lo.0;
432 self.push_scope(ScopeKind::Function, func_start, fn_expr.function.span.hi.0);
433
434 if let Some(ident) = &fn_expr.ident {
436 let name = ident.sym.to_string();
437 let start = ident.span.lo.0;
438 self.add_binding(
439 name,
440 BindingKind::Local,
441 self.current_scope(),
442 "FunctionExpression".to_string(),
443 Some(start),
444 None,
445 );
446 }
447
448 for param in &fn_expr.function.params {
449 self.collect_pat_bindings(
450 ¶m.pat,
451 BindingKind::Param,
452 self.current_scope(),
453 "FormalParameter",
454 );
455 }
456
457 if let Some(body) = &fn_expr.function.body {
458 self.function_body_spans.insert(body.span.lo.0);
459 body.visit_with(self);
460 }
461
462 self.pop_scope();
463 }
464
465 fn visit_arrow_expr(&mut self, arrow: &ArrowExpr) {
466 let func_start = arrow.span.lo.0;
467 self.push_scope(ScopeKind::Function, func_start, arrow.span.hi.0);
468
469 for param in &arrow.params {
470 self.collect_pat_bindings(
471 param,
472 BindingKind::Param,
473 self.current_scope(),
474 "FormalParameter",
475 );
476 }
477
478 match &*arrow.body {
479 BlockStmtOrExpr::BlockStmt(block) => {
480 self.function_body_spans.insert(block.span.lo.0);
481 block.visit_with(self);
482 }
483 BlockStmtOrExpr::Expr(expr) => {
484 expr.visit_with(self);
485 }
486 }
487
488 self.pop_scope();
489 }
490
491 fn visit_block_stmt(&mut self, block: &BlockStmt) {
492 if self.function_body_spans.remove(&block.span.lo.0) {
493 block.visit_children_with(self);
495 } else {
496 self.push_scope(ScopeKind::Block, block.span.lo.0, block.span.hi.0);
497 block.visit_children_with(self);
498 self.pop_scope();
499 }
500 }
501
502 fn visit_for_stmt(&mut self, for_stmt: &ForStmt) {
503 self.push_scope(ScopeKind::For, for_stmt.span.lo.0, for_stmt.span.hi.0);
504
505 if let Some(init) = &for_stmt.init {
506 init.visit_with(self);
507 }
508 if let Some(test) = &for_stmt.test {
509 test.visit_with(self);
510 }
511 if let Some(update) = &for_stmt.update {
512 update.visit_with(self);
513 }
514 for_stmt.body.visit_with(self);
515
516 self.pop_scope();
517 }
518
519 fn visit_for_in_stmt(&mut self, for_in: &ForInStmt) {
520 self.push_scope(ScopeKind::For, for_in.span.lo.0, for_in.span.hi.0);
521 for_in.left.visit_with(self);
522 for_in.right.visit_with(self);
523 for_in.body.visit_with(self);
524 self.pop_scope();
525 }
526
527 fn visit_for_of_stmt(&mut self, for_of: &ForOfStmt) {
528 self.push_scope(ScopeKind::For, for_of.span.lo.0, for_of.span.hi.0);
529 for_of.left.visit_with(self);
530 for_of.right.visit_with(self);
531 for_of.body.visit_with(self);
532 self.pop_scope();
533 }
534
535 fn visit_catch_clause(&mut self, catch: &CatchClause) {
536 self.push_scope(ScopeKind::Catch, catch.span.lo.0, catch.span.hi.0);
537
538 if let Some(param) = &catch.param {
539 self.collect_pat_bindings(param, BindingKind::Let, self.current_scope(), "CatchClause");
540 }
541
542 self.function_body_spans.insert(catch.body.span.lo.0);
544 catch.body.visit_with(self);
545
546 self.pop_scope();
547 }
548
549 fn visit_switch_stmt(&mut self, switch: &SwitchStmt) {
550 switch.discriminant.visit_with(self);
552
553 self.push_scope(ScopeKind::Switch, switch.span.lo.0, switch.span.hi.0);
554 for case in &switch.cases {
555 case.visit_with(self);
556 }
557 self.pop_scope();
558 }
559
560 fn visit_class_decl(&mut self, class_decl: &ClassDecl) {
561 let name = class_decl.ident.sym.to_string();
562 let start = class_decl.ident.span.lo.0;
563 self.add_binding(
564 name,
565 BindingKind::Local,
566 self.current_scope(),
567 "ClassDeclaration".to_string(),
568 Some(start),
569 None,
570 );
571
572 self.push_scope(
573 ScopeKind::Class,
574 class_decl.class.span.lo.0,
575 class_decl.class.span.hi.0,
576 );
577 class_decl.class.visit_children_with(self);
578 self.pop_scope();
579 }
580
581 fn visit_class_expr(&mut self, class_expr: &ClassExpr) {
582 self.push_scope(
583 ScopeKind::Class,
584 class_expr.class.span.lo.0,
585 class_expr.class.span.hi.0,
586 );
587
588 if let Some(ident) = &class_expr.ident {
589 let name = ident.sym.to_string();
590 let start = ident.span.lo.0;
591 self.add_binding(
592 name,
593 BindingKind::Local,
594 self.current_scope(),
595 "ClassExpression".to_string(),
596 Some(start),
597 None,
598 );
599 }
600
601 class_expr.class.visit_children_with(self);
602 self.pop_scope();
603 }
604
605 fn visit_function(&mut self, f: &Function) {
608 self.visit_function_inner(f);
610 }
611}
612
613struct ReferenceResolver<'a> {
616 scopes: &'a [ScopeData],
617 #[allow(dead_code)]
618 bindings: &'a [BindingData],
619 node_to_scope: &'a HashMap<u32, ScopeId>,
620 reference_to_binding: IndexMap<u32, BindingId>,
621 scope_stack: Vec<ScopeId>,
623 declaration_starts: HashSet<u32>,
625 function_body_spans: HashSet<u32>,
627}
628
629impl<'a> ReferenceResolver<'a> {
630 fn new(collector: &'a ScopeCollector) -> Self {
631 let mut declaration_starts = HashSet::new();
632 for binding in &collector.bindings {
633 if let Some(start) = binding.declaration_start {
634 declaration_starts.insert(start);
635 }
636 }
637 Self {
638 scopes: &collector.scopes,
639 bindings: &collector.bindings,
640 node_to_scope: &collector.node_to_scope,
641 reference_to_binding: IndexMap::new(),
642 scope_stack: Vec::new(),
643 declaration_starts,
644 function_body_spans: HashSet::new(),
645 }
646 }
647
648 fn current_scope(&self) -> ScopeId {
649 *self.scope_stack.last().expect("scope stack is empty")
650 }
651
652 fn resolve_ident(&mut self, name: &str, start: u32) {
653 if self.declaration_starts.contains(&start) {
655 return;
656 }
657
658 let mut current = Some(self.current_scope());
660 while let Some(scope_id) = current {
661 let scope = &self.scopes[scope_id.0 as usize];
662 if let Some(&binding_id) = scope.bindings.get(name) {
663 self.reference_to_binding.insert(start, binding_id);
664 return;
665 }
666 current = scope.parent;
667 }
668 }
670
671 fn find_scope_at(&self, node_start: u32) -> Option<&ScopeId> {
672 self.node_to_scope.get(&node_start)
673 }
674
675 fn visit_param_pattern(&mut self, pat: &Pat) {
678 match pat {
679 Pat::Ident(_) => {
680 }
682 Pat::Array(arr) => {
683 for elem in &arr.elems {
684 if let Some(p) = elem {
685 self.visit_param_pattern(p);
686 }
687 }
688 }
689 Pat::Object(obj) => {
690 for prop in &obj.props {
691 match prop {
692 ObjectPatProp::KeyValue(kv) => {
693 if let PropName::Computed(computed) = &kv.key {
694 computed.visit_with(self);
695 }
696 self.visit_param_pattern(&kv.value);
697 }
698 ObjectPatProp::Assign(assign) => {
699 if let Some(value) = &assign.value {
700 value.visit_with(self);
701 }
702 }
703 ObjectPatProp::Rest(rest) => {
704 self.visit_param_pattern(&rest.arg);
705 }
706 }
707 }
708 }
709 Pat::Assign(assign) => {
710 self.visit_param_pattern(&assign.left);
711 assign.right.visit_with(self);
713 }
714 Pat::Rest(rest) => {
715 self.visit_param_pattern(&rest.arg);
716 }
717 Pat::Expr(expr) => {
718 expr.visit_with(self);
719 }
720 Pat::Invalid(_) => {}
721 }
722 }
723
724 fn visit_function_inner(&mut self, function: &Function) {
726 let func_start = function.span.lo.0;
727 if let Some(&scope_id) = self.find_scope_at(func_start) {
728 self.scope_stack.push(scope_id);
729
730 for param in &function.params {
731 self.visit_param_pattern(¶m.pat);
732 }
733
734 if let Some(body) = &function.body {
735 self.function_body_spans.insert(body.span.lo.0);
736 body.visit_with(self);
737 }
738
739 self.scope_stack.pop();
740 }
741 }
742}
743
744impl<'a> Visit for ReferenceResolver<'a> {
745 fn visit_module(&mut self, module: &Module) {
746 self.scope_stack.push(ScopeId(0));
747 module.visit_children_with(self);
748 self.scope_stack.pop();
749 }
750
751 fn visit_ident(&mut self, ident: &Ident) {
752 let name = ident.sym.to_string();
753 let start = ident.span.lo.0;
754 self.resolve_ident(&name, start);
755 }
756
757 fn visit_import_decl(&mut self, _import: &ImportDecl) {
758 }
760
761 fn visit_var_decl(&mut self, var_decl: &VarDecl) {
762 for declarator in &var_decl.decls {
764 if let Some(init) = &declarator.init {
765 init.visit_with(self);
766 }
767 }
768 }
769
770 fn visit_fn_decl(&mut self, fn_decl: &FnDecl) {
771 self.visit_function_inner(&fn_decl.function);
773 }
774
775 fn visit_export_default_decl(&mut self, decl: &ExportDefaultDecl) {
776 match &decl.decl {
779 DefaultDecl::Fn(fn_expr) => {
780 self.visit_function_inner(&fn_expr.function);
782 }
783 DefaultDecl::Class(class_expr) => {
784 if let Some(&scope_id) = self.find_scope_at(class_expr.class.span.lo.0) {
785 self.scope_stack.push(scope_id);
786 class_expr.class.visit_children_with(self);
787 self.scope_stack.pop();
788 }
789 }
790 DefaultDecl::TsInterfaceDecl(d) => {
791 d.visit_with(self);
792 }
793 }
794 }
795
796 fn visit_fn_expr(&mut self, fn_expr: &FnExpr) {
797 let func_start = fn_expr.function.span.lo.0;
798 if let Some(&scope_id) = self.find_scope_at(func_start) {
799 self.scope_stack.push(scope_id);
800
801 for param in &fn_expr.function.params {
804 self.visit_param_pattern(¶m.pat);
805 }
806
807 if let Some(body) = &fn_expr.function.body {
808 self.function_body_spans.insert(body.span.lo.0);
809 body.visit_with(self);
810 }
811
812 self.scope_stack.pop();
813 }
814 }
815
816 fn visit_arrow_expr(&mut self, arrow: &ArrowExpr) {
817 let func_start = arrow.span.lo.0;
818 if let Some(&scope_id) = self.find_scope_at(func_start) {
819 self.scope_stack.push(scope_id);
820
821 for param in &arrow.params {
822 self.visit_param_pattern(param);
823 }
824
825 match &*arrow.body {
826 BlockStmtOrExpr::BlockStmt(block) => {
827 self.function_body_spans.insert(block.span.lo.0);
828 block.visit_with(self);
829 }
830 BlockStmtOrExpr::Expr(expr) => {
831 expr.visit_with(self);
832 }
833 }
834
835 self.scope_stack.pop();
836 }
837 }
838
839 fn visit_block_stmt(&mut self, block: &BlockStmt) {
840 if self.function_body_spans.remove(&block.span.lo.0) {
841 block.visit_children_with(self);
843 } else if let Some(&scope_id) = self.find_scope_at(block.span.lo.0) {
844 self.scope_stack.push(scope_id);
845 block.visit_children_with(self);
846 self.scope_stack.pop();
847 } else {
848 block.visit_children_with(self);
849 }
850 }
851
852 fn visit_for_stmt(&mut self, for_stmt: &ForStmt) {
853 if let Some(&scope_id) = self.find_scope_at(for_stmt.span.lo.0) {
854 self.scope_stack.push(scope_id);
855
856 if let Some(init) = &for_stmt.init {
857 init.visit_with(self);
858 }
859 if let Some(test) = &for_stmt.test {
860 test.visit_with(self);
861 }
862 if let Some(update) = &for_stmt.update {
863 update.visit_with(self);
864 }
865 for_stmt.body.visit_with(self);
866
867 self.scope_stack.pop();
868 }
869 }
870
871 fn visit_for_in_stmt(&mut self, for_in: &ForInStmt) {
872 if let Some(&scope_id) = self.find_scope_at(for_in.span.lo.0) {
873 self.scope_stack.push(scope_id);
874 for_in.left.visit_with(self);
875 for_in.right.visit_with(self);
876 for_in.body.visit_with(self);
877 self.scope_stack.pop();
878 }
879 }
880
881 fn visit_for_of_stmt(&mut self, for_of: &ForOfStmt) {
882 if let Some(&scope_id) = self.find_scope_at(for_of.span.lo.0) {
883 self.scope_stack.push(scope_id);
884 for_of.left.visit_with(self);
885 for_of.right.visit_with(self);
886 for_of.body.visit_with(self);
887 self.scope_stack.pop();
888 }
889 }
890
891 fn visit_catch_clause(&mut self, catch: &CatchClause) {
892 if let Some(&scope_id) = self.find_scope_at(catch.span.lo.0) {
893 self.scope_stack.push(scope_id);
894 self.function_body_spans.insert(catch.body.span.lo.0);
896 catch.body.visit_with(self);
897 self.scope_stack.pop();
898 }
899 }
900
901 fn visit_switch_stmt(&mut self, switch: &SwitchStmt) {
902 switch.discriminant.visit_with(self);
903
904 if let Some(&scope_id) = self.find_scope_at(switch.span.lo.0) {
905 self.scope_stack.push(scope_id);
906 for case in &switch.cases {
907 case.visit_with(self);
908 }
909 self.scope_stack.pop();
910 }
911 }
912
913 fn visit_class_decl(&mut self, class_decl: &ClassDecl) {
914 if let Some(&scope_id) = self.find_scope_at(class_decl.class.span.lo.0) {
916 self.scope_stack.push(scope_id);
917 class_decl.class.visit_children_with(self);
918 self.scope_stack.pop();
919 }
920 }
921
922 fn visit_class_expr(&mut self, class_expr: &ClassExpr) {
923 if let Some(&scope_id) = self.find_scope_at(class_expr.class.span.lo.0) {
924 self.scope_stack.push(scope_id);
925 class_expr.class.visit_children_with(self);
927 self.scope_stack.pop();
928 }
929 }
930
931 fn visit_function(&mut self, f: &Function) {
932 self.visit_function_inner(f);
934 }
935
936 fn visit_member_expr(&mut self, member: &MemberExpr) {
938 member.obj.visit_with(self);
939 if let MemberProp::Computed(computed) = &member.prop {
940 computed.visit_with(self);
941 }
942 }
943
944 fn visit_prop(&mut self, prop: &Prop) {
946 match prop {
947 Prop::Shorthand(ident) => {
948 self.visit_ident(ident);
950 }
951 Prop::KeyValue(kv) => {
952 if let PropName::Computed(computed) = &kv.key {
953 computed.visit_with(self);
954 }
955 kv.value.visit_with(self);
956 }
957 Prop::Assign(assign) => {
958 assign.value.visit_with(self);
959 }
960 Prop::Getter(getter) => {
961 if let PropName::Computed(computed) = &getter.key {
962 computed.visit_with(self);
963 }
964 if let Some(body) = &getter.body {
965 body.visit_with(self);
966 }
967 }
968 Prop::Setter(setter) => {
969 if let PropName::Computed(computed) = &setter.key {
970 computed.visit_with(self);
971 }
972 setter.param.visit_with(self);
973 if let Some(body) = &setter.body {
974 body.visit_with(self);
975 }
976 }
977 Prop::Method(method) => {
978 if let PropName::Computed(computed) = &method.key {
979 computed.visit_with(self);
980 }
981 method.function.visit_with(self);
982 }
983 }
984 }
985
986 fn visit_labeled_stmt(&mut self, labeled: &LabeledStmt) {
988 labeled.body.visit_with(self);
989 }
990
991 fn visit_break_stmt(&mut self, _break_stmt: &BreakStmt) {}
992
993 fn visit_continue_stmt(&mut self, _continue_stmt: &ContinueStmt) {}
994}