diff --git a/crates/oxc_linter/src/rules/eslint/no_control_regex.rs b/crates/oxc_linter/src/rules/eslint/no_control_regex.rs index f4e938335c168..007103bbf25b3 100644 --- a/crates/oxc_linter/src/rules/eslint/no_control_regex.rs +++ b/crates/oxc_linter/src/rules/eslint/no_control_regex.rs @@ -362,6 +362,11 @@ mod tests { // globalThis "var regex = new globalThis.RegExp('\\x1f\\x1e')", "var regex = globalThis.RegExp('\\x1f')", + // inner expressions (parentheses and type expressions) + "RegExp(('\\x1f'))", + "new RegExp(('\\x1f'))", + "new RegExp((('\\x1f')))", + "new RegExp('\\x1f' as string)", ], ) .test_and_snapshot(); diff --git a/crates/oxc_linter/src/snapshots/eslint_no_control_regex.snap b/crates/oxc_linter/src/snapshots/eslint_no_control_regex.snap index 11b85edd2c7e4..b2a6d09412279 100644 Binary files a/crates/oxc_linter/src/snapshots/eslint_no_control_regex.snap and b/crates/oxc_linter/src/snapshots/eslint_no_control_regex.snap differ diff --git a/crates/oxc_linter/src/utils/regex.rs b/crates/oxc_linter/src/utils/regex.rs index 8b4041a511abc..428ca1e7d7b11 100644 --- a/crates/oxc_linter/src/utils/regex.rs +++ b/crates/oxc_linter/src/utils/regex.rs @@ -20,45 +20,36 @@ where } } AstKind::NewExpression(expr) if is_regexp_callee(&expr.callee, ctx) => { - // note: improvements required for strings used via identifier references - // Missing or non-string arguments will be runtime errors, but are not covered by this rule. - match (&expr.arguments.first(), &expr.arguments.get(1)) { - (Some(Argument::StringLiteral(pattern)), Some(Argument::StringLiteral(flags))) => { - let allocator = Allocator::default(); - if let Some(pat) = parse_regex(&allocator, pattern.span, Some(flags.span), ctx) - { - cb(&pat, pattern.span); - } - } - (Some(Argument::StringLiteral(pattern)), _) => { - let allocator = Allocator::default(); - if let Some(pat) = parse_regex(&allocator, pattern.span, None, ctx) { - cb(&pat, pattern.span); - } - } - _ => {} - } + run_on_arguments(expr.arguments.first(), expr.arguments.get(1), ctx, cb); } // RegExp() AstKind::CallExpression(expr) if is_regexp_callee(&expr.callee, ctx) => { - // note: improvements required for strings used via identifier references - // Missing or non-string arguments will be runtime errors, but are not covered by this rule. - match (&expr.arguments.first(), &expr.arguments.get(1)) { - (Some(Argument::StringLiteral(pattern)), Some(Argument::StringLiteral(flags))) => { - let allocator = Allocator::default(); - if let Some(pat) = parse_regex(&allocator, pattern.span, Some(flags.span), ctx) - { - cb(&pat, pattern.span); - } - } - (Some(Argument::StringLiteral(pattern)), _) => { - let allocator = Allocator::default(); - if let Some(pat) = parse_regex(&allocator, pattern.span, None, ctx) { - cb(&pat, pattern.span); - } - } - _ => {} + run_on_arguments(expr.arguments.first(), expr.arguments.get(1), ctx, cb); + } + _ => {} + } +} + +fn run_on_arguments(arg1: Option<&Argument>, arg2: Option<&Argument>, ctx: &LintContext, cb: M) +where + M: FnOnce(&Pattern<'_>, Span), +{ + let arg1 = arg1.map(|arg| arg.to_expression().get_inner_expression()); + let arg2 = arg2.map(|arg| arg.to_expression().get_inner_expression()); + // note: improvements required for strings used via identifier references + // Missing or non-string arguments will be runtime errors, but are not covered by this rule. + match (&arg1, &arg2) { + (Some(Expression::StringLiteral(pattern)), Some(Expression::StringLiteral(flags))) => { + let allocator = Allocator::default(); + if let Some(pat) = parse_regex(&allocator, pattern.span, Some(flags.span), ctx) { + cb(&pat, pattern.span); + } + } + (Some(Expression::StringLiteral(pattern)), _) => { + let allocator = Allocator::default(); + if let Some(pat) = parse_regex(&allocator, pattern.span, None, ctx) { + cb(&pat, pattern.span); } } _ => {}