diff --git a/crates/oxc_linter/src/rules/react/rules_of_hooks.rs b/crates/oxc_linter/src/rules/react/rules_of_hooks.rs index e4e4a125f4588..053665a86e353 100644 --- a/crates/oxc_linter/src/rules/react/rules_of_hooks.rs +++ b/crates/oxc_linter/src/rules/react/rules_of_hooks.rs @@ -343,7 +343,7 @@ fn has_conditional_path_accept_throw( // } // _ => None, // }) - // .filter(|it| it.id() != to.id()) + // .filter(|it| it.node_id() != to.node_id()) // .any(|it| { // // TODO: it.may_throw() // matches!( diff --git a/crates/oxc_semantic/src/binder.rs b/crates/oxc_semantic/src/binder.rs index aefcd82195020..acb7ea2f6e6a7 100644 --- a/crates/oxc_semantic/src/binder.rs +++ b/crates/oxc_semantic/src/binder.rs @@ -655,16 +655,18 @@ fn get_module_instance_state_for_alias_target<'a>( } } - let Some(node) = builder.nodes.ancestors(current_node_id).find(|node| { - matches!( - node.kind(), - AstKind::Program(_) | AstKind::TSModuleBlock(_) | AstKind::BlockStatement(_) - ) - }) else { + let Some((node_id, node)) = + builder.nodes.ancestors_enumerated(current_node_id).find(|(_, node)| { + matches!( + node.kind(), + AstKind::Program(_) | AstKind::TSModuleBlock(_) | AstKind::BlockStatement(_) + ) + }) + else { break; }; - current_node_id = node.id(); + current_node_id = node_id; current_block_stmts.clear(); // Didn't find the declaration whose name matches export specifier // in the current block, so we need to check the parent block. diff --git a/crates/oxc_semantic/src/checker/javascript.rs b/crates/oxc_semantic/src/checker/javascript.rs index fc47f02570f08..fe32e42807961 100644 --- a/crates/oxc_semantic/src/checker/javascript.rs +++ b/crates/oxc_semantic/src/checker/javascript.rs @@ -212,14 +212,16 @@ pub fn check_binding_identifier(ident: &BindingIdentifier, ctx: &SemanticBuilder }; let parent = ctx.nodes.parent_node(ctx.current_node_id); + let parent_id = parent.id(); let is_ok = match parent.kind() { AstKind::Function(func) => matches!(func.r#type, FunctionType::TSDeclareFunction), AstKind::FormalParameter(_) | AstKind::FormalParameterRest(_) => { - is_declare_function(&ctx.nodes.parent_kind(parent.id())) + is_declare_function(&ctx.nodes.parent_kind(parent_id)) } AstKind::BindingRestElement(_) => { - let grand_parent = ctx.nodes.parent_node(parent.id()); - is_declare_function(&ctx.nodes.parent_kind(grand_parent.id())) + let grand_parent = ctx.nodes.parent_node(parent_id); + let grand_parent_id = grand_parent.id(); + is_declare_function(&ctx.nodes.parent_kind(grand_parent_id)) } _ => false, }; diff --git a/crates/oxc_semantic/src/node/mod.rs b/crates/oxc_semantic/src/node/mod.rs index 9ffb982ad7373..d57f3b8a6a294 100644 --- a/crates/oxc_semantic/src/node/mod.rs +++ b/crates/oxc_semantic/src/node/mod.rs @@ -10,7 +10,6 @@ use oxc_syntax::{node::NodeId, scope::ScopeId}; /// Semantic node contains all the semantic information about an ast node. #[derive(Debug, Clone, Copy)] pub struct AstNode<'a> { - id: NodeId, /// A pointer to the ast node, which resides in the memory arena. kind: AstKind<'a>, @@ -19,14 +18,8 @@ pub struct AstNode<'a> { } impl<'a> AstNode<'a> { - pub(crate) fn new(kind: AstKind<'a>, scope_id: ScopeId, id: NodeId) -> Self { - Self { id, kind, scope_id } - } - - /// This node's unique identifier. - #[inline] - pub fn id(&self) -> NodeId { - self.id + pub(crate) fn new(kind: AstKind<'a>, scope_id: ScopeId) -> Self { + Self { kind, scope_id } } /// Access the underlying struct from [`oxc_ast`]. @@ -35,6 +28,12 @@ impl<'a> AstNode<'a> { self.kind } + /// Node id assigned to this AST node. + #[inline] + pub fn id(&self) -> NodeId { + self.kind.node_id() + } + /// The scope in which this node was declared. /// /// It is important to note that this is _not_ the scope created _by_ the diff --git a/crates/oxc_semantic/src/node/nodes.rs b/crates/oxc_semantic/src/node/nodes.rs index c3152ee287658..bf9d4c230ff4d 100644 --- a/crates/oxc_semantic/src/node/nodes.rs +++ b/crates/oxc_semantic/src/node/nodes.rs @@ -42,6 +42,11 @@ impl<'a> AstNodes<'a> { self.nodes.iter() } + /// Iterate over all [`AstNode`]s with their [`NodeId`]. + pub fn iter_enumerated(&self) -> impl Iterator)> + '_ { + self.nodes.iter_enumerated() + } + /// Returns the number of node in this AST. #[inline] pub fn len(&self) -> usize { @@ -84,6 +89,18 @@ impl<'a> AstNodes<'a> { self.ancestor_ids(node_id).map(|id| self.get_node(id)) } + /// Walk up the AST, iterating over each parent [`NodeId`] and [`AstNode`]. + /// + /// The first node produced by this iterator is the parent of `node_id`. + /// The last node will always be [`AstKind::Program`]. + #[inline] + pub fn ancestors_enumerated( + &self, + node_id: NodeId, + ) -> impl Iterator)> + Clone + '_ { + self.ancestor_ids(node_id).map(|id| (id, self.get_node(id))) + } + /// Access the underlying struct from [`oxc_ast`]. #[inline] pub fn kind(&self, node_id: NodeId) -> AstKind<'a> { @@ -165,7 +182,7 @@ impl<'a> AstNodes<'a> { ) -> NodeId { let node_id = self.parent_ids.push(parent_node_id); kind.set_node_id(node_id); - let node = AstNode::new(kind, scope_id, node_id); + let node = AstNode::new(kind, scope_id); self.nodes.push(node); self.flags.push(flags); #[cfg(feature = "cfg")] @@ -194,7 +211,7 @@ impl<'a> AstNodes<'a> { ); kind.set_node_id(NodeId::ROOT); self.parent_ids.push(NodeId::ROOT); - self.nodes.push(AstNode::new(kind, scope_id, NodeId::ROOT)); + self.nodes.push(AstNode::new(kind, scope_id)); self.flags.push(flags); #[cfg(feature = "cfg")] self.cfg_ids.push(cfg_id);