diff --git a/crates/oxc_ast/src/ast/ts.rs b/crates/oxc_ast/src/ast/ts.rs index 65334e1b1..bd62bfca2 100644 --- a/crates/oxc_ast/src/ast/ts.rs +++ b/crates/oxc_ast/src/ast/ts.rs @@ -868,8 +868,8 @@ pub enum TSTypePredicateName<'a> { This(TSThisType), } -#[visited_node] -#[derive(Debug, Hash)] +#[visited_node(scope(ScopeFlags::TsModuleBlock), enter_scope_before(body))] +#[derive(Debug)] #[cfg_attr(feature = "serialize", derive(Serialize, Tsify))] #[cfg_attr(feature = "serialize", serde(tag = "type", rename_all = "camelCase"))] pub struct TSModuleDeclaration<'a> { @@ -889,6 +889,28 @@ pub struct TSModuleDeclaration<'a> { pub kind: TSModuleDeclarationKind, /// Valid Modifiers: `declare`, `export` pub modifiers: Modifiers<'a>, + pub scope_id: Cell>, +} + +impl<'a> TSModuleDeclaration<'a> { + pub fn new( + span: Span, + id: TSModuleDeclarationName<'a>, + body: Option>, + kind: TSModuleDeclarationKind, + modifiers: Modifiers<'a>, + ) -> Self { + Self { span, id, body, kind, modifiers, scope_id: Cell::default() } + } +} + +impl<'a> Hash for TSModuleDeclaration<'a> { + fn hash(&self, state: &mut H) { + self.id.hash(state); + self.body.hash(state); + self.kind.hash(state); + self.modifiers.hash(state); + } } #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] @@ -931,27 +953,14 @@ pub enum TSModuleDeclarationBody<'a> { TSModuleBlock(Box<'a, TSModuleBlock<'a>>), } -#[visited_node(scope(ScopeFlags::TsModuleBlock))] -#[derive(Debug)] +#[visited_node] +#[derive(Debug, Hash)] #[cfg_attr(feature = "serialize", derive(Serialize, Tsify))] #[cfg_attr(feature = "serialize", serde(tag = "type", rename_all = "camelCase"))] pub struct TSModuleBlock<'a> { #[cfg_attr(feature = "serialize", serde(flatten))] pub span: Span, pub body: Vec<'a, Statement<'a>>, - pub scope_id: Cell>, -} - -impl<'a> TSModuleBlock<'a> { - pub fn new(span: Span, body: Vec<'a, Statement<'a>>) -> Self { - Self { span, body, scope_id: Cell::default() } - } -} - -impl<'a> Hash for TSModuleBlock<'a> { - fn hash(&self, state: &mut H) { - self.body.hash(state); - } } #[visited_node] diff --git a/crates/oxc_ast/src/ast_builder.rs b/crates/oxc_ast/src/ast_builder.rs index b88097408..6fc16ce3d 100644 --- a/crates/oxc_ast/src/ast_builder.rs +++ b/crates/oxc_ast/src/ast_builder.rs @@ -1495,7 +1495,7 @@ impl<'a> AstBuilder<'a> { kind: TSModuleDeclarationKind, modifiers: Modifiers<'a>, ) -> Box<'a, TSModuleDeclaration<'a>> { - self.alloc(TSModuleDeclaration { span, id, body, kind, modifiers }) + self.alloc(TSModuleDeclaration::new(span, id, body, kind, modifiers)) } #[inline] @@ -1734,7 +1734,7 @@ impl<'a> AstBuilder<'a> { span: Span, body: Vec<'a, Statement<'a>>, ) -> Box<'a, TSModuleBlock<'a>> { - self.alloc(TSModuleBlock::new(span, body)) + self.alloc(TSModuleBlock { span, body }) } #[inline] diff --git a/crates/oxc_ast/src/visit/visit.rs b/crates/oxc_ast/src/visit/visit.rs index d694f7c03..a17c7d890 100644 --- a/crates/oxc_ast/src/visit/visit.rs +++ b/crates/oxc_ast/src/visit/visit.rs @@ -2579,6 +2579,7 @@ pub mod walk { TSModuleDeclarationName::Identifier(ident) => visitor.visit_identifier_name(ident), TSModuleDeclarationName::StringLiteral(lit) => visitor.visit_string_literal(lit), } + visitor.enter_scope(ScopeFlags::TsModuleBlock); match &decl.body { Some(TSModuleDeclarationBody::TSModuleDeclaration(decl)) => { visitor.visit_ts_module_declaration(decl); @@ -2588,16 +2589,15 @@ pub mod walk { } None => {} } + visitor.leave_scope(); visitor.leave_node(kind); } pub fn walk_ts_module_block<'a, V: Visit<'a>>(visitor: &mut V, block: &TSModuleBlock<'a>) { let kind = AstKind::TSModuleBlock(visitor.alloc(block)); - visitor.enter_scope(ScopeFlags::TsModuleBlock); visitor.enter_node(kind); visitor.visit_statements(&block.body); visitor.leave_node(kind); - visitor.leave_scope(); } pub fn walk_ts_type_alias_declaration<'a, V: Visit<'a>>( diff --git a/crates/oxc_ast/src/visit/visit_mut.rs b/crates/oxc_ast/src/visit/visit_mut.rs index a4a3494e2..cb35a3e9e 100644 --- a/crates/oxc_ast/src/visit/visit_mut.rs +++ b/crates/oxc_ast/src/visit/visit_mut.rs @@ -2728,6 +2728,7 @@ pub mod walk_mut { TSModuleDeclarationName::Identifier(ident) => visitor.visit_identifier_name(ident), TSModuleDeclarationName::StringLiteral(lit) => visitor.visit_string_literal(lit), } + visitor.enter_scope(ScopeFlags::TsModuleBlock); match &mut decl.body { Some(TSModuleDeclarationBody::TSModuleDeclaration(decl)) => { visitor.visit_ts_module_declaration(decl); @@ -2737,6 +2738,7 @@ pub mod walk_mut { } None => {} } + visitor.leave_scope(); visitor.leave_node(kind); } @@ -2745,11 +2747,9 @@ pub mod walk_mut { block: &mut TSModuleBlock<'a>, ) { let kind = AstType::TSModuleBlock; - visitor.enter_scope(ScopeFlags::TsModuleBlock); visitor.enter_node(kind); visitor.visit_statements(&mut block.body); visitor.leave_node(kind); - visitor.leave_scope(); } pub fn walk_ts_type_alias_declaration_mut<'a, V: VisitMut<'a>>( diff --git a/crates/oxc_semantic/src/builder.rs b/crates/oxc_semantic/src/builder.rs index 73751a272..e8f825ba1 100644 --- a/crates/oxc_semantic/src/builder.rs +++ b/crates/oxc_semantic/src/builder.rs @@ -1772,14 +1772,26 @@ impl<'a> Visit<'a> for SemanticBuilder<'a> { self.leave_node(kind); } - fn visit_ts_module_block(&mut self, block: &TSModuleBlock<'a>) { - let kind = AstKind::TSModuleBlock(self.alloc(block)); - self.enter_scope(ScopeFlags::TsModuleBlock); - block.scope_id.set(Some(self.current_scope_id)); + fn visit_ts_module_declaration(&mut self, decl: &TSModuleDeclaration<'a>) { + let kind = AstKind::TSModuleDeclaration(self.alloc(decl)); self.enter_node(kind); - self.visit_statements(&block.body); - self.leave_node(kind); + match &decl.id { + TSModuleDeclarationName::Identifier(ident) => self.visit_identifier_name(ident), + TSModuleDeclarationName::StringLiteral(lit) => self.visit_string_literal(lit), + } + self.enter_scope(ScopeFlags::TsModuleBlock); + decl.scope_id.set(Some(self.current_scope_id)); + match &decl.body { + Some(TSModuleDeclarationBody::TSModuleDeclaration(decl)) => { + self.visit_ts_module_declaration(decl); + } + Some(TSModuleDeclarationBody::TSModuleBlock(block)) => { + self.visit_ts_module_block(block); + } + None => {} + } self.leave_scope(); + self.leave_node(kind); } fn visit_ts_type_parameter(&mut self, ty: &TSTypeParameter<'a>) { diff --git a/crates/oxc_transformer/src/typescript/namespace.rs b/crates/oxc_transformer/src/typescript/namespace.rs index 71198b1b2..e124a65f2 100644 --- a/crates/oxc_transformer/src/typescript/namespace.rs +++ b/crates/oxc_transformer/src/typescript/namespace.rs @@ -144,14 +144,11 @@ impl<'a> TypeScript<'a> { ); // Reuse TSModuleBlock's scope id in transformed function. - let mut scope_id = None; + let scope_id = decl.scope_id.get(); let namespace_top_level = if let Some(body) = decl.body { match body { - TSModuleDeclarationBody::TSModuleBlock(block) => { - scope_id = block.scope_id.get(); - block.unbox().body - } + TSModuleDeclarationBody::TSModuleBlock(block) => block.unbox().body, // We handle `namespace X.Y {}` as if it was // namespace X { // export namespace Y {} diff --git a/crates/oxc_traverse/src/ancestor.rs b/crates/oxc_traverse/src/ancestor.rs index c703dbc31..efc9cde3f 100644 --- a/crates/oxc_traverse/src/ancestor.rs +++ b/crates/oxc_traverse/src/ancestor.rs @@ -10662,6 +10662,8 @@ pub(crate) const OFFSET_TS_MODULE_DECLARATION_BODY: usize = offset_of!(TSModuleD pub(crate) const OFFSET_TS_MODULE_DECLARATION_KIND: usize = offset_of!(TSModuleDeclaration, kind); pub(crate) const OFFSET_TS_MODULE_DECLARATION_MODIFIERS: usize = offset_of!(TSModuleDeclaration, modifiers); +pub(crate) const OFFSET_TS_MODULE_DECLARATION_SCOPE_ID: usize = + offset_of!(TSModuleDeclaration, scope_id); #[repr(transparent)] #[derive(Debug)] @@ -10696,6 +10698,14 @@ impl<'a> TSModuleDeclarationWithoutId<'a> { as *const Modifiers<'a>) } } + + #[inline] + pub fn scope_id(&self) -> &Cell> { + unsafe { + &*((self.0 as *const u8).add(OFFSET_TS_MODULE_DECLARATION_SCOPE_ID) + as *const Cell>) + } + } } #[repr(transparent)] @@ -10731,11 +10741,18 @@ impl<'a> TSModuleDeclarationWithoutBody<'a> { as *const Modifiers<'a>) } } + + #[inline] + pub fn scope_id(&self) -> &Cell> { + unsafe { + &*((self.0 as *const u8).add(OFFSET_TS_MODULE_DECLARATION_SCOPE_ID) + as *const Cell>) + } + } } pub(crate) const OFFSET_TS_MODULE_BLOCK_SPAN: usize = offset_of!(TSModuleBlock, span); pub(crate) const OFFSET_TS_MODULE_BLOCK_BODY: usize = offset_of!(TSModuleBlock, body); -pub(crate) const OFFSET_TS_MODULE_BLOCK_SCOPE_ID: usize = offset_of!(TSModuleBlock, scope_id); #[repr(transparent)] #[derive(Debug)] @@ -10746,14 +10763,6 @@ impl<'a> TSModuleBlockWithoutBody<'a> { pub fn span(&self) -> &Span { unsafe { &*((self.0 as *const u8).add(OFFSET_TS_MODULE_BLOCK_SPAN) as *const Span) } } - - #[inline] - pub fn scope_id(&self) -> &Cell> { - unsafe { - &*((self.0 as *const u8).add(OFFSET_TS_MODULE_BLOCK_SCOPE_ID) - as *const Cell>) - } - } } pub(crate) const OFFSET_TS_TYPE_LITERAL_SPAN: usize = offset_of!(TSTypeLiteral, span); diff --git a/crates/oxc_traverse/src/walk.rs b/crates/oxc_traverse/src/walk.rs index b96b5e61e..fbc900e83 100644 --- a/crates/oxc_traverse/src/walk.rs +++ b/crates/oxc_traverse/src/walk.rs @@ -4826,6 +4826,15 @@ pub(crate) unsafe fn walk_ts_module_declaration<'a, Tr: Traverse<'a>>( as *mut TSModuleDeclarationName, ctx, ); + let mut previous_scope_id = None; + if let Some(scope_id) = (*((node as *mut u8) + .add(ancestor::OFFSET_TS_MODULE_DECLARATION_SCOPE_ID) + as *mut Cell>)) + .get() + { + previous_scope_id = Some(ctx.current_scope_id()); + ctx.set_current_scope_id(scope_id); + } if let Some(field) = &mut *((node as *mut u8).add(ancestor::OFFSET_TS_MODULE_DECLARATION_BODY) as *mut Option) { @@ -4834,6 +4843,9 @@ pub(crate) unsafe fn walk_ts_module_declaration<'a, Tr: Traverse<'a>>( } ctx.pop_stack(); traverser.exit_ts_module_declaration(&mut *node, ctx); + if let Some(previous_scope_id) = previous_scope_id { + ctx.set_current_scope_id(previous_scope_id); + } } pub(crate) unsafe fn walk_ts_module_declaration_name<'a, Tr: Traverse<'a>>( @@ -4875,14 +4887,6 @@ pub(crate) unsafe fn walk_ts_module_block<'a, Tr: Traverse<'a>>( node: *mut TSModuleBlock<'a>, ctx: &mut TraverseCtx<'a>, ) { - let mut previous_scope_id = None; - if let Some(scope_id) = (*((node as *mut u8).add(ancestor::OFFSET_TS_MODULE_BLOCK_SCOPE_ID) - as *mut Cell>)) - .get() - { - previous_scope_id = Some(ctx.current_scope_id()); - ctx.set_current_scope_id(scope_id); - } traverser.enter_ts_module_block(&mut *node, ctx); ctx.push_stack(Ancestor::TSModuleBlockBody(ancestor::TSModuleBlockWithoutBody(node))); walk_statements( @@ -4892,9 +4896,6 @@ pub(crate) unsafe fn walk_ts_module_block<'a, Tr: Traverse<'a>>( ); ctx.pop_stack(); traverser.exit_ts_module_block(&mut *node, ctx); - if let Some(previous_scope_id) = previous_scope_id { - ctx.set_current_scope_id(previous_scope_id); - } } pub(crate) unsafe fn walk_ts_type_literal<'a, Tr: Traverse<'a>>(