Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 9f164c6

Browse files
authored
feat(rust): ensure span uniqueness of oxc AST (#1927)
<!-- Thank you for contributing! --> ### Description Rolldown uses `Span` as the way to indentify AST ndoes. Now the `inject` feature would generate improt statements with empty Span. They might be duplicated, we need ensure it's uniqueness. Contexts: - Closes #1875 - #1926 - #1899 (comment) <!-- Please insert your description here and provide especially info about the "what" this PR is solving -->
1 parent 305f7cb commit 9f164c6

3 files changed

Lines changed: 55 additions & 0 deletions

File tree

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
use oxc::{
2+
ast::{visit::walk_mut, VisitMut},
3+
span::{GetSpanMut, Span},
4+
};
5+
use rustc_hash::FxHashSet;
6+
7+
/// Make sure there aren't any duplicate spans in the AST.
8+
pub struct EnsureSpanUniqueness {
9+
// visited_spans: FxHashMap</* start */ u32, /* ends */ FxHashSet<u32>>,
10+
visited_spans: FxHashSet<Span>,
11+
next_unique_span_start: u32,
12+
}
13+
14+
impl<'a> VisitMut<'a> for EnsureSpanUniqueness {
15+
fn visit_program(&mut self, it: &mut oxc::ast::ast::Program<'a>) {
16+
self.next_unique_span_start = it.span.end + 1;
17+
walk_mut::walk_program(self, it);
18+
}
19+
20+
// TODO: it's better use `visit_span`, but it's not implemented yet by oxc. https://github.com/oxc-project/oxc/issues/4799
21+
fn visit_module_declaration(&mut self, it: &mut oxc::ast::ast::ModuleDeclaration<'a>) {
22+
self.ensure_uniqueness(it.span_mut());
23+
walk_mut::walk_module_declaration(self, it);
24+
}
25+
}
26+
27+
impl EnsureSpanUniqueness {
28+
pub fn new() -> Self {
29+
Self { visited_spans: FxHashSet::default(), next_unique_span_start: 1 }
30+
}
31+
32+
fn ensure_uniqueness(&mut self, span: &mut Span) {
33+
if self.visited_spans.contains(span) {
34+
*span = self.generate_unique_span();
35+
}
36+
self.visited_spans.insert(*span);
37+
}
38+
39+
fn generate_unique_span(&mut self) -> Span {
40+
let mut span_candidate = Span::new(self.next_unique_span_start, self.next_unique_span_start);
41+
while self.visited_spans.contains(&span_candidate) {
42+
self.next_unique_span_start += 1;
43+
span_candidate = Span::new(self.next_unique_span_start, self.next_unique_span_start);
44+
}
45+
debug_assert!(span_candidate.is_empty());
46+
span_candidate
47+
}
48+
}

crates/rolldown/src/utils/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ pub mod apply_inner_plugins;
99
pub mod augment_chunk_hash;
1010
pub mod call_expression_ext;
1111
pub mod chunk;
12+
pub mod ecma_visitors;
1213
pub mod extract_hash_pattern;
1314
pub mod extract_meaningful_input_name_from_path;
1415
pub mod hash_placeholder;

crates/rolldown/src/utils/pre_process_ecma_ast.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
use std::path::Path;
22

3+
use oxc::ast::VisitMut;
34
use oxc::minifier::{
45
CompressOptions, Compressor, ReplaceGlobalDefines, ReplaceGlobalDefinesConfig,
56
};
@@ -10,6 +11,7 @@ use rolldown_ecmascript::EcmaAst;
1011

1112
use crate::types::oxc_parse_type::OxcParseType;
1213

14+
use super::ecma_visitors::EnsureSpanUniqueness;
1315
use super::tweak_ast_for_scanning::tweak_ast_for_scanning;
1416

1517
// #[allow(clippy::match_same_arms)]: `OxcParseType::Tsx` will have special logic to deal with ts compared to `OxcParseType::Jsx`
@@ -62,6 +64,10 @@ pub fn pre_process_ecma_ast(
6264

6365
tweak_ast_for_scanning(&mut ast);
6466

67+
ast.program.with_mut(|fields| {
68+
EnsureSpanUniqueness::new().visit_program(fields.program);
69+
});
70+
6571
// We have to re-create the symbol table and scope tree after the transformation so far to make sure they are up-to-date.
6672
let (symbols, scopes) = ast.make_symbol_table_and_scope_tree();
6773

0 commit comments

Comments
 (0)