From 8c3915e37b89ce7bb97201bda64dbf3f5d990662 Mon Sep 17 00:00:00 2001 From: Arhan Chaudhary Date: Sun, 5 Jul 2026 00:13:39 +0530 Subject: [PATCH] perf: optimize msrv calls (again) --- book/src/development/adding_lints.md | 4 ++++ clippy_lints/src/attrs/deprecated_cfg_attr.rs | 2 +- clippy_lints/src/casts/ptr_as_ptr.rs | 2 +- clippy_lints/src/methods/inefficient_to_string.rs | 2 +- clippy_lints/src/methods/manual_is_variant_and.rs | 2 +- clippy_lints/src/methods/manual_try_fold.rs | 2 +- clippy_lints/src/methods/mod.rs | 9 ++++----- clippy_lints/src/methods/string_lit_chars_any.rs | 2 +- clippy_lints/src/operators/manual_is_multiple_of.rs | 4 ++-- clippy_lints/src/unnested_or_patterns.rs | 4 ++-- 10 files changed, 18 insertions(+), 15 deletions(-) diff --git a/book/src/development/adding_lints.md b/book/src/development/adding_lints.md index f28985d375f6..9cc6e0040a23 100644 --- a/book/src/development/adding_lints.md +++ b/book/src/development/adding_lints.md @@ -485,6 +485,10 @@ if !self.msrv.meets(cx, msrvs::STR_STRIP_PREFIX) { } ``` +An important consideration is that `Msrv::meets` is relatively expensive to +call, so you should typically match the MSRV at the end of an if let chain, +after other short-circuiting checks. + Early lint passes should instead use `MsrvStack` coupled with `extract_msrv_attr!()` diff --git a/clippy_lints/src/attrs/deprecated_cfg_attr.rs b/clippy_lints/src/attrs/deprecated_cfg_attr.rs index d67a194b0206..29169770ca73 100644 --- a/clippy_lints/src/attrs/deprecated_cfg_attr.rs +++ b/clippy_lints/src/attrs/deprecated_cfg_attr.rs @@ -15,7 +15,6 @@ pub(super) fn check(cx: &EarlyContext<'_>, attr: &Attribute, msrv: &MsrvStack) { { // check for `rustfmt` if feature_item.has_name(sym::rustfmt) - && msrv.meets(msrvs::TOOL_ATTRIBUTES) // check for `rustfmt_skip` and `rustfmt::skip` && let Some(skip_item) = &items[1].meta_item() && (skip_item.has_name(sym::rustfmt_skip) @@ -30,6 +29,7 @@ pub(super) fn check(cx: &EarlyContext<'_>, attr: &Attribute, msrv: &MsrvStack) { // Only lint outer attributes, because custom inner attributes are unstable // Tracking issue: https://github.com/rust-lang/rust/issues/54726 && attr.style == AttrStyle::Outer + && msrv.meets(msrvs::TOOL_ATTRIBUTES) { span_lint_and_sugg( cx, diff --git a/clippy_lints/src/casts/ptr_as_ptr.rs b/clippy_lints/src/casts/ptr_as_ptr.rs index 61fe563512b6..d012380cb762 100644 --- a/clippy_lints/src/casts/ptr_as_ptr.rs +++ b/clippy_lints/src/casts/ptr_as_ptr.rs @@ -41,8 +41,8 @@ pub(super) fn check<'tcx>( // The `U` in `pointer::cast` have to be `Sized` // as explained here: https://github.com/rust-lang/rust/issues/60602. && to_pointee_ty.is_sized(cx.tcx, cx.typing_env()) - && !is_from_proc_macro(cx, expr) && msrv.meets(cx, msrvs::POINTER_CAST) + && !is_from_proc_macro(cx, expr) { let mut app = Applicability::MachineApplicable; let turbofish = match &cast_to_hir.kind { diff --git a/clippy_lints/src/methods/inefficient_to_string.rs b/clippy_lints/src/methods/inefficient_to_string.rs index 374639985bee..fa55e176351e 100644 --- a/clippy_lints/src/methods/inefficient_to_string.rs +++ b/clippy_lints/src/methods/inefficient_to_string.rs @@ -19,9 +19,9 @@ pub fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, receiver: &hir::Expr<'_ && let self_ty = args.type_at(0) && let (deref_self_ty, deref_count, _) = peel_and_count_ty_refs(self_ty) && deref_count >= 1 + && specializes_tostring(cx, deref_self_ty) // Since Rust 1.82, the specialized `ToString` is properly called && !msrv.meets(cx, msrvs::SPECIALIZED_TO_STRING_FOR_REFS) - && specializes_tostring(cx, deref_self_ty) { span_lint_and_then( cx, diff --git a/clippy_lints/src/methods/manual_is_variant_and.rs b/clippy_lints/src/methods/manual_is_variant_and.rs index 8a0da622982c..66a53a3061ae 100644 --- a/clippy_lints/src/methods/manual_is_variant_and.rs +++ b/clippy_lints/src/methods/manual_is_variant_and.rs @@ -314,8 +314,8 @@ pub(super) fn check_is_some_is_none<'tcx>( .expr_ty_adjusted(recv) .peel_refs() .is_diag_item(cx, sym::Option) - && (is_some || msrv.meets(cx, msrvs::IS_NONE_OR)) && let Ok(map_func) = MapFunc::try_from(arg) + && (is_some || msrv.meets(cx, msrvs::IS_NONE_OR)) { let method = if is_some { "is_some_and" } else { "is_none_or" }; let lint_span = recv.span.to(call_span); diff --git a/clippy_lints/src/methods/manual_try_fold.rs b/clippy_lints/src/methods/manual_try_fold.rs index 6ef7abffb0b2..20dd840fd16f 100644 --- a/clippy_lints/src/methods/manual_try_fold.rs +++ b/clippy_lints/src/methods/manual_try_fold.rs @@ -29,9 +29,9 @@ pub(super) fn check<'tcx>( && let ExprKind::Path(qpath) = path.kind && let Res::Def(DefKind::Ctor(_, _), _) = cx.qpath_res(&qpath, path.hir_id) && let ExprKind::Closure(closure) = acc.kind + && let Some(args_snip) = closure.fn_arg_span.and_then(|fn_arg_span| fn_arg_span.get_text(cx)) && msrv.meets(cx, msrvs::ITERATOR_TRY_FOLD) && !is_from_proc_macro(cx, expr) - && let Some(args_snip) = closure.fn_arg_span.and_then(|fn_arg_span| fn_arg_span.get_text(cx)) { let init_snip = rest .is_empty() diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 22fca3647b75..2f671573a303 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -5728,9 +5728,9 @@ impl Methods { no_effect_replace::check(cx, expr, arg1, arg2); // Check for repeated `str::replace` calls to perform `collapsible_str_replace` lint - if self.msrv.meets(cx, msrvs::PATTERN_TRAIT_CHAR_ARRAY) - && name == sym::replace + if name == sym::replace && let Some((sym::replace, ..)) = method_call(recv) + && self.msrv.meets(cx, msrvs::PATTERN_TRAIT_CHAR_ARRAY) { collapsible_str_replace::check(cx, expr, arg1, arg2); } @@ -5801,10 +5801,9 @@ impl Methods { }, (sym::take, []) => needless_option_take::check(cx, expr, recv), (sym::then, [arg]) => { - if !self.msrv.meets(cx, msrvs::BOOL_THEN_SOME) { - return; + if self.msrv.meets(cx, msrvs::BOOL_THEN_SOME) { + unnecessary_lazy_eval::check(cx, expr, recv, arg, "then_some", true); } - unnecessary_lazy_eval::check(cx, expr, recv, arg, "then_some", true); }, (sym::try_into, []) if cx.ty_based_def(expr).opt_parent(cx).is_diag_item(cx, sym::TryInto) => { unnecessary_fallible_conversions::check_method(cx, expr); diff --git a/clippy_lints/src/methods/string_lit_chars_any.rs b/clippy_lints/src/methods/string_lit_chars_any.rs index 53c695e37847..e3ccfd02832d 100644 --- a/clippy_lints/src/methods/string_lit_chars_any.rs +++ b/clippy_lints/src/methods/string_lit_chars_any.rs @@ -33,9 +33,9 @@ pub(super) fn check<'tcx>( (false, true) => lhs, _ => return, } + && let Some(scrutinee_snip) = scrutinee.span.get_text(cx) && msrv.meets(cx, msrvs::MATCHES_MACRO) && !is_from_proc_macro(cx, expr) - && let Some(scrutinee_snip) = scrutinee.span.get_text(cx) { // Normalize the char using `map` so `join` doesn't use `Display`, if we don't then // something like `r"\"` will become `'\'`, which is of course invalid diff --git a/clippy_lints/src/operators/manual_is_multiple_of.rs b/clippy_lints/src/operators/manual_is_multiple_of.rs index 291d81097b51..4a13f798c103 100644 --- a/clippy_lints/src/operators/manual_is_multiple_of.rs +++ b/clippy_lints/src/operators/manual_is_multiple_of.rs @@ -19,8 +19,7 @@ pub(super) fn check<'tcx>( rhs: &'tcx Expr<'tcx>, msrv: Msrv, ) { - if msrv.meets(cx, msrvs::UNSIGNED_IS_MULTIPLE_OF) - && let Some(operand) = uint_compare_to_zero(cx, expr, op, lhs, rhs) + if let Some(operand) = uint_compare_to_zero(cx, expr, op, lhs, rhs) && let ExprKind::Binary(operand_op, operand_left, operand_right) = operand.kind && operand_op.node == BinOpKind::Rem && matches!( @@ -32,6 +31,7 @@ pub(super) fn check<'tcx>( ty::Uint(_) ) && expr_type_is_certain(cx, operand_left) + && msrv.meets(cx, msrvs::UNSIGNED_IS_MULTIPLE_OF) { let mut app = Applicability::MachineApplicable; let divisor = deref_sugg( diff --git a/clippy_lints/src/unnested_or_patterns.rs b/clippy_lints/src/unnested_or_patterns.rs index d1096a02fd63..c95d687e1e67 100644 --- a/clippy_lints/src/unnested_or_patterns.rs +++ b/clippy_lints/src/unnested_or_patterns.rs @@ -70,8 +70,8 @@ impl EarlyLintPass for UnnestedOrPatterns { } fn check_expr(&mut self, cx: &EarlyContext<'_>, e: &ast::Expr) { - if self.msrv.meets(msrvs::OR_PATTERNS) - && let ast::ExprKind::Let(pat, _, _, _) = &e.kind + if let ast::ExprKind::Let(pat, _, _, _) = &e.kind + && self.msrv.meets(msrvs::OR_PATTERNS) { lint_unnested_or_patterns(cx, pat); }