1use std::str;
2
3use oxc_allocator::{Allocator, Vec as ArenaVec};
4use oxc_ast::ast::*;
5use oxc_ast_visit::Visit;
6use oxc_semantic::{NodeId, Reference, Scoping};
7use oxc_span::{Ident, SPAN};
8use oxc_syntax::{
9 reference::{ReferenceFlags, ReferenceId},
10 scope::{ScopeFlags, ScopeId},
11 symbol::{SymbolFlags, SymbolId},
12};
13
14use crate::{BoundIdentifier, scopes_collector::ChildScopeCollector};
15
16use super::uid::UidGenerator;
17
18pub struct TraverseScoping<'a> {
25 scoping: Scoping,
26 uid_generator: Option<UidGenerator<'a>>,
27 current_scope_id: ScopeId,
28 current_hoist_scope_id: ScopeId,
29 current_block_scope_id: ScopeId,
30}
31
32impl<'a> TraverseScoping<'a> {
34 #[inline]
36 pub fn current_scope_id(&self) -> ScopeId {
37 self.current_scope_id
38 }
39
40 #[inline]
42 pub(crate) fn current_hoist_scope_id(&self) -> ScopeId {
43 self.current_hoist_scope_id
44 }
45
46 #[inline]
48 pub(crate) fn current_block_scope_id(&self) -> ScopeId {
49 self.current_block_scope_id
50 }
51
52 #[inline]
54 pub fn current_scope_flags(&self) -> ScopeFlags {
55 self.scoping.scope_flags(self.current_scope_id)
56 }
57
58 #[inline]
60 pub fn scoping(&self) -> &Scoping {
61 &self.scoping
62 }
63
64 #[inline]
66 pub fn scoping_mut(&mut self) -> &mut Scoping {
67 &mut self.scoping
68 }
69
70 pub fn ancestor_scopes(&self) -> impl Iterator<Item = ScopeId> + '_ {
72 self.scoping.scope_ancestors(self.current_scope_id)
73 }
74
75 pub fn create_child_scope(&mut self, parent_id: ScopeId, flags: ScopeFlags) -> ScopeId {
79 let flags = self.scoping.get_new_scope_flags(flags, parent_id);
80 self.scoping.add_scope(Some(parent_id), NodeId::DUMMY, flags)
81 }
82
83 pub fn create_child_scope_of_current(&mut self, flags: ScopeFlags) -> ScopeId {
87 self.create_child_scope(self.current_scope_id, flags)
88 }
89
90 pub fn insert_scope_below_statement(&mut self, stmt: &Statement, flags: ScopeFlags) -> ScopeId {
98 self.insert_scope_below_statement_from_scope_id(stmt, self.current_scope_id, flags)
99 }
100
101 pub fn insert_scope_below_statement_from_scope_id(
109 &mut self,
110 stmt: &Statement,
111 scope_id: ScopeId,
112 flags: ScopeFlags,
113 ) -> ScopeId {
114 let mut collector = ChildScopeCollector::new();
115 collector.visit_statement(stmt);
116 self.insert_scope_below(scope_id, &collector.scope_ids, flags)
117 }
118
119 pub fn insert_scope_below_expression(
127 &mut self,
128 expr: &Expression,
129 flags: ScopeFlags,
130 ) -> ScopeId {
131 let mut collector = ChildScopeCollector::new();
132 collector.visit_expression(expr);
133 self.insert_scope_below(self.current_scope_id, &collector.scope_ids, flags)
134 }
135
136 pub fn insert_scope_below_statements(
144 &mut self,
145 stmts: &ArenaVec<Statement>,
146 flags: ScopeFlags,
147 ) -> ScopeId {
148 let mut collector = ChildScopeCollector::new();
149 collector.visit_statements(stmts);
150 self.insert_scope_below(self.current_scope_id, &collector.scope_ids, flags)
151 }
152
153 fn insert_scope_below(
154 &mut self,
155 scope_id: ScopeId,
156 child_scope_ids: &[ScopeId],
157 flags: ScopeFlags,
158 ) -> ScopeId {
159 let new_scope_id = self.create_child_scope(scope_id, flags);
161
162 for &child_id in child_scope_ids {
164 self.scoping.set_scope_parent_id(child_id, Some(new_scope_id));
165 }
166
167 new_scope_id
168 }
169
170 pub fn insert_scope_between(
190 &mut self,
191 parent_id: ScopeId,
192 child_id: ScopeId,
193 flags: ScopeFlags,
194 ) -> ScopeId {
195 let scope_id = self.create_child_scope(parent_id, flags);
196
197 debug_assert_eq!(
198 self.scoping.scope_parent_id(child_id),
199 Some(parent_id),
200 "Child scope must be a child of parent scope"
201 );
202
203 self.scoping.set_scope_parent_id(child_id, Some(scope_id));
204 scope_id
205 }
206
207 pub fn remove_scope_for_expression(&mut self, scope_id: ScopeId, expr: &Expression) {
219 let mut collector = ChildScopeCollector::new();
220 collector.visit_expression(expr);
221
222 let child_ids = collector.scope_ids;
223 if !child_ids.is_empty() {
224 let parent_id = self.scoping.scope_parent_id(scope_id);
225 for child_id in child_ids {
226 self.scoping.set_scope_parent_id(child_id, parent_id);
227 }
228 }
229 }
230
231 #[inline]
233 pub(crate) fn add_binding(
234 &mut self,
235 name: Ident<'_>,
236 scope_id: ScopeId,
237 flags: SymbolFlags,
238 ) -> SymbolId {
239 let symbol_id = self.scoping.create_symbol(SPAN, name, flags, scope_id, NodeId::DUMMY);
240 self.scoping.add_binding(scope_id, name, symbol_id);
241
242 symbol_id
243 }
244
245 pub fn generate_binding(
249 &mut self,
250 name: Ident<'a>,
251 scope_id: ScopeId,
252 flags: SymbolFlags,
253 ) -> BoundIdentifier<'a> {
254 let symbol_id = self.add_binding(name, scope_id, flags);
255 BoundIdentifier::new(name, symbol_id)
256 }
257
258 pub fn generate_binding_in_current_scope(
262 &mut self,
263 name: Ident<'a>,
264 flags: SymbolFlags,
265 ) -> BoundIdentifier<'a> {
266 self.generate_binding(name, self.current_scope_id, flags)
267 }
268
269 pub fn generate_uid_name(&mut self, name: &str, allocator: &'a Allocator) -> Ident<'a> {
279 let uid_generator =
281 self.uid_generator.get_or_insert_with(|| UidGenerator::new(&self.scoping, allocator));
282 uid_generator.create(name)
284 }
285
286 pub fn create_bound_reference(
288 &mut self,
289 symbol_id: SymbolId,
290 flags: ReferenceFlags,
291 ) -> ReferenceId {
292 let reference =
293 Reference::new_with_symbol_id(NodeId::DUMMY, symbol_id, self.current_scope_id, flags);
294 let reference_id = self.scoping.create_reference(reference);
295 self.scoping.add_resolved_reference(symbol_id, reference_id);
296 reference_id
297 }
298
299 pub fn create_unbound_reference(
301 &mut self,
302 name: Ident<'_>,
303 flags: ReferenceFlags,
304 ) -> ReferenceId {
305 let reference = Reference::new(NodeId::DUMMY, self.current_scope_id, flags);
306 let reference_id = self.scoping.create_reference(reference);
307 self.scoping.add_root_unresolved_reference(name, reference_id);
308 reference_id
309 }
310
311 pub fn create_reference(
316 &mut self,
317 name: Ident<'_>,
318 symbol_id: Option<SymbolId>,
319 flags: ReferenceFlags,
320 ) -> ReferenceId {
321 if let Some(symbol_id) = symbol_id {
322 self.create_bound_reference(symbol_id, flags)
323 } else {
324 self.create_unbound_reference(name, flags)
325 }
326 }
327
328 pub fn create_reference_in_current_scope(
330 &mut self,
331 name: Ident<'_>,
332 flags: ReferenceFlags,
333 ) -> ReferenceId {
334 let symbol_id = self.scoping.find_binding(self.current_scope_id, name);
335 self.create_reference(name, symbol_id, flags)
336 }
337
338 pub fn delete_reference(&mut self, reference_id: ReferenceId, name: Ident<'_>) {
342 let symbol_id = self.scoping.get_reference(reference_id).symbol_id();
343 if let Some(symbol_id) = symbol_id {
344 self.scoping.delete_resolved_reference(symbol_id, reference_id);
345 } else {
346 self.scoping.delete_root_unresolved_reference(name, reference_id);
347 }
348 }
349
350 pub fn delete_reference_for_identifier(&mut self, ident: &IdentifierReference) {
352 self.delete_reference(ident.reference_id(), ident.name);
353 }
354}
355
356impl TraverseScoping<'_> {
358 pub(super) fn new(scoping: Scoping) -> Self {
360 Self {
361 scoping,
362 uid_generator: None,
363 current_scope_id: ScopeId::new(0),
365 current_hoist_scope_id: ScopeId::new(0),
366 current_block_scope_id: ScopeId::new(0),
367 }
368 }
369
370 pub(super) fn into_scoping(self) -> Scoping {
372 self.scoping
373 }
374
375 #[inline]
377 pub(crate) fn set_current_scope_id(&mut self, scope_id: ScopeId) {
378 self.current_scope_id = scope_id;
379 }
380
381 #[inline]
383 pub(crate) fn set_current_hoist_scope_id(&mut self, scope_id: ScopeId) {
384 self.current_hoist_scope_id = scope_id;
385 }
386
387 #[inline]
389 pub(crate) fn set_current_block_scope_id(&mut self, scope_id: ScopeId) {
390 self.current_block_scope_id = scope_id;
391 }
392
393 pub fn delete_typescript_bindings(&mut self) {
394 self.scoping.delete_typescript_bindings();
395 }
396}