diff --git a/crates/oxc_semantic/src/builder.rs b/crates/oxc_semantic/src/builder.rs index de728a6c35590..b843701f95e1d 100644 --- a/crates/oxc_semantic/src/builder.rs +++ b/crates/oxc_semantic/src/builder.rs @@ -529,7 +529,19 @@ impl<'a> Visit<'a> for SemanticBuilder<'a> { }); /* cfg - must be above directives as directives are in cfg */ - self.enter_node(kind); + // Don't call `enter_node` here as `Program` is a special case - node has no `parent_id`. + // Inline the specific logic for `Program` here instead. + // This avoids `Nodes::add_node` having to handle the special case. + // We can also skip calling `self.enter_kind`, and `self.jsdoc.retrieve_attached_jsdoc` + // as they are no-ops for `Program`. + self.current_node_id = self.nodes.add_program_node( + kind, + self.current_scope_id, + control_flow!(self, |cfg| cfg.current_node_ix), + self.current_node_flags, + ); + self.record_ast_node(); + self.enter_scope( { let mut flags = ScopeFlags::Top; diff --git a/crates/oxc_semantic/src/node.rs b/crates/oxc_semantic/src/node.rs index 8c4805b68a243..fd6ddfcf86524 100644 --- a/crates/oxc_semantic/src/node.rs +++ b/crates/oxc_semantic/src/node.rs @@ -142,6 +142,7 @@ impl<'a> AstNodes<'a> { } /// Create and add an `AstNode` to the `AstNodes` tree and returns its `AstNodeId`. + /// Node must not be `Program`. Use `add_program_node` instead. pub fn add_node( &mut self, kind: AstKind<'a>, @@ -150,14 +151,22 @@ impl<'a> AstNodes<'a> { cfg_id: BasicBlockId, flags: NodeFlags, ) -> AstNodeId { - let ast_node_id = match kind { - AstKind::Program(_) => { - let id = self.parent_ids.push(None); - self.root = Some(id); - id - } - _ => self.parent_ids.push(Some(parent_node_id)), - }; + let ast_node_id = self.parent_ids.push(Some(parent_node_id)); + let node = AstNode::new(kind, scope_id, cfg_id, flags, ast_node_id); + self.nodes.push(node); + ast_node_id + } + + /// Create and add an `AstNode` to the `AstNodes` tree and returns its `AstNodeId`. + pub fn add_program_node( + &mut self, + kind: AstKind<'a>, + scope_id: ScopeId, + cfg_id: BasicBlockId, + flags: NodeFlags, + ) -> AstNodeId { + let ast_node_id = self.parent_ids.push(None); + self.root = Some(ast_node_id); let node = AstNode::new(kind, scope_id, cfg_id, flags, ast_node_id); self.nodes.push(node); ast_node_id