From fca9706ab30e9513c6f05559ee68fec4586fc570 Mon Sep 17 00:00:00 2001 From: Boshen Date: Wed, 10 Jul 2024 09:54:26 +0800 Subject: [PATCH] perf(semantic): faster search for leading comments (#4140) fixes #4114 @leaysgur This is my wild guess, I need a second pairs of eyes to make sure this is correct. --- crates/oxc_semantic/src/jsdoc/builder.rs | 31 +++++++++++++----------- 1 file changed, 17 insertions(+), 14 deletions(-) diff --git a/crates/oxc_semantic/src/jsdoc/builder.rs b/crates/oxc_semantic/src/jsdoc/builder.rs index f61a308c4..60bd7b79c 100644 --- a/crates/oxc_semantic/src/jsdoc/builder.rs +++ b/crates/oxc_semantic/src/jsdoc/builder.rs @@ -12,6 +12,8 @@ pub struct JSDocBuilder<'a> { trivias: Trivias, attached_docs: BTreeMap>>, leading_comments_seen: FxHashSet, + /// End span of the previous successful comment search. + previous_span_end: u32, } impl<'a> JSDocBuilder<'a> { @@ -21,6 +23,7 @@ impl<'a> JSDocBuilder<'a> { trivias, attached_docs: BTreeMap::default(), leading_comments_seen: FxHashSet::default(), + previous_span_end: 0, } } @@ -116,29 +119,29 @@ impl<'a> JSDocBuilder<'a> { } let span = kind.span(); - let mut leading_comments = vec![]; - // May be better to set range start for perf? - // But once I tried, coverage tests start failing... - for comment in self.trivias.comments_range(..span.start) { + let comments_range = self.trivias.comments_range(self.previous_span_end..span.start); + let comments_len = comments_range.size_hint().1; + let mut leading_jsdoc_comments = Vec::with_capacity(comments_len.unwrap_or(0)); + + for comment in comments_range { if self.leading_comments_seen.contains(&comment.span.start) { continue; } - leading_comments.push(comment); self.leading_comments_seen.insert(comment.span.start); + if let Some(jsdoc) = self.parse_if_jsdoc_comment(comment.kind, comment.span) { + leading_jsdoc_comments.push(jsdoc); + } } - let leading_jsdoc_comments = leading_comments - .into_iter() - .filter_map(|comment| self.parse_if_jsdoc_comment(comment.kind, comment.span)) - .collect::>(); - - if !leading_jsdoc_comments.is_empty() { - self.attached_docs.insert(span, leading_jsdoc_comments); - return true; + if leading_jsdoc_comments.is_empty() { + return false; } - false + leading_jsdoc_comments.shrink_to_fit(); + self.attached_docs.insert(span, leading_jsdoc_comments); + self.previous_span_end = span.end; + true } fn parse_if_jsdoc_comment(&self, kind: CommentKind, comment_span: Span) -> Option> {