From ab5655ae5c89f2c7ec9a1f9d8b7f53cf6397f353 Mon Sep 17 00:00:00 2001 From: Boshen Date: Thu, 29 Oct 2026 16:30:16 +0800 Subject: [PATCH] perf(regex): remove redundant character-class and quantifier checks (#28288) Character classes cannot contain strings outside Unicode sets mode, and existing parser invariants already establish the removed class-string and quantifier checks. AI-assisted implementation. --- .../parser/pattern_parser/pattern_parser_impl.rs | 11 +++++------ .../misc/pass/regexp-character-class-strings.js | 13 +++++++++++++ tasks/coverage/snapshots/codegen_misc.snap | 4 ++-- tasks/coverage/snapshots/formatter_misc.snap | 4 ++-- tasks/coverage/snapshots/lexer_misc.snap | 4 ++-- tasks/coverage/snapshots/parser_misc.snap | 4 ++-- tasks/coverage/snapshots/semantic_misc.snap | 4 ++-- tasks/coverage/snapshots/transformer_misc.snap | 4 ++-- 8 files changed, 30 insertions(+), 18 deletions(-) create mode 100644 tasks/coverage/misc/pass/regexp-character-class-strings.js diff --git a/crates/oxc_regular_expression/src/parser/pattern_parser/pattern_parser_impl.rs b/crates/oxc_regular_expression/src/parser/pattern_parser/pattern_parser_impl.rs index 50dcdabdf5..45ab3c013b 100644 --- a/crates/oxc_regular_expression/src/parser/pattern_parser/pattern_parser_impl.rs +++ b/crates/oxc_regular_expression/src/parser/pattern_parser/pattern_parser_impl.rs @@ -782,7 +782,10 @@ impl<'a> PatternParser<'a> { let (kind, body) = self.parse_class_contents()?; if self.reader.eat(']') { - let strings = PatternParser::may_contain_strings_in_class_contents(kind, &body); + // Without UnicodeSetsMode, ClassContents is empty or NonemptyClassRanges, + // whose MayContainStrings is always false. + let strings = self.state.unicode_sets_mode + && PatternParser::may_contain_strings_in_class_contents(kind, &body); // [SS:EE] CharacterClass :: [^ ClassContents ] // It is a Syntax Error if MayContainStrings of the ClassContents is true. @@ -1432,10 +1435,6 @@ impl<'a> PatternParser<'a> { } } - if body.is_empty() { - strings = true; - } - Ok((body, strings)) } @@ -1777,7 +1776,7 @@ impl<'a> PatternParser<'a> { self.span_factory.create(span_start, self.reader.offset()), )); } - if MAX_QUANTIFIER < min || MAX_QUANTIFIER < max { + if MAX_QUANTIFIER < max { return Err(diagnostics::too_large_number_in_braced_quantifier( self.span_factory.create(span_start, self.reader.offset()), )); diff --git a/tasks/coverage/misc/pass/regexp-character-class-strings.js b/tasks/coverage/misc/pass/regexp-character-class-strings.js new file mode 100644 index 0000000000..dd57268435 --- /dev/null +++ b/tasks/coverage/misc/pass/regexp-character-class-strings.js @@ -0,0 +1,13 @@ +const patterns = [ + /[]/, + /[a-z\d]/, + /[a-z\p{Letter}]/u, + /[a-z]/v, + /[\q{}]/v, + /[\q{a|b}]/v, + /[\q{ab}]/v, + /[\p{Basic_Emoji}]/v, + /[[\q{ab}]&&[a-z]]/v, + /[[\q{ab}]--[a-z]]/v, + /[[a-z]--[\q{ab}]]/v, +]; diff --git a/tasks/coverage/snapshots/codegen_misc.snap b/tasks/coverage/snapshots/codegen_misc.snap index 6302943e05..c48512e8d2 100644 --- a/tasks/coverage/snapshots/codegen_misc.snap +++ b/tasks/coverage/snapshots/codegen_misc.snap @@ -1,3 +1,3 @@ codegen_misc Summary: -AST Parsed : 118/118 (100.00%) -Positive Passed: 118/118 (100.00%) +AST Parsed : 119/119 (100.00%) +Positive Passed: 119/119 (100.00%) diff --git a/tasks/coverage/snapshots/formatter_misc.snap b/tasks/coverage/snapshots/formatter_misc.snap index 1aeef96a95..d42b742e76 100644 --- a/tasks/coverage/snapshots/formatter_misc.snap +++ b/tasks/coverage/snapshots/formatter_misc.snap @@ -1,3 +1,3 @@ formatter_misc Summary: -AST Parsed : 118/118 (100.00%) -Positive Passed: 118/118 (100.00%) +AST Parsed : 119/119 (100.00%) +Positive Passed: 119/119 (100.00%) diff --git a/tasks/coverage/snapshots/lexer_misc.snap b/tasks/coverage/snapshots/lexer_misc.snap index 1d0c9fa28f..5f20be6ca5 100644 --- a/tasks/coverage/snapshots/lexer_misc.snap +++ b/tasks/coverage/snapshots/lexer_misc.snap @@ -1,3 +1,3 @@ lexer_misc Summary: -AST Parsed : 373/373 (100.00%) -Positive Passed: 373/373 (100.00%) +AST Parsed : 374/374 (100.00%) +Positive Passed: 374/374 (100.00%) diff --git a/tasks/coverage/snapshots/parser_misc.snap b/tasks/coverage/snapshots/parser_misc.snap index 0191607100..547cf13d7a 100644 --- a/tasks/coverage/snapshots/parser_misc.snap +++ b/tasks/coverage/snapshots/parser_misc.snap @@ -1,6 +1,6 @@ parser_misc Summary: -AST Parsed : 118/118 (100.00%) -Positive Passed: 118/118 (100.00%) +AST Parsed : 119/119 (100.00%) +Positive Passed: 119/119 (100.00%) Negative Passed: 257/257 (100.00%) × TS(1275): 'accessor' modifier can only appear on a property declaration. diff --git a/tasks/coverage/snapshots/semantic_misc.snap b/tasks/coverage/snapshots/semantic_misc.snap index 35188280f3..01e98bcb33 100644 --- a/tasks/coverage/snapshots/semantic_misc.snap +++ b/tasks/coverage/snapshots/semantic_misc.snap @@ -1,6 +1,6 @@ semantic_misc Summary: -AST Parsed : 118/118 (100.00%) -Positive Passed: 112/118 (94.92%) +AST Parsed : 119/119 (100.00%) +Positive Passed: 113/119 (94.96%) semantic Error: tasks/coverage/misc/pass/declare-let-private.ts Bindings mismatch: after transform: ScopeId(0): ["private"] diff --git a/tasks/coverage/snapshots/transformer_misc.snap b/tasks/coverage/snapshots/transformer_misc.snap index 6bdf80ec73..afa164a385 100644 --- a/tasks/coverage/snapshots/transformer_misc.snap +++ b/tasks/coverage/snapshots/transformer_misc.snap @@ -1,3 +1,3 @@ transformer_misc Summary: -AST Parsed : 118/118 (100.00%) -Positive Passed: 118/118 (100.00%) +AST Parsed : 119/119 (100.00%) +Positive Passed: 119/119 (100.00%)