From 6a72d840ed732d5ff06ec17acca23ddf9e35345b Mon Sep 17 00:00:00 2001 From: Cam McHenry Date: Fri, 30 Oct 2026 12:26:32 -0400 Subject: [PATCH] perf(linter): reduce no-dupe-class-members allocations (#28476) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Search preceding elements directly for small classes, preserving the last-seen member semantics and the hash-map path for larger classes. On local fixtures: Metric | Before → After -- | -- Allocations | 580 → 274 (−52.8%) Allocated bytes | 132,616 → 99,908 (−24.7%) Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../src/rules/eslint/no_dupe_class_members.rs | 39 ++++++++++++------- 1 file changed, 25 insertions(+), 14 deletions(-) diff --git a/crates/oxc_linter/src/rules/eslint/no_dupe_class_members.rs b/crates/oxc_linter/src/rules/eslint/no_dupe_class_members.rs index 0ba5c325ad..0e3f642c8e 100644 --- a/crates/oxc_linter/src/rules/eslint/no_dupe_class_members.rs +++ b/crates/oxc_linter/src/rules/eslint/no_dupe_class_members.rs @@ -62,26 +62,37 @@ declare_oxc_lint!( short_description = "Disallow duplicate class members.", ); +const LINEAR_SEARCH_LIMIT: usize = 8; + impl Rule for NoDupeClassMembers { fn run_once(&self, ctx: &LintContext) { ctx.classes().iter_enumerated().for_each(|(class_id, _)| { let mut defined_elements = FxHashMap::default(); let elements = &ctx.classes().elements[class_id]; for (element_id, element) in elements.iter_enumerated() { - if let Some(prev_element_id) = defined_elements.insert(&element.name, element_id) { - let prev_element = &elements[prev_element_id]; - if element.r#static == prev_element.r#static - && element.is_private == prev_element.is_private - && (!(element.kind.is_setter_or_getter() - && prev_element.kind.is_setter_or_getter()) - || element.kind == prev_element.kind) - { - ctx.diagnostic(no_dupe_class_members_diagnostic( - &element.name, - prev_element.span, - element.span, - )); - } + let prev_element = if elements.len() <= LINEAR_SEARCH_LIMIT { + // Search backwards to preserve the map's last-seen member semantics. + elements + .iter() + .take(element_id.index()) + .rfind(|previous| previous.name == element.name) + } else { + defined_elements + .insert(&element.name, element_id) + .map(|prev_element_id| &elements[prev_element_id]) + }; + if let Some(prev_element) = prev_element + && element.r#static == prev_element.r#static + && element.is_private == prev_element.is_private + && (!(element.kind.is_setter_or_getter() + && prev_element.kind.is_setter_or_getter()) + || element.kind == prev_element.kind) + { + ctx.diagnostic(no_dupe_class_members_diagnostic( + &element.name, + prev_element.span, + element.span, + )); } } });