Skip to content

Commit f41705f

Browse files
committed
fix(codegen): do not generate sourcemap for empty length spans (#11892)
Upstream may have modified and generated an incorrect span.
1 parent e36ca9a commit f41705f

File tree

4 files changed

+86
-61
lines changed

4 files changed

+86
-61
lines changed

crates/oxc_codegen/src/lib.rs

Lines changed: 10 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ use std::borrow::Cow;
1818
use oxc_ast::ast::*;
1919
use oxc_data_structures::{code_buffer::CodeBuffer, stack::Stack};
2020
use oxc_semantic::Scoping;
21-
use oxc_span::{GetSpan, SPAN, Span};
21+
use oxc_span::{GetSpan, Span};
2222
use oxc_syntax::{
2323
identifier::{is_identifier_part, is_identifier_part_ascii},
2424
operator::{BinaryOperator, UnaryOperator, UpdateOperator},
@@ -690,29 +690,26 @@ impl<'a> Codegen<'a> {
690690
}
691691

692692
fn add_source_mapping(&mut self, span: Span) {
693-
if span == SPAN {
694-
return;
695-
}
696693
if let Some(sourcemap_builder) = self.sourcemap_builder.as_mut() {
697-
sourcemap_builder.add_source_mapping(self.code.as_bytes(), span.start, None);
694+
if !span.is_empty() {
695+
sourcemap_builder.add_source_mapping(self.code.as_bytes(), span.start, None);
696+
}
698697
}
699698
}
700699

701700
fn add_source_mapping_end(&mut self, span: Span) {
702-
if span == SPAN {
703-
return;
704-
}
705701
if let Some(sourcemap_builder) = self.sourcemap_builder.as_mut() {
706-
sourcemap_builder.add_source_mapping(self.code.as_bytes(), span.end, None);
702+
if !span.is_empty() {
703+
sourcemap_builder.add_source_mapping(self.code.as_bytes(), span.end, None);
704+
}
707705
}
708706
}
709707

710708
fn add_source_mapping_for_name(&mut self, span: Span, name: &str) {
711-
if span == SPAN {
712-
return;
713-
}
714709
if let Some(sourcemap_builder) = self.sourcemap_builder.as_mut() {
715-
sourcemap_builder.add_source_mapping_for_name(self.code.as_bytes(), span, name);
710+
if !span.is_empty() {
711+
sourcemap_builder.add_source_mapping_for_name(self.code.as_bytes(), span, name);
712+
}
716713
}
717714
}
718715
}

crates/oxc_codegen/tests/integration/main.rs

Lines changed: 3 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -2,45 +2,9 @@
22
pub mod comments;
33
pub mod esbuild;
44
pub mod js;
5-
pub mod tester;
5+
pub mod sourcemap;
66
pub mod ts;
77

8-
use oxc_allocator::Allocator;
9-
use oxc_codegen::{Codegen, CodegenOptions, CodegenReturn};
10-
use oxc_parser::Parser;
11-
use oxc_span::SourceType;
8+
mod tester;
129

13-
#[track_caller]
14-
pub fn codegen(source_text: &str) -> String {
15-
codegen_options(source_text, &CodegenOptions::default()).code
16-
}
17-
18-
#[track_caller]
19-
pub fn codegen_options(source_text: &str, options: &CodegenOptions) -> CodegenReturn {
20-
let allocator = Allocator::default();
21-
let source_type = SourceType::ts();
22-
let ret = Parser::new(&allocator, source_text, source_type).parse();
23-
let mut options = options.clone();
24-
options.single_quote = true;
25-
Codegen::new().with_options(options).build(&ret.program)
26-
}
27-
28-
#[track_caller]
29-
pub fn snapshot(name: &str, cases: &[&str]) {
30-
snapshot_options(name, cases, &CodegenOptions::default());
31-
}
32-
33-
#[track_caller]
34-
pub fn snapshot_options(name: &str, cases: &[&str], options: &CodegenOptions) {
35-
use std::fmt::Write;
36-
37-
let snapshot = cases.iter().enumerate().fold(String::new(), |mut w, (i, case)| {
38-
let result = codegen_options(case, options).code;
39-
write!(w, "########## {i}\n{case}\n----------\n{result}\n",).unwrap();
40-
w
41-
});
42-
43-
insta::with_settings!({ prepend_module_to_snapshot => false, snapshot_suffix => "", omit_expression => true }, {
44-
insta::assert_snapshot!(name, snapshot);
45-
});
46-
}
10+
pub use tester::*;
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
use oxc_allocator::Allocator;
2+
use oxc_ast::ast::{Expression, Statement};
3+
use oxc_codegen::Codegen;
4+
use oxc_parser::Parser;
5+
use oxc_span::{SourceType, Span};
6+
7+
use crate::tester::default_options;
8+
9+
/// Upstream may have modified the AST to include incorrect spans.
10+
/// e.g. <https://github.com/rolldown/rolldown/blob/v1.0.0-beta.19/crates/rolldown/src/utils/ecma_visitors/mod.rs>
11+
#[test]
12+
fn incorrect_ast() {
13+
let allocator = Allocator::default();
14+
let source_type = SourceType::ts();
15+
let source_text = "foo\nvar bar = '测试'";
16+
let ret = Parser::new(&allocator, source_text, source_type).parse();
17+
18+
let mut program = ret.program;
19+
program.span = Span::new(0, 0);
20+
if let Statement::ExpressionStatement(s) = &mut program.body[0] {
21+
s.span = Span::new(17, 17);
22+
if let Expression::Identifier(ident) = &mut s.expression {
23+
ident.span = Span::new(17, 17);
24+
}
25+
}
26+
27+
let ret = Codegen::new().with_options(default_options()).build(&program);
28+
assert!(ret.map.is_some(), "sourcemap exists");
29+
}

crates/oxc_codegen/tests/integration/tester.rs

Lines changed: 44 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,25 @@
11
use oxc_allocator::Allocator;
2-
use oxc_codegen::{Codegen, CodegenOptions};
2+
use oxc_codegen::{Codegen, CodegenOptions, CodegenReturn};
33
use oxc_parser::{ParseOptions, Parser};
44
use oxc_span::SourceType;
55

6+
pub fn default_options() -> CodegenOptions {
7+
// Ensure sourcemap do not crash.
8+
CodegenOptions { source_map_path: Some("test.js".into()), ..CodegenOptions::default() }
9+
}
10+
611
#[track_caller]
712
pub fn test_with_parse_options(source_text: &str, expected: &str, parse_options: ParseOptions) {
813
let allocator = Allocator::default();
914
let ret =
1015
Parser::new(&allocator, source_text, SourceType::tsx()).with_options(parse_options).parse();
11-
let result = Codegen::new().build(&ret.program).code;
16+
let result = Codegen::new().with_options(default_options()).build(&ret.program).code;
1217
assert_eq!(result, expected, "\nfor source: {source_text}");
1318
}
1419

1520
#[track_caller]
1621
pub fn test(source_text: &str, expected: &str) {
17-
test_options(source_text, expected, CodegenOptions::default());
22+
test_options(source_text, expected, default_options());
1823
}
1924

2025
#[track_caller]
@@ -29,12 +34,7 @@ pub fn test_options(source_text: &str, expected: &str, options: CodegenOptions)
2934

3035
#[track_caller]
3136
pub fn test_tsx(source_text: &str, expected: &str) {
32-
test_options_with_source_type(
33-
source_text,
34-
expected,
35-
SourceType::tsx(),
36-
CodegenOptions::default(),
37-
);
37+
test_options_with_source_type(source_text, expected, SourceType::tsx(), default_options());
3838
}
3939

4040
#[track_caller]
@@ -66,3 +66,38 @@ pub fn test_minify(source_text: &str, expected: &str) {
6666
pub fn test_minify_same(source_text: &str) {
6767
test_minify(source_text, source_text);
6868
}
69+
70+
#[track_caller]
71+
pub fn codegen(source_text: &str) -> String {
72+
codegen_options(source_text, &default_options()).code
73+
}
74+
75+
#[track_caller]
76+
pub fn codegen_options(source_text: &str, options: &CodegenOptions) -> CodegenReturn {
77+
let allocator = Allocator::default();
78+
let source_type = SourceType::ts();
79+
let ret = Parser::new(&allocator, source_text, source_type).parse();
80+
let mut options = options.clone();
81+
options.single_quote = true;
82+
Codegen::new().with_options(options).build(&ret.program)
83+
}
84+
85+
#[track_caller]
86+
pub fn snapshot(name: &str, cases: &[&str]) {
87+
snapshot_options(name, cases, &default_options());
88+
}
89+
90+
#[track_caller]
91+
pub fn snapshot_options(name: &str, cases: &[&str], options: &CodegenOptions) {
92+
use std::fmt::Write;
93+
94+
let snapshot = cases.iter().enumerate().fold(String::new(), |mut w, (i, case)| {
95+
let result = codegen_options(case, options).code;
96+
write!(w, "########## {i}\n{case}\n----------\n{result}\n",).unwrap();
97+
w
98+
});
99+
100+
insta::with_settings!({ prepend_module_to_snapshot => false, snapshot_suffix => "", omit_expression => true }, {
101+
insta::assert_snapshot!(name, snapshot);
102+
});
103+
}

0 commit comments

Comments
 (0)