diff --git a/crates/oxc_transformer/src/lib.rs b/crates/oxc_transformer/src/lib.rs index cb3d3f637a608..4d9d59ed641d4 100644 --- a/crates/oxc_transformer/src/lib.rs +++ b/crates/oxc_transformer/src/lib.rs @@ -354,6 +354,7 @@ impl<'a, 'ctx> Traverse<'a> for TransformerImpl<'a, 'ctx> { } fn enter_statement(&mut self, stmt: &mut Statement<'a>, ctx: &mut TraverseCtx<'a>) { + println!("index {:?}", ctx.ancestor_index(stmt)); self.x0_typescript.enter_statement(stmt, ctx); } diff --git a/crates/oxc_traverse/src/context/ancestry.rs b/crates/oxc_traverse/src/context/ancestry.rs index d3523beaac728..7138c8172731f 100644 --- a/crates/oxc_traverse/src/context/ancestry.rs +++ b/crates/oxc_traverse/src/context/ancestry.rs @@ -1,8 +1,11 @@ use std::mem::transmute; +use oxc_ast::ast::Statement; use oxc_data_structures::stack::NonEmptyStack; -use crate::ancestor::{Ancestor, AncestorType}; +use crate::ancestor::{ + Ancestor, AncestorType, OFFSET_FUNCTION_BODY_STATEMENTS, OFFSET_PROGRAM_BODY, +}; const INITIAL_STACK_CAPACITY: usize = 64; // 64 entries = 1 KiB @@ -88,6 +91,33 @@ impl<'a> TraverseAncestry<'a> { } } + #[allow(clippy::cast_ptr_alignment)] + pub fn ancestor_index<'t>(&'t self, statement: &Statement<'a>) -> Option { + let ancestor = self.ancestor(0); + + let node_ptr = statement as *const Statement<'a>; + + let base_ptr = match ancestor { + Ancestor::FunctionBodyStatements(container) => unsafe { + &*container + .0 + .cast::() + .add(OFFSET_FUNCTION_BODY_STATEMENTS) + .cast::>>() + }, + Ancestor::ProgramBody(container) => unsafe { + &*container + .0 + .cast::() + .add(OFFSET_PROGRAM_BODY) + .cast::>>() + }, + _ => return None, + }; + + Some(unsafe { node_ptr.offset_from(base_ptr.as_ptr()) as usize }) + } + /// Get iterator over ancestors, starting with parent and working up. /// /// Last `Ancestor` returned will be `Program`. `Ancestor::None` is not included in iteration. diff --git a/crates/oxc_traverse/src/context/mod.rs b/crates/oxc_traverse/src/context/mod.rs index 3e61dffb0b454..b49c609631bc5 100644 --- a/crates/oxc_traverse/src/context/mod.rs +++ b/crates/oxc_traverse/src/context/mod.rs @@ -156,6 +156,12 @@ impl<'a> TraverseCtx<'a> { self.ancestry.ancestor(level) } + /// Get the index of the current node in `Vec<'a, Statements<'a>>`. + #[inline] + pub fn ancestor_index<'t>(&'t self, statement: &Statement<'a>) -> Option { + self.ancestry.ancestor_index(statement) + } + /// Get iterator over ancestors, starting with parent and working up. /// /// Last `Ancestor` returned will be `Program`. `Ancestor::None` is not included in iteration.