From 1ec9991cb274c61ca7a72d4bed5cb16f2a5ccbd4 Mon Sep 17 00:00:00 2001 From: Cam McHenry Date: Wed, 28 Oct 2026 22:28:46 -0400 Subject: [PATCH] perf(linter/oxc/number-arg-out-of-range): narrow AST dispatch (#28355) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Start from numeric literals used as direct first arguments. Preserve range boundaries and optional calls, and reduce fixture callbacks from 62,606 to 14,295. --- Stack created with GitHub Stacks CLI โ€ข Give Feedback ๐Ÿ’ฌ Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../src/generated/rule_runner_impls.rs | 2 +- .../src/rules/oxc/number_arg_out_of_range.rs | 29 +++++++++++++++---- .../oxc_number_arg_out_of_range.snap | 14 +++++++++ .../track_linter_timings/linter_timings.snap | 2 +- 4 files changed, 40 insertions(+), 7 deletions(-) diff --git a/crates/oxc_linter/src/generated/rule_runner_impls.rs b/crates/oxc_linter/src/generated/rule_runner_impls.rs index bf1cd6b3cf..fd389ab45c 100644 --- a/crates/oxc_linter/src/generated/rule_runner_impls.rs +++ b/crates/oxc_linter/src/generated/rule_runner_impls.rs @@ -4448,7 +4448,7 @@ impl RuleRunner for crate::rules::oxc::no_this_in_exported_function::NoThisInExp impl RuleRunner for crate::rules::oxc::number_arg_out_of_range::NumberArgOutOfRange { const NODE_TYPES: Option<&AstTypesBitset> = - Some(&AstTypesBitset::from_types(&[AstType::CallExpression])); + Some(&AstTypesBitset::from_types(&[AstType::NumericLiteral])); const RUN_FUNCTIONS: RuleRunFunctionsImplemented = RuleRunFunctionsImplemented::Run; } diff --git a/crates/oxc_linter/src/rules/oxc/number_arg_out_of_range.rs b/crates/oxc_linter/src/rules/oxc/number_arg_out_of_range.rs index 0b033701a9..ca473d3907 100644 --- a/crates/oxc_linter/src/rules/oxc/number_arg_out_of_range.rs +++ b/crates/oxc_linter/src/rules/oxc/number_arg_out_of_range.rs @@ -1,7 +1,7 @@ -use oxc_ast::{AstKind, ast::Argument}; +use oxc_ast::AstKind; use oxc_diagnostics::OxcDiagnostic; use oxc_macros::declare_oxc_lint; -use oxc_span::Span; +use oxc_span::{GetSpan, Span}; use oxc_str::JSStr; use crate::{AstNode, context::LintContext, rule::Rule}; @@ -58,9 +58,12 @@ declare_oxc_lint!( impl Rule for NumberArgOutOfRange { fn run<'a>(&self, node: &AstNode<'a>, ctx: &LintContext<'a>) { - if let AstKind::CallExpression(expr) = node.kind() + let AstKind::NumericLiteral(literal) = node.kind() else { + return; + }; + if let AstKind::CallExpression(expr) = ctx.nodes().parent_kind(node.id()) + && expr.arguments.first().is_some_and(|argument| argument.span() == literal.span) && let Some(member) = expr.callee.get_member_expr() - && let Some(Argument::NumericLiteral(literal)) = expr.arguments.first() { let value = literal.value; match member.static_property_name().and_then(JSStr::as_str) { @@ -85,7 +88,21 @@ impl Rule for NumberArgOutOfRange { fn test() { use crate::tester::Tester; - let pass = vec![("var x = 42;var s = x.toString(16);", None)]; + let pass = vec![ + ("var x = 42;var s = x.toString(16);", None), + ("x.toString(2); x.toString(36)", None), + ("x.toFixed(0); x.toFixed(20)", None), + ("x.toExponential(0); x.toExponential(20)", None), + ("x.toPrecision(1); x.toPrecision(21)", None), + ("x.toString(16, 1)", None), + ("x.toString((1))", None), + ("x.toString(1 as number)", None), + ("x.toString(-1)", None), + ("x.toString(...[1])", None), + ("new x.toString(1)", None), + ("x.toString()", None), + ("x.otherMethod(100)", None), + ]; let fail = vec![ ("var x = 42;var s = x.toString(1);", None), @@ -94,6 +111,8 @@ fn test() { ("var x = 42;var s = x['toExponential'](22);", None), ("var x = 42;var s = x.toPrecision(0);", None), ("var x = 42;var s = x.toPrecision(100);", None), + ("x.toString(1, 43)", None), + ("x?.toFixed(22)", None), ]; Tester::new(NumberArgOutOfRange::NAME, NumberArgOutOfRange::PLUGIN, pass, fail) diff --git a/crates/oxc_linter/src/snapshots/oxc_number_arg_out_of_range.snap b/crates/oxc_linter/src/snapshots/oxc_number_arg_out_of_range.snap index b747377b61..f9d083a3b0 100644 --- a/crates/oxc_linter/src/snapshots/oxc_number_arg_out_of_range.snap +++ b/crates/oxc_linter/src/snapshots/oxc_number_arg_out_of_range.snap @@ -43,3 +43,17 @@ source: crates/oxc_linter/src/tester.rs ยท โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ โ•ฐโ”€โ”€โ”€โ”€ help: The first argument of 'Number.prototype.toPrecision' should be a number between 1 and 21 + + โš  oxc(number-arg-out-of-range): Radix or precision arguments of number-related functions should not exceed the limit + โ•ญโ”€[number_arg_out_of_range.tsx:1:1] + 1 โ”‚ x.toString(1, 43) + ยท โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ + โ•ฐโ”€โ”€โ”€โ”€ + help: The first argument of 'Number.prototype.toString' should be a number between 2 and 36 + + โš  oxc(number-arg-out-of-range): Radix or precision arguments of number-related functions should not exceed the limit + โ•ญโ”€[number_arg_out_of_range.tsx:1:1] + 1 โ”‚ x?.toFixed(22) + ยท โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ + โ•ฐโ”€โ”€โ”€โ”€ + help: The first argument of 'Number.prototype.toFixed' should be a number between 0 and 20 diff --git a/tasks/track_linter_timings/linter_timings.snap b/tasks/track_linter_timings/linter_timings.snap index 734915f3c3..579bf50943 100644 --- a/tasks/track_linter_timings/linter_timings.snap +++ b/tasks/track_linter_timings/linter_timings.snap @@ -355,7 +355,7 @@ oxc/no-map-spread | 62606 oxc/no-optional-chaining | 792 oxc/no-rest-spread-properties | 564 oxc/no-this-in-exported-function | 112 -oxc/number-arg-out-of-range | 62606 +oxc/number-arg-out-of-range | 14295 oxc/only-used-in-recursion | 16812 oxc/uninvoked-array-callback | 1421 promise/always-return | 16812