diff --git a/crates/oxc/README.md b/crates/oxc/README.md index 20d07dfaf5dfa..39a894cbb41cd 100644 --- a/crates/oxc/README.md +++ b/crates/oxc/README.md @@ -101,7 +101,6 @@ let SemanticBuilderReturn { errors: semantic_errors, } = SemanticBuilder::new() .with_check_syntax_error(true) // Enable extra syntax error checking - .with_trivias(trivias) // Pass comments for JSDoc parsing .with_build_jsdoc(true) // Enable JSDoc parsing .with_cfg(true) // Build a Control Flow Graph .build(&program); // Produce the `Semantic` diff --git a/crates/oxc/src/compiler.rs b/crates/oxc/src/compiler.rs index 30027347a5bea..a0c30aea74920 100644 --- a/crates/oxc/src/compiler.rs +++ b/crates/oxc/src/compiler.rs @@ -1,7 +1,7 @@ use std::{mem, ops::ControlFlow, path::Path}; use oxc_allocator::Allocator; -use oxc_ast::{ast::Program, Trivias}; +use oxc_ast::ast::Program; use oxc_codegen::{CodeGenerator, CodegenOptions, CodegenReturn, CommentOptions}; use oxc_diagnostics::OxcDiagnostic; use oxc_isolated_declarations::{IsolatedDeclarations, IsolatedDeclarationsOptions}; @@ -135,11 +135,10 @@ pub trait CompilerInterface { } let mut program = parser_return.program; - let trivias = parser_return.trivias; /* Isolated Declarations */ if let Some(options) = self.isolated_declaration_options() { - self.isolated_declaration(options, &allocator, &program, source_path, &trivias); + self.isolated_declaration(options, &allocator, &program, source_path); } /* Semantic */ @@ -158,15 +157,8 @@ pub trait CompilerInterface { /* Transform */ if let Some(options) = self.transform_options() { - let mut transformer_return = self.transform( - options, - &allocator, - &mut program, - source_path, - &trivias, - symbols, - scopes, - ); + let mut transformer_return = + self.transform(options, &allocator, &mut program, source_path, symbols, scopes); if !transformer_return.errors.is_empty() { self.handle_errors(transformer_return.errors); @@ -210,7 +202,7 @@ pub trait CompilerInterface { /* Codegen */ if let Some(options) = self.codegen_options() { - let ret = self.codegen(&program, source_path, &trivias, mangler, options); + let ret = self.codegen(&program, source_path, mangler, options); self.after_codegen(ret); } } @@ -245,15 +237,12 @@ pub trait CompilerInterface { allocator: &'a Allocator, program: &Program<'a>, source_path: &Path, - trivias: &Trivias, ) { - let ret = IsolatedDeclarations::new(allocator, program.source_text, trivias, options) - .build(program); + let ret = IsolatedDeclarations::new(allocator, options).build(program); self.handle_errors(ret.errors); let ret = self.codegen( &ret.program, source_path, - trivias, None, self.codegen_options().unwrap_or_default(), ); @@ -267,11 +256,10 @@ pub trait CompilerInterface { allocator: &'a Allocator, program: &mut Program<'a>, source_path: &Path, - trivias: &Trivias, symbols: SymbolTable, scopes: ScopeTree, ) -> TransformerReturn { - Transformer::new(allocator, source_path, trivias.clone(), options) + Transformer::new(allocator, source_path, options) .build_with_symbols_and_scopes(symbols, scopes, program) } @@ -292,7 +280,6 @@ pub trait CompilerInterface { &self, program: &Program<'_>, source_path: &Path, - trivias: &Trivias, mangler: Option, options: CodegenOptions, ) -> CodegenReturn { @@ -300,7 +287,7 @@ pub trait CompilerInterface { let mut codegen = CodeGenerator::new() .with_options(options) .with_mangler(mangler) - .enable_comment(program.source_text, trivias.clone(), comment_options); + .enable_comment(program, comment_options); if self.enable_sourcemap() { codegen = codegen .enable_source_map(source_path.to_string_lossy().as_ref(), program.source_text); diff --git a/crates/oxc_ast/src/lib.rs b/crates/oxc_ast/src/lib.rs index 52711c9461f71..eab91afe0b717 100644 --- a/crates/oxc_ast/src/lib.rs +++ b/crates/oxc_ast/src/lib.rs @@ -61,7 +61,7 @@ pub use crate::{ ast_builder::AstBuilder, ast_builder_impl::NONE, ast_kind::{AstKind, AstType}, - trivia::{SortedComments, Trivias}, + trivia::{comments_range, has_comments_between, CommentsRange}, visit::{Visit, VisitMut}, }; diff --git a/crates/oxc_ast/src/trivia.rs b/crates/oxc_ast/src/trivia.rs index 52b4c0da497d3..cd9ae1df92c1e 100644 --- a/crates/oxc_ast/src/trivia.rs +++ b/crates/oxc_ast/src/trivia.rs @@ -2,63 +2,22 @@ use std::{ iter::FusedIterator, - ops::{Bound, Deref, RangeBounds}, - sync::Arc, + ops::{Bound, RangeBounds}, }; use oxc_span::Span; use crate::ast::comment::*; -/// Sorted set of unique trivia comments, in ascending order by starting position. -pub type SortedComments = Box<[Comment]>; - -#[derive(Debug, Clone, Default)] -pub struct Trivias(Arc); - -#[derive(Debug, Default)] -pub struct TriviasImpl { - /// Unique comments, ordered by increasing span-start. - comments: SortedComments, - - irregular_whitespaces: Box<[Span]>, +pub fn comments_range(comments: &[Comment], range: R) -> CommentsRange<'_> +where + R: RangeBounds, +{ + CommentsRange::new(comments, range.start_bound().cloned(), range.end_bound().cloned()) } -impl Deref for Trivias { - type Target = TriviasImpl; - - #[inline] - fn deref(&self) -> &Self::Target { - self.0.as_ref() - } -} - -impl Trivias { - pub fn new(comments: SortedComments, irregular_whitespaces: Vec) -> Trivias { - Self(Arc::new(TriviasImpl { - comments, - irregular_whitespaces: irregular_whitespaces.into_boxed_slice(), - })) - } - - pub fn comments(&self) -> impl Iterator { - self.comments.iter() - } - - pub fn comments_range(&self, range: R) -> CommentsRange<'_> - where - R: RangeBounds, - { - CommentsRange::new(&self.comments, range.start_bound().cloned(), range.end_bound().cloned()) - } - - pub fn has_comments_between(&self, span: Span) -> bool { - self.comments_range(span.start..span.end).count() > 0 - } - - pub fn irregular_whitespaces(&self) -> &[Span] { - &self.irregular_whitespaces - } +pub fn has_comments_between(comments: &[Comment], span: Span) -> bool { + comments_range(comments, span.start..span.end).count() > 0 } /// Double-ended iterator over a range of comments, by starting position. @@ -141,7 +100,7 @@ mod test { #[test] fn test_comments_range() { - let comments: SortedComments = vec![ + let comments = vec![ Comment::new(0, 4, CommentKind::Line), Comment::new(5, 9, CommentKind::Line), Comment::new(10, 13, CommentKind::Line), @@ -150,10 +109,9 @@ mod test { ] .into_boxed_slice(); let full_len = comments.len(); - let trivias = Trivias::new(comments, vec![]); - assert_eq!(trivias.comments_range(..).count(), full_len); - assert_eq!(trivias.comments_range(1..).count(), full_len.saturating_sub(1)); - assert_eq!(trivias.comments_range(..18).count(), full_len.saturating_sub(1)); - assert_eq!(trivias.comments_range(..=18).count(), full_len); + assert_eq!(comments_range(&comments, ..).count(), full_len); + assert_eq!(comments_range(&comments, 1..).count(), full_len.saturating_sub(1)); + assert_eq!(comments_range(&comments, ..18).count(), full_len.saturating_sub(1)); + assert_eq!(comments_range(&comments, ..=18).count(), full_len); } } diff --git a/crates/oxc_codegen/examples/codegen.rs b/crates/oxc_codegen/examples/codegen.rs index 3804cf50d0921..895a7f3eeb41d 100644 --- a/crates/oxc_codegen/examples/codegen.rs +++ b/crates/oxc_codegen/examples/codegen.rs @@ -24,7 +24,7 @@ fn main() -> std::io::Result<()> { let printed = { let Some(ret) = parse(&allocator, &source_text, source_type) else { return Ok(()) }; - codegen(&source_text, &ret, minify) + codegen(&ret, minify) }; println!("First time:"); println!("{printed}"); @@ -35,7 +35,7 @@ fn main() -> std::io::Result<()> { let Some(ret) = parse(&allocator, &printed, source_type) else { return Ok(()) }; println!("Second time:"); - let printed = codegen(&printed, &ret, minify); + let printed = codegen(&ret, minify); println!("{printed}"); // Check syntax error parse(&allocator, &printed, source_type); @@ -59,13 +59,9 @@ fn parse<'a>( Some(ret) } -fn codegen(source_text: &str, ret: &ParserReturn<'_>, minify: bool) -> String { +fn codegen(ret: &ParserReturn<'_>, minify: bool) -> String { CodeGenerator::new() - .enable_comment( - source_text, - ret.trivias.clone(), - CommentOptions { preserve_annotate_comments: true }, - ) + .enable_comment(&ret.program, CommentOptions { preserve_annotate_comments: true }) .with_options(CodegenOptions { minify, ..CodegenOptions::default() }) .build(&ret.program) .code diff --git a/crates/oxc_codegen/src/comment.rs b/crates/oxc_codegen/src/comment.rs index aa2b41dd58ebd..389b0ad55ad5d 100644 --- a/crates/oxc_codegen/src/comment.rs +++ b/crates/oxc_codegen/src/comment.rs @@ -2,7 +2,7 @@ use daachorse::DoubleArrayAhoCorasick; use once_cell::sync::Lazy; use rustc_hash::FxHashMap; -use oxc_ast::{Comment, CommentKind, Trivias}; +use oxc_ast::{Comment, CommentKind}; use oxc_syntax::identifier::is_line_terminator; use crate::Codegen; @@ -20,9 +20,9 @@ impl<'a> Codegen<'a> { self.comment_options.preserve_annotate_comments && !self.options.minify } - pub(crate) fn build_comments(&mut self, trivias: &Trivias) { - for comment in trivias.comments().copied() { - self.comments.entry(comment.attached_to).or_default().push(comment); + pub(crate) fn build_comments(&mut self, comments: &[Comment]) { + for comment in comments { + self.comments.entry(comment.attached_to).or_default().push(*comment); } } diff --git a/crates/oxc_codegen/src/lib.rs b/crates/oxc_codegen/src/lib.rs index 9d8fe0cc30a71..8fc7f1d2f67f8 100644 --- a/crates/oxc_codegen/src/lib.rs +++ b/crates/oxc_codegen/src/lib.rs @@ -12,9 +12,8 @@ mod sourcemap_builder; use std::borrow::Cow; -use oxc_ast::{ - ast::{BindingIdentifier, BlockStatement, Expression, IdentifierReference, Program, Statement}, - Trivias, +use oxc_ast::ast::{ + BindingIdentifier, BlockStatement, Expression, IdentifierReference, Program, Statement, }; use oxc_mangler::Mangler; use oxc_span::{GetSpan, Span}; @@ -72,7 +71,6 @@ pub struct Codegen<'a> { /// Original source code of the AST source_text: Option<&'a str>, - trivias: Trivias, comments: CommentsMap, /// Start of comment that needs to be moved to the before VariableDeclarator @@ -146,7 +144,6 @@ impl<'a> Codegen<'a> { options: CodegenOptions::default(), comment_options: CommentOptions::default(), source_text: None, - trivias: Trivias::default(), comments: CommentsMap::default(), start_of_annotation_comment: None, mangler: None, @@ -199,16 +196,10 @@ impl<'a> Codegen<'a> { /// Also sets the [Self::with_source_text] #[must_use] - pub fn enable_comment( - mut self, - source_text: &'a str, - trivias: Trivias, - options: CommentOptions, - ) -> Self { + pub fn enable_comment(mut self, program: &Program<'a>, options: CommentOptions) -> Self { self.comment_options = options; - self.build_comments(&trivias); - self.trivias = trivias; - self.with_source_text(source_text) + self.build_comments(&program.comments); + self.with_source_text(program.source_text) } #[must_use] diff --git a/crates/oxc_codegen/tests/integration/main.rs b/crates/oxc_codegen/tests/integration/main.rs index 73e5b9827b3b2..21e6e641aaa75 100644 --- a/crates/oxc_codegen/tests/integration/main.rs +++ b/crates/oxc_codegen/tests/integration/main.rs @@ -17,11 +17,7 @@ pub fn codegen(source_text: &str) -> String { let ret = Parser::new(&allocator, source_text, source_type).parse(); CodeGenerator::new() .with_options(CodegenOptions { single_quote: true, ..CodegenOptions::default() }) - .enable_comment( - source_text, - ret.trivias, - CommentOptions { preserve_annotate_comments: true }, - ) + .enable_comment(&ret.program, CommentOptions { preserve_annotate_comments: true }) .build(&ret.program) .code } diff --git a/crates/oxc_codegen/tests/integration/tester.rs b/crates/oxc_codegen/tests/integration/tester.rs index 6dd64ba49a1af..e6460fd82af45 100644 --- a/crates/oxc_codegen/tests/integration/tester.rs +++ b/crates/oxc_codegen/tests/integration/tester.rs @@ -8,11 +8,7 @@ pub fn test(source_text: &str, expected: &str) { let allocator = Allocator::default(); let ret = Parser::new(&allocator, source_text, source_type).parse(); let result = CodeGenerator::new() - .enable_comment( - source_text, - ret.trivias, - CommentOptions { preserve_annotate_comments: true }, - ) + .enable_comment(&ret.program, CommentOptions { preserve_annotate_comments: true }) .build(&ret.program) .code; assert_eq!(result, expected, "\nfor source: {source_text:?}"); diff --git a/crates/oxc_isolated_declarations/examples/isolated_declarations.rs b/crates/oxc_isolated_declarations/examples/isolated_declarations.rs index fedc99f37c04a..2074fcb19d820 100644 --- a/crates/oxc_isolated_declarations/examples/isolated_declarations.rs +++ b/crates/oxc_isolated_declarations/examples/isolated_declarations.rs @@ -32,19 +32,11 @@ fn main() { println!("Original:\n"); println!("{source_text}\n"); - let id_ret = IsolatedDeclarations::new( - &allocator, - &source_text, - &ret.trivias, - IsolatedDeclarationsOptions { strip_internal: true }, - ) - .build(&ret.program); + let id_ret = + IsolatedDeclarations::new(&allocator, IsolatedDeclarationsOptions { strip_internal: true }) + .build(&ret.program); let printed = CodeGenerator::new() - .enable_comment( - &source_text, - ret.trivias, - CommentOptions { preserve_annotate_comments: false }, - ) + .enable_comment(&ret.program, CommentOptions { preserve_annotate_comments: false }) .build(&id_ret.program) .code; diff --git a/crates/oxc_isolated_declarations/src/lib.rs b/crates/oxc_isolated_declarations/src/lib.rs index b3f65227e9648..84303623efda5 100644 --- a/crates/oxc_isolated_declarations/src/lib.rs +++ b/crates/oxc_isolated_declarations/src/lib.rs @@ -24,7 +24,7 @@ use std::{cell::RefCell, mem}; use diagnostics::function_with_assigning_properties; use oxc_allocator::{Allocator, CloneIn}; #[allow(clippy::wildcard_imports)] -use oxc_ast::{ast::*, AstBuilder, Trivias, Visit, NONE}; +use oxc_ast::{ast::*, AstBuilder, Visit, NONE}; use oxc_diagnostics::OxcDiagnostic; use oxc_span::{Atom, GetSpan, SourceType, SPAN}; use rustc_hash::{FxHashMap, FxHashSet}; @@ -65,21 +65,12 @@ pub struct IsolatedDeclarations<'a> { } impl<'a> IsolatedDeclarations<'a> { - pub fn new( - allocator: &'a Allocator, - source_text: &str, - trivias: &Trivias, - options: IsolatedDeclarationsOptions, - ) -> Self { + pub fn new(allocator: &'a Allocator, options: IsolatedDeclarationsOptions) -> Self { let strip_internal = options.strip_internal; - let is_internal_set = strip_internal - .then(|| Self::build_internal_annotations(source_text, trivias)) - .unwrap_or_default(); - Self { ast: AstBuilder::new(allocator), strip_internal, - internal_annotations: is_internal_set, + internal_annotations: FxHashSet::default(), scope: ScopeTree::new(allocator), errors: RefCell::new(vec![]), } @@ -89,6 +80,10 @@ impl<'a> IsolatedDeclarations<'a> { /// /// Returns `Vec` if any errors were collected during the transformation. pub fn build(mut self, program: &Program<'a>) -> IsolatedDeclarationsReturn<'a> { + self.internal_annotations = self + .strip_internal + .then(|| Self::build_internal_annotations(program)) + .unwrap_or_default(); let source_type = SourceType::d_ts(); let directives = self.ast.vec(); let stmts = self.transform_program(program); @@ -114,10 +109,10 @@ impl<'a> IsolatedDeclarations<'a> { } /// Build the lookup table for jsdoc `@internal`. - fn build_internal_annotations(source_text: &str, trivias: &Trivias) -> FxHashSet { + fn build_internal_annotations(program: &Program<'a>) -> FxHashSet { let mut set = FxHashSet::default(); - for comment in trivias.comments() { - let has_internal = comment.span.source_text(source_text).contains("@internal"); + for comment in &program.comments { + let has_internal = comment.span.source_text(program.source_text).contains("@internal"); // Use the first jsdoc comment if there are multiple jsdoc comments for the same node. if has_internal && !set.contains(&comment.attached_to) { set.insert(comment.attached_to); diff --git a/crates/oxc_isolated_declarations/tests/deno/mod.rs b/crates/oxc_isolated_declarations/tests/deno/mod.rs index d9ca61aecdb9d..b320b6738032c 100644 --- a/crates/oxc_isolated_declarations/tests/deno/mod.rs +++ b/crates/oxc_isolated_declarations/tests/deno/mod.rs @@ -15,8 +15,6 @@ mod tests { let ret = Parser::new(&allocator, source, source_type).parse(); let ret = IsolatedDeclarations::new( &allocator, - source, - &ret.trivias, IsolatedDeclarationsOptions { strip_internal: true }, ) .build(&ret.program); diff --git a/crates/oxc_isolated_declarations/tests/mod.rs b/crates/oxc_isolated_declarations/tests/mod.rs index e67169764e6d2..dc0f18e6ca9e7 100644 --- a/crates/oxc_isolated_declarations/tests/mod.rs +++ b/crates/oxc_isolated_declarations/tests/mod.rs @@ -13,19 +13,11 @@ fn transform(path: &Path, source_text: &str) -> String { let source_type = SourceType::from_path(path).unwrap(); let parser_ret = Parser::new(&allocator, source_text, source_type).parse(); - let id_ret = IsolatedDeclarations::new( - &allocator, - source_text, - &parser_ret.trivias, - IsolatedDeclarationsOptions { strip_internal: true }, - ) - .build(&parser_ret.program); + let id_ret = + IsolatedDeclarations::new(&allocator, IsolatedDeclarationsOptions { strip_internal: true }) + .build(&parser_ret.program); let code = CodeGenerator::new() - .enable_comment( - source_text, - parser_ret.trivias, - CommentOptions { preserve_annotate_comments: false }, - ) + .enable_comment(&parser_ret.program, CommentOptions { preserve_annotate_comments: false }) .build(&id_ret.program) .code; diff --git a/crates/oxc_language_server/src/linter.rs b/crates/oxc_language_server/src/linter.rs index 6bc98d6b1c3f1..0191a26cf1640 100644 --- a/crates/oxc_language_server/src/linter.rs +++ b/crates/oxc_language_server/src/linter.rs @@ -260,11 +260,8 @@ impl IsolatedLintHandler { }; let program = allocator.alloc(ret.program); - let semantic_ret = SemanticBuilder::new() - .with_cfg(true) - .with_trivias(ret.trivias) - .with_check_syntax_error(true) - .build(program); + let semantic_ret = + SemanticBuilder::new().with_cfg(true).with_check_syntax_error(true).build(program); if !semantic_ret.errors.is_empty() { let reports = semantic_ret @@ -278,7 +275,9 @@ impl IsolatedLintHandler { return Some(Self::wrap_diagnostics(path, &source_text, reports, start)); }; - let result = self.linter.run(path, Rc::new(semantic_ret.semantic)); + let mut semantic = semantic_ret.semantic; + semantic.set_irregular_whitespaces(ret.irregular_whitespaces); + let result = self.linter.run(path, Rc::new(semantic)); let reports = result .into_iter() diff --git a/crates/oxc_linter/examples/linter.rs b/crates/oxc_linter/examples/linter.rs index c93dbef31ac13..a2522866781ab 100644 --- a/crates/oxc_linter/examples/linter.rs +++ b/crates/oxc_linter/examples/linter.rs @@ -30,7 +30,7 @@ fn main() -> std::io::Result<()> { } let program = allocator.alloc(ret.program); - let semantic_ret = SemanticBuilder::new().with_trivias(ret.trivias).build(program); + let semantic_ret = SemanticBuilder::new().build(program); let mut errors: Vec = vec![]; diff --git a/crates/oxc_linter/src/context/host.rs b/crates/oxc_linter/src/context/host.rs index ceca3b8968211..f285ce5e60b7e 100644 --- a/crates/oxc_linter/src/context/host.rs +++ b/crates/oxc_linter/src/context/host.rs @@ -79,8 +79,7 @@ impl<'a> ContextHost<'a> { ); let disable_directives = - DisableDirectivesBuilder::new(semantic.source_text(), semantic.trivias().clone()) - .build(); + DisableDirectivesBuilder::new().build(semantic.source_text(), semantic.comments()); let file_path = file_path.as_ref().to_path_buf().into_boxed_path(); diff --git a/crates/oxc_linter/src/disable_directives.rs b/crates/oxc_linter/src/disable_directives.rs index eada7a89aceb7..812229f1919b6 100644 --- a/crates/oxc_linter/src/disable_directives.rs +++ b/crates/oxc_linter/src/disable_directives.rs @@ -1,4 +1,4 @@ -use oxc_ast::Trivias; +use oxc_ast::Comment; use oxc_span::Span; use rust_lapper::{Interval, Lapper}; use rustc_hash::FxHashMap; @@ -48,8 +48,6 @@ impl<'a> DisableDirectives<'a> { } pub struct DisableDirectivesBuilder<'a> { - source_text: &'a str, - trivias: Trivias, /// All the disabled rules with their corresponding covering spans intervals: Lapper>, /// Start of `eslint-disable` or `oxlint-disable` @@ -63,10 +61,8 @@ pub struct DisableDirectivesBuilder<'a> { } impl<'a> DisableDirectivesBuilder<'a> { - pub fn new(source_text: &'a str, trivias: Trivias) -> Self { + pub fn new() -> Self { Self { - source_text, - trivias, intervals: Lapper::new(vec![]), disable_all_start: None, disable_start_map: FxHashMap::default(), @@ -75,8 +71,8 @@ impl<'a> DisableDirectivesBuilder<'a> { } } - pub fn build(mut self) -> DisableDirectives<'a> { - self.build_impl(); + pub fn build(mut self, source_text: &'a str, comments: &[Comment]) -> DisableDirectives<'a> { + self.build_impl(source_text, comments); DisableDirectives { intervals: self.intervals, disable_all_comments: self.disable_all_comments.into_boxed_slice(), @@ -89,13 +85,13 @@ impl<'a> DisableDirectivesBuilder<'a> { } #[allow(clippy::cast_possible_truncation)] // for `as u32` - fn build_impl(&mut self) { - let source_len = self.source_text.len() as u32; + fn build_impl(&mut self, source_text: &'a str, comments: &[Comment]) { + let source_len = source_text.len() as u32; // This algorithm iterates through the comments and builds all intervals // for matching disable and enable pairs. // Wrongly ordered matching pairs are not taken into consideration. - for comment in self.trivias.clone().comments() { - let text = comment.span.source_text(self.source_text); + for comment in comments { + let text = comment.span.source_text(source_text); let text = text.trim_start(); if let Some(text) = @@ -112,7 +108,7 @@ impl<'a> DisableDirectivesBuilder<'a> { // `eslint-disable-next-line` else if let Some(text) = text.strip_prefix("-next-line") { // Get the span up to the next new line - let stop = self.source_text[comment.span.end as usize..] + let stop = source_text[comment.span.end as usize..] .lines() .take(2) .fold(comment.span.end, |acc, line| acc + line.len() as u32); @@ -138,7 +134,7 @@ impl<'a> DisableDirectivesBuilder<'a> { // `eslint-disable-line` else if let Some(text) = text.strip_prefix("-line") { // Get the span between the preceding newline to this comment - let start = self.source_text[..=comment.span.start as usize] + let start = source_text[..=comment.span.start as usize] .lines() .next_back() .map_or(0, |line| comment.span.start - (line.len() as u32 - 1)); @@ -369,7 +365,7 @@ fn test() { debugger; debugger; /*{prefix}-disable-line*/ - + debugger; //{prefix}-disable-line no-debugger //{prefix}-disable-next-line no-debugger @@ -393,7 +389,7 @@ fn test() { debugger; debugger; /* {prefix}-disable-line */ - + debugger; // {prefix}-disable-line no-debugger // {prefix}-disable-next-line no-debugger @@ -597,15 +593,15 @@ semi*/ " ), format!( - "debugger; // \t\t {prefix}-disable-line \t\t no-alert, \t\t quotes, \t\t semi \t\t + "debugger; // \t\t {prefix}-disable-line \t\t no-alert, \t\t quotes, \t\t semi \t\t // \t\t {prefix}-disable-next-line \t\t no-alert, \t\t quotes, \t\t semi debugger; debugger; /* \t\t {prefix}-disable-line \t\t no-alert, \t\t quotes, \t\t semi \t\t */ /* \t\t {prefix}-disable-next-line \t\t no-alert, \t\t quotes, \t\t semi */ debugger; /* \t\t {prefix}-disable-next-line - \t\t no-alert, \t\t - \t\t quotes, \t\t + \t\t no-alert, \t\t + \t\t quotes, \t\t \t\t semi \t\t */ debugger; " diff --git a/crates/oxc_linter/src/rules/eslint/default_case.rs b/crates/oxc_linter/src/rules/eslint/default_case.rs index e3e329dcf1929..59977313b665b 100644 --- a/crates/oxc_linter/src/rules/eslint/default_case.rs +++ b/crates/oxc_linter/src/rules/eslint/default_case.rs @@ -76,7 +76,6 @@ impl Rule for DefaultCase { let has_default_comment = ctx .semantic() - .trivias() .comments_range(last_case.span.start..switch.span.end) .last() .is_some_and(|comment| { diff --git a/crates/oxc_linter/src/rules/eslint/max_lines.rs b/crates/oxc_linter/src/rules/eslint/max_lines.rs index 1f6a3955b0d44..2311b346a411b 100644 --- a/crates/oxc_linter/src/rules/eslint/max_lines.rs +++ b/crates/oxc_linter/src/rules/eslint/max_lines.rs @@ -82,7 +82,7 @@ impl Rule for MaxLines { fn run_once(&self, ctx: &LintContext) { let comment_lines = if self.skip_comments { let mut comment_lines: usize = 0; - for comment in ctx.semantic().trivias().comments() { + for comment in ctx.semantic().comments() { if comment.is_line() { let comment_line = ctx.source_text()[..comment.span.start as usize] .lines() diff --git a/crates/oxc_linter/src/rules/eslint/no_empty.rs b/crates/oxc_linter/src/rules/eslint/no_empty.rs index 4949672d74907..5ee42bec6415b 100644 --- a/crates/oxc_linter/src/rules/eslint/no_empty.rs +++ b/crates/oxc_linter/src/rules/eslint/no_empty.rs @@ -54,7 +54,7 @@ impl Rule for NoEmpty { return; } - if ctx.semantic().trivias().has_comments_between(block.span) { + if ctx.semantic().has_comments_between(block.span) { return; } ctx.diagnostic_with_suggestion(no_empty_diagnostic("block", block.span), |fixer| { @@ -72,7 +72,7 @@ impl Rule for NoEmpty { // The visitor does not visit the `BlockStatement` inside the `FinallyClause`. // See `Visit::visit_finally_clause`. AstKind::FinallyClause(finally_clause) if finally_clause.body.is_empty() => { - if ctx.semantic().trivias().has_comments_between(finally_clause.span) { + if ctx.semantic().has_comments_between(finally_clause.span) { return; } ctx.diagnostic_with_suggestion( diff --git a/crates/oxc_linter/src/rules/eslint/no_empty_function.rs b/crates/oxc_linter/src/rules/eslint/no_empty_function.rs index 2eea58efe2b74..2a50b77550c81 100644 --- a/crates/oxc_linter/src/rules/eslint/no_empty_function.rs +++ b/crates/oxc_linter/src/rules/eslint/no_empty_function.rs @@ -65,7 +65,7 @@ impl Rule for NoEmptyFunction { let AstKind::FunctionBody(fb) = node.kind() else { return; }; - if fb.is_empty() && !ctx.semantic().trivias().has_comments_between(fb.span) { + if fb.is_empty() && !ctx.semantic().has_comments_between(fb.span) { let (kind, fn_name) = get_function_name_and_kind(node, ctx); ctx.diagnostic(no_empty_function_diagnostic(fb.span, kind, fn_name)); } diff --git a/crates/oxc_linter/src/rules/eslint/no_empty_static_block.rs b/crates/oxc_linter/src/rules/eslint/no_empty_static_block.rs index 2ac6e0d24d6fd..24de7dc61d01a 100644 --- a/crates/oxc_linter/src/rules/eslint/no_empty_static_block.rs +++ b/crates/oxc_linter/src/rules/eslint/no_empty_static_block.rs @@ -55,7 +55,7 @@ impl Rule for NoEmptyStaticBlock { fn run<'a>(&self, node: &AstNode<'a>, ctx: &LintContext<'a>) { if let AstKind::StaticBlock(static_block) = node.kind() { if static_block.body.is_empty() { - if ctx.semantic().trivias().has_comments_between(static_block.span) { + if ctx.semantic().has_comments_between(static_block.span) { return; } ctx.diagnostic(no_empty_static_block_diagnostic(static_block.span)); diff --git a/crates/oxc_linter/src/rules/eslint/no_fallthrough.rs b/crates/oxc_linter/src/rules/eslint/no_fallthrough.rs index 8fce6e0fdd48a..4476fe38b9711 100644 --- a/crates/oxc_linter/src/rules/eslint/no_fallthrough.rs +++ b/crates/oxc_linter/src/rules/eslint/no_fallthrough.rs @@ -381,7 +381,6 @@ impl NoFallthrough { let semantic = ctx.semantic(); let is_fallthrough_comment_in_range = |range: Range| { let comment = semantic - .trivias() .comments_range(range) .map(|comment| { &semantic.source_text()[comment.span.start as usize..comment.span.end as usize] diff --git a/crates/oxc_linter/src/rules/eslint/no_irregular_whitespace.rs b/crates/oxc_linter/src/rules/eslint/no_irregular_whitespace.rs index 7a32b33668fd5..5729c450ec1cb 100644 --- a/crates/oxc_linter/src/rules/eslint/no_irregular_whitespace.rs +++ b/crates/oxc_linter/src/rules/eslint/no_irregular_whitespace.rs @@ -33,7 +33,7 @@ declare_oxc_lint!( impl Rule for NoIrregularWhitespace { fn run_once(&self, ctx: &LintContext) { - let irregular_whitespaces = ctx.semantic().trivias().irregular_whitespaces(); + let irregular_whitespaces = ctx.semantic().irregular_whitespaces(); for irregular_whitespace in irregular_whitespaces { ctx.diagnostic(no_irregular_whitespace_diagnostic(*irregular_whitespace)); } diff --git a/crates/oxc_linter/src/rules/eslint/sort_imports.rs b/crates/oxc_linter/src/rules/eslint/sort_imports.rs index b5473af98bb80..7e8b4408f19bb 100644 --- a/crates/oxc_linter/src/rules/eslint/sort_imports.rs +++ b/crates/oxc_linter/src/rules/eslint/sort_imports.rs @@ -302,7 +302,7 @@ impl SortImports { // import { /* comment */ a, b, c, d } from 'foo.js' // ``` // I use ImportStatement's span to check if there are comments between the specifiers. - let is_fixable = !ctx.semantic().trivias().has_comments_between(current.span); + let is_fixable = !ctx.semantic().has_comments_between(current.span); if is_fixable { // Safe to index because we know that `specifiers` is at least 2 element long diff --git a/crates/oxc_linter/src/rules/jest/no_commented_out_tests.rs b/crates/oxc_linter/src/rules/jest/no_commented_out_tests.rs index d4552c1ea7dee..089b017666a4e 100644 --- a/crates/oxc_linter/src/rules/jest/no_commented_out_tests.rs +++ b/crates/oxc_linter/src/rules/jest/no_commented_out_tests.rs @@ -59,9 +59,9 @@ impl Rule for NoCommentedOutTests { static ref RE: Regex = Regex::new(r#"(?mu)^\s*[xf]?(test|it|describe)(\.\w+|\[['"]\w+['"]\])?\s*\("#).unwrap(); } - let comments = ctx.semantic().trivias().comments(); + let comments = ctx.semantic().comments(); let source_text = ctx.semantic().source_text(); - let commented_tests = comments.filter_map(|comment| { + let commented_tests = comments.iter().filter_map(|comment| { let text = comment.span.source_text(source_text); if RE.is_match(text) { Some(comment.span) diff --git a/crates/oxc_linter/src/rules/typescript/ban_ts_comment.rs b/crates/oxc_linter/src/rules/typescript/ban_ts_comment.rs index 8bfc9b8c918e8..cafcf4514b6c8 100644 --- a/crates/oxc_linter/src/rules/typescript/ban_ts_comment.rs +++ b/crates/oxc_linter/src/rules/typescript/ban_ts_comment.rs @@ -155,7 +155,7 @@ impl Rule for BanTsComment { } fn run_once(&self, ctx: &LintContext) { - let comments = ctx.semantic().trivias().comments(); + let comments = ctx.semantic().comments(); for comm in comments { let raw = ctx.source_range(comm.span); if let Some(captures) = find_ts_comment_directive(raw, comm.is_line()) { diff --git a/crates/oxc_linter/src/rules/typescript/ban_tslint_comment.rs b/crates/oxc_linter/src/rules/typescript/ban_tslint_comment.rs index be50f9de759e4..6f3a08da1d2d3 100644 --- a/crates/oxc_linter/src/rules/typescript/ban_tslint_comment.rs +++ b/crates/oxc_linter/src/rules/typescript/ban_tslint_comment.rs @@ -33,7 +33,7 @@ declare_oxc_lint!( impl Rule for BanTslintComment { fn run_once(&self, ctx: &LintContext) { - let comments = ctx.semantic().trivias().comments(); + let comments = ctx.semantic().comments(); let source_text_len = ctx.semantic().source_text().len(); for comment in comments { diff --git a/crates/oxc_linter/src/rules/typescript/prefer_function_type.rs b/crates/oxc_linter/src/rules/typescript/prefer_function_type.rs index d5ef6a106a2d1..82ad8493ab6bd 100644 --- a/crates/oxc_linter/src/rules/typescript/prefer_function_type.rs +++ b/crates/oxc_linter/src/rules/typescript/prefer_function_type.rs @@ -159,15 +159,12 @@ fn check_member(member: &TSSignature, node: &AstNode<'_>, ctx: &LintContext<'_>) } } - let has_comments = ctx - .semantic() - .trivias() - .has_comments_between(interface_decl.span); + let has_comments = + ctx.semantic().has_comments_between(interface_decl.span); if has_comments { let comments = ctx .semantic() - .trivias() .comments_range(node_start..node_end) .map(|comment| (*comment, comment.span)); diff --git a/crates/oxc_linter/src/rules/typescript/prefer_ts_expect_error.rs b/crates/oxc_linter/src/rules/typescript/prefer_ts_expect_error.rs index 0eb26802eefa1..d0a138798b47a 100644 --- a/crates/oxc_linter/src/rules/typescript/prefer_ts_expect_error.rs +++ b/crates/oxc_linter/src/rules/typescript/prefer_ts_expect_error.rs @@ -48,7 +48,7 @@ declare_oxc_lint!( impl Rule for PreferTsExpectError { fn run_once(&self, ctx: &LintContext) { - let comments = ctx.semantic().trivias().comments(); + let comments = ctx.semantic().comments(); for comment in comments { let raw = comment.span.source_text(ctx.semantic().source_text()); diff --git a/crates/oxc_linter/src/rules/typescript/triple_slash_reference.rs b/crates/oxc_linter/src/rules/typescript/triple_slash_reference.rs index 509bd9217a75e..2adab5bcb3f99 100644 --- a/crates/oxc_linter/src/rules/typescript/triple_slash_reference.rs +++ b/crates/oxc_linter/src/rules/typescript/triple_slash_reference.rs @@ -114,7 +114,7 @@ impl Rule for TripleSlashReference { let comments_range_end = program.body.first().map_or(program.span.end, |v| v.span().start); let mut refs_for_import = FxHashMap::default(); - for comment in ctx.semantic().trivias().comments_range(0..comments_range_end) { + for comment in ctx.semantic().comments_range(0..comments_range_end) { let raw = &ctx.semantic().source_text() [comment.span.start as usize..comment.span.end as usize]; if let Some((group1, group2)) = get_attr_key_and_value(raw) { diff --git a/crates/oxc_linter/src/rules/unicorn/empty_brace_spaces.rs b/crates/oxc_linter/src/rules/unicorn/empty_brace_spaces.rs index bc8dafdf9ae6e..17f867bd3ae0b 100644 --- a/crates/oxc_linter/src/rules/unicorn/empty_brace_spaces.rs +++ b/crates/oxc_linter/src/rules/unicorn/empty_brace_spaces.rs @@ -43,7 +43,7 @@ impl Rule for EmptyBraceSpaces { if static_block.body.is_empty() && end - start > static_leading_count + 2 - && !ctx.semantic().trivias().has_comments_between(static_block.span) + && !ctx.semantic().has_comments_between(static_block.span) { ctx.diagnostic_with_fix( empty_brace_spaces_diagnostic(static_block.span), @@ -79,7 +79,7 @@ fn remove_empty_braces_spaces(ctx: &LintContext, is_empty_body: bool, span: Span let start = span.start; let end = span.end; - if is_empty_body && end - start > 2 && !ctx.semantic().trivias().has_comments_between(span) { + if is_empty_body && end - start > 2 && !ctx.semantic().has_comments_between(span) { // length of "{}" ctx.diagnostic_with_fix(empty_brace_spaces_diagnostic(span), |fixer| { fixer.replace(span, "{}") diff --git a/crates/oxc_linter/src/rules/unicorn/no_empty_file.rs b/crates/oxc_linter/src/rules/unicorn/no_empty_file.rs index dc928bf8dbc2a..37732d5cfc59c 100644 --- a/crates/oxc_linter/src/rules/unicorn/no_empty_file.rs +++ b/crates/oxc_linter/src/rules/unicorn/no_empty_file.rs @@ -69,7 +69,7 @@ impl Rule for NoEmptyFile { } fn has_triple_slash_directive(ctx: &LintContext<'_>) -> bool { - for comment in ctx.semantic().trivias().comments() { + for comment in ctx.semantic().comments() { if !comment.is_line() { continue; } diff --git a/crates/oxc_linter/src/rules/unicorn/no_magic_array_flat_depth.rs b/crates/oxc_linter/src/rules/unicorn/no_magic_array_flat_depth.rs index 33f08fb5ea3a0..eccf93ac98b3b 100644 --- a/crates/oxc_linter/src/rules/unicorn/no_magic_array_flat_depth.rs +++ b/crates/oxc_linter/src/rules/unicorn/no_magic_array_flat_depth.rs @@ -72,12 +72,8 @@ impl Rule for NoMagicArrayFlatDepth { return; }; - let has_explaining_comment = ctx - .semantic() - .trivias() - .comments_range(arguments_span.start..arguments_span.end) - .count() - != 0; + let has_explaining_comment = + ctx.semantic().comments_range(arguments_span.start..arguments_span.end).count() != 0; if has_explaining_comment { return; diff --git a/crates/oxc_linter/src/rules/unicorn/no_useless_undefined.rs b/crates/oxc_linter/src/rules/unicorn/no_useless_undefined.rs index 56a01a718b7ce..c5ea0e8b7f7f6 100644 --- a/crates/oxc_linter/src/rules/unicorn/no_useless_undefined.rs +++ b/crates/oxc_linter/src/rules/unicorn/no_useless_undefined.rs @@ -184,7 +184,6 @@ impl Rule for NoUselessUndefined { |fixer| { let delete_span = if let Some(comment) = ctx .semantic() - .trivias() .comments_range(ret_stmt.span.start..ret_stmt.span.end) .last() { diff --git a/crates/oxc_linter/src/service/runtime.rs b/crates/oxc_linter/src/service/runtime.rs index 1820efb090099..43bcdfb0e1d76 100644 --- a/crates/oxc_linter/src/service/runtime.rs +++ b/crates/oxc_linter/src/service/runtime.rs @@ -202,18 +202,13 @@ impl Runtime { return ret.errors.into_iter().map(|err| Message::new(err, None)).collect(); }; - let program = allocator.alloc(ret.program); - - let trivias = ret.trivias; - // Build the module record to unblock other threads from waiting for too long. // The semantic model is not built at this stage. let semantic_builder = SemanticBuilder::new() .with_cfg(true) - .with_trivias(trivias) .with_build_jsdoc(true) .with_check_syntax_error(check_syntax_errors) - .build_module_record(path, program); + .build_module_record(path, &ret.program); let module_record = semantic_builder.module_record(); if self.resolver.is_some() { @@ -284,13 +279,16 @@ impl Runtime { } } + let program = allocator.alloc(ret.program); let semantic_ret = semantic_builder.build(program); if !semantic_ret.errors.is_empty() { return semantic_ret.errors.into_iter().map(|err| Message::new(err, None)).collect(); }; - self.linter.run(path, Rc::new(semantic_ret.semantic)) + let mut semantic = semantic_ret.semantic; + semantic.set_irregular_whitespaces(ret.irregular_whitespaces); + self.linter.run(path, Rc::new(semantic)) } pub(super) fn init_cache_state(&self, path: &Path) -> bool { diff --git a/crates/oxc_linter/src/utils/tree_shaking.rs b/crates/oxc_linter/src/utils/tree_shaking.rs index 0f6f83dd5f738..0dded6cdf9634 100644 --- a/crates/oxc_linter/src/utils/tree_shaking.rs +++ b/crates/oxc_linter/src/utils/tree_shaking.rs @@ -223,7 +223,7 @@ fn flatten_member_expr_if_possible(function_name: &FunctionName) -> CompactStr { /// /// pub fn has_pure_notation(span: Span, ctx: &LintContext) -> bool { - let Some(comment) = ctx.semantic().trivias().comments_range(..span.start).next_back() else { + let Some(comment) = ctx.semantic().comments_range(..span.start).next_back() else { return false; }; let raw = comment.span.source_text(ctx.semantic().source_text()); @@ -263,7 +263,7 @@ pub fn has_comment_about_side_effect_check(span: Span, ctx: &LintContext) -> boo /// let e = 2 /// ``` pub fn get_leading_tree_shaking_comment<'a>(span: Span, ctx: &LintContext<'a>) -> Option<&'a str> { - let comment = ctx.semantic().trivias().comments_range(..span.start).next_back()?; + let comment = ctx.semantic().comments_range(..span.start).next_back()?; let comment_text = comment.span.source_text(ctx.source_text()); diff --git a/crates/oxc_parser/examples/parser.rs b/crates/oxc_parser/examples/parser.rs index fe3f863988168..7e43ee125c94d 100644 --- a/crates/oxc_parser/examples/parser.rs +++ b/crates/oxc_parser/examples/parser.rs @@ -34,7 +34,7 @@ fn main() -> Result<(), String> { if show_comments { println!("Comments:"); - for comment in ret.trivias.comments() { + for comment in ret.program.comments { let s = comment.real_span().source_text(&source_text); println!("{s}"); } diff --git a/crates/oxc_parser/examples/parser_tsx.rs b/crates/oxc_parser/examples/parser_tsx.rs index 4ba88838e19cb..27507f39422e1 100644 --- a/crates/oxc_parser/examples/parser_tsx.rs +++ b/crates/oxc_parser/examples/parser_tsx.rs @@ -30,11 +30,11 @@ export const Counter: React.FC = () => { program, // AST errors, // Syntax errors panicked, // Parser encountered an error it couldn't recover from - trivias, // Comments, whitespace, etc. + .. } = Parser::new(&allocator, source_text, source_type).parse(); assert!(!panicked); assert!(errors.is_empty()); assert!(!program.body.is_empty()); - assert_eq!(trivias.comments().count(), 1); + assert_eq!(program.comments.len(), 1); } diff --git a/crates/oxc_parser/src/lexer/trivia_builder.rs b/crates/oxc_parser/src/lexer/trivia_builder.rs index acbe2294c88d5..e3449a6fa82c6 100644 --- a/crates/oxc_parser/src/lexer/trivia_builder.rs +++ b/crates/oxc_parser/src/lexer/trivia_builder.rs @@ -1,7 +1,4 @@ -use oxc_ast::{ - ast::{Comment, CommentKind, CommentPosition}, - Trivias, -}; +use oxc_ast::ast::{Comment, CommentKind, CommentPosition}; use oxc_span::Span; use super::{Kind, Token}; @@ -13,7 +10,7 @@ pub struct TriviaBuilder { // filtered out at insertion time. pub(crate) comments: Vec, - irregular_whitespaces: Vec, + pub(crate) irregular_whitespaces: Vec, // states /// index of processed comments @@ -39,10 +36,6 @@ impl Default for TriviaBuilder { } impl TriviaBuilder { - pub fn build(self) -> Trivias { - Trivias::new(self.comments.into_boxed_slice(), self.irregular_whitespaces) - } - pub fn add_irregular_whitespace(&mut self, start: u32, end: u32) { self.irregular_whitespaces.push(Span::new(start, end)); } @@ -122,7 +115,7 @@ mod test { let allocator = Allocator::default(); let source_type = SourceType::default(); let ret = Parser::new(&allocator, source_text, source_type).parse(); - ret.trivias.comments().copied().collect::>() + ret.program.comments.iter().copied().collect::>() } #[test] diff --git a/crates/oxc_parser/src/lib.rs b/crates/oxc_parser/src/lib.rs index ee6d242b9ccb5..fe76fff88538d 100644 --- a/crates/oxc_parser/src/lib.rs +++ b/crates/oxc_parser/src/lib.rs @@ -88,7 +88,7 @@ use context::{Context, StatementContext}; use oxc_allocator::Allocator; use oxc_ast::{ ast::{Expression, Program}, - AstBuilder, Trivias, + AstBuilder, }; use oxc_diagnostics::{OxcDiagnostic, Result}; use oxc_span::{ModuleKind, SourceType, Span}; @@ -156,8 +156,8 @@ pub struct ParserReturn<'a> { /// [`SemanticBuilder::with_check_syntax_error`](https://docs.rs/oxc_semantic/latest/oxc_semantic/struct.SemanticBuilder.html#method.with_check_syntax_error). pub errors: Vec, - /// Comments and whitespace - pub trivias: Trivias, + /// Irregular whitespaces for `Oxlint` + pub irregular_whitespaces: Box<[Span]>, /// Whether the parser panicked and terminated early. /// @@ -425,8 +425,9 @@ impl<'a> ParserImpl<'a> { errors.extend(self.lexer.errors); errors.extend(self.errors); } - let trivias = self.lexer.trivia_builder.build(); - ParserReturn { program, errors, trivias, panicked } + let irregular_whitespaces = + self.lexer.trivia_builder.irregular_whitespaces.into_boxed_slice(); + ParserReturn { program, errors, irregular_whitespaces, panicked } } pub fn parse_expression(mut self) -> std::result::Result, Vec> { @@ -623,7 +624,7 @@ mod test { ]; for (source, kind) in sources { let ret = Parser::new(&allocator, source, source_type).parse(); - let comments = ret.trivias.comments().collect::>(); + let comments = &ret.program.comments; assert_eq!(comments.len(), 1, "{source}"); assert_eq!(comments.first().unwrap().kind, kind, "{source}"); } diff --git a/crates/oxc_prettier/examples/prettier.rs b/crates/oxc_prettier/examples/prettier.rs index 26b849d0756b0..038819de2d6c3 100644 --- a/crates/oxc_prettier/examples/prettier.rs +++ b/crates/oxc_prettier/examples/prettier.rs @@ -28,7 +28,6 @@ fn main() -> std::io::Result<()> { let output = Prettier::new( &allocator, &source_text, - ret.trivias, PrettierOptions { semi, trailing_comma: TrailingComma::All, ..PrettierOptions::default() }, ) .build(&ret.program); diff --git a/crates/oxc_prettier/src/lib.rs b/crates/oxc_prettier/src/lib.rs index aad776e8b775e..5475ecee1b36f 100644 --- a/crates/oxc_prettier/src/lib.rs +++ b/crates/oxc_prettier/src/lib.rs @@ -17,7 +17,7 @@ mod utils; use std::vec; use oxc_allocator::Allocator; -use oxc_ast::{ast::Program, AstKind, Trivias}; +use oxc_ast::{ast::Program, AstKind}; use oxc_span::Span; use oxc_syntax::identifier::is_line_terminator; @@ -54,8 +54,6 @@ pub struct Prettier<'a> { options: PrettierOptions, - trivias: Trivias, - /// The stack of AST Nodes /// See stack: Vec>, @@ -73,17 +71,11 @@ impl<'a> DocBuilder<'a> for Prettier<'a> { impl<'a> Prettier<'a> { #[allow(clippy::needless_pass_by_value)] - pub fn new( - allocator: &'a Allocator, - source_text: &'a str, - trivias: Trivias, - options: PrettierOptions, - ) -> Self { + pub fn new(allocator: &'a Allocator, source_text: &'a str, options: PrettierOptions) -> Self { Self { allocator, source_text, options, - trivias, stack: vec![], group_id_builder: GroupIdBuilder::default(), args: PrettierArgs::default(), diff --git a/crates/oxc_semantic/examples/cfg.rs b/crates/oxc_semantic/examples/cfg.rs index e3a94b4ca3451..c97fc89bfc0e9 100644 --- a/crates/oxc_semantic/examples/cfg.rs +++ b/crates/oxc_semantic/examples/cfg.rs @@ -55,11 +55,8 @@ fn main() -> std::io::Result<()> { std::fs::write(ast_file_path, format!("{:#?}", &program))?; println!("Wrote AST to: {}", &ast_file_name); - let semantic = SemanticBuilder::new() - .with_check_syntax_error(true) - .with_trivias(parser_ret.trivias) - .with_cfg(true) - .build(program); + let semantic = + SemanticBuilder::new().with_check_syntax_error(true).with_cfg(true).build(program); if !semantic.errors.is_empty() { let error_message: String = semantic diff --git a/crates/oxc_semantic/examples/simple.rs b/crates/oxc_semantic/examples/simple.rs index 29609e2a079bd..a8d2a10af0d6c 100644 --- a/crates/oxc_semantic/examples/simple.rs +++ b/crates/oxc_semantic/examples/simple.rs @@ -38,8 +38,6 @@ fn main() -> std::io::Result<()> { .build_module_record(path, program) // Enable additional syntax checks not performed by the parser .with_check_syntax_error(true) - // Inform Semantic about comments found while parsing - .with_trivias(parser_ret.trivias) .build(program); if !semantic.errors.is_empty() { diff --git a/crates/oxc_semantic/src/builder.rs b/crates/oxc_semantic/src/builder.rs index 45aa581730d40..000e1a34c92db 100644 --- a/crates/oxc_semantic/src/builder.rs +++ b/crates/oxc_semantic/src/builder.rs @@ -9,7 +9,7 @@ use std::{ use rustc_hash::FxHashMap; #[allow(clippy::wildcard_imports)] -use oxc_ast::{ast::*, AstKind, Trivias, Visit}; +use oxc_ast::{ast::*, AstKind, Visit}; use oxc_cfg::{ ControlFlowGraphBuilder, CtxCursor, CtxFlags, EdgeType, ErrorEdgeKind, IterationInstructionKind, ReturnInstructionKind, @@ -66,8 +66,6 @@ pub struct SemanticBuilder<'a> { /// source type of the parsed program pub(crate) source_type: SourceType, - trivias: Trivias, - /// Semantic early errors such as redeclaration errors. errors: RefCell>, @@ -130,11 +128,9 @@ impl<'a> SemanticBuilder<'a> { let scope = ScopeTree::default(); let current_scope_id = scope.root_scope_id(); - let trivias = Trivias::default(); Self { source_text: "", source_type: SourceType::default(), - trivias: trivias.clone(), errors: RefCell::new(vec![]), current_node_id: NodeId::new(0), current_node_flags: NodeFlags::empty(), @@ -161,12 +157,6 @@ impl<'a> SemanticBuilder<'a> { } } - #[must_use] - pub fn with_trivias(mut self, trivias: Trivias) -> Self { - self.trivias = trivias; - self - } - /// Enable/disable additional syntax checks. /// /// Set this to `true` to enable additional syntax checks. Without these, @@ -181,7 +171,6 @@ impl<'a> SemanticBuilder<'a> { } /// Enable/disable JSDoc parsing. - /// `with_trivias` must be called prior to this call. #[must_use] pub fn with_build_jsdoc(mut self, yes: bool) -> Self { self.build_jsdoc = yes; @@ -260,7 +249,7 @@ impl<'a> SemanticBuilder<'a> { self.source_text = program.source_text; self.source_type = program.source_type; if self.build_jsdoc { - self.jsdoc = JSDocBuilder::new(self.source_text, &self.trivias); + self.jsdoc = JSDocBuilder::new(self.source_text, &program.comments); } if self.source_type.is_typescript_definition() { let scope_id = self.scope.add_scope(None, NodeId::DUMMY, ScopeFlags::Top); @@ -311,6 +300,8 @@ impl<'a> SemanticBuilder<'a> { } } + let comments = self.alloc(&program.comments); + debug_assert_eq!(self.unresolved_references.scope_depth(), 1); self.scope.root_unresolved_references = self .unresolved_references @@ -324,7 +315,8 @@ impl<'a> SemanticBuilder<'a> { let semantic = Semantic { source_text: self.source_text, source_type: self.source_type, - trivias: self.trivias, + comments, + irregular_whitespaces: [].into(), nodes: self.nodes, scopes: self.scope, symbols: self.symbols, diff --git a/crates/oxc_semantic/src/jsdoc/builder.rs b/crates/oxc_semantic/src/jsdoc/builder.rs index 3f655d47daa85..f7cbcc7cbae0e 100644 --- a/crates/oxc_semantic/src/jsdoc/builder.rs +++ b/crates/oxc_semantic/src/jsdoc/builder.rs @@ -1,6 +1,6 @@ use rustc_hash::FxHashMap; -use oxc_ast::{ast::Comment, AstKind, Trivias}; +use oxc_ast::{ast::Comment, AstKind}; use oxc_span::{GetSpan, Span}; use crate::jsdoc::JSDocFinder; @@ -14,9 +14,9 @@ pub struct JSDocBuilder<'a> { } impl<'a> JSDocBuilder<'a> { - pub fn new(source_text: &'a str, trivias: &Trivias) -> Self { + pub fn new(source_text: &'a str, comments: &[Comment]) -> Self { let mut not_attached_docs: FxHashMap> = FxHashMap::default(); - for comment in trivias.comments().filter(|comment| comment.is_jsdoc(source_text)) { + for comment in comments.iter().filter(|comment| comment.is_jsdoc(source_text)) { not_attached_docs .entry(comment.attached_to) .or_default() @@ -208,11 +208,7 @@ mod test { let source_type = source_type.unwrap_or_default(); let ret = Parser::new(allocator, source_text, source_type).parse(); let program = allocator.alloc(ret.program); - let semantic = SemanticBuilder::new() - .with_trivias(ret.trivias) - .with_build_jsdoc(true) - .build(program) - .semantic; + let semantic = SemanticBuilder::new().with_build_jsdoc(true).build(program).semantic; semantic } diff --git a/crates/oxc_semantic/src/jsdoc/parser/jsdoc.rs b/crates/oxc_semantic/src/jsdoc/parser/jsdoc.rs index ddd8d3c757e55..d10bb473c00fb 100644 --- a/crates/oxc_semantic/src/jsdoc/parser/jsdoc.rs +++ b/crates/oxc_semantic/src/jsdoc/parser/jsdoc.rs @@ -46,11 +46,7 @@ mod test { let source_type = SourceType::default(); let ret = Parser::new(allocator, source_text, source_type).parse(); let program = allocator.alloc(ret.program); - let semantic = SemanticBuilder::new() - .with_trivias(ret.trivias) - .with_build_jsdoc(true) - .build(program) - .semantic; + let semantic = SemanticBuilder::new().with_build_jsdoc(true).build(program).semantic; semantic } diff --git a/crates/oxc_semantic/src/jsdoc/parser/jsdoc_tag.rs b/crates/oxc_semantic/src/jsdoc/parser/jsdoc_tag.rs index de79328e0a4ca..2567f4f42f662 100644 --- a/crates/oxc_semantic/src/jsdoc/parser/jsdoc_tag.rs +++ b/crates/oxc_semantic/src/jsdoc/parser/jsdoc_tag.rs @@ -195,11 +195,7 @@ mod test { let source_type = SourceType::default(); let ret = Parser::new(allocator, source_text, source_type).parse(); let program = allocator.alloc(ret.program); - let semantic = SemanticBuilder::new() - .with_trivias(ret.trivias) - .with_build_jsdoc(true) - .build(program) - .semantic; + let semantic = SemanticBuilder::new().with_build_jsdoc(true).build(program).semantic; semantic } diff --git a/crates/oxc_semantic/src/lib.rs b/crates/oxc_semantic/src/lib.rs index 65db5557fb02b..54bd7ebae3f88 100644 --- a/crates/oxc_semantic/src/lib.rs +++ b/crates/oxc_semantic/src/lib.rs @@ -5,9 +5,12 @@ #![doc = include_str!("../examples/simple.rs")] //! ``` +use std::ops::RangeBounds; use std::sync::Arc; -use oxc_ast::{ast::IdentifierReference, AstKind, Trivias}; +use oxc_ast::{ + ast::IdentifierReference, comments_range, has_comments_between, AstKind, Comment, CommentsRange, +}; use oxc_cfg::ControlFlowGraph; use oxc_span::{GetSpan, SourceType, Span}; pub use oxc_syntax::{ @@ -76,7 +79,8 @@ pub struct Semantic<'a> { classes: ClassTable, /// Parsed comments. - trivias: Trivias, + comments: &'a oxc_allocator::Vec<'a, Comment>, + irregular_whitespaces: Box<[Span]>, module_record: Arc, @@ -127,9 +131,28 @@ impl<'a> Semantic<'a> { &mut self.scopes } + pub fn set_irregular_whitespaces(&mut self, irregular_whitespaces: Box<[Span]>) { + self.irregular_whitespaces = irregular_whitespaces; + } + /// Trivias (comments) found while parsing - pub fn trivias(&self) -> &Trivias { - &self.trivias + pub fn comments(&self) -> &[Comment] { + self.comments + } + + pub fn comments_range(&self, range: R) -> CommentsRange<'_> + where + R: RangeBounds, + { + comments_range(self.comments, range) + } + + pub fn has_comments_between(&self, span: Span) -> bool { + has_comments_between(self.comments, span) + } + + pub fn irregular_whitespaces(&self) -> &[Span] { + &self.irregular_whitespaces } /// Parsed [`JSDoc`] comments. diff --git a/crates/oxc_semantic/tests/integration/util/mod.rs b/crates/oxc_semantic/tests/integration/util/mod.rs index 505739d46f3f2..77e9e50253872 100644 --- a/crates/oxc_semantic/tests/integration/util/mod.rs +++ b/crates/oxc_semantic/tests/integration/util/mod.rs @@ -169,7 +169,6 @@ impl<'a> SemanticTester<'a> { let program = self.allocator.alloc(parse.program); SemanticBuilder::new() .with_check_syntax_error(true) - .with_trivias(parse.trivias) .with_cfg(self.cfg) .with_scope_tree_child_ids(self.scope_tree_child_ids) .build(program) diff --git a/crates/oxc_transformer/examples/transformer.rs b/crates/oxc_transformer/examples/transformer.rs index a99222b468304..b851b6890561a 100644 --- a/crates/oxc_transformer/examples/transformer.rs +++ b/crates/oxc_transformer/examples/transformer.rs @@ -38,7 +38,6 @@ fn main() { println!("{source_text}\n"); let mut program = ret.program; - let trivias = ret.trivias; let ret = SemanticBuilder::new() // Estimate transformer will triple scopes, symbols, references @@ -65,8 +64,11 @@ fn main() { TransformOptions::enable_all() }; - let ret = Transformer::new(&allocator, path, trivias.clone(), transform_options) - .build_with_symbols_and_scopes(symbols, scopes, &mut program); + let ret = Transformer::new(&allocator, path, transform_options).build_with_symbols_and_scopes( + symbols, + scopes, + &mut program, + ); if !ret.errors.is_empty() { println!("Transformer Errors:"); diff --git a/crates/oxc_transformer/src/context.rs b/crates/oxc_transformer/src/context.rs index aba1ec3c57b13..6a90318f1d2f9 100644 --- a/crates/oxc_transformer/src/context.rs +++ b/crates/oxc_transformer/src/context.rs @@ -4,7 +4,6 @@ use std::{ path::{Path, PathBuf}, }; -use oxc_ast::Trivias; use oxc_diagnostics::OxcDiagnostic; use oxc_span::SourceType; @@ -19,8 +18,6 @@ use crate::{ pub struct TransformCtx<'a> { errors: RefCell>, - pub trivias: Trivias, - /// pub filename: String, @@ -41,7 +38,7 @@ pub struct TransformCtx<'a> { } impl<'a> TransformCtx<'a> { - pub fn new(source_path: &Path, trivias: Trivias, options: &TransformOptions) -> Self { + pub fn new(source_path: &Path, options: &TransformOptions) -> Self { let filename = source_path .file_stem() // omit file extension .map_or_else(|| String::from("unknown"), |name| name.to_string_lossy().to_string()); @@ -56,7 +53,6 @@ impl<'a> TransformCtx<'a> { source_path, source_type: SourceType::default(), source_text: "", - trivias, module_imports: ModuleImportsStore::new(), var_declarations: VarDeclarationsStore::new(), top_level_statements: TopLevelStatementsStore::new(), diff --git a/crates/oxc_transformer/src/lib.rs b/crates/oxc_transformer/src/lib.rs index ea92aa0d89628..5e94ac6226a42 100644 --- a/crates/oxc_transformer/src/lib.rs +++ b/crates/oxc_transformer/src/lib.rs @@ -38,7 +38,7 @@ use es2019::ES2019; use es2020::ES2020; use es2021::ES2021; use oxc_allocator::{Allocator, Vec}; -use oxc_ast::{ast::*, Trivias}; +use oxc_ast::ast::*; use oxc_diagnostics::OxcDiagnostic; use oxc_semantic::{ScopeTree, SymbolTable}; use oxc_span::SPAN; @@ -69,13 +69,8 @@ pub struct Transformer<'a> { } impl<'a> Transformer<'a> { - pub fn new( - allocator: &'a Allocator, - source_path: &Path, - trivias: Trivias, - options: TransformOptions, - ) -> Self { - let ctx = TransformCtx::new(source_path, trivias, &options); + pub fn new(allocator: &'a Allocator, source_path: &Path, options: TransformOptions) -> Self { + let ctx = TransformCtx::new(source_path, &options); Self { ctx, options, allocator } } @@ -90,7 +85,7 @@ impl<'a> Transformer<'a> { self.ctx.source_type = program.source_type; self.ctx.source_text = program.source_text; - react::update_options_with_comments(&mut self.options, &self.ctx); + react::update_options_with_comments(&program.comments, &mut self.options, &self.ctx); let mut transformer = TransformerImpl { x0_typescript: TypeScript::new(&self.options.typescript, &self.ctx), diff --git a/crates/oxc_transformer/src/react/comments.rs b/crates/oxc_transformer/src/react/comments.rs index 0470ba2cc97fd..6212c73394782 100644 --- a/crates/oxc_transformer/src/react/comments.rs +++ b/crates/oxc_transformer/src/react/comments.rs @@ -16,8 +16,12 @@ use crate::{JsxRuntime, TransformCtx, TransformOptions}; /// otherwise `JSDoc` could be used instead. /// /// This behavior is aligned with Babel. -pub(crate) fn update_options_with_comments(options: &mut TransformOptions, ctx: &TransformCtx) { - for comment in ctx.trivias.comments() { +pub(crate) fn update_options_with_comments( + comments: &[Comment], + options: &mut TransformOptions, + ctx: &TransformCtx, +) { + for comment in comments { update_options_with_comment(options, comment, ctx.source_text); } } diff --git a/crates/oxc_wasm/src/lib.rs b/crates/oxc_wasm/src/lib.rs index 65ebccc4c63f7..4f533bb99b32d 100644 --- a/crates/oxc_wasm/src/lib.rs +++ b/crates/oxc_wasm/src/lib.rs @@ -11,7 +11,7 @@ use std::{ use oxc::{ allocator::Allocator, - ast::{ast::Program, CommentKind, Trivias, Visit}, + ast::{ast::Program, Comment as OxcComment, CommentKind, Visit}, codegen::{CodeGenerator, CodegenOptions}, diagnostics::Error, minifier::{CompressOptions, Minifier, MinifierOptions}, @@ -188,12 +188,12 @@ impl Oxc { .preserve_parens .unwrap_or(default_parser_options.preserve_parens), }; - let ParserReturn { mut program, errors, trivias, .. } = + let ParserReturn { mut program, errors, .. } = Parser::new(&allocator, source_text, source_type) .with_options(oxc_parser_options) .parse(); - self.comments = Self::map_comments(source_text, &trivias); + self.comments = Self::map_comments(source_text, &program.comments); self.ir = format!("{:#?}", program.body); self.ast = program.serialize(&self.serializer)?; @@ -203,7 +203,6 @@ impl Oxc { semantic_builder = semantic_builder.with_excess_capacity(2.0); } let semantic_ret = semantic_builder - .with_trivias(trivias.clone()) .with_check_syntax_error(true) .with_cfg(true) .build_module_record(&path, &program) @@ -221,7 +220,7 @@ impl Oxc { ); } - self.run_linter(&run_options, &path, &trivias, &program); + self.run_linter(&run_options, &path, &program); self.run_prettier(&run_options, source_text, source_type); @@ -241,7 +240,7 @@ impl Oxc { targets: Targets::from_query("chrome 51"), ..EnvOptions::default() }) { - let result = Transformer::new(&allocator, &path, trivias.clone(), options) + let result = Transformer::new(&allocator, &path, options) .build_with_symbols_and_scopes(symbols, scopes, &mut program); if !result.errors.is_empty() { self.save_diagnostics( @@ -289,18 +288,11 @@ impl Oxc { Ok(()) } - fn run_linter( - &mut self, - run_options: &OxcRunOptions, - path: &Path, - trivias: &Trivias, - program: &Program, - ) { + fn run_linter(&mut self, run_options: &OxcRunOptions, path: &Path, program: &Program) { // Only lint if there are no syntax errors if run_options.lint.unwrap_or_default() && self.diagnostics.borrow().is_empty() { let semantic_ret = SemanticBuilder::new() .with_cfg(true) - .with_trivias(trivias.clone()) .build_module_record(path, program) .build(program); let semantic = Rc::new(semantic_ret.semantic); @@ -324,12 +316,7 @@ impl Oxc { .with_options(ParseOptions { preserve_parens: false, ..ParseOptions::default() }) .parse(); - let mut prettier = Prettier::new( - &allocator, - source_text, - ret.trivias.clone(), - PrettierOptions::default(), - ); + let mut prettier = Prettier::new(&allocator, source_text, PrettierOptions::default()); if run_options.prettier_format.unwrap_or_default() { self.prettier_formatted_text = prettier.build(&ret.program); @@ -339,13 +326,8 @@ impl Oxc { let prettier_doc = prettier.doc(&ret.program).to_string(); self.prettier_ir_text = { let ret = Parser::new(&allocator, &prettier_doc, SourceType::default()).parse(); - Prettier::new( - &allocator, - &prettier_doc, - ret.trivias, - PrettierOptions::default(), - ) - .build(&ret.program) + Prettier::new(&allocator, &prettier_doc, PrettierOptions::default()) + .build(&ret.program) }; } } @@ -415,9 +397,9 @@ impl Oxc { self.diagnostics.borrow_mut().extend(diagnostics); } - fn map_comments(source_text: &str, trivias: &Trivias) -> Vec { - trivias - .comments() + fn map_comments(source_text: &str, comments: &[OxcComment]) -> Vec { + comments + .iter() .map(|comment| Comment { r#type: match comment.kind { CommentKind::Line => CommentType::Line, diff --git a/napi/parser/src/lib.rs b/napi/parser/src/lib.rs index 6744e534c4d8d..3f9efe1209460 100644 --- a/napi/parser/src/lib.rs +++ b/napi/parser/src/lib.rs @@ -73,8 +73,9 @@ fn parse_with_return<'a>(source_text: &'a str, options: &ParserOptions) -> Parse }; let comments = ret - .trivias - .comments() + .program + .comments + .iter() .map(|comment| Comment { r#type: match comment.kind { CommentKind::Line => "Line", diff --git a/napi/transform/src/isolated_declaration.rs b/napi/transform/src/isolated_declaration.rs index bda6c65a9744e..72867b8200858 100644 --- a/napi/transform/src/isolated_declaration.rs +++ b/napi/transform/src/isolated_declaration.rs @@ -33,19 +33,14 @@ pub fn isolated_declaration( let transformed_ret = IsolatedDeclarations::new( &allocator, - &source_text, - &ret.trivias, oxc::isolated_declarations::IsolatedDeclarationsOptions { strip_internal: options.strip_internal.unwrap_or(false), }, ) .build(&ret.program); - let mut codegen = CodeGenerator::new().enable_comment( - &source_text, - ret.trivias.clone(), - CommentOptions { preserve_annotate_comments: false }, - ); + let mut codegen = CodeGenerator::new() + .enable_comment(&ret.program, CommentOptions { preserve_annotate_comments: false }); if options.sourcemap == Some(true) { codegen = codegen.enable_source_map(&filename, &source_text); } diff --git a/tasks/benchmark/benches/isolated_declarations.rs b/tasks/benchmark/benches/isolated_declarations.rs index 3c44c84b563fd..91d02286fc43c 100644 --- a/tasks/benchmark/benches/isolated_declarations.rs +++ b/tasks/benchmark/benches/isolated_declarations.rs @@ -18,12 +18,10 @@ fn bench_isolated_declarations(criterion: &mut Criterion) { group.bench_with_input(id, &file.source_text, |b, source_text| { b.iter_with_large_drop(|| { let allocator = Allocator::default(); - let ParserReturn { program, trivias, .. } = + let ParserReturn { program, .. } = Parser::new(&allocator, source_text, source_type).parse(); IsolatedDeclarations::new( &allocator, - source_text, - &trivias, IsolatedDeclarationsOptions { strip_internal: true }, ) .build(&program); diff --git a/tasks/benchmark/benches/linter.rs b/tasks/benchmark/benches/linter.rs index d3f25a9b97e6c..7fa52aee27bd3 100644 --- a/tasks/benchmark/benches/linter.rs +++ b/tasks/benchmark/benches/linter.rs @@ -29,7 +29,6 @@ fn bench_linter(criterion: &mut Criterion) { let ret = Parser::new(&allocator, source_text, source_type).parse(); let program = allocator.alloc(ret.program); let semantic_ret = SemanticBuilder::new() - .with_trivias(ret.trivias) .with_build_jsdoc(true) .with_cfg(true) .build_module_record(Path::new(""), program) diff --git a/tasks/benchmark/benches/prettier.rs b/tasks/benchmark/benches/prettier.rs index ef0a295f929dd..73037a8c09485 100644 --- a/tasks/benchmark/benches/prettier.rs +++ b/tasks/benchmark/benches/prettier.rs @@ -17,13 +17,8 @@ fn bench_prettier(criterion: &mut Criterion) { let allocator1 = Allocator::default(); let allocator2 = Allocator::default(); let ret = Parser::new(&allocator1, source_text, source_type).parse(); - let _ = Prettier::new( - &allocator2, - source_text, - ret.trivias, - PrettierOptions::default(), - ) - .build(&ret.program); + let _ = Prettier::new(&allocator2, source_text, PrettierOptions::default()) + .build(&ret.program); }); }, ); diff --git a/tasks/benchmark/benches/semantic.rs b/tasks/benchmark/benches/semantic.rs index bc8823e1d8556..7ee1189ddc611 100644 --- a/tasks/benchmark/benches/semantic.rs +++ b/tasks/benchmark/benches/semantic.rs @@ -24,7 +24,6 @@ fn bench_semantic(criterion: &mut Criterion) { // code would have no errors. One of our benchmarks `cal.com.tsx` has a lot of errors, // but that's atypical, so don't want to include it in benchmark time. let ret = SemanticBuilder::new() - .with_trivias(ret.trivias.clone()) .with_build_jsdoc(true) .build_module_record(Path::new(""), program) .build(program); diff --git a/tasks/benchmark/benches/transformer.rs b/tasks/benchmark/benches/transformer.rs index b83698f667c0c..0116ad32b9954 100644 --- a/tasks/benchmark/benches/transformer.rs +++ b/tasks/benchmark/benches/transformer.rs @@ -26,7 +26,7 @@ fn bench_transformer(criterion: &mut Criterion) { allocator.reset(); // Create fresh AST + semantic data for each iteration - let ParserReturn { trivias, program, .. } = + let ParserReturn { program, .. } = Parser::new(&allocator, source_text, source_type).parse(); let program = allocator.alloc(program); let (symbols, scopes) = SemanticBuilder::new() @@ -36,28 +36,19 @@ fn bench_transformer(criterion: &mut Criterion) { .semantic .into_symbol_table_and_scope_tree(); - // Clone `trivias` (which is an `Arc`). We keep a 2nd copy, so the value is not dropped - // when `Transformer` is dropped inside the measured section. - // We clone `trivias` here rather than in `routine` to avoid the cloning being included - // in measure. - let trivias_copy = trivias.clone(); - // `enable_all` enables all transforms except arrow functions transform let mut options = TransformOptions::enable_all(); options.es2015.arrow_function = Some(ArrowFunctionsOptions { spec: true }); runner.run(|| { - let ret = - Transformer::new(&allocator, Path::new(&file.file_name), trivias, options) - .build_with_symbols_and_scopes(symbols, scopes, program); + let ret = Transformer::new(&allocator, Path::new(&file.file_name), options) + .build_with_symbols_and_scopes(symbols, scopes, program); // Return the `TransformerReturn`, so it's dropped outside of the measured section. // `TransformerReturn` contains `ScopeTree` and `SymbolTable` which are costly to drop. // That's not central to transformer, so we don't want it included in this measure. ret }); - - drop(trivias_copy); }); }); } diff --git a/tasks/coverage/src/driver.rs b/tasks/coverage/src/driver.rs index aac49759cc9a2..58819f50b1758 100644 --- a/tasks/coverage/src/driver.rs +++ b/tasks/coverage/src/driver.rs @@ -4,7 +4,7 @@ use rustc_hash::FxHashSet; use oxc::{ allocator::Allocator, - ast::{ast::Program, Trivias}, + ast::{ast::Program, Comment}, codegen::{CodegenOptions, CodegenReturn}, diagnostics::OxcDiagnostic, minifier::CompressOptions, @@ -67,9 +67,9 @@ impl CompilerInterface for Driver { } fn after_parse(&mut self, parser_return: &mut ParserReturn) -> ControlFlow<()> { - let ParserReturn { program, trivias, panicked, errors } = parser_return; + let ParserReturn { program, panicked, errors, .. } = parser_return; self.panicked = *panicked; - if self.check_comments(trivias) { + if self.check_comments(&program.comments) { return ControlFlow::Break(()); } if (errors.is_empty() || !*panicked) && program.source_type.is_unambiguous() { @@ -145,9 +145,9 @@ impl Driver { self.compile(source_text, source_type, &path); } - fn check_comments(&mut self, trivias: &Trivias) -> bool { + fn check_comments(&mut self, comments: &[Comment]) -> bool { let mut uniq: FxHashSet = FxHashSet::default(); - for comment in trivias.comments() { + for comment in comments { if !uniq.insert(comment.span) { self.errors .push(OxcDiagnostic::error("Duplicate Comment").with_label(comment.span)); diff --git a/tasks/coverage/src/tools/prettier.rs b/tasks/coverage/src/tools/prettier.rs index 605c800626e3f..9cfadbf1123b3 100644 --- a/tasks/coverage/src/tools/prettier.rs +++ b/tasks/coverage/src/tools/prettier.rs @@ -21,14 +21,14 @@ fn get_result(source_text: &str, source_type: SourceType) -> TestResult { let allocator = Allocator::default(); let parse_options = ParseOptions { preserve_parens: false, ..ParseOptions::default() }; - let ParserReturn { program, trivias, .. } = + let ParserReturn { program, .. } = Parser::new(&allocator, source_text, source_type).with_options(parse_options).parse(); - let source_text1 = Prettier::new(&allocator, source_text, trivias, options).build(&program); + let source_text1 = Prettier::new(&allocator, source_text, options).build(&program); let allocator = Allocator::default(); - let ParserReturn { program, trivias, .. } = + let ParserReturn { program, .. } = Parser::new(&allocator, &source_text1, source_type).with_options(parse_options).parse(); - let source_text2 = Prettier::new(&allocator, &source_text1, trivias, options).build(&program); + let source_text2 = Prettier::new(&allocator, &source_text1, options).build(&program); if source_text1 == source_text2 { TestResult::Passed diff --git a/tasks/coverage/src/typescript/transpile_runner.rs b/tasks/coverage/src/typescript/transpile_runner.rs index c04325b015cc0..1f292cb589786 100644 --- a/tasks/coverage/src/typescript/transpile_runner.rs +++ b/tasks/coverage/src/typescript/transpile_runner.rs @@ -178,13 +178,9 @@ fn transpile(path: &Path, source_text: &str) -> (String, Vec) { let allocator = Allocator::default(); let source_type = SourceType::from_path(path).unwrap(); let ret = Parser::new(&allocator, source_text, source_type).parse(); - let ret = IsolatedDeclarations::new( - &allocator, - source_text, - &ret.trivias, - IsolatedDeclarationsOptions { strip_internal: true }, - ) - .build(&ret.program); + let ret = + IsolatedDeclarations::new(&allocator, IsolatedDeclarationsOptions { strip_internal: true }) + .build(&ret.program); let printed = CodeGenerator::new().build(&ret.program).code; (printed, ret.errors) } diff --git a/tasks/prettier_conformance/src/lib.rs b/tasks/prettier_conformance/src/lib.rs index c04dce386e3e3..31d4153c05057 100644 --- a/tasks/prettier_conformance/src/lib.rs +++ b/tasks/prettier_conformance/src/lib.rs @@ -389,7 +389,7 @@ impl TestRunner { let ret = Parser::new(&allocator, source_text, source_type) .with_options(ParseOptions { preserve_parens: false, ..ParseOptions::default() }) .parse(); - Prettier::new(&allocator, source_text, ret.trivias, prettier_options).build(&ret.program) + Prettier::new(&allocator, source_text, prettier_options).build(&ret.program) } } diff --git a/tasks/transform_conformance/src/driver.rs b/tasks/transform_conformance/src/driver.rs index 56778147f253d..107328276d8f2 100644 --- a/tasks/transform_conformance/src/driver.rs +++ b/tasks/transform_conformance/src/driver.rs @@ -1,7 +1,7 @@ use std::{mem, ops::ControlFlow, path::Path}; use oxc::{ - ast::{ast::Program, Trivias}, + ast::ast::Program, codegen::{CodeGenerator, CodegenOptions, CodegenReturn}, diagnostics::OxcDiagnostic, mangler::Mangler, @@ -61,7 +61,6 @@ impl CompilerInterface for Driver { &self, program: &Program<'_>, _source_path: &Path, - _trivias: &Trivias, mangler: Option, options: CodegenOptions, ) -> CodegenReturn {