Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -786,7 +786,7 @@ impl<'a> ArrowFunctionConverter<'a> {
if let Some(assign_value) = assign_value {
arguments.push(Argument::from(assign_value.take_in(ctx.ast)));
}
let call = ctx.ast.expression_call(SPAN, callee, NONE, arguments, false);
let call = ctx.ast.expression_call(expr.span(), callee, NONE, arguments, false);
Some(call)
}

Expand Down Expand Up @@ -826,7 +826,7 @@ impl<'a> ArrowFunctionConverter<'a> {
let property = ctx.ast.identifier_name(SPAN, "call");
let callee = ctx.ast.member_expression_static(SPAN, object, property, false);
let callee = Expression::from(callee);
Some(ctx.ast.expression_call(SPAN, callee, NONE, arguments, false))
Some(ctx.ast.expression_call(call.span, callee, NONE, arguments, false))
}

/// Transform an `AssignmentExpression` whose assignment target is a `super` member expression.
Expand Down
3 changes: 2 additions & 1 deletion crates/oxc_transformer/src/common/computed_key.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

use oxc_ast::ast::Expression;
use oxc_semantic::SymbolFlags;
use oxc_span::SPAN;

use crate::{context::TraverseCtx, utils::ast_builder::create_assignment};

Expand Down Expand Up @@ -67,7 +68,7 @@ pub fn create_computed_key_temp_var<'a>(

ctx.state.var_declarations.insert_let(&binding, None, ctx.ast);

let assignment = create_assignment(&binding, key, ctx);
let assignment = create_assignment(&binding, key, SPAN, ctx);
let ident = binding.create_read_expression(ctx);
Comment on lines 69 to 72
Copy link

Copilot AI Feb 11, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

create_computed_key_temp_var passes SPAN into create_assignment, so the generated _tmp = <key> assignment will have an empty span and be skipped by sourcemap generation. Since this assignment corresponds to evaluating the original computed key expression, capture the original key span before moving it and pass that span instead.

Copilot uses AI. Check for mistakes.

(assignment, ident)
Expand Down
9 changes: 7 additions & 2 deletions crates/oxc_transformer/src/decorator/legacy/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -662,7 +662,12 @@ impl<'a> LegacyDecorator<'a> {
// `_Class = this`;
let class_alias_with_this_assignment = ctx.ast.statement_expression(
SPAN,
create_assignment(class_alias_binding, ctx.ast.expression_this(SPAN), ctx),
create_assignment(
class_alias_binding,
ctx.ast.expression_this(SPAN),
SPAN,
ctx,
),
);
let body = ctx.ast.vec1(class_alias_with_this_assignment);
let scope_id = ctx.create_child_scope_of_current(ScopeFlags::ClassStaticBlock);
Expand Down Expand Up @@ -1051,7 +1056,7 @@ impl<'a> LegacyDecorator<'a> {
ctx: &mut TraverseCtx<'a>,
) -> Expression<'a> {
let ident = class_binding.create_read_expression(ctx);
if is_static { ident } else { create_prototype_member(ident, ctx) }
if is_static { ident } else { create_prototype_member(ident, SPAN, ctx) }
}

/// Get the name of the property key.
Expand Down
27 changes: 17 additions & 10 deletions crates/oxc_transformer/src/es2016/exponentiation_operator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@
use oxc_allocator::{CloneIn, TakeIn, Vec as ArenaVec};
use oxc_ast::{NONE, ast::*};
use oxc_semantic::ReferenceFlags;
use oxc_span::SPAN;
use oxc_span::{SPAN, Span};
use oxc_syntax::operator::{AssignmentOperator, BinaryOperator};
use oxc_traverse::{BoundIdentifier, Traverse};

Expand Down Expand Up @@ -112,7 +112,7 @@ impl<'a> ExponentiationOperator<'a> {
Expression::BinaryExpression(binary_expr) => binary_expr.unbox(),
_ => unreachable!(),
};
*expr = Self::math_pow(binary_expr.left, binary_expr.right, ctx);
*expr = Self::math_pow(binary_expr.span, binary_expr.left, binary_expr.right, ctx);
}

/// Convert `AssignmentExpression` where assignee is an identifier.
Expand All @@ -129,13 +129,14 @@ impl<'a> ExponentiationOperator<'a> {
#[inline]
fn convert_identifier_assignment(&self, expr: &mut Expression<'a>, ctx: &mut TraverseCtx<'a>) {
let Expression::AssignmentExpression(assign_expr) = expr else { unreachable!() };
let span = assign_expr.span;
let AssignmentTarget::AssignmentTargetIdentifier(ident) = &mut assign_expr.left else {
unreachable!()
};

let (pow_left, temp_var_inits) = self.get_pow_left_identifier(ident, ctx);
Self::convert_assignment(assign_expr, pow_left, ctx);
Self::revise_expression(expr, temp_var_inits, ctx);
Self::revise_expression(expr, temp_var_inits, span, ctx);
}

/// Get left side of `Math.pow(pow_left, ...)` for identifier
Expand Down Expand Up @@ -199,6 +200,7 @@ impl<'a> ExponentiationOperator<'a> {
ctx: &mut TraverseCtx<'a>,
) {
let Expression::AssignmentExpression(assign_expr) = expr else { unreachable!() };
let span = assign_expr.span;
let AssignmentTarget::StaticMemberExpression(member_expr) = &mut assign_expr.left else {
unreachable!()
};
Expand All @@ -207,7 +209,7 @@ impl<'a> ExponentiationOperator<'a> {
self.get_pow_left_static_member(member_expr, ctx);
assign_expr.left = replacement_left;
Self::convert_assignment(assign_expr, pow_left, ctx);
Self::revise_expression(expr, temp_var_inits, ctx);
Self::revise_expression(expr, temp_var_inits, span, ctx);
}

/// Get left side of `Math.pow(pow_left, ...)` for static member expression
Expand Down Expand Up @@ -298,13 +300,14 @@ impl<'a> ExponentiationOperator<'a> {
ctx: &mut TraverseCtx<'a>,
) {
let Expression::AssignmentExpression(assign_expr) = expr else { unreachable!() };
let span = assign_expr.span;
let AssignmentTarget::ComputedMemberExpression(member_expr) = &mut assign_expr.left else {
unreachable!()
};

let (pow_left, temp_var_inits) = self.get_pow_left_computed_member(member_expr, ctx);
Self::convert_assignment(assign_expr, pow_left, ctx);
Self::revise_expression(expr, temp_var_inits, ctx);
Self::revise_expression(expr, temp_var_inits, span, ctx);
}

/// Get left side of `Math.pow(pow_left, ...)` for computed member expression
Expand Down Expand Up @@ -379,13 +382,14 @@ impl<'a> ExponentiationOperator<'a> {
ctx: &mut TraverseCtx<'a>,
) {
let Expression::AssignmentExpression(assign_expr) = expr else { unreachable!() };
let span = assign_expr.span;
let AssignmentTarget::PrivateFieldExpression(member_expr) = &mut assign_expr.left else {
unreachable!()
};

let (pow_left, temp_var_inits) = self.get_pow_left_private_field(member_expr, ctx);
Self::convert_assignment(assign_expr, pow_left, ctx);
Self::revise_expression(expr, temp_var_inits, ctx);
Self::revise_expression(expr, temp_var_inits, span, ctx);
}

/// Get left side of `Math.pow(pow_left, ...)` for static member expression
Expand Down Expand Up @@ -511,26 +515,29 @@ impl<'a> ExponentiationOperator<'a> {
pow_left: Expression<'a>,
ctx: &mut TraverseCtx<'a>,
) {
let span = assign_expr.span;
let pow_right = assign_expr.right.take_in(ctx.ast);
assign_expr.right = Self::math_pow(pow_left, pow_right, ctx);
assign_expr.right = Self::math_pow(span, pow_left, pow_right, ctx);
assign_expr.operator = AssignmentOperator::Assign;
}

/// If needs temp var initializers, replace expression `expr` with `(temp1, temp2, expr)`.
fn revise_expression(
expr: &mut Expression<'a>,
mut temp_var_inits: ArenaVec<'a, Expression<'a>>,
span: Span,
ctx: &TraverseCtx<'a>,
) {
if !temp_var_inits.is_empty() {
temp_var_inits.reserve_exact(1);
temp_var_inits.push(expr.take_in(ctx.ast));
*expr = ctx.ast.expression_sequence(SPAN, temp_var_inits);
*expr = ctx.ast.expression_sequence(span, temp_var_inits);
}
}

/// `Math.pow(left, right)`
fn math_pow(
span: Span,
left: Expression<'a>,
right: Expression<'a>,
ctx: &mut TraverseCtx<'a>,
Expand All @@ -540,9 +547,9 @@ impl<'a> ExponentiationOperator<'a> {
let object = ctx.create_ident_expr(SPAN, 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));
Expression::from(ctx.ast.member_expression_static(span, object, property, false));
let arguments = ctx.ast.vec_from_array([Argument::from(left), Argument::from(right)]);
ctx.ast.expression_call(SPAN, callee, NONE, arguments, false)
ctx.ast.expression_call(span, callee, NONE, arguments, false)
}

/// Create a temporary variable.
Expand Down
8 changes: 5 additions & 3 deletions crates/oxc_transformer/src/es2017/async_to_generator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -178,7 +178,7 @@ impl<'a> AsyncToGenerator<'a> {
) -> Option<Expression<'a>> {
// We don't need to handle top-level await.
if Self::is_inside_async_function(ctx) {
Some(ctx.ast.expression_yield(SPAN, false, Some(expr.argument.take_in(ctx.ast))))
Some(ctx.ast.expression_yield(expr.span, false, Some(expr.argument.take_in(ctx.ast))))
} else {
None
}
Expand Down Expand Up @@ -302,6 +302,7 @@ impl<'a> AsyncGeneratorExecutor<'a> {
wrapper_function: &mut Function<'a>,
ctx: &mut TraverseCtx<'a>,
) -> Expression<'a> {
let span = wrapper_function.span;
let body = wrapper_function.body.take().unwrap();
let params = wrapper_function.params.take_in_box(ctx.ast);
let id = wrapper_function.id.take();
Expand Down Expand Up @@ -391,7 +392,7 @@ impl<'a> AsyncGeneratorExecutor<'a> {

// Construct the IIFE
let callee = Expression::FunctionExpression(wrapper_function.take_in_box(ctx.ast));
ctx.ast.expression_call_with_pure(SPAN, callee, NONE, ctx.ast.vec(), false, true)
ctx.ast.expression_call_with_pure(span, callee, NONE, ctx.ast.vec(), false, true)
}

/// Transforms async function declarations into generator functions wrapped in the asyncToGenerator helper.
Expand Down Expand Up @@ -465,6 +466,7 @@ impl<'a> AsyncGeneratorExecutor<'a> {
arrow: &mut ArrowFunctionExpression<'a>,
ctx: &mut TraverseCtx<'a>,
) -> Expression<'a> {
let arrow_span = arrow.span;
let mut body = arrow.body.take_in_box(ctx.ast);

// If the arrow's expression is true, we need to wrap the only one expression with return statement.
Expand Down Expand Up @@ -528,7 +530,7 @@ impl<'a> AsyncGeneratorExecutor<'a> {
let wrapper_function = Self::create_function(None, params, body, wrapper_scope_id, ctx);
// Construct the IIFE
let callee = Expression::FunctionExpression(wrapper_function);
ctx.ast.expression_call(SPAN, callee, NONE, ctx.ast.vec(), false)
ctx.ast.expression_call(arrow_span, callee, NONE, ctx.ast.vec(), false)
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
use oxc_allocator::{TakeIn, Vec as ArenaVec};
use oxc_ast::{NONE, ast::*};
use oxc_semantic::{ScopeFlags, ScopeId, SymbolFlags};
use oxc_span::SPAN;
use oxc_span::{SPAN, Span};
use oxc_traverse::{Ancestor, BoundIdentifier};

use crate::{
Expand Down Expand Up @@ -45,6 +45,7 @@ impl<'a> AsyncGeneratorFunctions<'a> {
return;
}

let for_of_span = for_of.span;
let allow_multiple_statements = Self::is_multiple_statements_allowed(ctx);
let parent_scope_id = if allow_multiple_statements {
ctx.current_scope_id()
Expand All @@ -59,7 +60,8 @@ impl<'a> AsyncGeneratorFunctions<'a> {
// 1. Use the last statement as the new statement.
// 2. insert the rest of the statements before the current statement.
// TODO: Once we have a method to replace the current statement, we can simplify this logic.
let mut statements = self.transform_for_of_statement(for_of, parent_scope_id, ctx);
let mut statements =
self.transform_for_of_statement(for_of, parent_scope_id, for_of_span, ctx);
let mut new_stmt = statements.pop().unwrap();

// If it's a labeled statement, we need to wrap the ForStatement with a labeled statement.
Expand All @@ -72,7 +74,7 @@ impl<'a> AsyncGeneratorFunctions<'a> {
let try_statement_block_body = &mut try_statement.block.body;
let for_statement = try_statement_block_body.pop().unwrap();
try_statement_block_body.push(ctx.ast.statement_labeled(
SPAN,
for_of_span,
label.clone(),
for_statement,
));
Expand All @@ -97,6 +99,7 @@ impl<'a> AsyncGeneratorFunctions<'a> {
&self,
stmt: &mut ForOfStatement<'a>,
parent_scope_id: ScopeId,
span: Span,
ctx: &mut TraverseCtx<'a>,
) -> ArenaVec<'a, Statement<'a>> {
let step_key =
Expand Down Expand Up @@ -153,7 +156,15 @@ impl<'a> AsyncGeneratorFunctions<'a> {
ctx.ast.vec1(Argument::from(iterator)),
ctx,
);
Self::build_for_await(iterator, &step_key, body, stmt.scope_id(), parent_scope_id, ctx)
Self::build_for_await(
iterator,
&step_key,
body,
stmt.scope_id(),
parent_scope_id,
span,
ctx,
)
}

/// Build a `for` statement used to replace the `for await` statement.
Expand Down Expand Up @@ -195,6 +206,7 @@ impl<'a> AsyncGeneratorFunctions<'a> {
body: ArenaVec<'a, Statement<'a>>,
for_of_scope_id: ScopeId,
parent_scope_id: ScopeId,
span: Span,
ctx: &mut TraverseCtx<'a>,
) -> ArenaVec<'a, Statement<'a>> {
let var_scope_id = ctx.current_scope_id();
Expand Down Expand Up @@ -258,7 +270,7 @@ impl<'a> AsyncGeneratorFunctions<'a> {
ctx.create_child_scope(block_scope_id, ScopeFlags::empty());

let for_statement = ctx.ast.statement_for_with_scope_id(
SPAN,
span,
Some(ctx.ast.for_statement_init_variable_declaration(
SPAN,
VariableDeclarationKind::Var,
Expand Down Expand Up @@ -477,7 +489,7 @@ impl<'a> AsyncGeneratorFunctions<'a> {
Some(block_statement)
};

let try_statement = ctx.ast.statement_try(SPAN, block, catch_clause, finally);
let try_statement = ctx.ast.statement_try(span, block, catch_clause, finally);

items.push(try_statement);
items
Expand Down
5 changes: 4 additions & 1 deletion crates/oxc_transformer/src/es2018/object_rest_spread.rs
Original file line number Diff line number Diff line change
Expand Up @@ -491,6 +491,7 @@ impl<'a> ObjectRestSpread<'a> {
return;
}

let span = obj_expr.span;
let mut call_expr: Option<ArenaBox<'a, CallExpression<'a>>> = None;
let mut props = ctx.ast.vec_with_capacity(obj_expr.properties.len());

Expand All @@ -508,7 +509,9 @@ impl<'a> ObjectRestSpread<'a> {
Self::make_object_spread(&mut call_expr, &mut props, ctx);
}

*expr = Expression::CallExpression(call_expr.unwrap());
let mut final_call = call_expr.unwrap();
final_call.span = span;
*expr = Expression::CallExpression(final_call);
}

fn make_object_spread(
Expand Down
8 changes: 5 additions & 3 deletions crates/oxc_transformer/src/es2020/optional_chaining.rs
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ use std::mem;

use oxc_allocator::{CloneIn, TakeIn};
use oxc_ast::{NONE, ast::*};
use oxc_span::SPAN;
use oxc_span::{GetSpan, SPAN, Span};
use oxc_traverse::{Ancestor, BoundIdentifier, MaybeBoundIdentifier, Traverse};

use crate::{
Expand Down Expand Up @@ -234,14 +234,15 @@ impl<'a> OptionalChaining<'a> {
is_delete: bool,
test: Expression<'a>,
alternate: Expression<'a>,
span: Span,
ctx: &TraverseCtx<'a>,
) -> Expression<'a> {
let consequent = if is_delete {
ctx.ast.expression_boolean_literal(SPAN, true)
} else {
ctx.ast.void_0(SPAN)
};
ctx.ast.expression_conditional(SPAN, test, consequent, alternate)
ctx.ast.expression_conditional(span, test, consequent, alternate)
}

/// Convert chain expression to expression
Expand Down Expand Up @@ -317,6 +318,7 @@ impl<'a> OptionalChaining<'a> {
chain_expr: &mut Expression<'a>,
ctx: &mut TraverseCtx<'a>,
) -> Expression<'a> {
let span = chain_expr.span();
let mut chain_expr = Self::convert_chain_expression_to_expression(chain_expr, ctx);
// ^^^^^^^^^^ After the recursive transformation, the chain_expr will be transformed into
// a pure non-optional expression and it's the last part of the chain expression.
Expand Down Expand Up @@ -349,7 +351,7 @@ impl<'a> OptionalChaining<'a> {
self.temp_binding = None;
self.call_context = CallContext::None;

Self::create_conditional_expression(is_delete, left, chain_expr, ctx)
Self::create_conditional_expression(is_delete, left, chain_expr, span, ctx)
}

/// Transform an expression to bind a proper context
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -123,11 +123,12 @@ impl<'a> LogicalAssignmentOperators {
_ => return,
};

let span = assignment_expr.span;
let assign_op = AssignmentOperator::Assign;
let right = assignment_expr.right.take_in(ctx.ast);
let right = ctx.ast.expression_assignment(SPAN, assign_op, assign_target, right);

let logical_expr = ctx.ast.expression_logical(SPAN, left_expr, operator, right);
let logical_expr = ctx.ast.expression_logical(span, left_expr, operator, right);

*expr = logical_expr;
}
Expand Down
Loading
Loading