From 7c93eef0bc44d397cbfdb10a00309ce6a893903b Mon Sep 17 00:00:00 2001 From: Cam McHenry Date: Fri, 30 Oct 2026 12:26:35 -0400 Subject: [PATCH] perf(linter): reduce branches-sharing-code scratch allocations (#28483) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Get rid of 1 Vec that was just used for scratch, and use smallvec for the other Vec. On local fixtures: Allocations: 24,658 → 346 (−98.6%) Allocated bytes: 797,698 → 18,466 (−97.7%) Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../src/rules/oxc/branches_sharing_code.rs | 36 ++++++++----------- 1 file changed, 14 insertions(+), 22 deletions(-) diff --git a/crates/oxc_linter/src/rules/oxc/branches_sharing_code.rs b/crates/oxc_linter/src/rules/oxc/branches_sharing_code.rs index 8ced928296..d2348cf7b0 100644 --- a/crates/oxc_linter/src/rules/oxc/branches_sharing_code.rs +++ b/crates/oxc_linter/src/rules/oxc/branches_sharing_code.rs @@ -1,7 +1,7 @@ // Inspired by https://github.com/rust-lang/rust-clippy/blob/95f5a00d8628fba223c802251af3c42547927c5a/clippy_lints/src/ifs/branches_sharing_code.rs use oxc_ast::{ AstKind, - ast::{Expression, IdentifierReference, IfStatement, Statement}, + ast::{IdentifierReference, IfStatement, Statement}, }; use oxc_ast_visit::Visit; use oxc_diagnostics::OxcDiagnostic; @@ -10,6 +10,7 @@ use oxc_macros::declare_oxc_lint; use oxc_semantic::{ReferenceId, SymbolId}; use oxc_span::{ContentEq, GetSpan, Span}; use rustc_hash::FxHashSet; +use smallvec::SmallVec; use crate::{AstNode, ast_util::get_preceding_indent_str, context::LintContext, rule::Rule}; @@ -111,11 +112,9 @@ impl Rule for BranchesSharingCode { return; } - let (conditions, bodies) = extract_if_sequence(if_stmt); - - if bodies.len() < 2 || bodies.len() == conditions.len() { + let Some(bodies) = extract_if_sequence(if_stmt) else { return; - } + }; let (start_eq, end_eq) = scan_blocks_for_eq(&bodies); @@ -341,30 +340,23 @@ fn scan_blocks_for_eq<'a>(bodies: &[&'a Statement<'a>]) -> (Option, Optio fn extract_if_sequence<'a>( if_stmt: &'a IfStatement<'a>, -) -> (Vec<&'a Expression<'a>>, Vec<&'a Statement<'a>>) { - let mut conditions = Vec::new(); - let mut bodies = Vec::new(); +) -> Option; 2]>> { + let mut bodies = SmallVec::new(); - let mut current_if = Some(if_stmt); - while let Some(if_node) = current_if { - conditions.push(&if_node.test); - bodies.push(&if_node.consequent); + let mut current_if = if_stmt; + loop { + bodies.push(¤t_if.consequent); - match &if_node.alternate { - Some(Statement::IfStatement(else_if)) => { - current_if = Some(else_if); + match current_if.alternate.as_ref()? { + Statement::IfStatement(else_if) => { + current_if = else_if; } - Some(else_stmt) => { + else_stmt => { bodies.push(else_stmt); - current_if = None; - } - None => { - current_if = None; + return Some(bodies); } } } - - (conditions, bodies) } #[test]