1use core::ops::ControlFlow;
6use std::convert::Infallible;
7
8use boa_interner::{Interner, Sym};
9use rustc_hash::FxHashSet;
10
11use crate::{
12 Declaration, Expression, LinearSpan, ModuleItem, Script, Statement, StatementList,
13 StatementListItem,
14 declaration::{
15 Binding, ExportDeclaration, ImportDeclaration, LexicalDeclaration, VarDeclaration, Variable,
16 },
17 expression::{
18 Await, Call, Identifier, NewTarget, OptionalOperationKind, SuperCall, This, Yield,
19 access::{PrivatePropertyAccess, SuperPropertyAccess},
20 literal::PropertyDefinition,
21 operator::BinaryInPrivate,
22 },
23 function::{
24 ArrowFunction, AsyncArrowFunction, AsyncFunctionDeclaration, AsyncFunctionExpression,
25 AsyncGeneratorDeclaration, AsyncGeneratorExpression, ClassDeclaration, ClassElement,
26 ClassElementName, ClassExpression, FormalParameterList, FunctionBody, FunctionDeclaration,
27 FunctionExpression, GeneratorDeclaration, GeneratorExpression, PrivateFieldDefinition,
28 },
29 statement::{
30 LabelledItem, With,
31 iteration::{ForLoopInitializer, IterableLoopInitializer},
32 },
33 visitor::{NodeRef, VisitWith, Visitor},
34};
35
36#[cfg(test)]
37mod tests;
38
39#[derive(Clone, Copy, Debug, PartialEq, Eq)]
43#[non_exhaustive]
44pub enum ContainsSymbol {
45 Super,
47 SuperProperty,
49 SuperCall,
51 YieldExpression,
53 AwaitExpression,
55 NewTarget,
57 ClassBody,
59 ClassHeritage,
61 This,
63 MethodDefinition,
65 EvalOrArguments,
67 DirectEval,
69}
70
71#[must_use]
77pub fn contains<N>(node: &N, symbol: ContainsSymbol) -> bool
78where
79 N: VisitWith,
80{
81 #[derive(Debug, Clone, Copy)]
83 struct ContainsVisitor(ContainsSymbol);
84
85 impl ContainsVisitor {
86 fn visit_contains_eval(&mut self, contains_direct_eval: bool) -> ControlFlow<()> {
87 if self.0 == ContainsSymbol::DirectEval && contains_direct_eval {
88 ControlFlow::Break(())
89 } else {
90 ControlFlow::Continue(())
91 }
92 }
93 }
94
95 impl<'ast> Visitor<'ast> for ContainsVisitor {
96 type BreakTy = ();
97
98 fn visit_with(&mut self, node: &'ast With) -> ControlFlow<Self::BreakTy> {
99 self.visit_expression(node.expression())?;
100 node.statement().visit_with(self)
101 }
102
103 fn visit_call(&mut self, node: &'ast Call) -> ControlFlow<Self::BreakTy> {
104 if self.0 == ContainsSymbol::DirectEval
105 && let Expression::Identifier(ident) = node.function().flatten()
106 && ident.sym() == Sym::EVAL
107 {
108 return ControlFlow::Break(());
109 }
110
111 self.visit_expression(node.function())?;
112 for arg in node.args() {
113 self.visit_expression(arg)?;
114 }
115 ControlFlow::Continue(())
116 }
117
118 fn visit_identifier(&mut self, node: &'ast Identifier) -> ControlFlow<Self::BreakTy> {
119 if self.0 == ContainsSymbol::EvalOrArguments
120 && (node.sym() == Sym::EVAL || node.sym() == Sym::ARGUMENTS)
121 {
122 return ControlFlow::Break(());
123 }
124 ControlFlow::Continue(())
125 }
126
127 fn visit_function_expression(
128 &mut self,
129 node: &'ast FunctionExpression,
130 ) -> ControlFlow<Self::BreakTy> {
131 self.visit_contains_eval(node.contains_direct_eval)?;
132 ControlFlow::Continue(())
133 }
134
135 fn visit_function_declaration(
136 &mut self,
137 node: &'ast FunctionDeclaration,
138 ) -> ControlFlow<Self::BreakTy> {
139 self.visit_contains_eval(node.contains_direct_eval)?;
140 ControlFlow::Continue(())
141 }
142
143 fn visit_async_function_expression(
144 &mut self,
145 node: &'ast AsyncFunctionExpression,
146 ) -> ControlFlow<Self::BreakTy> {
147 self.visit_contains_eval(node.contains_direct_eval)?;
148 ControlFlow::Continue(())
149 }
150
151 fn visit_async_function_declaration(
152 &mut self,
153 node: &'ast AsyncFunctionDeclaration,
154 ) -> ControlFlow<Self::BreakTy> {
155 self.visit_contains_eval(node.contains_direct_eval)?;
156 ControlFlow::Continue(())
157 }
158
159 fn visit_generator_expression(
160 &mut self,
161 node: &'ast GeneratorExpression,
162 ) -> ControlFlow<Self::BreakTy> {
163 self.visit_contains_eval(node.contains_direct_eval)?;
164 ControlFlow::Continue(())
165 }
166
167 fn visit_generator_declaration(
168 &mut self,
169 node: &'ast GeneratorDeclaration,
170 ) -> ControlFlow<Self::BreakTy> {
171 self.visit_contains_eval(node.contains_direct_eval)?;
172 ControlFlow::Continue(())
173 }
174
175 fn visit_async_generator_expression(
176 &mut self,
177 node: &'ast AsyncGeneratorExpression,
178 ) -> ControlFlow<Self::BreakTy> {
179 self.visit_contains_eval(node.contains_direct_eval)?;
180 ControlFlow::Continue(())
181 }
182
183 fn visit_async_generator_declaration(
184 &mut self,
185 node: &'ast AsyncGeneratorDeclaration,
186 ) -> ControlFlow<Self::BreakTy> {
187 self.visit_contains_eval(node.contains_direct_eval)?;
188 ControlFlow::Continue(())
189 }
190
191 fn visit_class_expression(
192 &mut self,
193 node: &'ast ClassExpression,
194 ) -> ControlFlow<Self::BreakTy> {
195 if !node.elements().is_empty() && self.0 == ContainsSymbol::ClassBody {
196 return ControlFlow::Break(());
197 }
198
199 if node.super_ref().is_some() && self.0 == ContainsSymbol::ClassHeritage {
200 return ControlFlow::Break(());
201 }
202
203 node.visit_with(self)
204 }
205
206 fn visit_class_declaration(
207 &mut self,
208 node: &'ast ClassDeclaration,
209 ) -> ControlFlow<Self::BreakTy> {
210 if !node.elements().is_empty() && self.0 == ContainsSymbol::ClassBody {
211 return ControlFlow::Break(());
212 }
213
214 if node.super_ref().is_some() && self.0 == ContainsSymbol::ClassHeritage {
215 return ControlFlow::Break(());
216 }
217
218 node.visit_with(self)
219 }
220
221 fn visit_class_element(&mut self, node: &'ast ClassElement) -> ControlFlow<Self::BreakTy> {
223 match node {
224 ClassElement::MethodDefinition(m) => {
225 if self.0 == ContainsSymbol::DirectEval {
226 return ControlFlow::Continue(());
227 }
228
229 if let ClassElementName::PropertyName(name) = m.name() {
230 name.visit_with(self)
231 } else {
232 ControlFlow::Continue(())
233 }
234 }
235 ClassElement::FieldDefinition(field)
236 | ClassElement::StaticFieldDefinition(field) => field.name.visit_with(self),
237 _ => ControlFlow::Continue(()),
238 }
239 }
240
241 fn visit_property_definition(
242 &mut self,
243 node: &'ast PropertyDefinition,
244 ) -> ControlFlow<Self::BreakTy> {
245 if let PropertyDefinition::MethodDefinition(m) = node {
246 if self.0 == ContainsSymbol::DirectEval {
247 return ControlFlow::Continue(());
248 }
249
250 if self.0 == ContainsSymbol::MethodDefinition {
251 return ControlFlow::Break(());
252 }
253 return m.name().visit_with(self);
254 }
255
256 node.visit_with(self)
257 }
258
259 fn visit_arrow_function(
260 &mut self,
261 node: &'ast ArrowFunction,
262 ) -> ControlFlow<Self::BreakTy> {
263 if ![
264 ContainsSymbol::NewTarget,
265 ContainsSymbol::SuperProperty,
266 ContainsSymbol::SuperCall,
267 ContainsSymbol::Super,
268 ContainsSymbol::This,
269 ContainsSymbol::DirectEval,
270 ]
271 .contains(&self.0)
272 {
273 return ControlFlow::Continue(());
274 }
275
276 node.visit_with(self)
277 }
278
279 fn visit_async_arrow_function(
280 &mut self,
281 node: &'ast AsyncArrowFunction,
282 ) -> ControlFlow<Self::BreakTy> {
283 if ![
284 ContainsSymbol::NewTarget,
285 ContainsSymbol::SuperProperty,
286 ContainsSymbol::SuperCall,
287 ContainsSymbol::Super,
288 ContainsSymbol::This,
289 ContainsSymbol::DirectEval,
290 ]
291 .contains(&self.0)
292 {
293 return ControlFlow::Continue(());
294 }
295
296 node.visit_with(self)
297 }
298
299 fn visit_super_property_access(
300 &mut self,
301 node: &'ast SuperPropertyAccess,
302 ) -> ControlFlow<Self::BreakTy> {
303 if [ContainsSymbol::SuperProperty, ContainsSymbol::Super].contains(&self.0) {
304 return ControlFlow::Break(());
305 }
306 node.visit_with(self)
307 }
308
309 fn visit_super_call(&mut self, node: &'ast SuperCall) -> ControlFlow<Self::BreakTy> {
310 if [ContainsSymbol::SuperCall, ContainsSymbol::Super].contains(&self.0) {
311 return ControlFlow::Break(());
312 }
313 node.visit_with(self)
314 }
315
316 fn visit_yield(&mut self, node: &'ast Yield) -> ControlFlow<Self::BreakTy> {
317 if self.0 == ContainsSymbol::YieldExpression {
318 return ControlFlow::Break(());
319 }
320
321 node.visit_with(self)
322 }
323
324 fn visit_await(&mut self, node: &'ast Await) -> ControlFlow<Self::BreakTy> {
325 if self.0 == ContainsSymbol::AwaitExpression {
326 return ControlFlow::Break(());
327 }
328
329 node.visit_with(self)
330 }
331
332 fn visit_this(&mut self, _node: &'ast This) -> ControlFlow<Self::BreakTy> {
333 if self.0 == ContainsSymbol::This {
334 return ControlFlow::Break(());
335 }
336 ControlFlow::Continue(())
337 }
338
339 fn visit_new_target(&mut self, _node: &'ast NewTarget) -> ControlFlow<Self::BreakTy> {
340 if self.0 == ContainsSymbol::NewTarget {
341 return ControlFlow::Break(());
342 }
343 ControlFlow::Continue(())
344 }
345 }
346
347 node.visit_with(&mut ContainsVisitor(symbol)).is_break()
348}
349
350#[must_use]
356pub fn contains_arguments<N>(node: &N) -> bool
357where
358 N: VisitWith,
359{
360 #[derive(Debug, Clone, Copy)]
362 struct ContainsArgsVisitor;
363
364 impl<'ast> Visitor<'ast> for ContainsArgsVisitor {
365 type BreakTy = ();
366
367 fn visit_identifier(&mut self, node: &'ast Identifier) -> ControlFlow<Self::BreakTy> {
368 if node.sym() == Sym::ARGUMENTS {
369 ControlFlow::Break(())
370 } else {
371 ControlFlow::Continue(())
372 }
373 }
374
375 fn visit_function_expression(
376 &mut self,
377 _: &'ast FunctionExpression,
378 ) -> ControlFlow<Self::BreakTy> {
379 ControlFlow::Continue(())
380 }
381
382 fn visit_function_declaration(
383 &mut self,
384 _: &'ast FunctionDeclaration,
385 ) -> ControlFlow<Self::BreakTy> {
386 ControlFlow::Continue(())
387 }
388
389 fn visit_async_function_expression(
390 &mut self,
391 _: &'ast AsyncFunctionExpression,
392 ) -> ControlFlow<Self::BreakTy> {
393 ControlFlow::Continue(())
394 }
395
396 fn visit_async_function_declaration(
397 &mut self,
398 _: &'ast AsyncFunctionDeclaration,
399 ) -> ControlFlow<Self::BreakTy> {
400 ControlFlow::Continue(())
401 }
402
403 fn visit_generator_expression(
404 &mut self,
405 _: &'ast GeneratorExpression,
406 ) -> ControlFlow<Self::BreakTy> {
407 ControlFlow::Continue(())
408 }
409
410 fn visit_generator_declaration(
411 &mut self,
412 _: &'ast GeneratorDeclaration,
413 ) -> ControlFlow<Self::BreakTy> {
414 ControlFlow::Continue(())
415 }
416
417 fn visit_async_generator_expression(
418 &mut self,
419 _: &'ast AsyncGeneratorExpression,
420 ) -> ControlFlow<Self::BreakTy> {
421 ControlFlow::Continue(())
422 }
423
424 fn visit_async_generator_declaration(
425 &mut self,
426 _: &'ast AsyncGeneratorDeclaration,
427 ) -> ControlFlow<Self::BreakTy> {
428 ControlFlow::Continue(())
429 }
430
431 fn visit_class_element(&mut self, node: &'ast ClassElement) -> ControlFlow<Self::BreakTy> {
432 if let ClassElement::MethodDefinition(m) = node
433 && let ClassElementName::PropertyName(name) = m.name()
434 {
435 return name.visit_with(self);
436 }
437
438 node.visit_with(self)
439 }
440
441 fn visit_property_definition(
442 &mut self,
443 node: &'ast PropertyDefinition,
444 ) -> ControlFlow<Self::BreakTy> {
445 if let PropertyDefinition::MethodDefinition(m) = node {
446 m.name().visit_with(self)
447 } else {
448 node.visit_with(self)
449 }
450 }
451 }
452 node.visit_with(&mut ContainsArgsVisitor).is_break()
453}
454
455#[must_use]
461#[inline]
462pub fn has_direct_super_new(params: &FormalParameterList, body: &FunctionBody) -> bool {
463 contains(params, ContainsSymbol::SuperCall) || contains(body, ContainsSymbol::SuperCall)
464}
465
466pub(crate) trait IdentList {
468 fn add(&mut self, value: Sym, function: bool);
469}
470
471impl IdentList for Vec<Sym> {
472 fn add(&mut self, value: Sym, _function: bool) {
473 self.push(value);
474 }
475}
476
477impl IdentList for Vec<(Sym, bool)> {
478 fn add(&mut self, value: Sym, function: bool) {
479 self.push((value, function));
480 }
481}
482
483impl IdentList for FxHashSet<Sym> {
484 fn add(&mut self, value: Sym, _function: bool) {
485 self.insert(value);
486 }
487}
488
489#[derive(Debug)]
491pub(crate) struct BoundNamesVisitor<'a, T: IdentList>(pub(crate) &'a mut T);
492
493impl<'ast, T: IdentList> Visitor<'ast> for BoundNamesVisitor<'_, T> {
494 type BreakTy = Infallible;
495
496 fn visit_identifier(&mut self, node: &'ast Identifier) -> ControlFlow<Self::BreakTy> {
497 self.0.add(node.sym(), false);
498 ControlFlow::Continue(())
499 }
500
501 fn visit_expression(&mut self, _: &'ast Expression) -> ControlFlow<Self::BreakTy> {
502 ControlFlow::Continue(())
503 }
504
505 fn visit_function_expression(
506 &mut self,
507 node: &'ast FunctionExpression,
508 ) -> ControlFlow<Self::BreakTy> {
509 if let Some(ident) = node.name() {
510 self.0.add(ident.sym(), true);
511 }
512 ControlFlow::Continue(())
513 }
514
515 fn visit_function_declaration(
516 &mut self,
517 node: &'ast FunctionDeclaration,
518 ) -> ControlFlow<Self::BreakTy> {
519 self.0.add(node.name().sym(), true);
520 ControlFlow::Continue(())
521 }
522
523 fn visit_generator_expression(
524 &mut self,
525 node: &'ast GeneratorExpression,
526 ) -> ControlFlow<Self::BreakTy> {
527 if let Some(ident) = node.name() {
528 self.0.add(ident.sym(), false);
529 }
530 ControlFlow::Continue(())
531 }
532
533 fn visit_generator_declaration(
534 &mut self,
535 node: &'ast GeneratorDeclaration,
536 ) -> ControlFlow<Self::BreakTy> {
537 self.0.add(node.name().sym(), false);
538 ControlFlow::Continue(())
539 }
540
541 fn visit_async_function_expression(
542 &mut self,
543 node: &'ast AsyncFunctionExpression,
544 ) -> ControlFlow<Self::BreakTy> {
545 if let Some(ident) = node.name() {
546 self.0.add(ident.sym(), false);
547 }
548 ControlFlow::Continue(())
549 }
550
551 fn visit_async_function_declaration(
552 &mut self,
553 node: &'ast AsyncFunctionDeclaration,
554 ) -> ControlFlow<Self::BreakTy> {
555 self.0.add(node.name().sym(), false);
556 ControlFlow::Continue(())
557 }
558
559 fn visit_async_generator_expression(
560 &mut self,
561 node: &'ast AsyncGeneratorExpression,
562 ) -> ControlFlow<Self::BreakTy> {
563 if let Some(ident) = node.name() {
564 self.0.add(ident.sym(), false);
565 }
566 ControlFlow::Continue(())
567 }
568
569 fn visit_async_generator_declaration(
570 &mut self,
571 node: &'ast AsyncGeneratorDeclaration,
572 ) -> ControlFlow<Self::BreakTy> {
573 self.0.add(node.name().sym(), false);
574 ControlFlow::Continue(())
575 }
576
577 fn visit_class_expression(
578 &mut self,
579 node: &'ast ClassExpression,
580 ) -> ControlFlow<Self::BreakTy> {
581 if let Some(ident) = node.name() {
582 self.0.add(ident.sym(), false);
583 }
584 ControlFlow::Continue(())
585 }
586
587 fn visit_class_declaration(
588 &mut self,
589 node: &'ast ClassDeclaration,
590 ) -> ControlFlow<Self::BreakTy> {
591 self.0.add(node.name().sym(), false);
592 ControlFlow::Continue(())
593 }
594
595 fn visit_export_declaration(
596 &mut self,
597 node: &'ast ExportDeclaration,
598 ) -> ControlFlow<Self::BreakTy> {
599 match node {
600 ExportDeclaration::VarStatement(var) => self.visit_var_declaration(var)?,
601 ExportDeclaration::Declaration(decl) => self.visit_declaration(decl)?,
602 ExportDeclaration::DefaultFunctionDeclaration(f) => {
603 self.0.add(f.name().sym(), true);
604 }
605 ExportDeclaration::DefaultGeneratorDeclaration(g) => {
606 self.0.add(g.name().sym(), false);
607 }
608 ExportDeclaration::DefaultAsyncFunctionDeclaration(af) => {
609 self.0.add(af.name().sym(), false);
610 }
611 ExportDeclaration::DefaultAsyncGeneratorDeclaration(ag) => {
612 self.0.add(ag.name().sym(), false);
613 }
614 ExportDeclaration::DefaultClassDeclaration(cl) => {
615 self.0.add(cl.name().sym(), false);
616 }
617 ExportDeclaration::DefaultAssignmentExpression(_) => {
618 self.0.add(Sym::DEFAULT_EXPORT, false);
619 }
620 ExportDeclaration::ReExport { .. } | ExportDeclaration::List(_) => {}
621 }
622
623 ControlFlow::Continue(())
624 }
625}
626
627#[must_use]
633pub fn bound_names<'a, N>(node: &'a N) -> Vec<Sym>
634where
635 &'a N: Into<NodeRef<'a>>,
636{
637 let mut names = Vec::new();
638 let _ = BoundNamesVisitor(&mut names).visit(node.into());
639
640 names
641}
642
643#[derive(Debug)]
645struct LexicallyDeclaredNamesVisitor<'a, T: IdentList>(&'a mut T);
646
647impl<'ast, T: IdentList> Visitor<'ast> for LexicallyDeclaredNamesVisitor<'_, T> {
648 type BreakTy = Infallible;
649
650 fn visit_script(&mut self, node: &'ast Script) -> ControlFlow<Self::BreakTy> {
651 top_level_lexicals(node.statements(), self.0);
652 ControlFlow::Continue(())
653 }
654
655 fn visit_function_body(&mut self, node: &'ast FunctionBody) -> ControlFlow<Self::BreakTy> {
656 top_level_lexicals(node.statement_list(), self.0);
657 ControlFlow::Continue(())
658 }
659
660 fn visit_module_item(&mut self, node: &'ast ModuleItem) -> ControlFlow<Self::BreakTy> {
661 match node {
662 ModuleItem::ImportDeclaration(import) => {
664 BoundNamesVisitor(self.0).visit_import_declaration(import)
666 }
667
668 ModuleItem::ExportDeclaration(export) => {
670 if matches!(export.as_ref(), ExportDeclaration::VarStatement(_)) {
672 ControlFlow::Continue(())
673 } else {
674 BoundNamesVisitor(self.0).visit_export_declaration(export)
676 }
677 }
678
679 ModuleItem::StatementListItem(item) => {
681 self.visit_statement_list_item(item)
683 }
684 }
685 }
686
687 fn visit_expression(&mut self, _: &'ast Expression) -> ControlFlow<Self::BreakTy> {
688 ControlFlow::Continue(())
689 }
690
691 fn visit_statement(&mut self, node: &'ast Statement) -> ControlFlow<Self::BreakTy> {
692 if let Statement::Labelled(labelled) = node {
693 return self.visit_labelled(labelled);
694 }
695 ControlFlow::Continue(())
696 }
697
698 fn visit_declaration(&mut self, node: &'ast Declaration) -> ControlFlow<Self::BreakTy> {
699 BoundNamesVisitor(self.0).visit_declaration(node)
700 }
701
702 fn visit_labelled_item(&mut self, node: &'ast LabelledItem) -> ControlFlow<Self::BreakTy> {
703 match node {
704 LabelledItem::FunctionDeclaration(f) => {
705 BoundNamesVisitor(self.0).visit_function_declaration(f)
706 }
707 LabelledItem::Statement(_) => ControlFlow::Continue(()),
708 }
709 }
710
711 fn visit_function_expression(
712 &mut self,
713 node: &'ast FunctionExpression,
714 ) -> ControlFlow<Self::BreakTy> {
715 self.visit_function_body(node.body())
716 }
717
718 fn visit_function_declaration(
719 &mut self,
720 node: &'ast FunctionDeclaration,
721 ) -> ControlFlow<Self::BreakTy> {
722 self.visit_function_body(node.body())
723 }
724
725 fn visit_async_function_expression(
726 &mut self,
727 node: &'ast AsyncFunctionExpression,
728 ) -> ControlFlow<Self::BreakTy> {
729 self.visit_function_body(node.body())
730 }
731
732 fn visit_async_function_declaration(
733 &mut self,
734 node: &'ast AsyncFunctionDeclaration,
735 ) -> ControlFlow<Self::BreakTy> {
736 self.visit_function_body(node.body())
737 }
738
739 fn visit_generator_expression(
740 &mut self,
741 node: &'ast GeneratorExpression,
742 ) -> ControlFlow<Self::BreakTy> {
743 self.visit_function_body(node.body())
744 }
745
746 fn visit_generator_declaration(
747 &mut self,
748 node: &'ast GeneratorDeclaration,
749 ) -> ControlFlow<Self::BreakTy> {
750 self.visit_function_body(node.body())
751 }
752
753 fn visit_async_generator_expression(
754 &mut self,
755 node: &'ast AsyncGeneratorExpression,
756 ) -> ControlFlow<Self::BreakTy> {
757 self.visit_function_body(node.body())
758 }
759
760 fn visit_async_generator_declaration(
761 &mut self,
762 node: &'ast AsyncGeneratorDeclaration,
763 ) -> ControlFlow<Self::BreakTy> {
764 self.visit_function_body(node.body())
765 }
766
767 fn visit_arrow_function(&mut self, node: &'ast ArrowFunction) -> ControlFlow<Self::BreakTy> {
768 self.visit_function_body(node.body())
769 }
770
771 fn visit_async_arrow_function(
772 &mut self,
773 node: &'ast AsyncArrowFunction,
774 ) -> ControlFlow<Self::BreakTy> {
775 self.visit_function_body(node.body())
776 }
777
778 fn visit_class_element(&mut self, node: &'ast ClassElement) -> ControlFlow<Self::BreakTy> {
779 if let ClassElement::StaticBlock(block) = node {
780 self.visit_function_body(&block.body)?;
781 }
782 ControlFlow::Continue(())
783 }
784
785 fn visit_import_declaration(
786 &mut self,
787 node: &'ast ImportDeclaration,
788 ) -> ControlFlow<Self::BreakTy> {
789 BoundNamesVisitor(self.0).visit_import_declaration(node)
790 }
791
792 fn visit_export_declaration(
793 &mut self,
794 node: &'ast ExportDeclaration,
795 ) -> ControlFlow<Self::BreakTy> {
796 if matches!(node, ExportDeclaration::VarStatement(_)) {
797 return ControlFlow::Continue(());
798 }
799 BoundNamesVisitor(self.0).visit_export_declaration(node)
800 }
801}
802
803#[must_use]
809pub fn lexically_declared_names<'a, N>(node: &'a N) -> Vec<Sym>
810where
811 &'a N: Into<NodeRef<'a>>,
812{
813 let mut names = Vec::new();
814 let _ = LexicallyDeclaredNamesVisitor(&mut names).visit(node.into());
815 names
816}
817
818#[must_use]
826pub fn lexically_declared_names_legacy<'a, N>(node: &'a N) -> Vec<(Sym, bool)>
827where
828 &'a N: Into<NodeRef<'a>>,
829{
830 let mut names = Vec::new();
831 let _ = LexicallyDeclaredNamesVisitor(&mut names).visit(node.into());
832 names
833}
834
835#[derive(Debug)]
837struct VarDeclaredNamesVisitor<'a>(&'a mut FxHashSet<Sym>);
838
839impl<'ast> Visitor<'ast> for VarDeclaredNamesVisitor<'_> {
840 type BreakTy = Infallible;
841
842 fn visit_script(&mut self, node: &'ast Script) -> ControlFlow<Self::BreakTy> {
843 top_level_vars(node.statements(), self.0);
844 ControlFlow::Continue(())
845 }
846
847 fn visit_function_body(&mut self, node: &'ast FunctionBody) -> ControlFlow<Self::BreakTy> {
848 top_level_vars(node.statement_list(), self.0);
849 ControlFlow::Continue(())
850 }
851
852 fn visit_module_item(&mut self, node: &'ast ModuleItem) -> ControlFlow<Self::BreakTy> {
853 match node {
854 ModuleItem::ImportDeclaration(_) => {
856 ControlFlow::Continue(())
858 }
859
860 ModuleItem::ExportDeclaration(export) => {
862 if let ExportDeclaration::VarStatement(var) = export.as_ref() {
864 BoundNamesVisitor(self.0).visit_var_declaration(var)
865 } else {
866 ControlFlow::Continue(())
868 }
869 }
870
871 ModuleItem::StatementListItem(item) => self.visit_statement_list_item(item),
872 }
873 }
874
875 fn visit_statement(&mut self, node: &'ast Statement) -> ControlFlow<Self::BreakTy> {
876 match node {
877 Statement::Empty
878 | Statement::Debugger
879 | Statement::Expression(_)
880 | Statement::Continue(_)
881 | Statement::Break(_)
882 | Statement::Return(_)
883 | Statement::Throw(_) => ControlFlow::Continue(()),
884 Statement::Block(node) => self.visit(node),
885 Statement::Var(node) => self.visit(node),
886 Statement::If(node) => self.visit(node),
887 Statement::DoWhileLoop(node) => self.visit(node),
888 Statement::WhileLoop(node) => self.visit(node),
889 Statement::ForLoop(node) => self.visit(node),
890 Statement::ForInLoop(node) => self.visit(node),
891 Statement::ForOfLoop(node) => self.visit(node),
892 Statement::Switch(node) => self.visit(node),
893 Statement::Labelled(node) => self.visit(node),
894 Statement::Try(node) => self.visit(node),
895 Statement::With(node) => self.visit(node),
896 }
897 }
898
899 fn visit_statement_list_item(
900 &mut self,
901 node: &'ast StatementListItem,
902 ) -> ControlFlow<Self::BreakTy> {
903 match node {
904 StatementListItem::Statement(stmt) => self.visit_statement(stmt),
905 StatementListItem::Declaration(_) => ControlFlow::Continue(()),
906 }
907 }
908
909 fn visit_variable(&mut self, node: &'ast Variable) -> ControlFlow<Self::BreakTy> {
910 BoundNamesVisitor(self.0).visit_variable(node)
911 }
912
913 fn visit_if(&mut self, node: &'ast crate::statement::If) -> ControlFlow<Self::BreakTy> {
914 if let Some(node) = node.else_node() {
915 self.visit(node)?;
916 }
917 self.visit(node.body())
918 }
919
920 fn visit_do_while_loop(
921 &mut self,
922 node: &'ast crate::statement::DoWhileLoop,
923 ) -> ControlFlow<Self::BreakTy> {
924 self.visit(node.body())
925 }
926
927 fn visit_while_loop(
928 &mut self,
929 node: &'ast crate::statement::WhileLoop,
930 ) -> ControlFlow<Self::BreakTy> {
931 self.visit(node.body())
932 }
933
934 fn visit_for_loop(
935 &mut self,
936 node: &'ast crate::statement::ForLoop,
937 ) -> ControlFlow<Self::BreakTy> {
938 if let Some(ForLoopInitializer::Var(node)) = node.init() {
939 BoundNamesVisitor(self.0).visit_var_declaration(node)?;
940 }
941 self.visit(node.body())
942 }
943
944 fn visit_for_in_loop(
945 &mut self,
946 node: &'ast crate::statement::ForInLoop,
947 ) -> ControlFlow<Self::BreakTy> {
948 if let IterableLoopInitializer::Var(node) = node.initializer() {
949 BoundNamesVisitor(self.0).visit_variable(node)?;
950 }
951 self.visit(node.body())
952 }
953
954 fn visit_for_of_loop(
955 &mut self,
956 node: &'ast crate::statement::ForOfLoop,
957 ) -> ControlFlow<Self::BreakTy> {
958 if let IterableLoopInitializer::Var(node) = node.initializer() {
959 BoundNamesVisitor(self.0).visit_variable(node)?;
960 }
961 self.visit(node.body())
962 }
963
964 fn visit_with(&mut self, node: &'ast With) -> ControlFlow<Self::BreakTy> {
965 self.visit(node.statement())
966 }
967
968 fn visit_switch(&mut self, node: &'ast crate::statement::Switch) -> ControlFlow<Self::BreakTy> {
969 for case in node.cases() {
970 self.visit(case)?;
971 }
972 if let Some(node) = node.default() {
973 self.visit(node)?;
974 }
975 ControlFlow::Continue(())
976 }
977
978 fn visit_labelled_item(&mut self, node: &'ast LabelledItem) -> ControlFlow<Self::BreakTy> {
979 match node {
980 LabelledItem::FunctionDeclaration(_) => ControlFlow::Continue(()),
981 LabelledItem::Statement(stmt) => self.visit(stmt),
982 }
983 }
984
985 fn visit_try(&mut self, node: &'ast crate::statement::Try) -> ControlFlow<Self::BreakTy> {
986 if let Some(node) = node.finally() {
987 self.visit(node)?;
988 }
989 if let Some(node) = node.catch() {
990 self.visit(node.block())?;
991 }
992 self.visit(node.block())
993 }
994
995 fn visit_function_expression(
996 &mut self,
997 node: &'ast FunctionExpression,
998 ) -> ControlFlow<Self::BreakTy> {
999 self.visit_function_body(node.body())
1000 }
1001
1002 fn visit_function_declaration(
1003 &mut self,
1004 node: &'ast FunctionDeclaration,
1005 ) -> ControlFlow<Self::BreakTy> {
1006 self.visit_function_body(node.body())
1007 }
1008
1009 fn visit_async_function_expression(
1010 &mut self,
1011 node: &'ast AsyncFunctionExpression,
1012 ) -> ControlFlow<Self::BreakTy> {
1013 self.visit_function_body(node.body())
1014 }
1015
1016 fn visit_async_function_declaration(
1017 &mut self,
1018 node: &'ast AsyncFunctionDeclaration,
1019 ) -> ControlFlow<Self::BreakTy> {
1020 self.visit_function_body(node.body())
1021 }
1022
1023 fn visit_generator_expression(
1024 &mut self,
1025 node: &'ast GeneratorExpression,
1026 ) -> ControlFlow<Self::BreakTy> {
1027 self.visit_function_body(node.body())
1028 }
1029
1030 fn visit_generator_declaration(
1031 &mut self,
1032 node: &'ast GeneratorDeclaration,
1033 ) -> ControlFlow<Self::BreakTy> {
1034 self.visit_function_body(node.body())
1035 }
1036
1037 fn visit_async_generator_expression(
1038 &mut self,
1039 node: &'ast AsyncGeneratorExpression,
1040 ) -> ControlFlow<Self::BreakTy> {
1041 self.visit_function_body(node.body())
1042 }
1043
1044 fn visit_async_generator_declaration(
1045 &mut self,
1046 node: &'ast AsyncGeneratorDeclaration,
1047 ) -> ControlFlow<Self::BreakTy> {
1048 self.visit_function_body(node.body())
1049 }
1050
1051 fn visit_class_element(&mut self, node: &'ast ClassElement) -> ControlFlow<Self::BreakTy> {
1052 if let ClassElement::StaticBlock(block) = node {
1053 self.visit_function_body(&block.body)?;
1054 }
1055 node.visit_with(self)
1056 }
1057
1058 fn visit_import_declaration(
1059 &mut self,
1060 _: &'ast ImportDeclaration,
1061 ) -> ControlFlow<Self::BreakTy> {
1062 ControlFlow::Continue(())
1063 }
1064
1065 fn visit_export_declaration(
1066 &mut self,
1067 node: &'ast ExportDeclaration,
1068 ) -> ControlFlow<Self::BreakTy> {
1069 match node {
1070 ExportDeclaration::VarStatement(var) => {
1071 BoundNamesVisitor(self.0).visit_var_declaration(var)
1072 }
1073 _ => ControlFlow::Continue(()),
1074 }
1075 }
1076}
1077
1078#[must_use]
1084pub fn var_declared_names<'a, N>(node: &'a N) -> FxHashSet<Sym>
1085where
1086 &'a N: Into<NodeRef<'a>>,
1087{
1088 let mut names = FxHashSet::default();
1089 let _ = VarDeclaredNamesVisitor(&mut names).visit(node.into());
1090 names
1091}
1092
1093fn top_level_lexicals<T: IdentList>(stmts: &StatementList, names: &mut T) {
1099 for stmt in stmts.statements() {
1100 if let StatementListItem::Declaration(decl) = stmt {
1101 match decl.as_ref() {
1102 Declaration::FunctionDeclaration(_)
1106 | Declaration::GeneratorDeclaration(_)
1107 | Declaration::AsyncFunctionDeclaration(_)
1108 | Declaration::AsyncGeneratorDeclaration(_) => {}
1109 Declaration::ClassDeclaration(class) => {
1110 let _ = BoundNamesVisitor(names).visit_class_declaration(class);
1111 }
1112 Declaration::Lexical(decl) => {
1113 let _ = BoundNamesVisitor(names).visit_lexical_declaration(decl);
1114 }
1115 }
1116 }
1117 }
1118}
1119
1120fn top_level_vars(stmts: &StatementList, names: &mut FxHashSet<Sym>) {
1126 for stmt in stmts.statements() {
1127 match stmt {
1128 StatementListItem::Declaration(decl) => {
1129 match decl.as_ref() {
1130 Declaration::FunctionDeclaration(f) => {
1134 let _ = BoundNamesVisitor(names).visit_function_declaration(f);
1135 }
1136 Declaration::GeneratorDeclaration(f) => {
1137 let _ = BoundNamesVisitor(names).visit_generator_declaration(f);
1138 }
1139 Declaration::AsyncFunctionDeclaration(f) => {
1140 let _ = BoundNamesVisitor(names).visit_async_function_declaration(f);
1141 }
1142 Declaration::AsyncGeneratorDeclaration(f) => {
1143 let _ = BoundNamesVisitor(names).visit_async_generator_declaration(f);
1144 }
1145 Declaration::ClassDeclaration(_) | Declaration::Lexical(_) => {}
1146 }
1147 }
1148 StatementListItem::Statement(stmt) => {
1149 let mut stmt = Some(stmt.as_ref());
1150 while let Some(Statement::Labelled(labelled)) = stmt.as_ref() {
1151 match labelled.item() {
1152 LabelledItem::FunctionDeclaration(f) => {
1153 let _ = BoundNamesVisitor(names).visit_function_declaration(f);
1154 stmt = None;
1155 }
1156 LabelledItem::Statement(s) => stmt = Some(s),
1157 }
1158 }
1159 if let Some(stmt) = stmt {
1160 let _ = VarDeclaredNamesVisitor(names).visit(stmt);
1161 }
1162 }
1163 }
1164 }
1165}
1166
1167#[must_use]
1173#[inline]
1174pub fn all_private_identifiers_valid<'a, N>(node: &'a N, private_names: Vec<Sym>) -> bool
1175where
1176 &'a N: Into<NodeRef<'a>>,
1177{
1178 AllPrivateIdentifiersValidVisitor(private_names)
1179 .visit(node.into())
1180 .is_continue()
1181}
1182
1183struct AllPrivateIdentifiersValidVisitor(Vec<Sym>);
1184
1185impl<'ast> Visitor<'ast> for AllPrivateIdentifiersValidVisitor {
1186 type BreakTy = ();
1187
1188 fn visit_class_expression(
1189 &mut self,
1190 node: &'ast ClassExpression,
1191 ) -> ControlFlow<Self::BreakTy> {
1192 if let Some(node) = node.super_ref() {
1193 self.visit(node)?;
1194 }
1195
1196 let mut names = self.0.clone();
1197 for element in node.elements() {
1198 match element {
1199 ClassElement::MethodDefinition(m) => {
1200 if let ClassElementName::PrivateName(name) = m.name() {
1201 names.push(name.description());
1202 }
1203 }
1204 ClassElement::PrivateFieldDefinition(PrivateFieldDefinition { name, .. })
1205 | ClassElement::PrivateStaticFieldDefinition(PrivateFieldDefinition {
1206 name, ..
1207 }) => {
1208 names.push(name.description());
1209 }
1210 _ => {}
1211 }
1212 }
1213
1214 let mut visitor = Self(names);
1215
1216 if let Some(node) = node.constructor() {
1217 visitor.visit(node)?;
1218 }
1219
1220 for element in node.elements() {
1221 match element {
1222 ClassElement::MethodDefinition(m) => {
1223 if let ClassElementName::PropertyName(name) = m.name() {
1224 visitor.visit(name)?;
1225 }
1226 visitor.visit(m.parameters())?;
1227 visitor.visit(m.body())?;
1228 }
1229 ClassElement::FieldDefinition(field)
1230 | ClassElement::StaticFieldDefinition(field) => {
1231 visitor.visit(&field.name)?;
1232 if let Some(expression) = &field.initializer {
1233 visitor.visit(expression)?;
1234 }
1235 }
1236 ClassElement::PrivateFieldDefinition(PrivateFieldDefinition {
1237 initializer,
1238 ..
1239 })
1240 | ClassElement::PrivateStaticFieldDefinition(PrivateFieldDefinition {
1241 initializer,
1242 ..
1243 }) => {
1244 if let Some(expression) = initializer {
1245 visitor.visit(expression)?;
1246 }
1247 }
1248 ClassElement::StaticBlock(block) => {
1249 visitor.visit(&block.body)?;
1250 }
1251 }
1252 }
1253
1254 ControlFlow::Continue(())
1255 }
1256
1257 fn visit_class_declaration(
1258 &mut self,
1259 node: &'ast ClassDeclaration,
1260 ) -> ControlFlow<Self::BreakTy> {
1261 if let Some(node) = node.super_ref() {
1262 self.visit(node)?;
1263 }
1264
1265 let mut names = self.0.clone();
1266 for element in node.elements() {
1267 match element {
1268 ClassElement::MethodDefinition(m) => {
1269 if let ClassElementName::PrivateName(name) = m.name() {
1270 names.push(name.description());
1271 }
1272 }
1273 ClassElement::PrivateFieldDefinition(PrivateFieldDefinition { name, .. })
1274 | ClassElement::PrivateStaticFieldDefinition(PrivateFieldDefinition {
1275 name, ..
1276 }) => {
1277 names.push(name.description());
1278 }
1279 _ => {}
1280 }
1281 }
1282
1283 let mut visitor = Self(names);
1284
1285 if let Some(node) = node.constructor() {
1286 visitor.visit(node)?;
1287 }
1288
1289 for element in node.elements() {
1290 match element {
1291 ClassElement::MethodDefinition(m) => {
1292 if let ClassElementName::PropertyName(name) = m.name() {
1293 visitor.visit(name)?;
1294 }
1295 visitor.visit(m.parameters())?;
1296 visitor.visit(m.body())?;
1297 }
1298 ClassElement::FieldDefinition(field)
1299 | ClassElement::StaticFieldDefinition(field) => {
1300 visitor.visit(&field.name)?;
1301 if let Some(expression) = &field.initializer {
1302 visitor.visit(expression)?;
1303 }
1304 }
1305 ClassElement::PrivateFieldDefinition(PrivateFieldDefinition {
1306 initializer,
1307 ..
1308 })
1309 | ClassElement::PrivateStaticFieldDefinition(PrivateFieldDefinition {
1310 initializer,
1311 ..
1312 }) => {
1313 if let Some(expression) = initializer {
1314 visitor.visit(expression)?;
1315 }
1316 }
1317 ClassElement::StaticBlock(block) => {
1318 visitor.visit(&block.body)?;
1319 }
1320 }
1321 }
1322
1323 ControlFlow::Continue(())
1324 }
1325
1326 fn visit_private_property_access(
1327 &mut self,
1328 node: &'ast PrivatePropertyAccess,
1329 ) -> ControlFlow<Self::BreakTy> {
1330 if self.0.contains(&node.field().description()) {
1331 self.visit(node.target())
1332 } else {
1333 ControlFlow::Break(())
1334 }
1335 }
1336
1337 fn visit_binary_in_private(
1338 &mut self,
1339 node: &'ast BinaryInPrivate,
1340 ) -> ControlFlow<Self::BreakTy> {
1341 if self.0.contains(&node.lhs().description()) {
1342 self.visit(node.rhs())
1343 } else {
1344 ControlFlow::Break(())
1345 }
1346 }
1347
1348 fn visit_optional_operation_kind(
1349 &mut self,
1350 node: &'ast OptionalOperationKind,
1351 ) -> ControlFlow<Self::BreakTy> {
1352 match node {
1353 OptionalOperationKind::SimplePropertyAccess { field } => {
1354 self.visit_property_access_field(field)
1355 }
1356 OptionalOperationKind::PrivatePropertyAccess { field } => {
1357 if self.0.contains(&field.description()) {
1358 ControlFlow::Continue(())
1359 } else {
1360 ControlFlow::Break(())
1361 }
1362 }
1363 OptionalOperationKind::Call { args } => {
1364 for arg in args {
1365 self.visit_expression(arg)?;
1366 }
1367 ControlFlow::Continue(())
1368 }
1369 }
1370 }
1371}
1372
1373#[derive(Debug, Clone, Copy)]
1375pub enum CheckLabelsError {
1376 DuplicateLabel(Sym),
1378
1379 UndefinedBreakTarget(Sym),
1381
1382 UndefinedContinueTarget(Sym),
1384
1385 IllegalBreakStatement,
1387
1388 IllegalContinueStatement,
1390}
1391
1392impl CheckLabelsError {
1393 #[must_use]
1395 pub fn message(&self, interner: &Interner) -> String {
1396 match self {
1397 Self::DuplicateLabel(label) => {
1398 format!("duplicate label: {}", interner.resolve_expect(*label))
1399 }
1400 Self::UndefinedBreakTarget(label) => {
1401 format!(
1402 "undefined break target: {}",
1403 interner.resolve_expect(*label)
1404 )
1405 }
1406 Self::UndefinedContinueTarget(label) => format!(
1407 "undefined continue target: {}",
1408 interner.resolve_expect(*label)
1409 ),
1410 Self::IllegalBreakStatement => "illegal break statement".into(),
1411 Self::IllegalContinueStatement => "illegal continue statement".into(),
1412 }
1413 }
1414}
1415
1416pub fn check_labels<N>(node: &N) -> Result<(), CheckLabelsError>
1435where
1436 N: VisitWith,
1437{
1438 #[derive(Debug, Clone)]
1439 struct CheckLabelsResolver {
1440 labels: FxHashSet<Sym>,
1441 continue_iteration_labels: FxHashSet<Sym>,
1442 continue_labels: Option<FxHashSet<Sym>>,
1443 iteration: bool,
1444 switch: bool,
1445 }
1446
1447 impl<'ast> Visitor<'ast> for CheckLabelsResolver {
1448 type BreakTy = CheckLabelsError;
1449
1450 fn visit_statement(&mut self, node: &'ast Statement) -> ControlFlow<Self::BreakTy> {
1451 match node {
1452 Statement::Block(node) => self.visit_block(node),
1453 Statement::Var(_)
1454 | Statement::Empty
1455 | Statement::Debugger
1456 | Statement::Expression(_)
1457 | Statement::Return(_)
1458 | Statement::Throw(_) => ControlFlow::Continue(()),
1459 Statement::If(node) => self.visit_if(node),
1460 Statement::DoWhileLoop(node) => self.visit_do_while_loop(node),
1461 Statement::WhileLoop(node) => self.visit_while_loop(node),
1462 Statement::ForLoop(node) => self.visit_for_loop(node),
1463 Statement::ForInLoop(node) => self.visit_for_in_loop(node),
1464 Statement::ForOfLoop(node) => self.visit_for_of_loop(node),
1465 Statement::Switch(node) => self.visit_switch(node),
1466 Statement::Labelled(node) => self.visit_labelled(node),
1467 Statement::Try(node) => self.visit_try(node),
1468 Statement::Continue(node) => self.visit_continue(node),
1469 Statement::Break(node) => self.visit_break(node),
1470 Statement::With(with) => self.visit_with(with),
1471 }
1472 }
1473
1474 fn visit_block(
1475 &mut self,
1476 node: &'ast crate::statement::Block,
1477 ) -> ControlFlow<Self::BreakTy> {
1478 let continue_labels = self.continue_labels.take();
1479 self.visit_statement_list(node.statement_list())?;
1480 self.continue_labels = continue_labels;
1481 ControlFlow::Continue(())
1482 }
1483
1484 fn visit_break(
1485 &mut self,
1486 node: &'ast crate::statement::Break,
1487 ) -> ControlFlow<Self::BreakTy> {
1488 if let Some(label) = node.label() {
1489 if !self.labels.contains(&label) {
1490 return ControlFlow::Break(CheckLabelsError::UndefinedBreakTarget(label));
1491 }
1492 } else if !self.iteration && !self.switch {
1493 return ControlFlow::Break(CheckLabelsError::IllegalBreakStatement);
1494 }
1495 ControlFlow::Continue(())
1496 }
1497
1498 fn visit_continue(
1499 &mut self,
1500 node: &'ast crate::statement::Continue,
1501 ) -> ControlFlow<Self::BreakTy> {
1502 if !self.iteration {
1503 return ControlFlow::Break(CheckLabelsError::IllegalContinueStatement);
1504 }
1505
1506 if let Some(label) = node.label()
1507 && !self.continue_iteration_labels.contains(&label)
1508 {
1509 return ControlFlow::Break(CheckLabelsError::UndefinedContinueTarget(label));
1510 }
1511 ControlFlow::Continue(())
1512 }
1513
1514 fn visit_do_while_loop(
1515 &mut self,
1516 node: &'ast crate::statement::DoWhileLoop,
1517 ) -> ControlFlow<Self::BreakTy> {
1518 let continue_labels = self.continue_labels.take();
1519 let continue_iteration_labels = self.continue_iteration_labels.clone();
1520 if let Some(continue_labels) = &continue_labels {
1521 self.continue_iteration_labels.extend(continue_labels);
1522 }
1523 let iteration = self.iteration;
1524 self.iteration = true;
1525 self.visit_statement(node.body())?;
1526 self.continue_iteration_labels = continue_iteration_labels;
1527 self.continue_labels = continue_labels;
1528 self.iteration = iteration;
1529 ControlFlow::Continue(())
1530 }
1531
1532 fn visit_while_loop(
1533 &mut self,
1534 node: &'ast crate::statement::WhileLoop,
1535 ) -> ControlFlow<Self::BreakTy> {
1536 let continue_labels = self.continue_labels.take();
1537 let continue_iteration_labels = self.continue_iteration_labels.clone();
1538 if let Some(continue_labels) = &continue_labels {
1539 self.continue_iteration_labels.extend(continue_labels);
1540 }
1541 let iteration = self.iteration;
1542 self.iteration = true;
1543 self.visit_statement(node.body())?;
1544 self.continue_iteration_labels = continue_iteration_labels;
1545 self.continue_labels = continue_labels;
1546 self.iteration = iteration;
1547 ControlFlow::Continue(())
1548 }
1549
1550 fn visit_for_loop(
1551 &mut self,
1552 node: &'ast crate::statement::ForLoop,
1553 ) -> ControlFlow<Self::BreakTy> {
1554 let continue_labels = self.continue_labels.take();
1555 let continue_iteration_labels = self.continue_iteration_labels.clone();
1556 if let Some(continue_labels) = &continue_labels {
1557 self.continue_iteration_labels.extend(continue_labels);
1558 }
1559 let iteration = self.iteration;
1560 self.iteration = true;
1561 self.visit_statement(node.body())?;
1562 self.continue_iteration_labels = continue_iteration_labels;
1563 self.continue_labels = continue_labels;
1564 self.iteration = iteration;
1565 ControlFlow::Continue(())
1566 }
1567
1568 fn visit_for_in_loop(
1569 &mut self,
1570 node: &'ast crate::statement::ForInLoop,
1571 ) -> ControlFlow<Self::BreakTy> {
1572 let continue_labels = self.continue_labels.take();
1573 let continue_iteration_labels = self.continue_iteration_labels.clone();
1574 if let Some(continue_labels) = &continue_labels {
1575 self.continue_iteration_labels.extend(continue_labels);
1576 }
1577 let iteration = self.iteration;
1578 self.iteration = true;
1579 self.visit_statement(node.body())?;
1580 self.continue_iteration_labels = continue_iteration_labels;
1581 self.continue_labels = continue_labels;
1582 self.iteration = iteration;
1583 ControlFlow::Continue(())
1584 }
1585
1586 fn visit_for_of_loop(
1587 &mut self,
1588 node: &'ast crate::statement::ForOfLoop,
1589 ) -> ControlFlow<Self::BreakTy> {
1590 let continue_labels = self.continue_labels.take();
1591 let continue_iteration_labels = self.continue_iteration_labels.clone();
1592 if let Some(continue_labels) = &continue_labels {
1593 self.continue_iteration_labels.extend(continue_labels);
1594 }
1595 let iteration = self.iteration;
1596 self.iteration = true;
1597 self.visit_statement(node.body())?;
1598 self.continue_iteration_labels = continue_iteration_labels;
1599 self.continue_labels = continue_labels;
1600 self.iteration = iteration;
1601 ControlFlow::Continue(())
1602 }
1603
1604 fn visit_statement_list_item(
1605 &mut self,
1606 node: &'ast StatementListItem,
1607 ) -> ControlFlow<Self::BreakTy> {
1608 let continue_labels = self.continue_labels.take();
1609 if let StatementListItem::Statement(stmt) = node {
1610 self.visit_statement(stmt)?;
1611 }
1612 self.continue_labels = continue_labels;
1613 ControlFlow::Continue(())
1614 }
1615
1616 fn visit_if(&mut self, node: &'ast crate::statement::If) -> ControlFlow<Self::BreakTy> {
1617 let continue_labels = self.continue_labels.take();
1618 self.visit_statement(node.body())?;
1619 if let Some(stmt) = node.else_node() {
1620 self.visit_statement(stmt)?;
1621 }
1622 self.continue_labels = continue_labels;
1623 ControlFlow::Continue(())
1624 }
1625
1626 fn visit_switch(
1627 &mut self,
1628 node: &'ast crate::statement::Switch,
1629 ) -> ControlFlow<Self::BreakTy> {
1630 let continue_labels = self.continue_labels.take();
1631 let switch = self.switch;
1632 self.switch = true;
1633 for case in node.cases() {
1634 self.visit_statement_list(case.body())?;
1635 }
1636 if let Some(default) = node.default() {
1637 self.visit_statement_list(default)?;
1638 }
1639 self.continue_labels = continue_labels;
1640 self.switch = switch;
1641 ControlFlow::Continue(())
1642 }
1643
1644 fn visit_labelled(
1645 &mut self,
1646 node: &'ast crate::statement::Labelled,
1647 ) -> ControlFlow<Self::BreakTy> {
1648 let continue_labels = self.continue_labels.clone();
1649 if let Some(continue_labels) = &mut self.continue_labels {
1650 continue_labels.insert(node.label());
1651 } else {
1652 let mut continue_labels = FxHashSet::default();
1653 continue_labels.insert(node.label());
1654 self.continue_labels = Some(continue_labels);
1655 }
1656
1657 if !self.labels.insert(node.label()) {
1658 return ControlFlow::Break(CheckLabelsError::DuplicateLabel(node.label()));
1659 }
1660 self.visit_labelled_item(node.item())?;
1661 self.labels.remove(&node.label());
1662 self.continue_labels = continue_labels;
1663 ControlFlow::Continue(())
1664 }
1665
1666 fn visit_labelled_item(&mut self, node: &'ast LabelledItem) -> ControlFlow<Self::BreakTy> {
1667 match node {
1668 LabelledItem::Statement(stmt) => self.visit_statement(stmt),
1669 LabelledItem::FunctionDeclaration(_) => ControlFlow::Continue(()),
1670 }
1671 }
1672
1673 fn visit_try(&mut self, node: &'ast crate::statement::Try) -> ControlFlow<Self::BreakTy> {
1674 let continue_labels = self.continue_labels.take();
1675 self.visit_block(node.block())?;
1676 if let Some(catch) = node.catch() {
1677 self.visit_block(catch.block())?;
1678 }
1679 if let Some(finally) = node.finally() {
1680 self.visit_block(finally.block())?;
1681 }
1682 self.continue_labels = continue_labels;
1683 ControlFlow::Continue(())
1684 }
1685
1686 fn visit_module_item_list(
1687 &mut self,
1688 node: &'ast crate::ModuleItemList,
1689 ) -> ControlFlow<Self::BreakTy> {
1690 let continue_labels = self.continue_labels.take();
1691 for item in node.items() {
1692 self.visit_module_item(item)?;
1693 }
1694 self.continue_labels = continue_labels;
1695 ControlFlow::Continue(())
1696 }
1697
1698 fn visit_module_item(&mut self, node: &'ast ModuleItem) -> ControlFlow<Self::BreakTy> {
1699 match node {
1700 ModuleItem::ImportDeclaration(_) | ModuleItem::ExportDeclaration(_) => {
1701 ControlFlow::Continue(())
1702 }
1703 ModuleItem::StatementListItem(node) => self.visit_statement_list_item(node),
1704 }
1705 }
1706 }
1707
1708 let mut visitor = CheckLabelsResolver {
1709 labels: FxHashSet::default(),
1710 continue_iteration_labels: FxHashSet::default(),
1711 continue_labels: None,
1712 iteration: false,
1713 switch: false,
1714 };
1715
1716 if let ControlFlow::Break(error) = node.visit_with(&mut visitor) {
1717 Err(error)
1718 } else {
1719 Ok(())
1720 }
1721}
1722
1723#[must_use]
1725pub fn contains_invalid_object_literal<N>(node: &N) -> bool
1726where
1727 N: VisitWith,
1728{
1729 #[derive(Debug, Clone)]
1730 struct ContainsInvalidObjectLiteral {}
1731
1732 impl<'ast> Visitor<'ast> for ContainsInvalidObjectLiteral {
1733 type BreakTy = ();
1734
1735 fn visit_object_literal(
1736 &mut self,
1737 node: &'ast crate::expression::literal::ObjectLiteral,
1738 ) -> ControlFlow<Self::BreakTy> {
1739 for pd in node.properties() {
1740 if let PropertyDefinition::CoverInitializedName(..) = pd {
1741 return ControlFlow::Break(());
1742 }
1743 self.visit_property_definition(pd)?;
1744 }
1745 ControlFlow::Continue(())
1746 }
1747 }
1748
1749 let mut visitor = ContainsInvalidObjectLiteral {};
1750
1751 node.visit_with(&mut visitor).is_break()
1752}
1753
1754#[derive(Copy, Clone, Debug)]
1756pub enum LexicallyScopedDeclaration<'a> {
1757 LexicalDeclaration(&'a LexicalDeclaration),
1759
1760 FunctionDeclaration(&'a FunctionDeclaration),
1762
1763 GeneratorDeclaration(&'a GeneratorDeclaration),
1765
1766 AsyncFunctionDeclaration(&'a AsyncFunctionDeclaration),
1768
1769 AsyncGeneratorDeclaration(&'a AsyncGeneratorDeclaration),
1771
1772 ClassDeclaration(&'a ClassDeclaration),
1774
1775 AssignmentExpression(&'a Expression),
1779}
1780
1781impl LexicallyScopedDeclaration<'_> {
1782 #[must_use]
1784 pub fn bound_names(&self) -> Vec<Sym> {
1785 match *self {
1786 Self::LexicalDeclaration(v) => bound_names(v),
1787 Self::FunctionDeclaration(f) => bound_names(f),
1788 Self::GeneratorDeclaration(g) => bound_names(g),
1789 Self::AsyncFunctionDeclaration(f) => bound_names(f),
1790 Self::AsyncGeneratorDeclaration(g) => bound_names(g),
1791 Self::ClassDeclaration(cl) => bound_names(cl),
1792 Self::AssignmentExpression(expr) => bound_names(expr),
1793 }
1794 }
1795}
1796
1797impl<'ast> From<&'ast Declaration> for LexicallyScopedDeclaration<'ast> {
1798 fn from(value: &'ast Declaration) -> LexicallyScopedDeclaration<'ast> {
1799 match value {
1800 Declaration::FunctionDeclaration(f) => Self::FunctionDeclaration(f),
1801 Declaration::GeneratorDeclaration(g) => Self::GeneratorDeclaration(g),
1802 Declaration::AsyncFunctionDeclaration(af) => Self::AsyncFunctionDeclaration(af),
1803 Declaration::AsyncGeneratorDeclaration(ag) => Self::AsyncGeneratorDeclaration(ag),
1804 Declaration::ClassDeclaration(c) => Self::ClassDeclaration(c),
1805 Declaration::Lexical(lex) => Self::LexicalDeclaration(lex),
1806 }
1807 }
1808}
1809
1810#[must_use]
1816pub fn lexically_scoped_declarations<'a, N>(node: &'a N) -> Vec<LexicallyScopedDeclaration<'a>>
1817where
1818 &'a N: Into<NodeRef<'a>>,
1819{
1820 let mut declarations = Vec::new();
1821 let _ = LexicallyScopedDeclarationsVisitor(&mut declarations).visit(node.into());
1822 declarations
1823}
1824
1825#[derive(Debug)]
1827struct LexicallyScopedDeclarationsVisitor<'a, 'ast>(&'a mut Vec<LexicallyScopedDeclaration<'ast>>);
1828
1829impl<'ast> Visitor<'ast> for LexicallyScopedDeclarationsVisitor<'_, 'ast> {
1830 type BreakTy = Infallible;
1831
1832 fn visit_script(&mut self, node: &'ast Script) -> ControlFlow<Self::BreakTy> {
1834 TopLevelLexicallyScopedDeclarationsVisitor(self.0).visit_statement_list(node.statements())
1836 }
1837
1838 fn visit_function_body(&mut self, node: &'ast FunctionBody) -> ControlFlow<Self::BreakTy> {
1839 TopLevelLexicallyScopedDeclarationsVisitor(self.0)
1841 .visit_statement_list(node.statement_list())
1842 }
1843
1844 fn visit_export_declaration(
1845 &mut self,
1846 node: &'ast ExportDeclaration,
1847 ) -> ControlFlow<Self::BreakTy> {
1848 let decl = match node {
1849 ExportDeclaration::ReExport { .. }
1854 | ExportDeclaration::List(_)
1855 | ExportDeclaration::VarStatement(_) => {
1856 return ControlFlow::Continue(());
1858 }
1859
1860 ExportDeclaration::Declaration(decl) => {
1862 decl.into()
1864 }
1865
1866 ExportDeclaration::DefaultFunctionDeclaration(f) => {
1869 LexicallyScopedDeclaration::FunctionDeclaration(f)
1870 }
1871 ExportDeclaration::DefaultGeneratorDeclaration(g) => {
1872 LexicallyScopedDeclaration::GeneratorDeclaration(g)
1873 }
1874 ExportDeclaration::DefaultAsyncFunctionDeclaration(af) => {
1875 LexicallyScopedDeclaration::AsyncFunctionDeclaration(af)
1876 }
1877 ExportDeclaration::DefaultAsyncGeneratorDeclaration(ag) => {
1878 LexicallyScopedDeclaration::AsyncGeneratorDeclaration(ag)
1879 }
1880
1881 ExportDeclaration::DefaultClassDeclaration(c) => {
1883 LexicallyScopedDeclaration::ClassDeclaration(c)
1885 }
1886
1887 ExportDeclaration::DefaultAssignmentExpression(expr) => {
1889 LexicallyScopedDeclaration::AssignmentExpression(expr)
1891 }
1892 };
1893
1894 self.0.push(decl);
1895
1896 ControlFlow::Continue(())
1897 }
1898
1899 fn visit_statement_list_item(
1900 &mut self,
1901 node: &'ast StatementListItem,
1902 ) -> ControlFlow<Self::BreakTy> {
1903 match node {
1904 StatementListItem::Statement(statement) => {
1906 if let Statement::Labelled(labelled) = statement.as_ref() {
1908 self.visit_labelled(labelled)
1909 } else {
1910 ControlFlow::Continue(())
1912 }
1913 }
1914
1915 StatementListItem::Declaration(declaration) => {
1917 self.0.push(declaration.as_ref().into());
1919 ControlFlow::Continue(())
1920 }
1921 }
1922 }
1923
1924 fn visit_labelled_item(&mut self, node: &'ast LabelledItem) -> ControlFlow<Self::BreakTy> {
1925 match node {
1926 LabelledItem::FunctionDeclaration(f) => {
1928 self.0
1930 .push(LexicallyScopedDeclaration::FunctionDeclaration(f));
1931 }
1932
1933 LabelledItem::Statement(_) => {
1935 }
1937 }
1938 ControlFlow::Continue(())
1939 }
1940
1941 fn visit_module_item(&mut self, node: &'ast ModuleItem) -> ControlFlow<Self::BreakTy> {
1942 match node {
1943 ModuleItem::StatementListItem(item) => self.visit_statement_list_item(item),
1944 ModuleItem::ExportDeclaration(export) => self.visit_export_declaration(export),
1945
1946 ModuleItem::ImportDeclaration(_) => {
1948 ControlFlow::Continue(())
1950 }
1951 }
1952 }
1953}
1954#[derive(Debug)]
1960struct TopLevelLexicallyScopedDeclarationsVisitor<'a, 'ast>(
1961 &'a mut Vec<LexicallyScopedDeclaration<'ast>>,
1962);
1963
1964impl<'ast> Visitor<'ast> for TopLevelLexicallyScopedDeclarationsVisitor<'_, 'ast> {
1965 type BreakTy = Infallible;
1966
1967 fn visit_statement_list_item(
1968 &mut self,
1969 node: &'ast StatementListItem,
1970 ) -> ControlFlow<Self::BreakTy> {
1971 match node {
1972 StatementListItem::Declaration(d) => match d.as_ref() {
1974 Declaration::FunctionDeclaration(_)
1976 | Declaration::GeneratorDeclaration(_)
1977 | Declaration::AsyncFunctionDeclaration(_)
1978 | Declaration::AsyncGeneratorDeclaration(_) => {
1979 }
1981
1982 Declaration::ClassDeclaration(cl) => {
1984 self.0
1985 .push(LexicallyScopedDeclaration::ClassDeclaration(cl));
1986 }
1987 Declaration::Lexical(lex) => {
1988 self.0
1989 .push(LexicallyScopedDeclaration::LexicalDeclaration(lex));
1990 }
1991 },
1992
1993 StatementListItem::Statement(_) => {
1995 }
1997 }
1998
1999 ControlFlow::Continue(())
2000 }
2001}
2002
2003#[derive(Clone, Debug)]
2005pub enum VarScopedDeclaration {
2006 VariableDeclaration(Variable),
2008
2009 FunctionDeclaration(FunctionDeclaration),
2011
2012 GeneratorDeclaration(GeneratorDeclaration),
2014
2015 AsyncFunctionDeclaration(AsyncFunctionDeclaration),
2017
2018 AsyncGeneratorDeclaration(AsyncGeneratorDeclaration),
2020}
2021
2022impl VarScopedDeclaration {
2023 #[must_use]
2025 pub fn bound_names(&self) -> Vec<Sym> {
2026 match self {
2027 Self::VariableDeclaration(v) => bound_names(v),
2028 Self::FunctionDeclaration(f) => bound_names(f),
2029 Self::GeneratorDeclaration(g) => bound_names(g),
2030 Self::AsyncFunctionDeclaration(f) => bound_names(f),
2031 Self::AsyncGeneratorDeclaration(g) => bound_names(g),
2032 }
2033 }
2034
2035 #[must_use]
2037 pub fn linear_span(&self) -> Option<LinearSpan> {
2038 match self {
2039 VarScopedDeclaration::FunctionDeclaration(f) => Some(f.linear_span()),
2040 VarScopedDeclaration::GeneratorDeclaration(f) => Some(f.linear_span()),
2041 VarScopedDeclaration::AsyncFunctionDeclaration(f) => Some(f.linear_span()),
2042 VarScopedDeclaration::AsyncGeneratorDeclaration(f) => Some(f.linear_span()),
2043 VarScopedDeclaration::VariableDeclaration(_) => None,
2044 }
2045 }
2046}
2047
2048#[must_use]
2054pub fn var_scoped_declarations<'a, N>(node: &'a N) -> Vec<VarScopedDeclaration>
2055where
2056 &'a N: Into<NodeRef<'a>>,
2057{
2058 let mut declarations = Vec::new();
2059 let _ = VarScopedDeclarationsVisitor(&mut declarations).visit(node.into());
2060 declarations
2061}
2062
2063#[derive(Debug)]
2065struct VarScopedDeclarationsVisitor<'a>(&'a mut Vec<VarScopedDeclaration>);
2066
2067impl<'ast> Visitor<'ast> for VarScopedDeclarationsVisitor<'_> {
2068 type BreakTy = Infallible;
2069
2070 fn visit_script(&mut self, node: &'ast Script) -> ControlFlow<Self::BreakTy> {
2072 TopLevelVarScopedDeclarationsVisitor(self.0).visit_statement_list(node.statements())
2074 }
2075
2076 fn visit_function_body(&mut self, node: &'ast FunctionBody) -> ControlFlow<Self::BreakTy> {
2077 TopLevelVarScopedDeclarationsVisitor(self.0).visit_statement_list(node.statement_list())
2079 }
2080
2081 fn visit_statement(&mut self, node: &'ast Statement) -> ControlFlow<Self::BreakTy> {
2082 match node {
2083 Statement::Block(s) => self.visit(s),
2084 Statement::Var(s) => self.visit(s),
2085 Statement::If(s) => self.visit(s),
2086 Statement::DoWhileLoop(s) => self.visit(s),
2087 Statement::WhileLoop(s) => self.visit(s),
2088 Statement::ForLoop(s) => self.visit(s),
2089 Statement::ForInLoop(s) => self.visit(s),
2090 Statement::ForOfLoop(s) => self.visit(s),
2091 Statement::Switch(s) => self.visit(s),
2092 Statement::Labelled(s) => self.visit(s),
2093 Statement::Try(s) => self.visit(s),
2094 Statement::With(s) => self.visit(s),
2095 Statement::Empty
2096 | Statement::Debugger
2097 | Statement::Expression(_)
2098 | Statement::Continue(_)
2099 | Statement::Break(_)
2100 | Statement::Return(_)
2101 | Statement::Throw(_) => ControlFlow::Continue(()),
2102 }
2103 }
2104
2105 fn visit_statement_list_item(
2106 &mut self,
2107 node: &'ast StatementListItem,
2108 ) -> ControlFlow<Self::BreakTy> {
2109 match node {
2110 StatementListItem::Declaration(_) => ControlFlow::Continue(()),
2111 StatementListItem::Statement(s) => self.visit(s.as_ref()),
2112 }
2113 }
2114
2115 fn visit_var_declaration(&mut self, node: &'ast VarDeclaration) -> ControlFlow<Self::BreakTy> {
2116 for var in node.0.as_ref() {
2117 self.0
2118 .push(VarScopedDeclaration::VariableDeclaration(var.clone()));
2119 }
2120 ControlFlow::Continue(())
2121 }
2122
2123 fn visit_if(&mut self, node: &'ast crate::statement::If) -> ControlFlow<Self::BreakTy> {
2124 self.visit(node.body())?;
2125 if let Some(else_node) = node.else_node() {
2126 self.visit(else_node)?;
2127 }
2128 ControlFlow::Continue(())
2129 }
2130
2131 fn visit_do_while_loop(
2132 &mut self,
2133 node: &'ast crate::statement::DoWhileLoop,
2134 ) -> ControlFlow<Self::BreakTy> {
2135 self.visit(node.body())?;
2136 ControlFlow::Continue(())
2137 }
2138
2139 fn visit_while_loop(
2140 &mut self,
2141 node: &'ast crate::statement::WhileLoop,
2142 ) -> ControlFlow<Self::BreakTy> {
2143 self.visit(node.body())?;
2144 ControlFlow::Continue(())
2145 }
2146
2147 fn visit_for_loop(
2148 &mut self,
2149 node: &'ast crate::statement::ForLoop,
2150 ) -> ControlFlow<Self::BreakTy> {
2151 if let Some(ForLoopInitializer::Var(v)) = node.init() {
2152 self.visit(v)?;
2153 }
2154 self.visit(node.body())?;
2155 ControlFlow::Continue(())
2156 }
2157
2158 fn visit_for_in_loop(
2159 &mut self,
2160 node: &'ast crate::statement::ForInLoop,
2161 ) -> ControlFlow<Self::BreakTy> {
2162 if let IterableLoopInitializer::Var(var) = node.initializer() {
2163 self.0
2164 .push(VarScopedDeclaration::VariableDeclaration(var.clone()));
2165 }
2166 self.visit(node.body())?;
2167 ControlFlow::Continue(())
2168 }
2169
2170 fn visit_for_of_loop(
2171 &mut self,
2172 node: &'ast crate::statement::ForOfLoop,
2173 ) -> ControlFlow<Self::BreakTy> {
2174 if let IterableLoopInitializer::Var(var) = node.initializer() {
2175 self.0
2176 .push(VarScopedDeclaration::VariableDeclaration(var.clone()));
2177 }
2178 self.visit(node.body())?;
2179 ControlFlow::Continue(())
2180 }
2181
2182 fn visit_with(&mut self, node: &'ast With) -> ControlFlow<Self::BreakTy> {
2183 self.visit(node.statement())?;
2184 ControlFlow::Continue(())
2185 }
2186
2187 fn visit_switch(&mut self, node: &'ast crate::statement::Switch) -> ControlFlow<Self::BreakTy> {
2188 for case in node.cases() {
2189 self.visit(case)?;
2190 }
2191 if let Some(default) = node.default() {
2192 self.visit(default)?;
2193 }
2194 ControlFlow::Continue(())
2195 }
2196
2197 fn visit_case(&mut self, node: &'ast crate::statement::Case) -> ControlFlow<Self::BreakTy> {
2198 self.visit(node.body())?;
2199 ControlFlow::Continue(())
2200 }
2201
2202 fn visit_labelled_item(&mut self, node: &'ast LabelledItem) -> ControlFlow<Self::BreakTy> {
2203 match node {
2204 LabelledItem::Statement(s) => self.visit(s),
2205 LabelledItem::FunctionDeclaration(_) => ControlFlow::Continue(()),
2206 }
2207 }
2208
2209 fn visit_catch(&mut self, node: &'ast crate::statement::Catch) -> ControlFlow<Self::BreakTy> {
2210 self.visit(node.block())?;
2211 ControlFlow::Continue(())
2212 }
2213
2214 fn visit_module_item(&mut self, node: &'ast ModuleItem) -> ControlFlow<Self::BreakTy> {
2215 match node {
2216 ModuleItem::ExportDeclaration(decl) => {
2218 if let ExportDeclaration::VarStatement(var) = decl.as_ref() {
2219 self.visit_var_declaration(var)?;
2221 }
2222 }
2224 ModuleItem::StatementListItem(item) => {
2225 self.visit_statement_list_item(item)?;
2226 }
2227 ModuleItem::ImportDeclaration(_) => {
2229 }
2231 }
2232 ControlFlow::Continue(())
2233 }
2234}
2235
2236#[derive(Debug)]
2242struct TopLevelVarScopedDeclarationsVisitor<'a>(&'a mut Vec<VarScopedDeclaration>);
2243
2244impl<'ast> Visitor<'ast> for TopLevelVarScopedDeclarationsVisitor<'_> {
2245 type BreakTy = Infallible;
2246
2247 fn visit_statement_list_item(
2248 &mut self,
2249 node: &'ast StatementListItem,
2250 ) -> ControlFlow<Self::BreakTy> {
2251 match node {
2252 StatementListItem::Declaration(d) => {
2253 match d.as_ref() {
2254 Declaration::FunctionDeclaration(f) => {
2255 self.0
2256 .push(VarScopedDeclaration::FunctionDeclaration(f.clone()));
2257 }
2258 Declaration::GeneratorDeclaration(f) => {
2259 self.0
2260 .push(VarScopedDeclaration::GeneratorDeclaration(f.clone()));
2261 }
2262 Declaration::AsyncFunctionDeclaration(f) => {
2263 self.0
2264 .push(VarScopedDeclaration::AsyncFunctionDeclaration(f.clone()));
2265 }
2266 Declaration::AsyncGeneratorDeclaration(f) => {
2267 self.0
2268 .push(VarScopedDeclaration::AsyncGeneratorDeclaration(f.clone()));
2269 }
2270 _ => {}
2271 }
2272 ControlFlow::Continue(())
2273 }
2274 StatementListItem::Statement(statement) => {
2275 if let Statement::Labelled(labelled) = statement.as_ref() {
2276 self.visit(labelled)
2277 } else {
2278 VarScopedDeclarationsVisitor(self.0).visit(statement.as_ref())
2279 }
2280 }
2281 }
2282 }
2283
2284 fn visit_labelled_item(&mut self, node: &'ast LabelledItem) -> ControlFlow<Self::BreakTy> {
2285 match node {
2286 LabelledItem::Statement(Statement::Labelled(s)) => self.visit(s),
2287 LabelledItem::Statement(s) => {
2288 VarScopedDeclarationsVisitor(self.0).visit(s)?;
2289 ControlFlow::Continue(())
2290 }
2291 LabelledItem::FunctionDeclaration(f) => {
2292 self.0
2293 .push(VarScopedDeclaration::FunctionDeclaration(f.clone()));
2294 ControlFlow::Continue(())
2295 }
2296 }
2297 }
2298}
2299
2300#[must_use]
2313pub fn annex_b_function_declarations_names<'a, N>(node: &'a N) -> Vec<Sym>
2314where
2315 &'a N: Into<NodeRef<'a>>,
2316{
2317 let mut declarations = Vec::new();
2318 let _ = AnnexBFunctionDeclarationNamesVisitor(&mut declarations).visit(node.into());
2319 declarations
2320}
2321
2322#[derive(Debug)]
2324struct AnnexBFunctionDeclarationNamesVisitor<'a>(&'a mut Vec<Sym>);
2325
2326impl<'ast> Visitor<'ast> for AnnexBFunctionDeclarationNamesVisitor<'_> {
2327 type BreakTy = Infallible;
2328
2329 fn visit_statement_list_item(
2330 &mut self,
2331 node: &'ast StatementListItem,
2332 ) -> ControlFlow<Self::BreakTy> {
2333 match node {
2334 StatementListItem::Statement(node) => self.visit(node.as_ref()),
2335 StatementListItem::Declaration(_) => ControlFlow::Continue(()),
2336 }
2337 }
2338
2339 fn visit_statement(&mut self, node: &'ast Statement) -> ControlFlow<Self::BreakTy> {
2340 match node {
2341 Statement::Block(node) => self.visit(node),
2342 Statement::If(node) => self.visit(node),
2343 Statement::DoWhileLoop(node) => self.visit(node),
2344 Statement::WhileLoop(node) => self.visit(node),
2345 Statement::ForLoop(node) => self.visit(node),
2346 Statement::ForInLoop(node) => self.visit(node),
2347 Statement::ForOfLoop(node) => self.visit(node),
2348 Statement::Switch(node) => self.visit(node),
2349 Statement::Labelled(node) => self.visit(node),
2350 Statement::Try(node) => self.visit(node),
2351 Statement::With(node) => self.visit(node),
2352 _ => ControlFlow::Continue(()),
2353 }
2354 }
2355
2356 fn visit_block(&mut self, node: &'ast crate::statement::Block) -> ControlFlow<Self::BreakTy> {
2357 self.visit(node.statement_list())?;
2358 for statement in node.statement_list().statements() {
2359 if let StatementListItem::Declaration(declaration) = statement
2360 && let Declaration::FunctionDeclaration(function) = &**declaration
2361 {
2362 let name = function.name();
2363 self.0.push(name.sym());
2364 }
2365 }
2366
2367 let lexically_declared_names = lexically_declared_names_legacy(node.statement_list());
2368
2369 self.0
2370 .retain(|name| !lexically_declared_names.contains(&(*name, false)));
2371
2372 ControlFlow::Continue(())
2373 }
2374
2375 fn visit_switch(&mut self, node: &'ast crate::statement::Switch) -> ControlFlow<Self::BreakTy> {
2376 for case in node.cases() {
2377 self.visit(case)?;
2378 for statement in case.body().statements() {
2379 if let StatementListItem::Declaration(declaration) = statement
2380 && let Declaration::FunctionDeclaration(function) = &**declaration
2381 {
2382 let name = function.name();
2383 self.0.push(name.sym());
2384 }
2385 }
2386 }
2387 if let Some(default) = node.default() {
2388 self.visit(default)?;
2389 for statement in default.statements() {
2390 if let StatementListItem::Declaration(declaration) = statement
2391 && let Declaration::FunctionDeclaration(function) = declaration.as_ref()
2392 {
2393 let name = function.name();
2394 self.0.push(name.sym());
2395 }
2396 }
2397 }
2398
2399 let lexically_declared_names = lexically_declared_names_legacy(node);
2400
2401 self.0
2402 .retain(|name| !lexically_declared_names.contains(&(*name, false)));
2403
2404 ControlFlow::Continue(())
2405 }
2406
2407 fn visit_try(&mut self, node: &'ast crate::statement::Try) -> ControlFlow<Self::BreakTy> {
2408 self.visit(node.block())?;
2409 if let Some(catch) = node.catch() {
2410 self.visit(catch.block())?;
2411
2412 if let Some(Binding::Pattern(pattern)) = catch.parameter() {
2413 let bound_names = bound_names(pattern);
2414
2415 self.0.retain(|name| !bound_names.contains(name));
2416 }
2417 }
2418 if let Some(finally) = node.finally() {
2419 self.visit(finally.block())?;
2420 }
2421 ControlFlow::Continue(())
2422 }
2423
2424 fn visit_if(&mut self, node: &'ast crate::statement::If) -> ControlFlow<Self::BreakTy> {
2425 if let Some(node) = node.else_node() {
2426 self.visit(node)?;
2427 }
2428 self.visit(node.body())
2429 }
2430
2431 fn visit_do_while_loop(
2432 &mut self,
2433 node: &'ast crate::statement::DoWhileLoop,
2434 ) -> ControlFlow<Self::BreakTy> {
2435 self.visit(node.body())
2436 }
2437
2438 fn visit_while_loop(
2439 &mut self,
2440 node: &'ast crate::statement::WhileLoop,
2441 ) -> ControlFlow<Self::BreakTy> {
2442 self.visit(node.body())
2443 }
2444
2445 fn visit_for_loop(
2446 &mut self,
2447 node: &'ast crate::statement::ForLoop,
2448 ) -> ControlFlow<Self::BreakTy> {
2449 self.visit(node.body())?;
2450
2451 if let Some(ForLoopInitializer::Lexical(node)) = node.init() {
2452 let bound_names = bound_names(&node.declaration);
2453 self.0.retain(|name| !bound_names.contains(name));
2454 }
2455
2456 ControlFlow::Continue(())
2457 }
2458
2459 fn visit_for_in_loop(
2460 &mut self,
2461 node: &'ast crate::statement::ForInLoop,
2462 ) -> ControlFlow<Self::BreakTy> {
2463 self.visit(node.body())?;
2464
2465 if let IterableLoopInitializer::Let(node) = node.initializer() {
2466 let bound_names = bound_names(node);
2467 self.0.retain(|name| !bound_names.contains(name));
2468 }
2469 if let IterableLoopInitializer::Const(node) = node.initializer() {
2470 let bound_names = bound_names(node);
2471 self.0.retain(|name| !bound_names.contains(name));
2472 }
2473
2474 ControlFlow::Continue(())
2475 }
2476
2477 fn visit_for_of_loop(
2478 &mut self,
2479 node: &'ast crate::statement::ForOfLoop,
2480 ) -> ControlFlow<Self::BreakTy> {
2481 self.visit(node.body())?;
2482
2483 if let IterableLoopInitializer::Let(node) = node.initializer() {
2484 let bound_names = bound_names(node);
2485 self.0.retain(|name| !bound_names.contains(name));
2486 }
2487 if let IterableLoopInitializer::Const(node) = node.initializer() {
2488 let bound_names = bound_names(node);
2489 self.0.retain(|name| !bound_names.contains(name));
2490 }
2491
2492 ControlFlow::Continue(())
2493 }
2494
2495 fn visit_labelled(
2496 &mut self,
2497 node: &'ast crate::statement::Labelled,
2498 ) -> ControlFlow<Self::BreakTy> {
2499 if let LabelledItem::Statement(node) = node.item() {
2500 self.visit(node)?;
2501 }
2502 ControlFlow::Continue(())
2503 }
2504
2505 fn visit_with(&mut self, node: &'ast With) -> ControlFlow<Self::BreakTy> {
2506 self.visit(node.statement())
2507 }
2508}
2509
2510#[must_use]
2512pub fn returns_value<'a, N>(node: &'a N) -> bool
2513where
2514 &'a N: Into<NodeRef<'a>>,
2515{
2516 ReturnsValueVisitor.visit(node.into()).is_break()
2517}
2518
2519#[derive(Debug)]
2521struct ReturnsValueVisitor;
2522
2523impl<'ast> Visitor<'ast> for ReturnsValueVisitor {
2524 type BreakTy = ();
2525
2526 fn visit_block(&mut self, node: &'ast crate::statement::Block) -> ControlFlow<Self::BreakTy> {
2527 for statement in node.statement_list().statements() {
2528 match statement {
2529 StatementListItem::Declaration(_) => {}
2530 StatementListItem::Statement(node) => self.visit(node.as_ref())?,
2531 }
2532 }
2533 ControlFlow::Continue(())
2534 }
2535
2536 fn visit_statement(&mut self, node: &'ast Statement) -> ControlFlow<Self::BreakTy> {
2537 match node {
2538 Statement::Empty | Statement::Var(_) => {}
2539 Statement::Block(node) => self.visit(node)?,
2540 Statement::Labelled(node) => self.visit(node)?,
2541 _ => return ControlFlow::Break(()),
2542 }
2543 ControlFlow::Continue(())
2544 }
2545
2546 fn visit_case(&mut self, node: &'ast crate::statement::Case) -> ControlFlow<Self::BreakTy> {
2547 for statement in node.body().statements() {
2548 match statement {
2549 StatementListItem::Declaration(_) => {}
2550 StatementListItem::Statement(node) => self.visit(node.as_ref())?,
2551 }
2552 }
2553 ControlFlow::Continue(())
2554 }
2555
2556 fn visit_labelled(
2557 &mut self,
2558 node: &'ast crate::statement::Labelled,
2559 ) -> ControlFlow<Self::BreakTy> {
2560 match node.item() {
2561 LabelledItem::Statement(node) => self.visit(node)?,
2562 LabelledItem::FunctionDeclaration(_) => {}
2563 }
2564 ControlFlow::Continue(())
2565 }
2566}