From bbfd692af6b7265e91ef00936a5e8949a204afa5 Mon Sep 17 00:00:00 2001 From: Cam McHenry Date: Wed, 28 Oct 2026 22:28:50 -0400 Subject: [PATCH] perf(linter/react/no-children-pop): narrow AST dispatch (#28365) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Inspect object literals in the createElement props position instead of every call, retaining JSX attribute checks. Reduce fixture callbacks from 63,410 to 14,929. --- 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/react/no_children_prop.rs | 16 ++++++++++------ tasks/track_linter_timings/linter_timings.snap | 2 +- 3 files changed, 12 insertions(+), 8 deletions(-) diff --git a/crates/oxc_linter/src/generated/rule_runner_impls.rs b/crates/oxc_linter/src/generated/rule_runner_impls.rs index 257dfa1f9c..240208e4b0 100644 --- a/crates/oxc_linter/src/generated/rule_runner_impls.rs +++ b/crates/oxc_linter/src/generated/rule_runner_impls.rs @@ -2825,7 +2825,7 @@ impl RuleRunner for crate::rules::react::no_array_index_key::NoArrayIndexKey { impl RuleRunner for crate::rules::react::no_children_prop::NoChildrenProp { const NODE_TYPES: Option<&AstTypesBitset> = - Some(&AstTypesBitset::from_types(&[AstType::CallExpression, AstType::JSXAttribute])); + Some(&AstTypesBitset::from_types(&[AstType::JSXAttribute, AstType::ObjectExpression])); const RUN_FUNCTIONS: RuleRunFunctionsImplemented = RuleRunFunctionsImplemented::Run; } diff --git a/crates/oxc_linter/src/rules/react/no_children_prop.rs b/crates/oxc_linter/src/rules/react/no_children_prop.rs index 253998ffe6..cb3e73f257 100644 --- a/crates/oxc_linter/src/rules/react/no_children_prop.rs +++ b/crates/oxc_linter/src/rules/react/no_children_prop.rs @@ -1,7 +1,4 @@ -use oxc_ast::{ - AstKind, - ast::{Argument, JSXAttributeName}, -}; +use oxc_ast::{AstKind, ast::JSXAttributeName}; use oxc_diagnostics::OxcDiagnostic; use oxc_macros::declare_oxc_lint; use oxc_span::{GetSpan, Span}; @@ -71,9 +68,12 @@ impl Rule for NoChildrenProp { ctx.diagnostic(no_children_prop_diagnostic(attr_ident.span)); } } - AstKind::CallExpression(call_expr) => { + AstKind::ObjectExpression(obj_expr) => { + let AstKind::CallExpression(call_expr) = ctx.nodes().parent_kind(node.id()) else { + return; + }; if is_create_element_call(call_expr) - && let Some(Argument::ObjectExpression(obj_expr)) = call_expr.arguments.get(1) + && call_expr.arguments.get(1).is_some_and(|arg| arg.span() == obj_expr.span) && let Some(prop) = obj_expr.find_property("children") { ctx.diagnostic(no_children_prop_diagnostic(prop.key.span())); @@ -128,6 +128,10 @@ fn test() { r#";"#, r#"foo(MyComponent, {...props, children: "Children"})"#, r#"React.createElement(MyComponent, {className: "class-name", ...props});"#, + r#"React.createElement({children: "Children"}, {});"#, + r#"React.createElement("div", {}, {children: "Children"});"#, + r#"React.createElement("div", ({children: "Children"}));"#, + r#"React.createElement("div", {props: {children: "Children"}});"#, ]; #[rustfmt::skip] diff --git a/tasks/track_linter_timings/linter_timings.snap b/tasks/track_linter_timings/linter_timings.snap index c9c5333831..98cd744e2c 100644 --- a/tasks/track_linter_timings/linter_timings.snap +++ b/tasks/track_linter_timings/linter_timings.snap @@ -411,7 +411,7 @@ react/jsx-props-no-spread-multi | 452 react/jsx-props-no-spreading | 6 react/memo-dependencies | 7 react/no-array-index-key | 63058 -react/no-children-prop | 63410 +react/no-children-prop | 14929 react/no-clone-element | 62606 react/no-danger | 7019 react/no-danger-with-children | 63058