1use oxc_span::Ident;
2use oxc_syntax::node::NodeId;
3
4#[derive(Debug)]
5pub struct LabeledScope<'a> {
6 pub name: Ident<'a>,
7 pub used: bool,
8 pub node_id: NodeId,
9}
10
11#[derive(Debug, Default)]
12pub struct UnusedLabels<'a> {
13 pub stack: Vec<LabeledScope<'a>>,
14 pub labels: Vec<NodeId>,
15}
16
17impl<'a> UnusedLabels<'a> {
18 pub fn add(&mut self, name: Ident<'a>, node_id: NodeId) {
19 self.stack.push(LabeledScope { name, used: false, node_id });
20 }
21
22 pub fn reference(&mut self, name: Ident<'_>) {
23 for scope in self.stack.iter_mut().rev() {
24 if scope.name == name {
25 scope.used = true;
26 return;
27 }
28 }
29 }
30
31 pub fn mark_unused(&mut self) {
32 debug_assert!(
33 !self.stack.is_empty(),
34 "mark_unused called with empty label stack - this indicates mismatched add/mark_unused calls"
35 );
36
37 if let Some(scope) = self.stack.pop()
38 && !scope.used
39 {
40 self.labels.push(scope.node_id);
41 }
42 }
43
44 #[cfg(debug_assertions)]
45 pub fn assert_empty(&self) {
46 debug_assert!(
47 self.stack.is_empty(),
48 "Label stack not empty at end of processing - {} labels remaining. This indicates mismatched add/mark_unused calls",
49 self.stack.len()
50 );
51 }
52}