diff --git a/crates/oxc_transformer/src/common/helper_loader.rs b/crates/oxc_transformer/src/common/helper_loader.rs index 0346c988765ff0..79e42f246dee56 100644 --- a/crates/oxc_transformer/src/common/helper_loader.rs +++ b/crates/oxc_transformer/src/common/helper_loader.rs @@ -277,13 +277,8 @@ impl<'a> HelperLoaderStore<'a> { static HELPER_VAR: &str = "babelHelpers"; let symbol_id = ctx.scopes().find_binding(ctx.current_scope_id(), HELPER_VAR); - let ident = ctx.create_ident_reference( - SPAN, - Atom::from(HELPER_VAR), - symbol_id, - ReferenceFlags::Read, - ); - let object = Expression::Identifier(ctx.alloc(ident)); + let object = + ctx.create_ident_expr(SPAN, Atom::from(HELPER_VAR), symbol_id, ReferenceFlags::Read); let property = ctx.ast.identifier_name(SPAN, Atom::from(helper.name())); Expression::from(ctx.ast.member_expression_static(SPAN, object, property, false)) } diff --git a/crates/oxc_transformer/src/common/module_imports.rs b/crates/oxc_transformer/src/common/module_imports.rs index 055849832c546a..94c4c2a1830b21 100644 --- a/crates/oxc_transformer/src/common/module_imports.rs +++ b/crates/oxc_transformer/src/common/module_imports.rs @@ -226,14 +226,12 @@ impl<'a> ModuleImportsStore<'a> { require_symbol_id: Option, ctx: &mut TraverseCtx<'a>, ) -> Statement<'a> { - let var_kind = VariableDeclarationKind::Var; - let ident = ctx.create_ident_reference( + let callee = ctx.create_ident_expr( SPAN, Atom::from("require"), require_symbol_id, ReferenceFlags::read(), ); - let callee = Expression::Identifier(ctx.alloc(ident)); let args = { let arg = Argument::from(ctx.ast.expression_string_literal(SPAN, source)); @@ -241,6 +239,7 @@ impl<'a> ModuleImportsStore<'a> { }; let Some(Import::Default(local)) = names.into_iter().next() else { unreachable!() }; let id = local.create_binding_pattern(ctx); + let var_kind = VariableDeclarationKind::Var; let decl = { let init = ctx.ast.expression_call(SPAN, callee, NONE, args, false); let decl = ctx.ast.variable_declarator(SPAN, var_kind, id, Some(init), false); diff --git a/crates/oxc_transformer/src/es2016/exponentiation_operator.rs b/crates/oxc_transformer/src/es2016/exponentiation_operator.rs index 2d787d592135b2..716ade8cf25dd4 100644 --- a/crates/oxc_transformer/src/es2016/exponentiation_operator.rs +++ b/crates/oxc_transformer/src/es2016/exponentiation_operator.rs @@ -164,18 +164,12 @@ impl<'a, 'ctx> ExponentiationOperator<'a, 'ctx> { *reference.flags_mut() = ReferenceFlags::Write; } - Expression::Identifier(ctx.ast.alloc(ctx.create_bound_ident_reference( - SPAN, - ident.name.clone(), - symbol_id, - ReferenceFlags::Read, - ))) + ctx.create_bound_ident_expr(SPAN, ident.name.clone(), symbol_id, ReferenceFlags::Read) } else { // Unbound reference. Could possibly trigger a getter so we need to only evaluate it once. // Assign to a temp var. - let reference = Expression::Identifier(ctx.ast.alloc( - ctx.create_unbound_ident_reference(SPAN, ident.name.clone(), ReferenceFlags::Read), - )); + let reference = + ctx.create_unbound_ident_expr(SPAN, ident.name.clone(), ReferenceFlags::Read); let binding = self.create_temp_var(reference, &mut temp_var_inits, ctx); binding.create_read_expression(ctx) }; @@ -495,14 +489,12 @@ impl<'a, 'ctx> ExponentiationOperator<'a, 'ctx> { if let Some(symbol_id) = symbol_id { // This variable is declared in scope so evaluating it multiple times can't trigger a getter. // No need for a temp var. - return Expression::Identifier(ctx.ast.alloc( - ctx.create_bound_ident_reference( - SPAN, - ident.name.clone(), - symbol_id, - ReferenceFlags::Read, - ), - )); + return ctx.create_bound_ident_expr( + SPAN, + ident.name.clone(), + symbol_id, + ReferenceFlags::Read, + ); } // Unbound reference. Could possibly trigger a getter so we need to only evaluate it once. // Assign to a temp var. @@ -548,13 +540,8 @@ impl<'a, 'ctx> ExponentiationOperator<'a, 'ctx> { ctx: &mut TraverseCtx<'a>, ) -> Expression<'a> { let math_symbol_id = ctx.scopes().find_binding(ctx.current_scope_id(), "Math"); - let ident_math = ctx.create_ident_reference( - SPAN, - Atom::from("Math"), - math_symbol_id, - ReferenceFlags::Read, - ); - let object = Expression::Identifier(ctx.alloc(ident_math)); + let object = + ctx.create_ident_expr(SPAN, Atom::from("Math"), math_symbol_id, ReferenceFlags::Read); let property = ctx.ast.identifier_name(SPAN, "pow"); let callee = Expression::from(ctx.ast.member_expression_static(SPAN, object, property, false)); diff --git a/crates/oxc_transformer/src/es2017/async_to_generator.rs b/crates/oxc_transformer/src/es2017/async_to_generator.rs index f8fe6520374c19..97cfab30326d73 100644 --- a/crates/oxc_transformer/src/es2017/async_to_generator.rs +++ b/crates/oxc_transformer/src/es2017/async_to_generator.rs @@ -310,7 +310,7 @@ impl<'a, 'ctx> AsyncGeneratorExecutor<'a, 'ctx> { let id = caller_function.id.as_ref().unwrap(); // If the function has an id, then we need to return the id. // `function foo() { ... }` -> `function foo() {} return foo;` - let reference = ctx.create_bound_ident_reference( + let reference = ctx.create_bound_ident_expr( SPAN, id.name.clone(), id.symbol_id(), @@ -318,8 +318,7 @@ impl<'a, 'ctx> AsyncGeneratorExecutor<'a, 'ctx> { ); let statement = Statement::FunctionDeclaration(caller_function); statements.push(statement); - let argument = Some(Expression::Identifier(ctx.alloc(reference))); - statements.push(ctx.ast.statement_return(SPAN, argument)); + statements.push(ctx.ast.statement_return(SPAN, Some(reference))); } else { // If the function doesn't have an id, then we need to return the function itself. // `function() { ... }` -> `return function() { ... };` @@ -597,13 +596,12 @@ impl<'a, 'ctx> AsyncGeneratorExecutor<'a, 'ctx> { ctx: &mut TraverseCtx<'a>, ) -> Statement<'a> { let symbol_id = ctx.scopes().find_binding(ctx.current_scope_id(), "arguments"); - let arguments_ident = ctx.create_ident_reference( + let arguments_ident = Argument::from(ctx.create_ident_expr( SPAN, Atom::from("arguments"), symbol_id, ReferenceFlags::Read, - ); - let arguments_ident = Argument::Identifier(ctx.alloc(arguments_ident)); + )); // (this, arguments) let mut arguments = ctx.ast.vec_with_capacity(2); diff --git a/crates/oxc_transformer/src/es2018/object_rest_spread.rs b/crates/oxc_transformer/src/es2018/object_rest_spread.rs index de17587cafea45..0daaf88ca3aa2c 100644 --- a/crates/oxc_transformer/src/es2018/object_rest_spread.rs +++ b/crates/oxc_transformer/src/es2018/object_rest_spread.rs @@ -141,9 +141,8 @@ impl<'a, 'ctx> ObjectRestSpread<'a, 'ctx> { } fn object_assign(symbol_id: Option, ctx: &mut TraverseCtx<'a>) -> Expression<'a> { - let ident = - ctx.create_ident_reference(SPAN, Atom::from("Object"), symbol_id, ReferenceFlags::Read); - let object = Expression::Identifier(ctx.alloc(ident)); + let object = + ctx.create_ident_expr(SPAN, Atom::from("Object"), symbol_id, ReferenceFlags::Read); let property = ctx.ast.identifier_name(SPAN, Atom::from("assign")); Expression::from(ctx.ast.member_expression_static(SPAN, object, property, false)) } diff --git a/crates/oxc_transformer/src/jsx/refresh.rs b/crates/oxc_transformer/src/jsx/refresh.rs index adfa56b2065a76..0598d5150719e5 100644 --- a/crates/oxc_transformer/src/jsx/refresh.rs +++ b/crates/oxc_transformer/src/jsx/refresh.rs @@ -336,13 +336,12 @@ impl<'a, 'ctx> Traverse<'a> for ReactRefresh<'a, 'ctx> { binding_name.as_str(), ) .map(|symbol_id| { - let ident = ctx.create_bound_ident_reference( + let mut expr = ctx.create_bound_ident_expr( SPAN, binding_name, symbol_id, ReferenceFlags::Read, ); - let mut expr = Expression::Identifier(ctx.alloc(ident)); if is_member_expression { // binding_name.hook_name @@ -496,13 +495,12 @@ impl<'a, 'ctx> ReactRefresh<'a, 'ctx> { ctx: &mut TraverseCtx<'a>, ) -> Statement<'a> { let left = self.create_registration(id.name.clone(), ReferenceFlags::Write, ctx); - let right = ctx.create_bound_ident_reference( + let right = ctx.create_bound_ident_expr( SPAN, id.name.clone(), id.symbol_id(), ReferenceFlags::Read, ); - let right = Expression::Identifier(ctx.alloc(right)); let expr = ctx.ast.expression_assignment(SPAN, AssignmentOperator::Assign, left, right); ctx.ast.statement_expression(SPAN, expr) } diff --git a/crates/oxc_transformer/src/regexp/mod.rs b/crates/oxc_transformer/src/regexp/mod.rs index bf1b816b1946b8..fdb69fdb00746c 100644 --- a/crates/oxc_transformer/src/regexp/mod.rs +++ b/crates/oxc_transformer/src/regexp/mod.rs @@ -180,13 +180,7 @@ impl<'a, 'ctx> Traverse<'a> for RegExp<'a, 'ctx> { let callee = { let symbol_id = ctx.scopes().find_binding(ctx.current_scope_id(), "RegExp"); - let ident = ctx.create_ident_reference( - SPAN, - Atom::from("RegExp"), - symbol_id, - ReferenceFlags::read(), - ); - Expression::Identifier(ctx.alloc(ident)) + ctx.create_ident_expr(SPAN, Atom::from("RegExp"), symbol_id, ReferenceFlags::read()) }; let mut arguments = ctx.ast.vec_with_capacity(2); diff --git a/crates/oxc_transformer/src/typescript/enum.rs b/crates/oxc_transformer/src/typescript/enum.rs index 708aeacf375b1d..b503f9ff327040 100644 --- a/crates/oxc_transformer/src/typescript/enum.rs +++ b/crates/oxc_transformer/src/typescript/enum.rs @@ -122,13 +122,12 @@ impl<'a> TypeScriptEnum<'a> { } else { // }(Foo || {}); let op = LogicalOperator::Or; - let left = ctx.create_bound_ident_reference( + let left = ctx.create_bound_ident_expr( decl.id.span, enum_name.clone(), var_symbol_id, ReferenceFlags::Read, ); - let left = Expression::Identifier(ctx.alloc(left)); let right = ast.expression_object(SPAN, ast.vec(), None); let expression = ast.expression_logical(SPAN, left, op, right); ast.vec1(Argument::from(expression)) diff --git a/crates/oxc_traverse/src/context/mod.rs b/crates/oxc_traverse/src/context/mod.rs index c9b735bff0ee92..eda09ba266cc6c 100644 --- a/crates/oxc_traverse/src/context/mod.rs +++ b/crates/oxc_traverse/src/context/mod.rs @@ -445,6 +445,18 @@ impl<'a> TraverseCtx<'a> { self.ast.identifier_reference_with_reference_id(span, name, reference_id) } + /// Create an `Expression::Identifier` bound to a `SymbolId`. + pub fn create_bound_ident_expr( + &mut self, + span: Span, + name: Atom<'a>, + symbol_id: SymbolId, + flags: ReferenceFlags, + ) -> Expression<'a> { + let ident = self.create_bound_ident_reference(span, name, symbol_id, flags); + Expression::Identifier(self.ast.alloc(ident)) + } + /// Create an unbound reference. /// /// This is a shortcut for `ctx.scoping.create_unbound_reference`. @@ -468,6 +480,17 @@ impl<'a> TraverseCtx<'a> { self.ast.identifier_reference_with_reference_id(span, name, reference_id) } + /// Create an unbound `Expression::Identifier`. + pub fn create_unbound_ident_expr( + &mut self, + span: Span, + name: Atom<'a>, + flags: ReferenceFlags, + ) -> Expression<'a> { + let ident = self.create_unbound_ident_reference(span, name, flags); + Expression::Identifier(self.ast.alloc(ident)) + } + /// Create a reference optionally bound to a `SymbolId`. /// /// If you know if there's a `SymbolId` or not, prefer `TraverseCtx::create_bound_reference` @@ -502,6 +525,24 @@ impl<'a> TraverseCtx<'a> { } } + /// Create an `Expression::Identifier` optionally bound to a `SymbolId`. + /// + /// If you know if there's a `SymbolId` or not, prefer `TraverseCtx::create_bound_ident_expr` + /// or `TraverseCtx::create_unbound_ident_expr`. + pub fn create_ident_expr( + &mut self, + span: Span, + name: Atom<'a>, + symbol_id: Option, + flags: ReferenceFlags, + ) -> Expression<'a> { + if let Some(symbol_id) = symbol_id { + self.create_bound_ident_expr(span, name, symbol_id, flags) + } else { + self.create_unbound_ident_expr(span, name, flags) + } + } + /// Create reference in current scope, looking up binding for `name`, /// /// This is a shortcut for `ctx.scoping.create_reference_in_current_scope`.