`assertions_on_constants`: Suggest using a const block when using a named constant (#15774)

changelog: [`assertions_on_constants`]: Suggest using a const block when
the assertion uses a named constant.
diff --git a/clippy_lints/src/double_parens.rs b/clippy_lints/src/double_parens.rs
index 4dd8f01..bddf470 100644
--- a/clippy_lints/src/double_parens.rs
+++ b/clippy_lints/src/double_parens.rs
@@ -1,5 +1,7 @@
-use clippy_utils::diagnostics::span_lint;
-use rustc_ast::ast::{Expr, ExprKind};
+use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::source::{HasSession, snippet_with_applicability, snippet_with_context};
+use rustc_ast::ast::{Expr, ExprKind, MethodCall};
+use rustc_errors::Applicability;
 use rustc_lint::{EarlyContext, EarlyLintPass};
 use rustc_session::declare_lint_pass;
 
@@ -24,7 +26,7 @@
     /// Use instead:
     /// ```no_run
     /// fn simple_no_parens() -> i32 {
-    ///     0
+    ///     (0)
     /// }
     ///
     /// # fn foo(bar: usize) {}
@@ -40,29 +42,54 @@
 
 impl EarlyLintPass for DoubleParens {
     fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &Expr) {
-        let span = match &expr.kind {
-            ExprKind::Paren(in_paren) if matches!(in_paren.kind, ExprKind::Paren(_) | ExprKind::Tup(_)) => expr.span,
-            ExprKind::Call(_, params)
-                if let [param] = &**params
-                    && let ExprKind::Paren(_) = param.kind =>
-            {
-                param.span
+        match &expr.kind {
+            // ((..))
+            // ^^^^^^ expr
+            //  ^^^^  inner
+            ExprKind::Paren(inner) if matches!(inner.kind, ExprKind::Paren(_) | ExprKind::Tup(_)) => {
+                // suggest removing the outer parens
+                if expr.span.eq_ctxt(inner.span) {
+                    let mut applicability = Applicability::MachineApplicable;
+                    // We don't need to use `snippet_with_context` here, because:
+                    // - if `inner`'s `ctxt` is from macro, we don't lint in the first place (see the check above)
+                    // - otherwise, calling `snippet_with_applicability` on a not-from-macro span is fine
+                    let sugg = snippet_with_applicability(cx.sess(), inner.span, "_", &mut applicability);
+                    span_lint_and_sugg(
+                        cx,
+                        DOUBLE_PARENS,
+                        expr.span,
+                        "unnecessary parentheses",
+                        "remove them",
+                        sugg.to_string(),
+                        applicability,
+                    );
+                }
             },
-            ExprKind::MethodCall(call)
-                if let [arg] = &*call.args
-                    && let ExprKind::Paren(_) = arg.kind =>
+
+            // func((n))
+            // ^^^^^^^^^ expr
+            //      ^^^  arg
+            //       ^   inner
+            ExprKind::Call(_, args) | ExprKind::MethodCall(box MethodCall { args, .. })
+                if let [arg] = &**args
+                    && let ExprKind::Paren(inner) = &arg.kind =>
             {
-                arg.span
+                // suggest removing the inner parens
+                if expr.span.eq_ctxt(arg.span) {
+                    let mut applicability = Applicability::MachineApplicable;
+                    let sugg = snippet_with_context(cx.sess(), inner.span, arg.span.ctxt(), "_", &mut applicability).0;
+                    span_lint_and_sugg(
+                        cx,
+                        DOUBLE_PARENS,
+                        arg.span,
+                        "unnecessary parentheses",
+                        "remove them",
+                        sugg.to_string(),
+                        applicability,
+                    );
+                }
             },
-            _ => return,
-        };
-        if !expr.span.from_expansion() {
-            span_lint(
-                cx,
-                DOUBLE_PARENS,
-                span,
-                "consider removing unnecessary double parentheses",
-            );
+            _ => {},
         }
     }
 }
diff --git a/clippy_lints/src/if_then_some_else_none.rs b/clippy_lints/src/if_then_some_else_none.rs
index b50d91f..f9fee29 100644
--- a/clippy_lints/src/if_then_some_else_none.rs
+++ b/clippy_lints/src/if_then_some_else_none.rs
@@ -79,6 +79,7 @@
             && !is_in_const_context(cx)
             && self.msrv.meets(cx, msrvs::BOOL_THEN)
             && !contains_return(then_block.stmts)
+            && then_block.expr.is_none_or(|expr| !contains_return(expr))
         {
             let method_name = if switch_to_eager_eval(cx, expr) && self.msrv.meets(cx, msrvs::BOOL_THEN_SOME) {
                 sym::then_some
diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs
index 0a955d2..c2c99904 100644
--- a/clippy_lints/src/lib.rs
+++ b/clippy_lints/src/lib.rs
@@ -482,7 +482,7 @@
     store.register_late_pass(|_| Box::new(needless_for_each::NeedlessForEach));
     store.register_late_pass(|_| Box::new(misc::LintPass));
     store.register_late_pass(|_| Box::new(eta_reduction::EtaReduction));
-    store.register_late_pass(|_| Box::new(mut_mut::MutMut));
+    store.register_late_pass(|_| Box::new(mut_mut::MutMut::default()));
     store.register_late_pass(|_| Box::new(unnecessary_mut_passed::UnnecessaryMutPassed));
     store.register_late_pass(|_| Box::<significant_drop_tightening::SignificantDropTightening<'_>>::default());
     store.register_late_pass(|_| Box::new(len_zero::LenZero));
diff --git a/clippy_lints/src/mem_replace.rs b/clippy_lints/src/mem_replace.rs
index e39916f..95ecef5 100644
--- a/clippy_lints/src/mem_replace.rs
+++ b/clippy_lints/src/mem_replace.rs
@@ -1,7 +1,7 @@
 use clippy_config::Conf;
 use clippy_utils::diagnostics::{span_lint_and_help, span_lint_and_sugg, span_lint_and_then};
 use clippy_utils::msrvs::{self, Msrv};
-use clippy_utils::source::{snippet, snippet_with_applicability};
+use clippy_utils::source::{snippet_with_applicability, snippet_with_context};
 use clippy_utils::sugg::Sugg;
 use clippy_utils::ty::is_non_aggregate_primitive_type;
 use clippy_utils::{
@@ -269,14 +269,11 @@
             ),
             |diag| {
                 if !expr.span.from_expansion() {
-                    let suggestion = format!("{top_crate}::mem::take({})", snippet(cx, dest.span, ""));
+                    let mut applicability = Applicability::MachineApplicable;
+                    let (dest_snip, _) = snippet_with_context(cx, dest.span, expr.span.ctxt(), "", &mut applicability);
+                    let suggestion = format!("{top_crate}::mem::take({dest_snip})");
 
-                    diag.span_suggestion(
-                        expr.span,
-                        "consider using",
-                        suggestion,
-                        Applicability::MachineApplicable,
-                    );
+                    diag.span_suggestion(expr.span, "consider using", suggestion, applicability);
                 }
             },
         );
diff --git a/clippy_lints/src/methods/lib.rs b/clippy_lints/src/methods/lib.rs
new file mode 100644
index 0000000..8403828
--- /dev/null
+++ b/clippy_lints/src/methods/lib.rs
@@ -0,0 +1,70 @@
+use clippy_utils::sym;
+use clippy_utils::ty::{implements_trait, is_copy};
+use rustc_hir::Mutability;
+use rustc_lint::LateContext;
+use rustc_middle::ty::{self, Ty};
+
+#[derive(Clone, Copy, PartialEq, Eq, Debug)]
+pub(super) enum SelfKind {
+    Value,
+    Ref,
+    RefMut,
+    No, // When we want the first argument type to be different than `Self`
+}
+
+impl SelfKind {
+    pub(super) fn matches<'a>(self, cx: &LateContext<'a>, parent_ty: Ty<'a>, ty: Ty<'a>) -> bool {
+        fn matches_value<'a>(cx: &LateContext<'a>, parent_ty: Ty<'a>, ty: Ty<'a>) -> bool {
+            if ty == parent_ty {
+                true
+            } else if let Some(boxed_ty) = ty.boxed_ty() {
+                boxed_ty == parent_ty
+            } else if let ty::Adt(adt_def, args) = ty.kind()
+                && matches!(cx.tcx.get_diagnostic_name(adt_def.did()), Some(sym::Rc | sym::Arc))
+            {
+                args.types().next() == Some(parent_ty)
+            } else {
+                false
+            }
+        }
+
+        fn matches_ref<'a>(cx: &LateContext<'a>, mutability: Mutability, parent_ty: Ty<'a>, ty: Ty<'a>) -> bool {
+            if let ty::Ref(_, t, m) = *ty.kind() {
+                return m == mutability && t == parent_ty;
+            }
+
+            let trait_sym = match mutability {
+                Mutability::Not => sym::AsRef,
+                Mutability::Mut => sym::AsMut,
+            };
+
+            let Some(trait_def_id) = cx.tcx.get_diagnostic_item(trait_sym) else {
+                return false;
+            };
+            implements_trait(cx, ty, trait_def_id, &[parent_ty.into()])
+        }
+
+        fn matches_none<'a>(cx: &LateContext<'a>, parent_ty: Ty<'a>, ty: Ty<'a>) -> bool {
+            !matches_value(cx, parent_ty, ty)
+                && !matches_ref(cx, Mutability::Not, parent_ty, ty)
+                && !matches_ref(cx, Mutability::Mut, parent_ty, ty)
+        }
+
+        match self {
+            Self::Value => matches_value(cx, parent_ty, ty),
+            Self::Ref => matches_ref(cx, Mutability::Not, parent_ty, ty) || ty == parent_ty && is_copy(cx, ty),
+            Self::RefMut => matches_ref(cx, Mutability::Mut, parent_ty, ty),
+            Self::No => matches_none(cx, parent_ty, ty),
+        }
+    }
+
+    #[must_use]
+    pub(super) fn description(self) -> &'static str {
+        match self {
+            Self::Value => "`self` by value",
+            Self::Ref => "`self` by reference",
+            Self::RefMut => "`self` by mutable reference",
+            Self::No => "no `self`",
+        }
+    }
+}
diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs
index a1cdab9..8c2948e 100644
--- a/clippy_lints/src/methods/mod.rs
+++ b/clippy_lints/src/methods/mod.rs
@@ -55,6 +55,7 @@
 mod iter_with_drain;
 mod iterator_step_by_zero;
 mod join_absolute_paths;
+mod lib;
 mod manual_c_str_literals;
 mod manual_contains;
 mod manual_inspect;
@@ -102,6 +103,7 @@
 mod search_is_some;
 mod seek_from_current;
 mod seek_to_start_instead_of_rewind;
+mod should_implement_trait;
 mod single_char_add_str;
 mod skip_while_next;
 mod sliced_string_as_bytes;
@@ -146,20 +148,18 @@
 
 use clippy_config::Conf;
 use clippy_utils::consts::{ConstEvalCtxt, Constant};
-use clippy_utils::diagnostics::{span_lint, span_lint_and_help};
+use clippy_utils::diagnostics::span_lint;
 use clippy_utils::macros::FormatArgsStorage;
 use clippy_utils::msrvs::{self, Msrv};
-use clippy_utils::ty::{contains_ty_adt_constructor_opaque, implements_trait, is_copy, is_type_diagnostic_item};
-use clippy_utils::{contains_return, is_bool, is_trait_method, iter_input_pats, peel_blocks, return_ty, sym};
+use clippy_utils::ty::contains_ty_adt_constructor_opaque;
+use clippy_utils::{contains_return, is_trait_method, iter_input_pats, peel_blocks, return_ty, sym};
 pub use path_ends_with_ext::DEFAULT_ALLOWED_DOTFILES;
-use rustc_abi::ExternAbi;
 use rustc_data_structures::fx::FxHashSet;
-use rustc_hir as hir;
-use rustc_hir::{Expr, ExprKind, Node, Stmt, StmtKind, TraitItem, TraitItemKind};
+use rustc_hir::{self as hir, Expr, ExprKind, Node, Stmt, StmtKind, TraitItem, TraitItemKind};
 use rustc_lint::{LateContext, LateLintPass, LintContext};
-use rustc_middle::ty::{self, TraitRef, Ty};
+use rustc_middle::ty::TraitRef;
 use rustc_session::impl_lint_pass;
-use rustc_span::{Span, Symbol, kw};
+use rustc_span::{Span, Symbol};
 
 declare_clippy_lint! {
     /// ### What it does
@@ -4889,48 +4889,17 @@
         if impl_item.span.in_external_macro(cx.sess().source_map()) {
             return;
         }
-        let name = impl_item.ident.name;
-        let parent = cx.tcx.hir_get_parent_item(impl_item.hir_id()).def_id;
-        let item = cx.tcx.hir_expect_item(parent);
-        let self_ty = cx.tcx.type_of(item.owner_id).instantiate_identity();
 
-        let implements_trait = matches!(item.kind, hir::ItemKind::Impl(hir::Impl { of_trait: Some(_), .. }));
         if let hir::ImplItemKind::Fn(ref sig, id) = impl_item.kind {
+            let parent = cx.tcx.hir_get_parent_item(impl_item.hir_id()).def_id;
+            let item = cx.tcx.hir_expect_item(parent);
+            let self_ty = cx.tcx.type_of(item.owner_id).instantiate_identity();
+            let implements_trait = matches!(item.kind, hir::ItemKind::Impl(hir::Impl { of_trait: Some(_), .. }));
+
             let method_sig = cx.tcx.fn_sig(impl_item.owner_id).instantiate_identity();
             let method_sig = cx.tcx.instantiate_bound_regions_with_erased(method_sig);
             let first_arg_ty_opt = method_sig.inputs().iter().next().copied();
-            // if this impl block implements a trait, lint in trait definition instead
-            if !implements_trait && cx.effective_visibilities.is_exported(impl_item.owner_id.def_id) {
-                // check missing trait implementations
-                for method_config in &TRAIT_METHODS {
-                    if name == method_config.method_name
-                        && sig.decl.inputs.len() == method_config.param_count
-                        && method_config.output_type.matches(&sig.decl.output)
-                        // in case there is no first arg, since we already have checked the number of arguments
-                        // it's should be always true
-                        && first_arg_ty_opt.is_none_or(|first_arg_ty| method_config
-                            .self_kind.matches(cx, self_ty, first_arg_ty)
-                            )
-                        && fn_header_equals(method_config.fn_header, sig.header)
-                        && method_config.lifetime_param_cond(impl_item)
-                    {
-                        span_lint_and_help(
-                            cx,
-                            SHOULD_IMPLEMENT_TRAIT,
-                            impl_item.span,
-                            format!(
-                                "method `{}` can be confused for the standard trait method `{}::{}`",
-                                method_config.method_name, method_config.trait_name, method_config.method_name
-                            ),
-                            None,
-                            format!(
-                                "consider implementing the trait `{}` or choosing a less ambiguous method name",
-                                method_config.trait_name
-                            ),
-                        );
-                    }
-                }
-            }
+            should_implement_trait::check_impl_item(cx, impl_item, self_ty, implements_trait, first_arg_ty_opt, sig);
 
             if sig.decl.implicit_self.has_implicit_self()
                 && !(self.avoid_breaking_exported_api
@@ -4940,7 +4909,7 @@
             {
                 wrong_self_convention::check(
                     cx,
-                    name,
+                    impl_item.ident.name,
                     self_ty,
                     first_arg_ty,
                     first_arg.pat.span,
@@ -4948,21 +4917,14 @@
                     false,
                 );
             }
-        }
 
-        // if this impl block implements a trait, lint in trait definition instead
-        if implements_trait {
-            return;
-        }
-
-        if let hir::ImplItemKind::Fn(_, _) = impl_item.kind {
-            let ret_ty = return_ty(cx, impl_item.owner_id);
-
-            if contains_ty_adt_constructor_opaque(cx, ret_ty, self_ty) {
-                return;
-            }
-
-            if name == sym::new && ret_ty != self_ty {
+            // if this impl block implements a trait, lint in trait definition instead
+            if !implements_trait
+                && impl_item.ident.name == sym::new
+                && let ret_ty = return_ty(cx, impl_item.owner_id)
+                && ret_ty != self_ty
+                && !contains_ty_adt_constructor_opaque(cx, ret_ty, self_ty)
+            {
                 span_lint(
                     cx,
                     NEW_RET_NO_SELF,
@@ -4978,41 +4940,41 @@
             return;
         }
 
-        if let TraitItemKind::Fn(ref sig, _) = item.kind
-            && sig.decl.implicit_self.has_implicit_self()
-            && let Some(first_arg_hir_ty) = sig.decl.inputs.first()
-            && let Some(&first_arg_ty) = cx
-                .tcx
-                .fn_sig(item.owner_id)
-                .instantiate_identity()
-                .inputs()
-                .skip_binder()
-                .first()
-        {
-            let self_ty = TraitRef::identity(cx.tcx, item.owner_id.to_def_id()).self_ty();
-            wrong_self_convention::check(
-                cx,
-                item.ident.name,
-                self_ty,
-                first_arg_ty,
-                first_arg_hir_ty.span,
-                false,
-                true,
-            );
-        }
+        if let TraitItemKind::Fn(ref sig, _) = item.kind {
+            if sig.decl.implicit_self.has_implicit_self()
+                && let Some(first_arg_hir_ty) = sig.decl.inputs.first()
+                && let Some(&first_arg_ty) = cx
+                    .tcx
+                    .fn_sig(item.owner_id)
+                    .instantiate_identity()
+                    .inputs()
+                    .skip_binder()
+                    .first()
+            {
+                let self_ty = TraitRef::identity(cx.tcx, item.owner_id.to_def_id()).self_ty();
+                wrong_self_convention::check(
+                    cx,
+                    item.ident.name,
+                    self_ty,
+                    first_arg_ty,
+                    first_arg_hir_ty.span,
+                    false,
+                    true,
+                );
+            }
 
-        if item.ident.name == sym::new
-            && let TraitItemKind::Fn(_, _) = item.kind
-            && let ret_ty = return_ty(cx, item.owner_id)
-            && let self_ty = TraitRef::identity(cx.tcx, item.owner_id.to_def_id()).self_ty()
-            && !ret_ty.contains(self_ty)
-        {
-            span_lint(
-                cx,
-                NEW_RET_NO_SELF,
-                item.span,
-                "methods called `new` usually return `Self`",
-            );
+            if item.ident.name == sym::new
+                && let ret_ty = return_ty(cx, item.owner_id)
+                && let self_ty = TraitRef::identity(cx.tcx, item.owner_id.to_def_id()).self_ty()
+                && !ret_ty.contains(self_ty)
+            {
+                span_lint(
+                    cx,
+                    NEW_RET_NO_SELF,
+                    item.span,
+                    "methods called `new` usually return `Self`",
+                );
+            }
         }
     }
 }
@@ -5720,183 +5682,3 @@
     lint_with_both_lhs_and_rhs!(chars_next_cmp_with_unwrap::check, cx, info);
     lint_with_both_lhs_and_rhs!(chars_last_cmp_with_unwrap::check, cx, info);
 }
-
-const FN_HEADER: hir::FnHeader = hir::FnHeader {
-    safety: hir::HeaderSafety::Normal(hir::Safety::Safe),
-    constness: hir::Constness::NotConst,
-    asyncness: hir::IsAsync::NotAsync,
-    abi: ExternAbi::Rust,
-};
-
-struct ShouldImplTraitCase {
-    trait_name: &'static str,
-    method_name: Symbol,
-    param_count: usize,
-    fn_header: hir::FnHeader,
-    // implicit self kind expected (none, self, &self, ...)
-    self_kind: SelfKind,
-    // checks against the output type
-    output_type: OutType,
-    // certain methods with explicit lifetimes can't implement the equivalent trait method
-    lint_explicit_lifetime: bool,
-}
-impl ShouldImplTraitCase {
-    const fn new(
-        trait_name: &'static str,
-        method_name: Symbol,
-        param_count: usize,
-        fn_header: hir::FnHeader,
-        self_kind: SelfKind,
-        output_type: OutType,
-        lint_explicit_lifetime: bool,
-    ) -> ShouldImplTraitCase {
-        ShouldImplTraitCase {
-            trait_name,
-            method_name,
-            param_count,
-            fn_header,
-            self_kind,
-            output_type,
-            lint_explicit_lifetime,
-        }
-    }
-
-    fn lifetime_param_cond(&self, impl_item: &hir::ImplItem<'_>) -> bool {
-        self.lint_explicit_lifetime
-            || !impl_item.generics.params.iter().any(|p| {
-                matches!(
-                    p.kind,
-                    hir::GenericParamKind::Lifetime {
-                        kind: hir::LifetimeParamKind::Explicit
-                    }
-                )
-            })
-    }
-}
-
-#[rustfmt::skip]
-const TRAIT_METHODS: [ShouldImplTraitCase; 30] = [
-    ShouldImplTraitCase::new("std::ops::Add", sym::add,  2,  FN_HEADER,  SelfKind::Value,  OutType::Any, true),
-    ShouldImplTraitCase::new("std::convert::AsMut", sym::as_mut,  1,  FN_HEADER,  SelfKind::RefMut,  OutType::Ref, true),
-    ShouldImplTraitCase::new("std::convert::AsRef", sym::as_ref,  1,  FN_HEADER,  SelfKind::Ref,  OutType::Ref, true),
-    ShouldImplTraitCase::new("std::ops::BitAnd", sym::bitand,  2,  FN_HEADER,  SelfKind::Value,  OutType::Any, true),
-    ShouldImplTraitCase::new("std::ops::BitOr", sym::bitor,  2,  FN_HEADER,  SelfKind::Value,  OutType::Any, true),
-    ShouldImplTraitCase::new("std::ops::BitXor", sym::bitxor,  2,  FN_HEADER,  SelfKind::Value,  OutType::Any, true),
-    ShouldImplTraitCase::new("std::borrow::Borrow", sym::borrow,  1,  FN_HEADER,  SelfKind::Ref,  OutType::Ref, true),
-    ShouldImplTraitCase::new("std::borrow::BorrowMut", sym::borrow_mut,  1,  FN_HEADER,  SelfKind::RefMut,  OutType::Ref, true),
-    ShouldImplTraitCase::new("std::clone::Clone", sym::clone,  1,  FN_HEADER,  SelfKind::Ref,  OutType::Any, true),
-    ShouldImplTraitCase::new("std::cmp::Ord", sym::cmp,  2,  FN_HEADER,  SelfKind::Ref,  OutType::Any, true),
-    ShouldImplTraitCase::new("std::default::Default", kw::Default,  0,  FN_HEADER,  SelfKind::No,  OutType::Any, true),
-    ShouldImplTraitCase::new("std::ops::Deref", sym::deref,  1,  FN_HEADER,  SelfKind::Ref,  OutType::Ref, true),
-    ShouldImplTraitCase::new("std::ops::DerefMut", sym::deref_mut,  1,  FN_HEADER,  SelfKind::RefMut,  OutType::Ref, true),
-    ShouldImplTraitCase::new("std::ops::Div", sym::div,  2,  FN_HEADER,  SelfKind::Value,  OutType::Any, true),
-    ShouldImplTraitCase::new("std::ops::Drop", sym::drop,  1,  FN_HEADER,  SelfKind::RefMut,  OutType::Unit, true),
-    ShouldImplTraitCase::new("std::cmp::PartialEq", sym::eq,  2,  FN_HEADER,  SelfKind::Ref,  OutType::Bool, true),
-    ShouldImplTraitCase::new("std::iter::FromIterator", sym::from_iter,  1,  FN_HEADER,  SelfKind::No,  OutType::Any, true),
-    ShouldImplTraitCase::new("std::str::FromStr", sym::from_str,  1,  FN_HEADER,  SelfKind::No,  OutType::Any, true),
-    ShouldImplTraitCase::new("std::hash::Hash", sym::hash,  2,  FN_HEADER,  SelfKind::Ref,  OutType::Unit, true),
-    ShouldImplTraitCase::new("std::ops::Index", sym::index,  2,  FN_HEADER,  SelfKind::Ref,  OutType::Ref, true),
-    ShouldImplTraitCase::new("std::ops::IndexMut", sym::index_mut,  2,  FN_HEADER,  SelfKind::RefMut,  OutType::Ref, true),
-    ShouldImplTraitCase::new("std::iter::IntoIterator", sym::into_iter,  1,  FN_HEADER,  SelfKind::Value,  OutType::Any, true),
-    ShouldImplTraitCase::new("std::ops::Mul", sym::mul,  2,  FN_HEADER,  SelfKind::Value,  OutType::Any, true),
-    ShouldImplTraitCase::new("std::ops::Neg", sym::neg,  1,  FN_HEADER,  SelfKind::Value,  OutType::Any, true),
-    ShouldImplTraitCase::new("std::iter::Iterator", sym::next,  1,  FN_HEADER,  SelfKind::RefMut,  OutType::Any, false),
-    ShouldImplTraitCase::new("std::ops::Not", sym::not,  1,  FN_HEADER,  SelfKind::Value,  OutType::Any, true),
-    ShouldImplTraitCase::new("std::ops::Rem", sym::rem,  2,  FN_HEADER,  SelfKind::Value,  OutType::Any, true),
-    ShouldImplTraitCase::new("std::ops::Shl", sym::shl,  2,  FN_HEADER,  SelfKind::Value,  OutType::Any, true),
-    ShouldImplTraitCase::new("std::ops::Shr", sym::shr,  2,  FN_HEADER,  SelfKind::Value,  OutType::Any, true),
-    ShouldImplTraitCase::new("std::ops::Sub", sym::sub,  2,  FN_HEADER,  SelfKind::Value,  OutType::Any, true),
-];
-
-#[derive(Clone, Copy, PartialEq, Eq, Debug)]
-enum SelfKind {
-    Value,
-    Ref,
-    RefMut,
-    No, // When we want the first argument type to be different than `Self`
-}
-
-impl SelfKind {
-    fn matches<'a>(self, cx: &LateContext<'a>, parent_ty: Ty<'a>, ty: Ty<'a>) -> bool {
-        fn matches_value<'a>(cx: &LateContext<'a>, parent_ty: Ty<'a>, ty: Ty<'a>) -> bool {
-            if ty == parent_ty {
-                true
-            } else if let Some(boxed_ty) = ty.boxed_ty() {
-                boxed_ty == parent_ty
-            } else if is_type_diagnostic_item(cx, ty, sym::Rc) || is_type_diagnostic_item(cx, ty, sym::Arc) {
-                if let ty::Adt(_, args) = ty.kind() {
-                    args.types().next() == Some(parent_ty)
-                } else {
-                    false
-                }
-            } else {
-                false
-            }
-        }
-
-        fn matches_ref<'a>(cx: &LateContext<'a>, mutability: hir::Mutability, parent_ty: Ty<'a>, ty: Ty<'a>) -> bool {
-            if let ty::Ref(_, t, m) = *ty.kind() {
-                return m == mutability && t == parent_ty;
-            }
-
-            let trait_sym = match mutability {
-                hir::Mutability::Not => sym::AsRef,
-                hir::Mutability::Mut => sym::AsMut,
-            };
-
-            let Some(trait_def_id) = cx.tcx.get_diagnostic_item(trait_sym) else {
-                return false;
-            };
-            implements_trait(cx, ty, trait_def_id, &[parent_ty.into()])
-        }
-
-        fn matches_none<'a>(cx: &LateContext<'a>, parent_ty: Ty<'a>, ty: Ty<'a>) -> bool {
-            !matches_value(cx, parent_ty, ty)
-                && !matches_ref(cx, hir::Mutability::Not, parent_ty, ty)
-                && !matches_ref(cx, hir::Mutability::Mut, parent_ty, ty)
-        }
-
-        match self {
-            Self::Value => matches_value(cx, parent_ty, ty),
-            Self::Ref => matches_ref(cx, hir::Mutability::Not, parent_ty, ty) || ty == parent_ty && is_copy(cx, ty),
-            Self::RefMut => matches_ref(cx, hir::Mutability::Mut, parent_ty, ty),
-            Self::No => matches_none(cx, parent_ty, ty),
-        }
-    }
-
-    #[must_use]
-    fn description(self) -> &'static str {
-        match self {
-            Self::Value => "`self` by value",
-            Self::Ref => "`self` by reference",
-            Self::RefMut => "`self` by mutable reference",
-            Self::No => "no `self`",
-        }
-    }
-}
-
-#[derive(Clone, Copy)]
-enum OutType {
-    Unit,
-    Bool,
-    Any,
-    Ref,
-}
-
-impl OutType {
-    fn matches(self, ty: &hir::FnRetTy<'_>) -> bool {
-        let is_unit = |ty: &hir::Ty<'_>| matches!(ty.kind, hir::TyKind::Tup(&[]));
-        match (self, ty) {
-            (Self::Unit, &hir::FnRetTy::DefaultReturn(_)) => true,
-            (Self::Unit, &hir::FnRetTy::Return(ty)) if is_unit(ty) => true,
-            (Self::Bool, &hir::FnRetTy::Return(ty)) if is_bool(ty) => true,
-            (Self::Any, &hir::FnRetTy::Return(ty)) if !is_unit(ty) => true,
-            (Self::Ref, &hir::FnRetTy::Return(ty)) => matches!(ty.kind, hir::TyKind::Ref(_, _)),
-            _ => false,
-        }
-    }
-}
-
-fn fn_header_equals(expected: hir::FnHeader, actual: hir::FnHeader) -> bool {
-    expected.constness == actual.constness && expected.safety == actual.safety && expected.asyncness == actual.asyncness
-}
diff --git a/clippy_lints/src/methods/should_implement_trait.rs b/clippy_lints/src/methods/should_implement_trait.rs
new file mode 100644
index 0000000..5f13b8c
--- /dev/null
+++ b/clippy_lints/src/methods/should_implement_trait.rs
@@ -0,0 +1,171 @@
+use clippy_utils::diagnostics::span_lint_and_help;
+use clippy_utils::{is_bool, sym};
+use rustc_abi::ExternAbi;
+use rustc_hir as hir;
+use rustc_hir::{FnSig, ImplItem};
+use rustc_lint::LateContext;
+use rustc_middle::ty::Ty;
+use rustc_span::edition::Edition::{self, Edition2015, Edition2021};
+use rustc_span::{Symbol, kw};
+
+use super::SHOULD_IMPLEMENT_TRAIT;
+use super::lib::SelfKind;
+
+pub(super) fn check_impl_item<'tcx>(
+    cx: &LateContext<'tcx>,
+    impl_item: &'tcx ImplItem<'_>,
+    self_ty: Ty<'tcx>,
+    impl_implements_trait: bool,
+    first_arg_ty_opt: Option<Ty<'tcx>>,
+    sig: &FnSig<'_>,
+) {
+    // if this impl block implements a trait, lint in trait definition instead
+    if !impl_implements_trait && cx.effective_visibilities.is_exported(impl_item.owner_id.def_id) {
+        // check missing trait implementations
+        for method_config in &TRAIT_METHODS {
+            if impl_item.ident.name == method_config.method_name
+                && sig.decl.inputs.len() == method_config.param_count
+                && method_config.output_type.matches(&sig.decl.output)
+                // in case there is no first arg, since we already have checked the number of arguments
+                // it's should be always true
+                && first_arg_ty_opt
+                    .is_none_or(|first_arg_ty| method_config.self_kind.matches(cx, self_ty, first_arg_ty))
+                && fn_header_equals(method_config.fn_header, sig.header)
+                && method_config.lifetime_param_cond(impl_item)
+                && method_config.in_prelude_since <= cx.tcx.sess.edition()
+            {
+                span_lint_and_help(
+                    cx,
+                    SHOULD_IMPLEMENT_TRAIT,
+                    impl_item.span,
+                    format!(
+                        "method `{}` can be confused for the standard trait method `{}::{}`",
+                        method_config.method_name, method_config.trait_name, method_config.method_name
+                    ),
+                    None,
+                    format!(
+                        "consider implementing the trait `{}` or choosing a less ambiguous method name",
+                        method_config.trait_name
+                    ),
+                );
+            }
+        }
+    }
+}
+
+const FN_HEADER: hir::FnHeader = hir::FnHeader {
+    safety: hir::HeaderSafety::Normal(hir::Safety::Safe),
+    constness: hir::Constness::NotConst,
+    asyncness: hir::IsAsync::NotAsync,
+    abi: ExternAbi::Rust,
+};
+
+struct ShouldImplTraitCase {
+    trait_name: &'static str,
+    method_name: Symbol,
+    param_count: usize,
+    fn_header: hir::FnHeader,
+    // implicit self kind expected (none, self, &self, ...)
+    self_kind: SelfKind,
+    // checks against the output type
+    output_type: OutType,
+    // certain methods with explicit lifetimes can't implement the equivalent trait method
+    lint_explicit_lifetime: bool,
+    in_prelude_since: Edition,
+}
+impl ShouldImplTraitCase {
+    #[expect(clippy::too_many_arguments)]
+    const fn new(
+        trait_name: &'static str,
+        method_name: Symbol,
+        param_count: usize,
+        fn_header: hir::FnHeader,
+        self_kind: SelfKind,
+        output_type: OutType,
+        lint_explicit_lifetime: bool,
+        in_prelude_since: Edition,
+    ) -> ShouldImplTraitCase {
+        ShouldImplTraitCase {
+            trait_name,
+            method_name,
+            param_count,
+            fn_header,
+            self_kind,
+            output_type,
+            lint_explicit_lifetime,
+            in_prelude_since,
+        }
+    }
+
+    fn lifetime_param_cond(&self, impl_item: &ImplItem<'_>) -> bool {
+        self.lint_explicit_lifetime
+            || !impl_item.generics.params.iter().any(|p| {
+                matches!(
+                    p.kind,
+                    hir::GenericParamKind::Lifetime {
+                        kind: hir::LifetimeParamKind::Explicit
+                    }
+                )
+            })
+    }
+}
+
+#[rustfmt::skip]
+const TRAIT_METHODS: [ShouldImplTraitCase; 30] = [
+    ShouldImplTraitCase::new("std::ops::Add",           sym::add,        2,  FN_HEADER, SelfKind::Value,  OutType::Any,  true,  Edition2015),
+    ShouldImplTraitCase::new("std::convert::AsMut",     sym::as_mut,     1,  FN_HEADER, SelfKind::RefMut, OutType::Ref,  true,  Edition2015),
+    ShouldImplTraitCase::new("std::convert::AsRef",     sym::as_ref,     1,  FN_HEADER, SelfKind::Ref,    OutType::Ref,  true,  Edition2015),
+    ShouldImplTraitCase::new("std::ops::BitAnd",        sym::bitand,     2,  FN_HEADER, SelfKind::Value,  OutType::Any,  true,  Edition2015),
+    ShouldImplTraitCase::new("std::ops::BitOr",         sym::bitor,      2,  FN_HEADER, SelfKind::Value,  OutType::Any,  true,  Edition2015),
+    ShouldImplTraitCase::new("std::ops::BitXor",        sym::bitxor,     2,  FN_HEADER, SelfKind::Value,  OutType::Any,  true,  Edition2015),
+    ShouldImplTraitCase::new("std::borrow::Borrow",     sym::borrow,     1,  FN_HEADER, SelfKind::Ref,    OutType::Ref,  true,  Edition2015),
+    ShouldImplTraitCase::new("std::borrow::BorrowMut",  sym::borrow_mut, 1,  FN_HEADER, SelfKind::RefMut, OutType::Ref,  true,  Edition2015),
+    ShouldImplTraitCase::new("std::clone::Clone",       sym::clone,      1,  FN_HEADER, SelfKind::Ref,    OutType::Any,  true,  Edition2015),
+    ShouldImplTraitCase::new("std::cmp::Ord",           sym::cmp,        2,  FN_HEADER, SelfKind::Ref,    OutType::Any,  true,  Edition2015),
+    ShouldImplTraitCase::new("std::default::Default",   kw::Default,     0,  FN_HEADER, SelfKind::No,     OutType::Any,  true,  Edition2015),
+    ShouldImplTraitCase::new("std::ops::Deref",         sym::deref,      1,  FN_HEADER, SelfKind::Ref,    OutType::Ref,  true,  Edition2015),
+    ShouldImplTraitCase::new("std::ops::DerefMut",      sym::deref_mut,  1,  FN_HEADER, SelfKind::RefMut, OutType::Ref,  true,  Edition2015),
+    ShouldImplTraitCase::new("std::ops::Div",           sym::div,        2,  FN_HEADER, SelfKind::Value,  OutType::Any,  true,  Edition2015),
+    ShouldImplTraitCase::new("std::ops::Drop",          sym::drop,       1,  FN_HEADER, SelfKind::RefMut, OutType::Unit, true,  Edition2015),
+    ShouldImplTraitCase::new("std::cmp::PartialEq",     sym::eq,         2,  FN_HEADER, SelfKind::Ref,    OutType::Bool, true,  Edition2015),
+    ShouldImplTraitCase::new("std::iter::FromIterator", sym::from_iter,  1,  FN_HEADER, SelfKind::No,     OutType::Any,  true,  Edition2021),
+    ShouldImplTraitCase::new("std::str::FromStr",       sym::from_str,   1,  FN_HEADER, SelfKind::No,     OutType::Any,  true,  Edition2015),
+    ShouldImplTraitCase::new("std::hash::Hash",         sym::hash,       2,  FN_HEADER, SelfKind::Ref,    OutType::Unit, true,  Edition2015),
+    ShouldImplTraitCase::new("std::ops::Index",         sym::index,      2,  FN_HEADER, SelfKind::Ref,    OutType::Ref,  true,  Edition2015),
+    ShouldImplTraitCase::new("std::ops::IndexMut",      sym::index_mut,  2,  FN_HEADER, SelfKind::RefMut, OutType::Ref,  true,  Edition2015),
+    ShouldImplTraitCase::new("std::iter::IntoIterator", sym::into_iter,  1,  FN_HEADER, SelfKind::Value,  OutType::Any,  true,  Edition2015),
+    ShouldImplTraitCase::new("std::ops::Mul",           sym::mul,        2,  FN_HEADER, SelfKind::Value,  OutType::Any,  true,  Edition2015),
+    ShouldImplTraitCase::new("std::ops::Neg",           sym::neg,        1,  FN_HEADER, SelfKind::Value,  OutType::Any,  true,  Edition2015),
+    ShouldImplTraitCase::new("std::iter::Iterator",     sym::next,       1,  FN_HEADER, SelfKind::RefMut, OutType::Any,  false, Edition2015),
+    ShouldImplTraitCase::new("std::ops::Not",           sym::not,        1,  FN_HEADER, SelfKind::Value,  OutType::Any,  true,  Edition2015),
+    ShouldImplTraitCase::new("std::ops::Rem",           sym::rem,        2,  FN_HEADER, SelfKind::Value,  OutType::Any,  true,  Edition2015),
+    ShouldImplTraitCase::new("std::ops::Shl",           sym::shl,        2,  FN_HEADER, SelfKind::Value,  OutType::Any,  true,  Edition2015),
+    ShouldImplTraitCase::new("std::ops::Shr",           sym::shr,        2,  FN_HEADER, SelfKind::Value,  OutType::Any,  true,  Edition2015),
+    ShouldImplTraitCase::new("std::ops::Sub",           sym::sub,        2,  FN_HEADER, SelfKind::Value,  OutType::Any,  true,  Edition2015),
+];
+
+#[derive(Clone, Copy)]
+enum OutType {
+    Unit,
+    Bool,
+    Any,
+    Ref,
+}
+
+impl OutType {
+    fn matches(self, ty: &hir::FnRetTy<'_>) -> bool {
+        let is_unit = |ty: &hir::Ty<'_>| matches!(ty.kind, hir::TyKind::Tup(&[]));
+        match (self, ty) {
+            (Self::Unit, &hir::FnRetTy::DefaultReturn(_)) => true,
+            (Self::Unit, &hir::FnRetTy::Return(ty)) if is_unit(ty) => true,
+            (Self::Bool, &hir::FnRetTy::Return(ty)) if is_bool(ty) => true,
+            (Self::Any, &hir::FnRetTy::Return(ty)) if !is_unit(ty) => true,
+            (Self::Ref, &hir::FnRetTy::Return(ty)) => matches!(ty.kind, hir::TyKind::Ref(_, _)),
+            _ => false,
+        }
+    }
+}
+
+fn fn_header_equals(expected: hir::FnHeader, actual: hir::FnHeader) -> bool {
+    expected.constness == actual.constness && expected.safety == actual.safety && expected.asyncness == actual.asyncness
+}
diff --git a/clippy_lints/src/methods/wrong_self_convention.rs b/clippy_lints/src/methods/wrong_self_convention.rs
index ad9b3c3..74b297c 100644
--- a/clippy_lints/src/methods/wrong_self_convention.rs
+++ b/clippy_lints/src/methods/wrong_self_convention.rs
@@ -1,12 +1,13 @@
-use crate::methods::SelfKind;
 use clippy_utils::diagnostics::span_lint_and_help;
 use clippy_utils::ty::is_copy;
+use itertools::Itertools;
 use rustc_lint::LateContext;
 use rustc_middle::ty::Ty;
 use rustc_span::{Span, Symbol};
 use std::fmt;
 
 use super::WRONG_SELF_CONVENTION;
+use super::lib::SelfKind;
 
 #[rustfmt::skip]
 const CONVENTIONS: [(&[Convention], &[SelfKind]); 9] = [
@@ -61,20 +62,20 @@
 impl fmt::Display for Convention {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
         match *self {
-            Self::Eq(this) => format!("`{this}`").fmt(f),
-            Self::StartsWith(this) => format!("`{this}*`").fmt(f),
-            Self::EndsWith(this) => format!("`*{this}`").fmt(f),
-            Self::NotEndsWith(this) => format!("`~{this}`").fmt(f),
+            Self::Eq(this) => write!(f, "`{this}`"),
+            Self::StartsWith(this) => write!(f, "`{this}*`"),
+            Self::EndsWith(this) => write!(f, "`*{this}`"),
+            Self::NotEndsWith(this) => write!(f, "`~{this}`"),
             Self::IsSelfTypeCopy(is_true) => {
-                format!("`self` type is{} `Copy`", if is_true { "" } else { " not" }).fmt(f)
+                write!(f, "`self` type is{} `Copy`", if is_true { "" } else { " not" })
             },
             Self::ImplementsTrait(is_true) => {
                 let (negation, s_suffix) = if is_true { ("", "s") } else { (" does not", "") };
-                format!("method{negation} implement{s_suffix} a trait").fmt(f)
+                write!(f, "method{negation} implement{s_suffix} a trait")
             },
             Self::IsTraitItem(is_true) => {
                 let suffix = if is_true { " is" } else { " is not" };
-                format!("method{suffix} a trait item").fmt(f)
+                write!(f, "method{suffix} a trait item")
             },
         }
     }
@@ -115,18 +116,9 @@
 
                     let s = conventions
                         .iter()
-                        .filter_map(|conv| {
-                            if (cut_ends_with_conv && matches!(conv, Convention::NotEndsWith(_)))
-                                || matches!(conv, Convention::ImplementsTrait(_))
-                                || matches!(conv, Convention::IsTraitItem(_))
-                            {
-                                None
-                            } else {
-                                Some(conv.to_string())
-                            }
-                        })
-                        .collect::<Vec<_>>()
-                        .join(" and ");
+                        .filter(|conv| !(cut_ends_with_conv && matches!(conv, Convention::NotEndsWith(_))))
+                        .filter(|conv| !matches!(conv, Convention::ImplementsTrait(_) | Convention::IsTraitItem(_)))
+                        .format(" and ");
 
                     format!("methods with the following characteristics: ({s})")
                 } else {
@@ -140,11 +132,7 @@
                 first_arg_span,
                 format!(
                     "{suggestion} usually take {}",
-                    &self_kinds
-                        .iter()
-                        .map(|k| k.description())
-                        .collect::<Vec<_>>()
-                        .join(" or ")
+                    self_kinds.iter().map(|k| k.description()).format(" or ")
                 ),
                 None,
                 "consider choosing a less ambiguous name",
diff --git a/clippy_lints/src/mut_mut.rs b/clippy_lints/src/mut_mut.rs
index d98c70e..588afd8 100644
--- a/clippy_lints/src/mut_mut.rs
+++ b/clippy_lints/src/mut_mut.rs
@@ -1,31 +1,51 @@
-use clippy_utils::diagnostics::{span_lint, span_lint_hir};
+use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_hir_and_then};
 use clippy_utils::higher;
-use rustc_hir::{self as hir, AmbigArg, intravisit};
+use clippy_utils::source::snippet_with_applicability;
+use clippy_utils::sugg::Sugg;
+use rustc_data_structures::fx::FxHashSet;
+use rustc_errors::Applicability;
+use rustc_hir::{self as hir, AmbigArg, BorrowKind, Expr, ExprKind, HirId, Mutability, TyKind, intravisit};
 use rustc_lint::{LateContext, LateLintPass, LintContext};
 use rustc_middle::ty;
-use rustc_session::declare_lint_pass;
+use rustc_session::impl_lint_pass;
 
 declare_clippy_lint! {
     /// ### What it does
     /// Checks for instances of `mut mut` references.
     ///
     /// ### Why is this bad?
-    /// Multiple `mut`s don't add anything meaningful to the
-    /// source. This is either a copy'n'paste error, or it shows a fundamental
-    /// misunderstanding of references.
+    /// This is usually just a typo or a misunderstanding of how references work.
     ///
     /// ### Example
     /// ```no_run
-    /// # let mut y = 1;
-    /// let x = &mut &mut y;
+    /// let x = &mut &mut 1;
+    ///
+    /// let mut x = &mut 1;
+    /// let y = &mut x;
+    ///
+    /// fn foo(x: &mut &mut u32) {}
+    /// ```
+    /// Use instead
+    /// ```no_run
+    /// let x = &mut 1;
+    ///
+    /// let mut x = &mut 1;
+    /// let y = &mut *x; // reborrow
+    ///
+    /// fn foo(x: &mut u32) {}
     /// ```
     #[clippy::version = "pre 1.29.0"]
     pub MUT_MUT,
     pedantic,
-    "usage of double-mut refs, e.g., `&mut &mut ...`"
+    "usage of double mut-refs, e.g., `&mut &mut ...`"
 }
 
-declare_lint_pass!(MutMut => [MUT_MUT]);
+impl_lint_pass!(MutMut => [MUT_MUT]);
+
+#[derive(Default)]
+pub(crate) struct MutMut {
+    seen_tys: FxHashSet<HirId>,
+}
 
 impl<'tcx> LateLintPass<'tcx> for MutMut {
     fn check_block(&mut self, cx: &LateContext<'tcx>, block: &'tcx hir::Block<'_>) {
@@ -33,17 +53,48 @@
     }
 
     fn check_ty(&mut self, cx: &LateContext<'tcx>, ty: &'tcx hir::Ty<'_, AmbigArg>) {
-        if let hir::TyKind::Ref(_, mty) = ty.kind
-            && mty.mutbl == hir::Mutability::Mut
-            && let hir::TyKind::Ref(_, mty) = mty.ty.kind
-            && mty.mutbl == hir::Mutability::Mut
+        if let TyKind::Ref(_, mty) = ty.kind
+            && mty.mutbl == Mutability::Mut
+            && let TyKind::Ref(_, mty2) = mty.ty.kind
+            && mty2.mutbl == Mutability::Mut
             && !ty.span.in_external_macro(cx.sess().source_map())
         {
-            span_lint(
+            if self.seen_tys.contains(&ty.hir_id) {
+                // we have 2+ `&mut`s, e.g., `&mut &mut &mut x`
+                // and we have already flagged on the outermost `&mut &mut (&mut x)`,
+                // so don't flag the inner `&mut &mut (x)`
+                return;
+            }
+
+            // if there is an even longer chain, like `&mut &mut &mut x`, suggest peeling off
+            // all extra ones at once
+            let (mut t, mut t2) = (mty.ty, mty2.ty);
+            let mut many_muts = false;
+            loop {
+                // this should allow us to remember all the nested types, so that the `contains`
+                // above fails faster
+                self.seen_tys.insert(t.hir_id);
+                if let TyKind::Ref(_, next) = t2.kind
+                    && next.mutbl == Mutability::Mut
+                {
+                    (t, t2) = (t2, next.ty);
+                    many_muts = true;
+                } else {
+                    break;
+                }
+            }
+
+            let mut applicability = Applicability::MaybeIncorrect;
+            let sugg = snippet_with_applicability(cx.sess(), t.span, "..", &mut applicability);
+            let suffix = if many_muts { "s" } else { "" };
+            span_lint_and_sugg(
                 cx,
                 MUT_MUT,
                 ty.span,
-                "generally you want to avoid `&mut &mut _` if possible",
+                "a type of form `&mut &mut _`",
+                format!("remove the extra `&mut`{suffix}"),
+                sugg.to_string(),
+                applicability,
             );
         }
     }
@@ -54,7 +105,7 @@
 }
 
 impl<'tcx> intravisit::Visitor<'tcx> for MutVisitor<'_, 'tcx> {
-    fn visit_expr(&mut self, expr: &'tcx hir::Expr<'_>) {
+    fn visit_expr(&mut self, expr: &'tcx Expr<'_>) {
         if expr.span.in_external_macro(self.cx.sess().source_map()) {
             return;
         }
@@ -68,24 +119,60 @@
             // Let's ignore the generated code.
             intravisit::walk_expr(self, arg);
             intravisit::walk_expr(self, body);
-        } else if let hir::ExprKind::AddrOf(hir::BorrowKind::Ref, hir::Mutability::Mut, e) = expr.kind {
-            if let hir::ExprKind::AddrOf(hir::BorrowKind::Ref, hir::Mutability::Mut, _) = e.kind {
-                span_lint_hir(
+        } else if let ExprKind::AddrOf(BorrowKind::Ref, Mutability::Mut, e) = expr.kind {
+            if let ExprKind::AddrOf(BorrowKind::Ref, Mutability::Mut, e2) = e.kind {
+                if !expr.span.eq_ctxt(e.span) {
+                    return;
+                }
+
+                // if there is an even longer chain, like `&mut &mut &mut x`, suggest peeling off
+                // all extra ones at once
+                let (mut e, mut e2) = (e, e2);
+                let mut many_muts = false;
+                loop {
+                    if !e.span.eq_ctxt(e2.span) {
+                        return;
+                    }
+                    if let ExprKind::AddrOf(BorrowKind::Ref, Mutability::Mut, next) = e2.kind {
+                        (e, e2) = (e2, next);
+                        many_muts = true;
+                    } else {
+                        break;
+                    }
+                }
+
+                let mut applicability = Applicability::MaybeIncorrect;
+                let sugg = Sugg::hir_with_applicability(self.cx, e, "..", &mut applicability);
+                let suffix = if many_muts { "s" } else { "" };
+                span_lint_hir_and_then(
                     self.cx,
                     MUT_MUT,
                     expr.hir_id,
                     expr.span,
-                    "generally you want to avoid `&mut &mut _` if possible",
+                    "an expression of form `&mut &mut _`",
+                    |diag| {
+                        diag.span_suggestion(
+                            expr.span,
+                            format!("remove the extra `&mut`{suffix}"),
+                            sugg,
+                            applicability,
+                        );
+                    },
                 );
-            } else if let ty::Ref(_, ty, hir::Mutability::Mut) = self.cx.typeck_results().expr_ty(e).kind()
+            } else if let ty::Ref(_, ty, Mutability::Mut) = self.cx.typeck_results().expr_ty(e).kind()
                 && ty.peel_refs().is_sized(self.cx.tcx, self.cx.typing_env())
             {
-                span_lint_hir(
+                let mut applicability = Applicability::MaybeIncorrect;
+                let sugg = Sugg::hir_with_applicability(self.cx, e, "..", &mut applicability).mut_addr_deref();
+                span_lint_hir_and_then(
                     self.cx,
                     MUT_MUT,
                     expr.hir_id,
                     expr.span,
-                    "this expression mutably borrows a mutable reference. Consider reborrowing",
+                    "this expression mutably borrows a mutable reference",
+                    |diag| {
+                        diag.span_suggestion(expr.span, "reborrow instead", sugg, applicability);
+                    },
                 );
             }
         }
diff --git a/clippy_lints/src/new_without_default.rs b/clippy_lints/src/new_without_default.rs
index b598a39..6fc034b 100644
--- a/clippy_lints/src/new_without_default.rs
+++ b/clippy_lints/src/new_without_default.rs
@@ -1,6 +1,6 @@
 use clippy_utils::diagnostics::span_lint_hir_and_then;
 use clippy_utils::return_ty;
-use clippy_utils::source::snippet;
+use clippy_utils::source::snippet_with_applicability;
 use clippy_utils::sugg::DiagExt;
 use rustc_errors::Applicability;
 use rustc_hir as hir;
@@ -58,116 +58,132 @@
 
 impl<'tcx> LateLintPass<'tcx> for NewWithoutDefault {
     fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::Item<'_>) {
-        if let hir::ItemKind::Impl(hir::Impl {
+        let hir::ItemKind::Impl(hir::Impl {
             of_trait: None,
             generics,
             self_ty: impl_self_ty,
             ..
         }) = item.kind
+        else {
+            return;
+        };
+
+        for assoc_item in cx
+            .tcx
+            .associated_items(item.owner_id.def_id)
+            .filter_by_name_unhygienic(sym::new)
         {
-            for assoc_item in cx
-                .tcx
-                .associated_items(item.owner_id.def_id)
-                .filter_by_name_unhygienic(sym::new)
+            if let AssocKind::Fn { has_self: false, .. } = assoc_item.kind
+                && let assoc_item_hir_id = cx.tcx.local_def_id_to_hir_id(assoc_item.def_id.expect_local())
+                && let impl_item = cx.tcx.hir_node(assoc_item_hir_id).expect_impl_item()
+                && !impl_item.span.in_external_macro(cx.sess().source_map())
+                && let hir::ImplItemKind::Fn(ref sig, _) = impl_item.kind
+                && let id = impl_item.owner_id
+                // can't be implemented for unsafe new
+                && !sig.header.is_unsafe()
+                // shouldn't be implemented when it is hidden in docs
+                && !cx.tcx.is_doc_hidden(impl_item.owner_id.def_id)
+                // when the result of `new()` depends on a parameter we should not require
+                // an impl of `Default`
+                && impl_item.generics.params.is_empty()
+                && sig.decl.inputs.is_empty()
+                && cx.effective_visibilities.is_exported(impl_item.owner_id.def_id)
+                && let self_ty = cx.tcx.type_of(item.owner_id).instantiate_identity()
+                && self_ty == return_ty(cx, impl_item.owner_id)
+                && let Some(default_trait_id) = cx.tcx.get_diagnostic_item(sym::Default)
             {
-                if let AssocKind::Fn { has_self: false, .. } = assoc_item.kind {
-                    let impl_item = cx
-                        .tcx
-                        .hir_node_by_def_id(assoc_item.def_id.expect_local())
-                        .expect_impl_item();
-                    if impl_item.span.in_external_macro(cx.sess().source_map()) {
-                        return;
-                    }
-                    if let hir::ImplItemKind::Fn(ref sig, _) = impl_item.kind {
-                        let id = impl_item.owner_id;
-                        if sig.header.is_unsafe() {
-                            // can't be implemented for unsafe new
-                            return;
-                        }
-                        if cx.tcx.is_doc_hidden(impl_item.owner_id.def_id) {
-                            // shouldn't be implemented when it is hidden in docs
-                            return;
-                        }
-                        if !impl_item.generics.params.is_empty() {
-                            // when the result of `new()` depends on a parameter we should not require
-                            // an impl of `Default`
-                            return;
-                        }
-                        if sig.decl.inputs.is_empty()
-                            && cx.effective_visibilities.is_reachable(impl_item.owner_id.def_id)
-                            && let self_ty = cx.tcx.type_of(item.owner_id).instantiate_identity()
-                            && self_ty == return_ty(cx, impl_item.owner_id)
-                            && let Some(default_trait_id) = cx.tcx.get_diagnostic_item(sym::Default)
+                if self.impling_types.is_none() {
+                    let mut impls = HirIdSet::default();
+                    for &d in cx.tcx.local_trait_impls(default_trait_id) {
+                        let ty = cx.tcx.type_of(d).instantiate_identity();
+                        if let Some(ty_def) = ty.ty_adt_def()
+                            && let Some(local_def_id) = ty_def.did().as_local()
                         {
-                            if self.impling_types.is_none() {
-                                let mut impls = HirIdSet::default();
-                                for &d in cx.tcx.local_trait_impls(default_trait_id) {
-                                    let ty = cx.tcx.type_of(d).instantiate_identity();
-                                    if let Some(ty_def) = ty.ty_adt_def()
-                                        && let Some(local_def_id) = ty_def.did().as_local()
-                                    {
-                                        impls.insert(cx.tcx.local_def_id_to_hir_id(local_def_id));
-                                    }
-                                }
-                                self.impling_types = Some(impls);
-                            }
-
-                            // Check if a Default implementation exists for the Self type, regardless of
-                            // generics
-                            if let Some(ref impling_types) = self.impling_types
-                                && let self_def = cx.tcx.type_of(item.owner_id).instantiate_identity()
-                                && let Some(self_def) = self_def.ty_adt_def()
-                                && let Some(self_local_did) = self_def.did().as_local()
-                                && let self_id = cx.tcx.local_def_id_to_hir_id(self_local_did)
-                                && impling_types.contains(&self_id)
-                            {
-                                return;
-                            }
-
-                            let generics_sugg = snippet(cx, generics.span, "");
-                            let where_clause_sugg = if generics.has_where_clause_predicates {
-                                format!("\n{}\n", snippet(cx, generics.where_clause_span, ""))
-                            } else {
-                                String::new()
-                            };
-                            let self_ty_fmt = self_ty.to_string();
-                            let self_type_snip = snippet(cx, impl_self_ty.span, &self_ty_fmt);
-                            span_lint_hir_and_then(
-                                cx,
-                                NEW_WITHOUT_DEFAULT,
-                                id.into(),
-                                impl_item.span,
-                                format!("you should consider adding a `Default` implementation for `{self_type_snip}`"),
-                                |diag| {
-                                    diag.suggest_prepend_item(
-                                        cx,
-                                        item.span,
-                                        "try adding this",
-                                        &create_new_without_default_suggest_msg(
-                                            &self_type_snip,
-                                            &generics_sugg,
-                                            &where_clause_sugg,
-                                        ),
-                                        Applicability::MachineApplicable,
-                                    );
-                                },
-                            );
+                            impls.insert(cx.tcx.local_def_id_to_hir_id(local_def_id));
                         }
                     }
+                    self.impling_types = Some(impls);
                 }
+
+                // Check if a Default implementation exists for the Self type, regardless of
+                // generics
+                if let Some(ref impling_types) = self.impling_types
+                    && let self_def = cx.tcx.type_of(item.owner_id).instantiate_identity()
+                    && let Some(self_def) = self_def.ty_adt_def()
+                    && let Some(self_local_did) = self_def.did().as_local()
+                    && let self_id = cx.tcx.local_def_id_to_hir_id(self_local_did)
+                    && impling_types.contains(&self_id)
+                {
+                    return;
+                }
+
+                let mut app = Applicability::MachineApplicable;
+                let attrs_sugg = {
+                    let mut sugg = String::new();
+                    for attr in cx.tcx.hir_attrs(assoc_item_hir_id) {
+                        if !attr.has_name(sym::cfg_trace) {
+                            // This might be some other attribute that the `impl Default` ought to inherit.
+                            // But it could also be one of the many attributes that:
+                            // - can't be put on an impl block -- like `#[inline]`
+                            // - we can't even build a suggestion for, since `Attribute::span` may panic.
+                            //
+                            // Because of all that, remain on the safer side -- don't inherit this attr, and just
+                            // reduce the applicability
+                            app = Applicability::MaybeIncorrect;
+                            continue;
+                        }
+
+                        sugg.push_str(&snippet_with_applicability(cx.sess(), attr.span(), "_", &mut app));
+                        sugg.push('\n');
+                    }
+                    sugg
+                };
+                let generics_sugg = snippet_with_applicability(cx, generics.span, "", &mut app);
+                let where_clause_sugg = if generics.has_where_clause_predicates {
+                    format!(
+                        "\n{}\n",
+                        snippet_with_applicability(cx, generics.where_clause_span, "", &mut app)
+                    )
+                } else {
+                    String::new()
+                };
+                let self_ty_fmt = self_ty.to_string();
+                let self_type_snip = snippet_with_applicability(cx, impl_self_ty.span, &self_ty_fmt, &mut app);
+                span_lint_hir_and_then(
+                    cx,
+                    NEW_WITHOUT_DEFAULT,
+                    id.into(),
+                    impl_item.span,
+                    format!("you should consider adding a `Default` implementation for `{self_type_snip}`"),
+                    |diag| {
+                        diag.suggest_prepend_item(
+                            cx,
+                            item.span,
+                            "try adding this",
+                            &create_new_without_default_suggest_msg(
+                                &attrs_sugg,
+                                &self_type_snip,
+                                &generics_sugg,
+                                &where_clause_sugg,
+                            ),
+                            app,
+                        );
+                    },
+                );
             }
         }
     }
 }
 
 fn create_new_without_default_suggest_msg(
+    attrs_sugg: &str,
     self_type_snip: &str,
     generics_sugg: &str,
     where_clause_sugg: &str,
 ) -> String {
     #[rustfmt::skip]
     format!(
-"impl{generics_sugg} Default for {self_type_snip}{where_clause_sugg} {{
+"{attrs_sugg}impl{generics_sugg} Default for {self_type_snip}{where_clause_sugg} {{
     fn default() -> Self {{
         Self::new()
     }}
diff --git a/clippy_lints/src/unit_types/let_unit_value.rs b/clippy_lints/src/unit_types/let_unit_value.rs
index d5b6c17..424aa14 100644
--- a/clippy_lints/src/unit_types/let_unit_value.rs
+++ b/clippy_lints/src/unit_types/let_unit_value.rs
@@ -1,6 +1,6 @@
 use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::macros::{FormatArgsStorage, find_format_arg_expr, is_format_macro, root_macro_call_first_node};
-use clippy_utils::source::{indent_of, reindent_multiline, snippet_with_context};
+use clippy_utils::source::{snippet_indent, walk_span_to_context};
 use clippy_utils::visitors::{for_each_local_assignment, for_each_value_source};
 use core::ops::ControlFlow;
 use rustc_ast::{FormatArgs, FormatArgumentKind};
@@ -74,10 +74,10 @@
                 "this let-binding has unit value",
                 |diag| {
                     let mut suggestions = Vec::new();
+                    let init_new_span = walk_span_to_context(init.span, local.span.ctxt()).unwrap();
 
                     // Suggest omitting the `let` binding
-                    let mut app = Applicability::MachineApplicable;
-                    let snip = snippet_with_context(cx, init.span, local.span.ctxt(), "()", &mut app).0;
+                    let app = Applicability::MachineApplicable;
 
                     // If this is a binding pattern, we need to add suggestions to remove any usages
                     // of the variable
@@ -89,35 +89,48 @@
                         walk_body(&mut visitor, body);
 
                         let mut has_in_format_capture = false;
-                        suggestions.extend(visitor.spans.iter().filter_map(|span| match span {
+                        suggestions.extend(visitor.spans.into_iter().filter_map(|span| match span {
                             MaybeInFormatCapture::Yes => {
                                 has_in_format_capture = true;
                                 None
                             },
-                            MaybeInFormatCapture::No(span) => Some((*span, "()".to_string())),
+                            MaybeInFormatCapture::No(span) => Some((span, "()".to_string())),
                         }));
 
                         if has_in_format_capture {
+                            // In a case like this:
+                            // ```
+                            // let unit = returns_unit();
+                            // eprintln!("{unit}");
+                            // ```
+                            // we can't remove the `unit` binding and replace its uses with a `()`,
+                            // because the `eprintln!` would break.
+                            //
+                            // So do the following instead:
+                            // ```
+                            // let unit = ();
+                            // returns_unit();
+                            // eprintln!("{unit}");
+                            // ```
+                            // TODO: find a less awkward way to do this
                             suggestions.push((
-                                init.span,
-                                format!("();\n{}", reindent_multiline(&snip, false, indent_of(cx, local.span))),
+                                init_new_span.shrink_to_lo(),
+                                format!("();\n{}", snippet_indent(cx, local.span).as_deref().unwrap_or("")),
                             ));
-                            diag.multipart_suggestion(
-                                "replace variable usages with `()`",
-                                suggestions,
-                                Applicability::MachineApplicable,
-                            );
+                            diag.multipart_suggestion_verbose("replace variable usages with `()`", suggestions, app);
                             return;
                         }
                     }
 
-                    suggestions.push((local.span, format!("{snip};")));
+                    // let local = returns_unit();
+                    // ^^^^^^^^^^^^ remove this
+                    suggestions.push((local.span.until(init_new_span), String::new()));
                     let message = if suggestions.len() == 1 {
                         "omit the `let` binding"
                     } else {
                         "omit the `let` binding and replace variable usages with `()`"
                     };
-                    diag.multipart_suggestion(message, suggestions, Applicability::MachineApplicable);
+                    diag.multipart_suggestion_verbose(message, suggestions, app);
                 },
             );
         }
@@ -132,6 +145,12 @@
     macro_call: Option<&'a FormatArgs>,
 }
 
+/// Whether the unit variable is captured in a `format!`:
+///
+/// ```ignore
+/// let unit = ();
+/// eprintln!("{unit}");
+/// ```
 enum MaybeInFormatCapture {
     Yes,
     No(Span),
diff --git a/tests/ui-toml/conf_deprecated_key/conf_deprecated_key.rs b/tests/ui-toml/conf_deprecated_key/conf_deprecated_key.rs
index ecb43dc..b28e46a 100644
--- a/tests/ui-toml/conf_deprecated_key/conf_deprecated_key.rs
+++ b/tests/ui-toml/conf_deprecated_key/conf_deprecated_key.rs
@@ -1,5 +1,3 @@
-#![allow(clippy::uninlined_format_args)]
-
 fn main() {}
 
 #[warn(clippy::cognitive_complexity)]
@@ -8,7 +6,7 @@
     let x = vec![1, 2, 3];
     for i in x {
         if i == 1 {
-            println!("{}", i);
+            println!("{i}");
         }
     }
 }
diff --git a/tests/ui-toml/conf_deprecated_key/conf_deprecated_key.stderr b/tests/ui-toml/conf_deprecated_key/conf_deprecated_key.stderr
index 627498d..95b0508 100644
--- a/tests/ui-toml/conf_deprecated_key/conf_deprecated_key.stderr
+++ b/tests/ui-toml/conf_deprecated_key/conf_deprecated_key.stderr
@@ -11,7 +11,7 @@
    | ^^^^^^^^^^^^^^^^^
 
 error: the function has a cognitive complexity of (3/2)
-  --> tests/ui-toml/conf_deprecated_key/conf_deprecated_key.rs:6:4
+  --> tests/ui-toml/conf_deprecated_key/conf_deprecated_key.rs:4:4
    |
 LL | fn cognitive_complexity() {
    |    ^^^^^^^^^^^^^^^^^^^^
diff --git a/tests/ui-toml/max_suggested_slice_pattern_length/index_refutable_slice.fixed b/tests/ui-toml/max_suggested_slice_pattern_length/index_refutable_slice.fixed
index 2877871..36540bf 100644
--- a/tests/ui-toml/max_suggested_slice_pattern_length/index_refutable_slice.fixed
+++ b/tests/ui-toml/max_suggested_slice_pattern_length/index_refutable_slice.fixed
@@ -1,4 +1,3 @@
-#![allow(clippy::uninlined_format_args)]
 #![deny(clippy::index_refutable_slice)]
 
 fn below_limit() {
diff --git a/tests/ui-toml/max_suggested_slice_pattern_length/index_refutable_slice.rs b/tests/ui-toml/max_suggested_slice_pattern_length/index_refutable_slice.rs
index f958b92..da76bb2 100644
--- a/tests/ui-toml/max_suggested_slice_pattern_length/index_refutable_slice.rs
+++ b/tests/ui-toml/max_suggested_slice_pattern_length/index_refutable_slice.rs
@@ -1,4 +1,3 @@
-#![allow(clippy::uninlined_format_args)]
 #![deny(clippy::index_refutable_slice)]
 
 fn below_limit() {
diff --git a/tests/ui-toml/max_suggested_slice_pattern_length/index_refutable_slice.stderr b/tests/ui-toml/max_suggested_slice_pattern_length/index_refutable_slice.stderr
index e1a8941..022deb3 100644
--- a/tests/ui-toml/max_suggested_slice_pattern_length/index_refutable_slice.stderr
+++ b/tests/ui-toml/max_suggested_slice_pattern_length/index_refutable_slice.stderr
@@ -1,11 +1,11 @@
 error: this binding can be a slice pattern to avoid indexing
-  --> tests/ui-toml/max_suggested_slice_pattern_length/index_refutable_slice.rs:6:17
+  --> tests/ui-toml/max_suggested_slice_pattern_length/index_refutable_slice.rs:5:17
    |
 LL |     if let Some(slice) = slice {
    |                 ^^^^^
    |
 note: the lint level is defined here
-  --> tests/ui-toml/max_suggested_slice_pattern_length/index_refutable_slice.rs:2:9
+  --> tests/ui-toml/max_suggested_slice_pattern_length/index_refutable_slice.rs:1:9
    |
 LL | #![deny(clippy::index_refutable_slice)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/tests/ui/bind_instead_of_map.fixed b/tests/ui/bind_instead_of_map.fixed
index 80e010e2..fa35a01 100644
--- a/tests/ui/bind_instead_of_map.fixed
+++ b/tests/ui/bind_instead_of_map.fixed
@@ -1,5 +1,4 @@
 #![deny(clippy::bind_instead_of_map)]
-#![allow(clippy::uninlined_format_args)]
 
 // need a main anyway, use it get rid of unused warnings too
 pub fn main() {
diff --git a/tests/ui/bind_instead_of_map.rs b/tests/ui/bind_instead_of_map.rs
index 09aa848..403077e 100644
--- a/tests/ui/bind_instead_of_map.rs
+++ b/tests/ui/bind_instead_of_map.rs
@@ -1,5 +1,4 @@
 #![deny(clippy::bind_instead_of_map)]
-#![allow(clippy::uninlined_format_args)]
 
 // need a main anyway, use it get rid of unused warnings too
 pub fn main() {
diff --git a/tests/ui/bind_instead_of_map.stderr b/tests/ui/bind_instead_of_map.stderr
index 08f85fb..3f8d631 100644
--- a/tests/ui/bind_instead_of_map.stderr
+++ b/tests/ui/bind_instead_of_map.stderr
@@ -1,5 +1,5 @@
 error: using `Option.and_then(Some)`, which is a no-op
-  --> tests/ui/bind_instead_of_map.rs:8:13
+  --> tests/ui/bind_instead_of_map.rs:7:13
    |
 LL |     let _ = x.and_then(Some);
    |             ^^^^^^^^^^^^^^^^ help: use the expression directly: `x`
@@ -11,13 +11,13 @@
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: using `Option.and_then(|x| Some(y))`, which is more succinctly expressed as `map(|x| y)`
-  --> tests/ui/bind_instead_of_map.rs:10:13
+  --> tests/ui/bind_instead_of_map.rs:9:13
    |
 LL |     let _ = x.and_then(|o| Some(o + 1));
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `x.map(|o| o + 1)`
 
 error: using `Result.and_then(Ok)`, which is a no-op
-  --> tests/ui/bind_instead_of_map.rs:17:13
+  --> tests/ui/bind_instead_of_map.rs:16:13
    |
 LL |     let _ = x.and_then(Ok);
    |             ^^^^^^^^^^^^^^ help: use the expression directly: `x`
diff --git a/tests/ui/branches_sharing_code/shared_at_top_and_bottom.rs b/tests/ui/branches_sharing_code/shared_at_top_and_bottom.rs
index e848f06..1646b57 100644
--- a/tests/ui/branches_sharing_code/shared_at_top_and_bottom.rs
+++ b/tests/ui/branches_sharing_code/shared_at_top_and_bottom.rs
@@ -1,6 +1,5 @@
 #![deny(clippy::branches_sharing_code, clippy::if_same_then_else)]
 #![allow(dead_code)]
-#![allow(clippy::uninlined_format_args)]
 //@no-rustfix
 // branches_sharing_code at the top and bottom of the if blocks
 
@@ -70,7 +69,7 @@
         let b = 0xffff00ff;
         let e_id = gen_id(a, b);
 
-        println!("From the a `{}` to the b `{}`", a, b);
+        println!("From the a `{a}` to the b `{b}`");
 
         let pack = DataPack {
             id: e_id,
@@ -83,7 +82,7 @@
         let b = 0xffff00ff;
         let e_id = gen_id(a, b);
 
-        println!("The new ID is '{}'", e_id);
+        println!("The new ID is '{e_id}'");
 
         let pack = DataPack {
             id: e_id,
diff --git a/tests/ui/branches_sharing_code/shared_at_top_and_bottom.stderr b/tests/ui/branches_sharing_code/shared_at_top_and_bottom.stderr
index 40f3453..f5c51f7 100644
--- a/tests/ui/branches_sharing_code/shared_at_top_and_bottom.stderr
+++ b/tests/ui/branches_sharing_code/shared_at_top_and_bottom.stderr
@@ -1,5 +1,5 @@
 error: all if blocks contain the same code at both the start and the end
-  --> tests/ui/branches_sharing_code/shared_at_top_and_bottom.rs:17:5
+  --> tests/ui/branches_sharing_code/shared_at_top_and_bottom.rs:16:5
    |
 LL | /     if x == 7 {
 LL | |
@@ -10,7 +10,7 @@
    | |_________________________________^
    |
 note: this code is shared at the end
-  --> tests/ui/branches_sharing_code/shared_at_top_and_bottom.rs:31:5
+  --> tests/ui/branches_sharing_code/shared_at_top_and_bottom.rs:30:5
    |
 LL | /         let _u = 9;
 LL | |     }
@@ -34,7 +34,7 @@
    |
 
 error: all if blocks contain the same code at both the start and the end
-  --> tests/ui/branches_sharing_code/shared_at_top_and_bottom.rs:35:5
+  --> tests/ui/branches_sharing_code/shared_at_top_and_bottom.rs:34:5
    |
 LL | /     if x == 99 {
 LL | |
@@ -45,7 +45,7 @@
    | |____________________________________^
    |
 note: this code is shared at the end
-  --> tests/ui/branches_sharing_code/shared_at_top_and_bottom.rs:48:5
+  --> tests/ui/branches_sharing_code/shared_at_top_and_bottom.rs:47:5
    |
 LL | /         let _overlap_end = r * r * r;
 LL | |         let z = "end";
@@ -67,7 +67,7 @@
    |
 
 error: all if blocks contain the same code at both the start and the end
-  --> tests/ui/branches_sharing_code/shared_at_top_and_bottom.rs:66:5
+  --> tests/ui/branches_sharing_code/shared_at_top_and_bottom.rs:65:5
    |
 LL | /     if (x > 7 && y < 13) || (x + y) % 2 == 1 {
 LL | |
@@ -78,7 +78,7 @@
    | |________________________________^
    |
 note: this code is shared at the end
-  --> tests/ui/branches_sharing_code/shared_at_top_and_bottom.rs:88:5
+  --> tests/ui/branches_sharing_code/shared_at_top_and_bottom.rs:87:5
    |
 LL | /         let pack = DataPack {
 LL | |             id: e_id,
@@ -108,7 +108,7 @@
    |
 
 error: all if blocks contain the same code at both the start and the end
-  --> tests/ui/branches_sharing_code/shared_at_top_and_bottom.rs:101:5
+  --> tests/ui/branches_sharing_code/shared_at_top_and_bottom.rs:100:5
    |
 LL | /     let _ = if x == 7 {
 ...  |
@@ -116,7 +116,7 @@
    | |___________________^
    |
 note: this code is shared at the end
-  --> tests/ui/branches_sharing_code/shared_at_top_and_bottom.rs:112:5
+  --> tests/ui/branches_sharing_code/shared_at_top_and_bottom.rs:111:5
    |
 LL | /         x << 2
 LL | |     };
@@ -134,7 +134,7 @@
    |
 
 error: all if blocks contain the same code at both the start and the end
-  --> tests/ui/branches_sharing_code/shared_at_top_and_bottom.rs:115:5
+  --> tests/ui/branches_sharing_code/shared_at_top_and_bottom.rs:114:5
    |
 LL | /     if x == 9 {
 ...  |
@@ -142,7 +142,7 @@
    | |___________________^
    |
 note: this code is shared at the end
-  --> tests/ui/branches_sharing_code/shared_at_top_and_bottom.rs:126:5
+  --> tests/ui/branches_sharing_code/shared_at_top_and_bottom.rs:125:5
    |
 LL | /         x * 4
 LL | |     }
@@ -160,7 +160,7 @@
    |
 
 error: all if blocks contain the same code at both the start and the end
-  --> tests/ui/branches_sharing_code/shared_at_top_and_bottom.rs:158:9
+  --> tests/ui/branches_sharing_code/shared_at_top_and_bottom.rs:157:9
    |
 LL | /         if false {
 LL | |
@@ -168,7 +168,7 @@
    | |______________________^
    |
 note: this code is shared at the end
-  --> tests/ui/branches_sharing_code/shared_at_top_and_bottom.rs:166:9
+  --> tests/ui/branches_sharing_code/shared_at_top_and_bottom.rs:165:9
    |
 LL | /             let y = 1;
 LL | |         }
diff --git a/tests/ui/cast_abs_to_unsigned.fixed b/tests/ui/cast_abs_to_unsigned.fixed
index b55c22f..44cb66a 100644
--- a/tests/ui/cast_abs_to_unsigned.fixed
+++ b/tests/ui/cast_abs_to_unsigned.fixed
@@ -1,11 +1,11 @@
 #![warn(clippy::cast_abs_to_unsigned)]
-#![allow(clippy::uninlined_format_args, unused)]
+#![allow(unused)]
 
 fn main() {
     let x: i32 = -42;
     let y: u32 = x.unsigned_abs();
     //~^ cast_abs_to_unsigned
-    println!("The absolute value of {} is {}", x, y);
+    println!("The absolute value of {x} is {y}");
 
     let a: i32 = -3;
     let _: usize = a.unsigned_abs() as usize;
diff --git a/tests/ui/cast_abs_to_unsigned.rs b/tests/ui/cast_abs_to_unsigned.rs
index 466aa6a..555b909 100644
--- a/tests/ui/cast_abs_to_unsigned.rs
+++ b/tests/ui/cast_abs_to_unsigned.rs
@@ -1,11 +1,11 @@
 #![warn(clippy::cast_abs_to_unsigned)]
-#![allow(clippy::uninlined_format_args, unused)]
+#![allow(unused)]
 
 fn main() {
     let x: i32 = -42;
     let y: u32 = x.abs() as u32;
     //~^ cast_abs_to_unsigned
-    println!("The absolute value of {} is {}", x, y);
+    println!("The absolute value of {x} is {y}");
 
     let a: i32 = -3;
     let _: usize = a.abs() as usize;
diff --git a/tests/ui/crashes/ice-4775.rs b/tests/ui/crashes/ice-4775.rs
index dd6c6b8..e8c47b4 100644
--- a/tests/ui/crashes/ice-4775.rs
+++ b/tests/ui/crashes/ice-4775.rs
@@ -7,7 +7,7 @@
 impl<const N: usize> ArrayWrapper<{ N }> {
     pub fn ice(&self) {
         for i in self.0.iter() {
-            println!("{}", i);
+            println!("{i}");
         }
     }
 }
diff --git a/tests/ui/default_trait_access.fixed b/tests/ui/default_trait_access.fixed
index d3fe09a..e3bf603 100644
--- a/tests/ui/default_trait_access.fixed
+++ b/tests/ui/default_trait_access.fixed
@@ -1,7 +1,6 @@
 //@aux-build: proc_macros.rs
 #![deny(clippy::default_trait_access)]
 #![allow(dead_code, unused_imports)]
-#![allow(clippy::uninlined_format_args)]
 
 extern crate proc_macros;
 
@@ -63,6 +62,7 @@
 
     let _s21: String = with_span!(s Default::default());
 
+    #[expect(clippy::uninlined_format_args)]
     println!(
         "[{}] [{}] [{}] [{}] [{}] [{}] [{}] [{}] [{}] [{:?}] [{:?}] [{:?}] [{:?}] [{:?}] [{:?}] [{:?}] [{:?}] [{:?}] [{:?}] [{:?}]",
         s1, s2, s3, s4, s5, s6, s7, s8, s9, s10, s11, s12, s13, s14, s15, s16, s17, s18, s19, s20,
diff --git a/tests/ui/default_trait_access.rs b/tests/ui/default_trait_access.rs
index cdffb2a..8cc065e 100644
--- a/tests/ui/default_trait_access.rs
+++ b/tests/ui/default_trait_access.rs
@@ -1,7 +1,6 @@
 //@aux-build: proc_macros.rs
 #![deny(clippy::default_trait_access)]
 #![allow(dead_code, unused_imports)]
-#![allow(clippy::uninlined_format_args)]
 
 extern crate proc_macros;
 
@@ -63,6 +62,7 @@
 
     let _s21: String = with_span!(s Default::default());
 
+    #[expect(clippy::uninlined_format_args)]
     println!(
         "[{}] [{}] [{}] [{}] [{}] [{}] [{}] [{}] [{}] [{:?}] [{:?}] [{:?}] [{:?}] [{:?}] [{:?}] [{:?}] [{:?}] [{:?}] [{:?}] [{:?}]",
         s1, s2, s3, s4, s5, s6, s7, s8, s9, s10, s11, s12, s13, s14, s15, s16, s17, s18, s19, s20,
diff --git a/tests/ui/default_trait_access.stderr b/tests/ui/default_trait_access.stderr
index aa7eb4f..aa89516 100644
--- a/tests/ui/default_trait_access.stderr
+++ b/tests/ui/default_trait_access.stderr
@@ -1,5 +1,5 @@
 error: calling `String::default()` is more clear than this expression
-  --> tests/ui/default_trait_access.rs:13:22
+  --> tests/ui/default_trait_access.rs:12:22
    |
 LL |     let s1: String = Default::default();
    |                      ^^^^^^^^^^^^^^^^^^ help: try: `String::default()`
@@ -11,43 +11,43 @@
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: calling `String::default()` is more clear than this expression
-  --> tests/ui/default_trait_access.rs:18:22
+  --> tests/ui/default_trait_access.rs:17:22
    |
 LL |     let s3: String = D2::default();
    |                      ^^^^^^^^^^^^^ help: try: `String::default()`
 
 error: calling `String::default()` is more clear than this expression
-  --> tests/ui/default_trait_access.rs:21:22
+  --> tests/ui/default_trait_access.rs:20:22
    |
 LL |     let s4: String = std::default::Default::default();
    |                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `String::default()`
 
 error: calling `String::default()` is more clear than this expression
-  --> tests/ui/default_trait_access.rs:26:22
+  --> tests/ui/default_trait_access.rs:25:22
    |
 LL |     let s6: String = default::Default::default();
    |                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `String::default()`
 
 error: calling `GenericDerivedDefault::default()` is more clear than this expression
-  --> tests/ui/default_trait_access.rs:37:46
+  --> tests/ui/default_trait_access.rs:36:46
    |
 LL |     let s11: GenericDerivedDefault<String> = Default::default();
    |                                              ^^^^^^^^^^^^^^^^^^ help: try: `GenericDerivedDefault::default()`
 
 error: calling `TupleDerivedDefault::default()` is more clear than this expression
-  --> tests/ui/default_trait_access.rs:44:36
+  --> tests/ui/default_trait_access.rs:43:36
    |
 LL |     let s14: TupleDerivedDefault = Default::default();
    |                                    ^^^^^^^^^^^^^^^^^^ help: try: `TupleDerivedDefault::default()`
 
 error: calling `ArrayDerivedDefault::default()` is more clear than this expression
-  --> tests/ui/default_trait_access.rs:47:36
+  --> tests/ui/default_trait_access.rs:46:36
    |
 LL |     let s15: ArrayDerivedDefault = Default::default();
    |                                    ^^^^^^^^^^^^^^^^^^ help: try: `ArrayDerivedDefault::default()`
 
 error: calling `TupleStructDerivedDefault::default()` is more clear than this expression
-  --> tests/ui/default_trait_access.rs:52:42
+  --> tests/ui/default_trait_access.rs:51:42
    |
 LL |     let s17: TupleStructDerivedDefault = Default::default();
    |                                          ^^^^^^^^^^^^^^^^^^ help: try: `TupleStructDerivedDefault::default()`
diff --git a/tests/ui/double_parens.fixed b/tests/ui/double_parens.fixed
new file mode 100644
index 0000000..dedc513
--- /dev/null
+++ b/tests/ui/double_parens.fixed
@@ -0,0 +1,99 @@
+#![warn(clippy::double_parens)]
+#![expect(clippy::eq_op, clippy::no_effect)]
+#![feature(custom_inner_attributes)]
+#![rustfmt::skip]
+
+fn dummy_fn<T>(_: T) {}
+
+struct DummyStruct;
+
+impl DummyStruct {
+    fn dummy_method<T>(&self, _: T) {}
+}
+
+fn simple_double_parens() -> i32 {
+    (0)
+    //~^ double_parens
+}
+
+fn fn_double_parens() {
+    dummy_fn(0);
+    //~^ double_parens
+}
+
+fn method_double_parens(x: DummyStruct) {
+    x.dummy_method(0);
+    //~^ double_parens
+}
+
+fn tuple_double_parens() -> (i32, i32) {
+    (1, 2)
+    //~^ double_parens
+}
+
+#[allow(clippy::unused_unit)]
+fn unit_double_parens() {
+    ()
+    //~^ double_parens
+}
+
+fn fn_tuple_ok() {
+    dummy_fn((1, 2));
+}
+
+fn method_tuple_ok(x: DummyStruct) {
+    x.dummy_method((1, 2));
+}
+
+fn fn_unit_ok() {
+    dummy_fn(());
+}
+
+fn method_unit_ok(x: DummyStruct) {
+    x.dummy_method(());
+}
+
+// Issue #3206
+fn inside_macro() {
+    assert_eq!((1, 2), (1, 2), "Error");
+    assert_eq!((1, 2), (1, 2), "Error");
+    //~^ double_parens
+}
+
+fn issue9000(x: DummyStruct) {
+    macro_rules! foo {
+        () => {(100)}
+    }
+    // don't lint: the inner paren comes from the macro expansion
+    (foo!());
+    dummy_fn(foo!());
+    x.dummy_method(foo!());
+
+    macro_rules! baz {
+        ($n:literal) => {($n)}
+    }
+    // don't lint: don't get confused by the expression inside the inner paren
+    // having the same `ctxt` as the overall expression
+    // (this is a bug that happened during the development of the fix)
+    (baz!(100));
+    dummy_fn(baz!(100));
+    x.dummy_method(baz!(100));
+
+    // should lint: both parens are from inside the macro
+    macro_rules! bar {
+        () => {(100)}
+        //~^ double_parens
+    }
+    bar!();
+
+    // should lint: both parens are from outside the macro;
+    // make sure to suggest the macro unexpanded
+    (vec![1, 2]);
+    //~^ double_parens
+    dummy_fn(vec![1, 2]);
+    //~^ double_parens
+    x.dummy_method(vec![1, 2]);
+    //~^ double_parens
+}
+
+fn main() {}
diff --git a/tests/ui/double_parens.rs b/tests/ui/double_parens.rs
index 7c97601..27f2524 100644
--- a/tests/ui/double_parens.rs
+++ b/tests/ui/double_parens.rs
@@ -1,5 +1,5 @@
 #![warn(clippy::double_parens)]
-#![allow(dead_code, clippy::eq_op)]
+#![expect(clippy::eq_op, clippy::no_effect)]
 #![feature(custom_inner_attributes)]
 #![rustfmt::skip]
 
@@ -8,38 +8,33 @@
 struct DummyStruct;
 
 impl DummyStruct {
-    fn dummy_method<T>(self, _: T) {}
+    fn dummy_method<T>(&self, _: T) {}
 }
 
 fn simple_double_parens() -> i32 {
     ((0))
     //~^ double_parens
-
-
 }
 
 fn fn_double_parens() {
     dummy_fn((0));
     //~^ double_parens
-
 }
 
 fn method_double_parens(x: DummyStruct) {
     x.dummy_method((0));
     //~^ double_parens
-
 }
 
 fn tuple_double_parens() -> (i32, i32) {
     ((1, 2))
     //~^ double_parens
-
 }
 
+#[allow(clippy::unused_unit)]
 fn unit_double_parens() {
     (())
     //~^ double_parens
-
 }
 
 fn fn_tuple_ok() {
@@ -63,7 +58,42 @@
     assert_eq!((1, 2), (1, 2), "Error");
     assert_eq!(((1, 2)), (1, 2), "Error");
     //~^ double_parens
+}
 
+fn issue9000(x: DummyStruct) {
+    macro_rules! foo {
+        () => {(100)}
+    }
+    // don't lint: the inner paren comes from the macro expansion
+    (foo!());
+    dummy_fn(foo!());
+    x.dummy_method(foo!());
+
+    macro_rules! baz {
+        ($n:literal) => {($n)}
+    }
+    // don't lint: don't get confused by the expression inside the inner paren
+    // having the same `ctxt` as the overall expression
+    // (this is a bug that happened during the development of the fix)
+    (baz!(100));
+    dummy_fn(baz!(100));
+    x.dummy_method(baz!(100));
+
+    // should lint: both parens are from inside the macro
+    macro_rules! bar {
+        () => {((100))}
+        //~^ double_parens
+    }
+    bar!();
+
+    // should lint: both parens are from outside the macro;
+    // make sure to suggest the macro unexpanded
+    ((vec![1, 2]));
+    //~^ double_parens
+    dummy_fn((vec![1, 2]));
+    //~^ double_parens
+    x.dummy_method((vec![1, 2]));
+    //~^ double_parens
 }
 
 fn main() {}
diff --git a/tests/ui/double_parens.stderr b/tests/ui/double_parens.stderr
index e119f54..3a740e4 100644
--- a/tests/ui/double_parens.stderr
+++ b/tests/ui/double_parens.stderr
@@ -1,41 +1,70 @@
-error: consider removing unnecessary double parentheses
+error: unnecessary parentheses
   --> tests/ui/double_parens.rs:15:5
    |
 LL |     ((0))
-   |     ^^^^^
+   |     ^^^^^ help: remove them: `(0)`
    |
    = note: `-D clippy::double-parens` implied by `-D warnings`
    = help: to override `-D warnings` add `#[allow(clippy::double_parens)]`
 
-error: consider removing unnecessary double parentheses
-  --> tests/ui/double_parens.rs:22:14
+error: unnecessary parentheses
+  --> tests/ui/double_parens.rs:20:14
    |
 LL |     dummy_fn((0));
-   |              ^^^
+   |              ^^^ help: remove them: `0`
 
-error: consider removing unnecessary double parentheses
-  --> tests/ui/double_parens.rs:28:20
+error: unnecessary parentheses
+  --> tests/ui/double_parens.rs:25:20
    |
 LL |     x.dummy_method((0));
-   |                    ^^^
+   |                    ^^^ help: remove them: `0`
 
-error: consider removing unnecessary double parentheses
-  --> tests/ui/double_parens.rs:34:5
+error: unnecessary parentheses
+  --> tests/ui/double_parens.rs:30:5
    |
 LL |     ((1, 2))
-   |     ^^^^^^^^
+   |     ^^^^^^^^ help: remove them: `(1, 2)`
 
-error: consider removing unnecessary double parentheses
-  --> tests/ui/double_parens.rs:40:5
+error: unnecessary parentheses
+  --> tests/ui/double_parens.rs:36:5
    |
 LL |     (())
-   |     ^^^^
+   |     ^^^^ help: remove them: `()`
 
-error: consider removing unnecessary double parentheses
-  --> tests/ui/double_parens.rs:64:16
+error: unnecessary parentheses
+  --> tests/ui/double_parens.rs:59:16
    |
 LL |     assert_eq!(((1, 2)), (1, 2), "Error");
-   |                ^^^^^^^^
+   |                ^^^^^^^^ help: remove them: `(1, 2)`
 
-error: aborting due to 6 previous errors
+error: unnecessary parentheses
+  --> tests/ui/double_parens.rs:84:16
+   |
+LL |         () => {((100))}
+   |                ^^^^^^^ help: remove them: `(100)`
+...
+LL |     bar!();
+   |     ------ in this macro invocation
+   |
+   = note: this error originates in the macro `bar` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: unnecessary parentheses
+  --> tests/ui/double_parens.rs:91:5
+   |
+LL |     ((vec![1, 2]));
+   |     ^^^^^^^^^^^^^^ help: remove them: `(vec![1, 2])`
+
+error: unnecessary parentheses
+  --> tests/ui/double_parens.rs:93:14
+   |
+LL |     dummy_fn((vec![1, 2]));
+   |              ^^^^^^^^^^^^ help: remove them: `vec![1, 2]`
+
+error: unnecessary parentheses
+  --> tests/ui/double_parens.rs:95:20
+   |
+LL |     x.dummy_method((vec![1, 2]));
+   |                    ^^^^^^^^^^^^ help: remove them: `vec![1, 2]`
+
+error: aborting due to 10 previous errors
 
diff --git a/tests/ui/explicit_counter_loop.rs b/tests/ui/explicit_counter_loop.rs
index 1393478..ec4cecf 100644
--- a/tests/ui/explicit_counter_loop.rs
+++ b/tests/ui/explicit_counter_loop.rs
@@ -1,5 +1,5 @@
 #![warn(clippy::explicit_counter_loop)]
-#![allow(clippy::uninlined_format_args, clippy::useless_vec)]
+#![allow(clippy::useless_vec)]
 //@no-rustfix: suggestion does not remove the `+= 1`
 fn main() {
     let mut vec = vec![1, 2, 3, 4];
@@ -89,13 +89,13 @@
         for _v in &vec {
             index += 1
         }
-        println!("index: {}", index);
+        println!("index: {index}");
 
         // should not trigger the lint because the count is conditional #1219
         let text = "banana";
         let mut count = 0;
         for ch in text.chars() {
-            println!("{}", count);
+            println!("{count}");
             if ch == 'a' {
                 continue;
             }
@@ -106,7 +106,7 @@
         let text = "banana";
         let mut count = 0;
         for ch in text.chars() {
-            println!("{}", count);
+            println!("{count}");
             if ch == 'a' {
                 count += 1;
             }
@@ -118,7 +118,7 @@
         for ch in text.chars() {
             //~^ explicit_counter_loop
 
-            println!("{}", count);
+            println!("{count}");
             count += 1;
             if ch == 'a' {
                 continue;
@@ -131,7 +131,7 @@
         for ch in text.chars() {
             //~^ explicit_counter_loop
 
-            println!("{}", count);
+            println!("{count}");
             count += 1;
             for i in 0..2 {
                 let _ = 123;
@@ -142,7 +142,7 @@
         let text = "banana";
         let mut count = 0;
         for ch in text.chars() {
-            println!("{}", count);
+            println!("{count}");
             count += 1;
             for i in 0..2 {
                 count += 1;
@@ -157,7 +157,7 @@
         let mut skips = 0;
         let erasures = vec![];
         for i in 0..10 {
-            println!("{}", skips);
+            println!("{skips}");
             while erasures.contains(&(i + skips)) {
                 skips += 1;
             }
@@ -166,7 +166,7 @@
         // should not trigger the lint because the count is incremented multiple times
         let mut skips = 0;
         for i in 0..10 {
-            println!("{}", skips);
+            println!("{skips}");
             let mut j = 0;
             while j < 5 {
                 skips += 1;
@@ -177,7 +177,7 @@
         // should not trigger the lint because the count is incremented multiple times
         let mut skips = 0;
         for i in 0..10 {
-            println!("{}", skips);
+            println!("{skips}");
             for j in 0..5 {
                 skips += 1;
             }
@@ -205,7 +205,7 @@
         for _v in slice {
             index += 1
         }
-        let _closure = || println!("index: {}", index);
+        let _closure = || println!("index: {index}");
     }
 }
 
@@ -217,7 +217,7 @@
         let mut count = 0;
         for _i in slice {
             count += 1;
-            println!("{}", count);
+            println!("{count}");
         }
     }
 }
diff --git a/tests/ui/explicit_write.fixed b/tests/ui/explicit_write.fixed
index 024999f..ab28c1c 100644
--- a/tests/ui/explicit_write.fixed
+++ b/tests/ui/explicit_write.fixed
@@ -1,6 +1,5 @@
 #![warn(clippy::explicit_write)]
 #![allow(unused_imports)]
-#![allow(clippy::uninlined_format_args)]
 
 fn stdout() -> String {
     String::new()
@@ -40,7 +39,7 @@
         //~^ explicit_write
 
         let value = 1;
-        eprintln!("with {}", value);
+        eprintln!("with {value}");
         //~^ explicit_write
         eprintln!("with {} {}", 2, value);
         //~^ explicit_write
@@ -49,7 +48,7 @@
         eprintln!("macro arg {}", one!());
         //~^ explicit_write
         let width = 2;
-        eprintln!("{:w$}", value, w = width);
+        eprintln!("{value:w$}", w = width);
         //~^ explicit_write
     }
     // these should not warn, different destination
diff --git a/tests/ui/explicit_write.rs b/tests/ui/explicit_write.rs
index c83c760..975ee10 100644
--- a/tests/ui/explicit_write.rs
+++ b/tests/ui/explicit_write.rs
@@ -1,6 +1,5 @@
 #![warn(clippy::explicit_write)]
 #![allow(unused_imports)]
-#![allow(clippy::uninlined_format_args)]
 
 fn stdout() -> String {
     String::new()
@@ -40,7 +39,7 @@
         //~^ explicit_write
 
         let value = 1;
-        writeln!(std::io::stderr(), "with {}", value).unwrap();
+        writeln!(std::io::stderr(), "with {value}").unwrap();
         //~^ explicit_write
         writeln!(std::io::stderr(), "with {} {}", 2, value).unwrap();
         //~^ explicit_write
@@ -49,7 +48,7 @@
         writeln!(std::io::stderr(), "macro arg {}", one!()).unwrap();
         //~^ explicit_write
         let width = 2;
-        writeln!(std::io::stderr(), "{:w$}", value, w = width).unwrap();
+        writeln!(std::io::stderr(), "{value:w$}", w = width).unwrap();
         //~^ explicit_write
     }
     // these should not warn, different destination
diff --git a/tests/ui/explicit_write.stderr b/tests/ui/explicit_write.stderr
index 670a041..ef4b2a0 100644
--- a/tests/ui/explicit_write.stderr
+++ b/tests/ui/explicit_write.stderr
@@ -1,5 +1,5 @@
 error: use of `write!(stdout(), ...).unwrap()`
-  --> tests/ui/explicit_write.rs:23:9
+  --> tests/ui/explicit_write.rs:22:9
    |
 LL |         write!(std::io::stdout(), "test").unwrap();
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `print!("test")`
@@ -8,76 +8,76 @@
    = help: to override `-D warnings` add `#[allow(clippy::explicit_write)]`
 
 error: use of `write!(stderr(), ...).unwrap()`
-  --> tests/ui/explicit_write.rs:25:9
+  --> tests/ui/explicit_write.rs:24:9
    |
 LL |         write!(std::io::stderr(), "test").unwrap();
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `eprint!("test")`
 
 error: use of `writeln!(stdout(), ...).unwrap()`
-  --> tests/ui/explicit_write.rs:27:9
+  --> tests/ui/explicit_write.rs:26:9
    |
 LL |         writeln!(std::io::stdout(), "test").unwrap();
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `println!("test")`
 
 error: use of `writeln!(stderr(), ...).unwrap()`
-  --> tests/ui/explicit_write.rs:29:9
+  --> tests/ui/explicit_write.rs:28:9
    |
 LL |         writeln!(std::io::stderr(), "test").unwrap();
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `eprintln!("test")`
 
 error: use of `stdout().write_fmt(...).unwrap()`
-  --> tests/ui/explicit_write.rs:31:9
+  --> tests/ui/explicit_write.rs:30:9
    |
 LL |         std::io::stdout().write_fmt(format_args!("test")).unwrap();
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `print!("test")`
 
 error: use of `stderr().write_fmt(...).unwrap()`
-  --> tests/ui/explicit_write.rs:33:9
+  --> tests/ui/explicit_write.rs:32:9
    |
 LL |         std::io::stderr().write_fmt(format_args!("test")).unwrap();
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `eprint!("test")`
 
 error: use of `writeln!(stdout(), ...).unwrap()`
-  --> tests/ui/explicit_write.rs:37:9
+  --> tests/ui/explicit_write.rs:36:9
    |
 LL |         writeln!(std::io::stdout(), "test\ntest").unwrap();
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `println!("test\ntest")`
 
 error: use of `writeln!(stderr(), ...).unwrap()`
-  --> tests/ui/explicit_write.rs:39:9
+  --> tests/ui/explicit_write.rs:38:9
    |
 LL |         writeln!(std::io::stderr(), "test\ntest").unwrap();
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `eprintln!("test\ntest")`
 
 error: use of `writeln!(stderr(), ...).unwrap()`
-  --> tests/ui/explicit_write.rs:43:9
-   |
-LL |         writeln!(std::io::stderr(), "with {}", value).unwrap();
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `eprintln!("with {}", value)`
-
-error: use of `writeln!(stderr(), ...).unwrap()`
-  --> tests/ui/explicit_write.rs:45:9
-   |
-LL |         writeln!(std::io::stderr(), "with {} {}", 2, value).unwrap();
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `eprintln!("with {} {}", 2, value)`
-
-error: use of `writeln!(stderr(), ...).unwrap()`
-  --> tests/ui/explicit_write.rs:47:9
+  --> tests/ui/explicit_write.rs:42:9
    |
 LL |         writeln!(std::io::stderr(), "with {value}").unwrap();
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `eprintln!("with {value}")`
 
 error: use of `writeln!(stderr(), ...).unwrap()`
-  --> tests/ui/explicit_write.rs:49:9
+  --> tests/ui/explicit_write.rs:44:9
+   |
+LL |         writeln!(std::io::stderr(), "with {} {}", 2, value).unwrap();
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `eprintln!("with {} {}", 2, value)`
+
+error: use of `writeln!(stderr(), ...).unwrap()`
+  --> tests/ui/explicit_write.rs:46:9
+   |
+LL |         writeln!(std::io::stderr(), "with {value}").unwrap();
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `eprintln!("with {value}")`
+
+error: use of `writeln!(stderr(), ...).unwrap()`
+  --> tests/ui/explicit_write.rs:48:9
    |
 LL |         writeln!(std::io::stderr(), "macro arg {}", one!()).unwrap();
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `eprintln!("macro arg {}", one!())`
 
 error: use of `writeln!(stderr(), ...).unwrap()`
-  --> tests/ui/explicit_write.rs:52:9
+  --> tests/ui/explicit_write.rs:51:9
    |
-LL |         writeln!(std::io::stderr(), "{:w$}", value, w = width).unwrap();
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `eprintln!("{:w$}", value, w = width)`
+LL |         writeln!(std::io::stderr(), "{value:w$}", w = width).unwrap();
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `eprintln!("{value:w$}", w = width)`
 
 error: aborting due to 13 previous errors
 
diff --git a/tests/ui/fallible_impl_from.rs b/tests/ui/fallible_impl_from.rs
index 1c62c1e..28bb115 100644
--- a/tests/ui/fallible_impl_from.rs
+++ b/tests/ui/fallible_impl_from.rs
@@ -1,5 +1,4 @@
 #![deny(clippy::fallible_impl_from)]
-#![allow(clippy::uninlined_format_args)]
 
 // docs example
 struct Foo(i32);
@@ -62,7 +61,7 @@
 
     fn from(s: &'a mut <Box<u32> as ProjStrTrait>::ProjString) -> Invalid {
         if s.parse::<u32>().ok().unwrap() != 42 {
-            panic!("{:?}", s);
+            panic!("{s:?}");
         }
         Invalid
     }
diff --git a/tests/ui/fallible_impl_from.stderr b/tests/ui/fallible_impl_from.stderr
index 402494b..25ecc8b 100644
--- a/tests/ui/fallible_impl_from.stderr
+++ b/tests/ui/fallible_impl_from.stderr
@@ -1,5 +1,5 @@
 error: consider implementing `TryFrom` instead
-  --> tests/ui/fallible_impl_from.rs:6:1
+  --> tests/ui/fallible_impl_from.rs:5:1
    |
 LL | / impl From<String> for Foo {
 LL | |
@@ -11,7 +11,7 @@
    |
    = help: `From` is intended for infallible conversions only. Use `TryFrom` if there's a possibility for the conversion to fail
 note: potential failure(s)
-  --> tests/ui/fallible_impl_from.rs:10:13
+  --> tests/ui/fallible_impl_from.rs:9:13
    |
 LL |         Foo(s.parse().unwrap())
    |             ^^^^^^^^^^^^^^^^^^
@@ -22,7 +22,7 @@
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: consider implementing `TryFrom` instead
-  --> tests/ui/fallible_impl_from.rs:29:1
+  --> tests/ui/fallible_impl_from.rs:28:1
    |
 LL | / impl From<usize> for Invalid {
 LL | |
@@ -34,13 +34,13 @@
    |
    = help: `From` is intended for infallible conversions only. Use `TryFrom` if there's a possibility for the conversion to fail
 note: potential failure(s)
-  --> tests/ui/fallible_impl_from.rs:34:13
+  --> tests/ui/fallible_impl_from.rs:33:13
    |
 LL |             panic!();
    |             ^^^^^^^^
 
 error: consider implementing `TryFrom` instead
-  --> tests/ui/fallible_impl_from.rs:40:1
+  --> tests/ui/fallible_impl_from.rs:39:1
    |
 LL | / impl From<Option<String>> for Invalid {
 LL | |
@@ -52,7 +52,7 @@
    |
    = help: `From` is intended for infallible conversions only. Use `TryFrom` if there's a possibility for the conversion to fail
 note: potential failure(s)
-  --> tests/ui/fallible_impl_from.rs:44:17
+  --> tests/ui/fallible_impl_from.rs:43:17
    |
 LL |         let s = s.unwrap();
    |                 ^^^^^^^^^^
@@ -65,7 +65,7 @@
    |             ^^^^^^^^^^^^^^^^^
 
 error: consider implementing `TryFrom` instead
-  --> tests/ui/fallible_impl_from.rs:60:1
+  --> tests/ui/fallible_impl_from.rs:59:1
    |
 LL | / impl<'a> From<&'a mut <Box<u32> as ProjStrTrait>::ProjString> for Invalid {
 LL | |
@@ -77,12 +77,12 @@
    |
    = help: `From` is intended for infallible conversions only. Use `TryFrom` if there's a possibility for the conversion to fail
 note: potential failure(s)
-  --> tests/ui/fallible_impl_from.rs:64:12
+  --> tests/ui/fallible_impl_from.rs:63:12
    |
 LL |         if s.parse::<u32>().ok().unwrap() != 42 {
    |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-LL |             panic!("{:?}", s);
-   |             ^^^^^^^^^^^^^^^^^
+LL |             panic!("{s:?}");
+   |             ^^^^^^^^^^^^^^^
 
 error: aborting due to 4 previous errors
 
diff --git a/tests/ui/if_then_some_else_none.fixed b/tests/ui/if_then_some_else_none.fixed
index 0fd1306..7da9401 100644
--- a/tests/ui/if_then_some_else_none.fixed
+++ b/tests/ui/if_then_some_else_none.fixed
@@ -206,3 +206,15 @@
     }
     let _: Option<u32> = mac!(true, 42);
 }
+
+mod issue15770 {
+    fn maybe_error() -> Result<u32, &'static str> {
+        Err("error!")
+    }
+
+    pub fn trying(b: bool) -> Result<(), &'static str> {
+        let _x: Option<u32> = if b { Some(maybe_error()?) } else { None };
+        // Process _x locally
+        Ok(())
+    }
+}
diff --git a/tests/ui/if_then_some_else_none.rs b/tests/ui/if_then_some_else_none.rs
index 640828a..02962f8 100644
--- a/tests/ui/if_then_some_else_none.rs
+++ b/tests/ui/if_then_some_else_none.rs
@@ -262,3 +262,15 @@
     }
     let _: Option<u32> = mac!(true, 42);
 }
+
+mod issue15770 {
+    fn maybe_error() -> Result<u32, &'static str> {
+        Err("error!")
+    }
+
+    pub fn trying(b: bool) -> Result<(), &'static str> {
+        let _x: Option<u32> = if b { Some(maybe_error()?) } else { None };
+        // Process _x locally
+        Ok(())
+    }
+}
diff --git a/tests/ui/index_refutable_slice/if_let_slice_binding.fixed b/tests/ui/index_refutable_slice/if_let_slice_binding.fixed
index 050cdfc..dc7e09b 100644
--- a/tests/ui/index_refutable_slice/if_let_slice_binding.fixed
+++ b/tests/ui/index_refutable_slice/if_let_slice_binding.fixed
@@ -1,5 +1,5 @@
 #![deny(clippy::index_refutable_slice)]
-#![allow(clippy::uninlined_format_args, clippy::needless_lifetimes, clippy::collapsible_if)]
+#![allow(clippy::needless_lifetimes, clippy::collapsible_if)]
 
 enum SomeEnum<T> {
     One(T),
@@ -60,7 +60,7 @@
 
         println!("{:?}", slice_1);
     }
-    println!("{:?}", slice);
+    println!("{slice:?}");
 
     // This should not suggest using the `ref` keyword as the scrutinee is already
     // a reference
@@ -70,7 +70,7 @@
 
         println!("{:?}", slice_0);
     }
-    println!("{:?}", slice);
+    println!("{slice:?}");
 }
 
 fn slice_index_above_limit() {
@@ -113,7 +113,7 @@
             println!("This is interesting {}", slice[0]);
         }
     }
-    println!("{:?}", slice_wrapped);
+    println!("{slice_wrapped:?}");
 }
 
 fn check_slice_in_struct() {
@@ -152,7 +152,7 @@
             println!("This is super awesome! {}", slice_0);
         }
     }
-    println!("Complete wrap: {:?}", wrap);
+    println!("Complete wrap: {wrap:?}");
 }
 
 /// This would be a nice additional feature to have in the future, but adding it
@@ -164,14 +164,14 @@
     if let Some(ref mut slice) = slice {
         slice[0] = String::from("Mr. Penguin");
     }
-    println!("Use after modification: {:?}", slice);
+    println!("Use after modification: {slice:?}");
 
     // Mut access on reference
     let mut slice: Option<[String; 1]> = Some([String::from("Cat")]);
     if let Some(slice) = &mut slice {
         slice[0] = String::from("Lord Meow Meow");
     }
-    println!("Use after modification: {:?}", slice);
+    println!("Use after modification: {slice:?}");
 }
 
 /// The lint will ignore bindings with sub patterns as it would be hard
diff --git a/tests/ui/index_refutable_slice/if_let_slice_binding.rs b/tests/ui/index_refutable_slice/if_let_slice_binding.rs
index 91429bf..f39ace1 100644
--- a/tests/ui/index_refutable_slice/if_let_slice_binding.rs
+++ b/tests/ui/index_refutable_slice/if_let_slice_binding.rs
@@ -1,5 +1,5 @@
 #![deny(clippy::index_refutable_slice)]
-#![allow(clippy::uninlined_format_args, clippy::needless_lifetimes, clippy::collapsible_if)]
+#![allow(clippy::needless_lifetimes, clippy::collapsible_if)]
 
 enum SomeEnum<T> {
     One(T),
@@ -60,7 +60,7 @@
 
         println!("{:?}", slice[1]);
     }
-    println!("{:?}", slice);
+    println!("{slice:?}");
 
     // This should not suggest using the `ref` keyword as the scrutinee is already
     // a reference
@@ -70,7 +70,7 @@
 
         println!("{:?}", slice[0]);
     }
-    println!("{:?}", slice);
+    println!("{slice:?}");
 }
 
 fn slice_index_above_limit() {
@@ -113,7 +113,7 @@
             println!("This is interesting {}", slice[0]);
         }
     }
-    println!("{:?}", slice_wrapped);
+    println!("{slice_wrapped:?}");
 }
 
 fn check_slice_in_struct() {
@@ -152,7 +152,7 @@
             println!("This is super awesome! {}", slice[0]);
         }
     }
-    println!("Complete wrap: {:?}", wrap);
+    println!("Complete wrap: {wrap:?}");
 }
 
 /// This would be a nice additional feature to have in the future, but adding it
@@ -164,14 +164,14 @@
     if let Some(ref mut slice) = slice {
         slice[0] = String::from("Mr. Penguin");
     }
-    println!("Use after modification: {:?}", slice);
+    println!("Use after modification: {slice:?}");
 
     // Mut access on reference
     let mut slice: Option<[String; 1]> = Some([String::from("Cat")]);
     if let Some(slice) = &mut slice {
         slice[0] = String::from("Lord Meow Meow");
     }
-    println!("Use after modification: {:?}", slice);
+    println!("Use after modification: {slice:?}");
 }
 
 /// The lint will ignore bindings with sub patterns as it would be hard
diff --git a/tests/ui/infinite_iter.rs b/tests/ui/infinite_iter.rs
index 701a865..4e1668e 100644
--- a/tests/ui/infinite_iter.rs
+++ b/tests/ui/infinite_iter.rs
@@ -1,4 +1,4 @@
-#![allow(clippy::uninlined_format_args, clippy::double_ended_iterator_last)]
+#![allow(clippy::double_ended_iterator_last)]
 
 use std::iter::repeat;
 fn square_is_lower_64(x: &u32) -> bool {
@@ -30,7 +30,7 @@
         .rev()
         .cycle()
         .map(|x| x + 1_u32)
-        .for_each(|x| println!("{}", x));
+        .for_each(|x| println!("{x}"));
     // infinite iter
     (0..3_u32).flat_map(|x| x..).sum::<u32>();
     // infinite iter
diff --git a/tests/ui/infinite_iter.stderr b/tests/ui/infinite_iter.stderr
index b9e7c00..3db9731 100644
--- a/tests/ui/infinite_iter.stderr
+++ b/tests/ui/infinite_iter.stderr
@@ -30,8 +30,8 @@
 LL | |         .rev()
 LL | |         .cycle()
 LL | |         .map(|x| x + 1_u32)
-LL | |         .for_each(|x| println!("{}", x));
-   | |________________________________________^
+LL | |         .for_each(|x| println!("{x}"));
+   | |______________________________________^
 
 error: infinite iteration detected
   --> tests/ui/infinite_iter.rs:37:5
diff --git a/tests/ui/issue_2356.fixed b/tests/ui/issue_2356.fixed
index 46ba653..3e066df 100644
--- a/tests/ui/issue_2356.fixed
+++ b/tests/ui/issue_2356.fixed
@@ -1,6 +1,5 @@
 #![deny(clippy::while_let_on_iterator)]
 #![allow(unused_mut)]
-#![allow(clippy::uninlined_format_args)]
 
 use std::iter::Iterator;
 
@@ -16,7 +15,7 @@
     fn foo2<I: Iterator<Item = usize>>(mut it: I) {
         for e in it {
             //~^ while_let_on_iterator
-            println!("{:?}", e);
+            println!("{e:?}");
         }
     }
 }
diff --git a/tests/ui/issue_2356.rs b/tests/ui/issue_2356.rs
index defe258..98600d1 100644
--- a/tests/ui/issue_2356.rs
+++ b/tests/ui/issue_2356.rs
@@ -1,6 +1,5 @@
 #![deny(clippy::while_let_on_iterator)]
 #![allow(unused_mut)]
-#![allow(clippy::uninlined_format_args)]
 
 use std::iter::Iterator;
 
@@ -16,7 +15,7 @@
     fn foo2<I: Iterator<Item = usize>>(mut it: I) {
         while let Some(e) = it.next() {
             //~^ while_let_on_iterator
-            println!("{:?}", e);
+            println!("{e:?}");
         }
     }
 }
diff --git a/tests/ui/issue_2356.stderr b/tests/ui/issue_2356.stderr
index eae2ce9..ddee91f 100644
--- a/tests/ui/issue_2356.stderr
+++ b/tests/ui/issue_2356.stderr
@@ -1,5 +1,5 @@
 error: this loop could be written as a `for` loop
-  --> tests/ui/issue_2356.rs:17:9
+  --> tests/ui/issue_2356.rs:16:9
    |
 LL |         while let Some(e) = it.next() {
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for e in it`
diff --git a/tests/ui/issue_4266.rs b/tests/ui/issue_4266.rs
index 664f0b8..b2a0112 100644
--- a/tests/ui/issue_4266.rs
+++ b/tests/ui/issue_4266.rs
@@ -1,5 +1,4 @@
 #![allow(dead_code)]
-#![allow(clippy::uninlined_format_args)]
 
 async fn sink1<'a>(_: &'a str) {} // lint
 //~^ needless_lifetimes
@@ -39,7 +38,7 @@
 // rust-lang/rust#61115
 // ok
 async fn print(s: &str) {
-    println!("{}", s);
+    println!("{s}");
 }
 
 fn main() {}
diff --git a/tests/ui/issue_4266.stderr b/tests/ui/issue_4266.stderr
index 0e18102..b80a738 100644
--- a/tests/ui/issue_4266.stderr
+++ b/tests/ui/issue_4266.stderr
@@ -1,5 +1,5 @@
 error: the following explicit lifetimes could be elided: 'a
-  --> tests/ui/issue_4266.rs:4:16
+  --> tests/ui/issue_4266.rs:3:16
    |
 LL | async fn sink1<'a>(_: &'a str) {} // lint
    |                ^^      ^^
@@ -8,13 +8,13 @@
    = help: to override `-D warnings` add `#[allow(clippy::needless_lifetimes)]`
 
 error: the following explicit lifetimes could be elided: 'a
-  --> tests/ui/issue_4266.rs:10:21
+  --> tests/ui/issue_4266.rs:9:21
    |
 LL | async fn one_to_one<'a>(s: &'a str) -> &'a str {
    |                     ^^      ^^          ^^
 
 error: methods called `new` usually take no `self`
-  --> tests/ui/issue_4266.rs:32:22
+  --> tests/ui/issue_4266.rs:31:22
    |
 LL |     pub async fn new(&mut self) -> Self {
    |                      ^^^^^^^^^
diff --git a/tests/ui/let_unit.fixed b/tests/ui/let_unit.fixed
index 381d4ca..e8517f1 100644
--- a/tests/ui/let_unit.fixed
+++ b/tests/ui/let_unit.fixed
@@ -1,5 +1,10 @@
 #![warn(clippy::let_unit_value)]
-#![allow(unused, clippy::no_effect, clippy::needless_late_init, path_statements)]
+#![allow(
+    clippy::no_effect,
+    clippy::needless_late_init,
+    path_statements,
+    clippy::match_single_binding
+)]
 
 macro_rules! let_and_return {
     ($n:expr) => {{
@@ -15,12 +20,12 @@
     if true {
         // do not lint this, since () is explicit
         let _a = ();
-        let () = dummy();
+        let () = returns_unit();
         let () = ();
-        () = dummy();
+        () = returns_unit();
         () = ();
         let _a: () = ();
-        let _a: () = dummy();
+        let _a: () = returns_unit();
     }
 
     consume_units_with_for_loop(); // should be fine as well
@@ -30,7 +35,7 @@
     let_and_return!(()) // should be fine
 }
 
-fn dummy() {}
+fn returns_unit() {}
 
 // Related to issue #1964
 fn consume_units_with_for_loop() {
@@ -181,8 +186,6 @@
 pub async fn issue11502(a: ()) {}
 
 pub fn issue12594() {
-    fn returns_unit() {}
-
     fn returns_result<T>(res: T) -> Result<T, ()> {
         Ok(res)
     }
@@ -199,13 +202,30 @@
     }
 }
 
-fn issue15061() {
-    fn return_unit() {}
-    fn do_something(x: ()) {}
+fn takes_unit(x: ()) {}
 
+fn issue15061() {
     let res = ();
-    return_unit();
+    returns_unit();
     //~^ let_unit_value
-    do_something(());
+    takes_unit(());
+    println!("{res:?}");
+}
+
+fn issue15771() {
+    match "Example String" {
+        _ => returns_unit(),
+        //~^ let_unit_value
+    }
+
+    if true {}
+    //~^ let_unit_value
+}
+
+fn issue_15784() {
+    let res = ();
+    eprintln!("I return unit");
+    //~^ let_unit_value
+    takes_unit(());
     println!("{res:?}");
 }
diff --git a/tests/ui/let_unit.rs b/tests/ui/let_unit.rs
index cdfc749..3f6f013 100644
--- a/tests/ui/let_unit.rs
+++ b/tests/ui/let_unit.rs
@@ -1,5 +1,10 @@
 #![warn(clippy::let_unit_value)]
-#![allow(unused, clippy::no_effect, clippy::needless_late_init, path_statements)]
+#![allow(
+    clippy::no_effect,
+    clippy::needless_late_init,
+    path_statements,
+    clippy::match_single_binding
+)]
 
 macro_rules! let_and_return {
     ($n:expr) => {{
@@ -15,12 +20,12 @@
     if true {
         // do not lint this, since () is explicit
         let _a = ();
-        let () = dummy();
+        let () = returns_unit();
         let () = ();
-        () = dummy();
+        () = returns_unit();
         () = ();
         let _a: () = ();
-        let _a: () = dummy();
+        let _a: () = returns_unit();
     }
 
     consume_units_with_for_loop(); // should be fine as well
@@ -30,7 +35,7 @@
     let_and_return!(()) // should be fine
 }
 
-fn dummy() {}
+fn returns_unit() {}
 
 // Related to issue #1964
 fn consume_units_with_for_loop() {
@@ -181,8 +186,6 @@
 pub async fn issue11502(a: ()) {}
 
 pub fn issue12594() {
-    fn returns_unit() {}
-
     fn returns_result<T>(res: T) -> Result<T, ()> {
         Ok(res)
     }
@@ -199,12 +202,28 @@
     }
 }
 
-fn issue15061() {
-    fn return_unit() {}
-    fn do_something(x: ()) {}
+fn takes_unit(x: ()) {}
 
-    let res = return_unit();
+fn issue15061() {
+    let res = returns_unit();
     //~^ let_unit_value
-    do_something(res);
+    takes_unit(res);
+    println!("{res:?}");
+}
+
+fn issue15771() {
+    match "Example String" {
+        _ => _ = returns_unit(),
+        //~^ let_unit_value
+    }
+
+    _ = if true {}
+    //~^ let_unit_value
+}
+
+fn issue_15784() {
+    let res = eprintln!("I return unit");
+    //~^ let_unit_value
+    takes_unit(res);
     println!("{res:?}");
 }
diff --git a/tests/ui/let_unit.stderr b/tests/ui/let_unit.stderr
index 637c9ff..8ced32a 100644
--- a/tests/ui/let_unit.stderr
+++ b/tests/ui/let_unit.stderr
@@ -1,14 +1,19 @@
 error: this let-binding has unit value
-  --> tests/ui/let_unit.rs:11:5
+  --> tests/ui/let_unit.rs:16:5
    |
 LL |     let _x = println!("x");
-   |     ^^^^^^^^^^^^^^^^^^^^^^^ help: omit the `let` binding: `println!("x");`
+   |     ^^^^^^^^^^^^^^^^^^^^^^^
    |
    = note: `-D clippy::let-unit-value` implied by `-D warnings`
    = help: to override `-D warnings` add `#[allow(clippy::let_unit_value)]`
+help: omit the `let` binding
+   |
+LL -     let _x = println!("x");
+LL +     println!("x");
+   |
 
 error: this let-binding has unit value
-  --> tests/ui/let_unit.rs:60:5
+  --> tests/ui/let_unit.rs:65:5
    |
 LL | /     let _ = v
 LL | |
@@ -21,18 +26,12 @@
    |
 help: omit the `let` binding
    |
-LL ~     v
-LL +
-LL +         .into_iter()
-LL +         .map(|i| i * 2)
-LL +         .filter(|i| i.is_multiple_of(2))
-LL +         .map(|_| ())
-LL +         .next()
-LL +         .unwrap();
+LL -     let _ = v
+LL +     v
    |
 
 error: this let-binding has unit value
-  --> tests/ui/let_unit.rs:110:5
+  --> tests/ui/let_unit.rs:115:5
    |
 LL | /     let x = match Some(0) {
 LL | |
@@ -45,17 +44,12 @@
    |
 help: omit the `let` binding
    |
-LL ~     match Some(0) {
-LL +
-LL +         None => f2(1),
-LL +         Some(0) => f(),
-LL +         Some(1) => f2(3),
-LL +         Some(_) => (),
-LL +     };
+LL -     let x = match Some(0) {
+LL +     match Some(0) {
    |
 
 error: this let-binding has unit value
-  --> tests/ui/let_unit.rs:192:9
+  --> tests/ui/let_unit.rs:195:9
    |
 LL |         let res = returns_unit();
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -69,18 +63,56 @@
    |
 
 error: this let-binding has unit value
-  --> tests/ui/let_unit.rs:206:5
+  --> tests/ui/let_unit.rs:208:5
    |
-LL |     let res = return_unit();
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^
+LL |     let res = returns_unit();
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
    |
 help: replace variable usages with `()`
    |
 LL ~     let res = ();
-LL ~     return_unit();
+LL ~     returns_unit();
 LL |
-LL ~     do_something(());
+LL ~     takes_unit(());
    |
 
-error: aborting due to 5 previous errors
+error: this let-binding has unit value
+  --> tests/ui/let_unit.rs:216:14
+   |
+LL |         _ => _ = returns_unit(),
+   |              ^^^^^^^^^^^^^^^^^^
+   |
+help: omit the `let` binding
+   |
+LL -         _ => _ = returns_unit(),
+LL +         _ => returns_unit(),
+   |
+
+error: this let-binding has unit value
+  --> tests/ui/let_unit.rs:220:5
+   |
+LL |     _ = if true {}
+   |     ^^^^^^^^^^^^^^
+   |
+help: omit the `let` binding
+   |
+LL -     _ = if true {}
+LL +     if true {}
+   |
+
+error: this let-binding has unit value
+  --> tests/ui/let_unit.rs:225:5
+   |
+LL |     let res = eprintln!("I return unit");
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: replace variable usages with `()`
+   |
+LL ~     let res = ();
+LL ~     eprintln!("I return unit");
+LL |
+LL ~     takes_unit(());
+   |
+
+error: aborting due to 8 previous errors
 
diff --git a/tests/ui/match_single_binding.fixed b/tests/ui/match_single_binding.fixed
index e29fb87..7e899a4 100644
--- a/tests/ui/match_single_binding.fixed
+++ b/tests/ui/match_single_binding.fixed
@@ -4,7 +4,6 @@
     clippy::let_unit_value,
     clippy::no_effect,
     clippy::toplevel_ref_arg,
-    clippy::uninlined_format_args,
     clippy::useless_vec
 )]
 
@@ -32,11 +31,11 @@
     // Lint
     let (x, y, z) = (a, b, c);
     {
-        println!("{} {} {}", x, y, z);
+        println!("{x} {y} {z}");
     }
     // Lint
     let (x, y, z) = (a, b, c);
-    println!("{} {} {}", x, y, z);
+    println!("{x} {y} {z}");
     // Ok
     foo!(a);
     // Ok
@@ -47,7 +46,7 @@
     // Ok
     let d = Some(5);
     match d {
-        Some(d) => println!("{}", d),
+        Some(d) => println!("{d}"),
         _ => println!("None"),
     }
     // Lint
@@ -55,7 +54,7 @@
     // Lint
     {
         let x = 29;
-        println!("x has a value of {}", x);
+        println!("x has a value of {x}");
     }
     // Lint
     {
@@ -67,18 +66,18 @@
     // Lint
     let p = Point { x: 0, y: 7 };
     let Point { x, y } = p;
-    println!("Coords: ({}, {})", x, y);
+    println!("Coords: ({x}, {y})");
     // Lint
     let Point { x: x1, y: y1 } = p;
-    println!("Coords: ({}, {})", x1, y1);
+    println!("Coords: ({x1}, {y1})");
     // Lint
     let x = 5;
     let ref r = x;
-    println!("Got a reference to {}", r);
+    println!("Got a reference to {r}");
     // Lint
     let mut x = 5;
     let ref mut mr = x;
-    println!("Got a mutable reference to {}", mr);
+    println!("Got a mutable reference to {mr}");
     // Lint
     let Point { x, y } = coords();
     let product = x * y;
@@ -122,7 +121,7 @@
 
     let (pre, suf) = val.split_at(idx);
     val = {
-        println!("{}", pre);
+        println!("{pre}");
         suf
     };
 
@@ -210,20 +209,20 @@
         let x = 1;
         {
             let (x, y, z) = (a, b, c);
-            println!("{} {} {}", x, y, z);
+            println!("{x} {y} {z}");
         }
         println!("x = {x}");
     }
 
     fn not_used_later(a: i32, b: i32, c: i32) {
         let (x, y, z) = (a, b, c);
-        println!("{} {} {}", x, y, z)
+        println!("{x} {y} {z}")
     }
 
     #[allow(irrefutable_let_patterns)]
     fn not_used_later_but_shadowed(a: i32, b: i32, c: i32) {
         let (x, y, z) = (a, b, c);
-        println!("{} {} {}", x, y, z);
+        println!("{x} {y} {z}");
         let x = 1;
         println!("x = {x}");
     }
@@ -231,27 +230,27 @@
     #[allow(irrefutable_let_patterns)]
     fn not_used_later_but_shadowed_nested(a: i32, b: i32, c: i32) {
         let (x, y, z) = (a, b, c);
-        println!("{} {} {}", x, y, z);
+        println!("{x} {x} {y}");
         if let (x, y, z) = (a, b, c) {
-            println!("{} {} {}", x, y, z)
+            println!("{x} {y} {z}")
         }
 
         {
             let x: i32 = 1;
             {
                 let (x, y, z) = (a, b, c);
-                println!("{} {} {}", x, y, z);
+                println!("{x} {y} {z}");
             }
             if let (x, y, z) = (a, x, c) {
-                println!("{} {} {}", x, y, z)
+                println!("{x} {y} {z}")
             }
         }
 
         {
             let (x, y, z) = (a, b, c);
-            println!("{} {} {}", x, y, z);
+            println!("{x} {y} {z}");
             let fn_ = |y| {
-                println!("{} {} {}", a, b, y);
+                println!("{a} {b} {y}");
             };
             fn_(c);
         }
diff --git a/tests/ui/match_single_binding.rs b/tests/ui/match_single_binding.rs
index ede1ab3..37a96f2 100644
--- a/tests/ui/match_single_binding.rs
+++ b/tests/ui/match_single_binding.rs
@@ -4,7 +4,6 @@
     clippy::let_unit_value,
     clippy::no_effect,
     clippy::toplevel_ref_arg,
-    clippy::uninlined_format_args,
     clippy::useless_vec
 )]
 
@@ -33,13 +32,13 @@
     match (a, b, c) {
         //~^ match_single_binding
         (x, y, z) => {
-            println!("{} {} {}", x, y, z);
+            println!("{x} {y} {z}");
         },
     }
     // Lint
     match (a, b, c) {
         //~^ match_single_binding
-        (x, y, z) => println!("{} {} {}", x, y, z),
+        (x, y, z) => println!("{x} {y} {z}"),
     }
     // Ok
     foo!(a);
@@ -51,7 +50,7 @@
     // Ok
     let d = Some(5);
     match d {
-        Some(d) => println!("{}", d),
+        Some(d) => println!("{d}"),
         _ => println!("None"),
     }
     // Lint
@@ -64,7 +63,7 @@
         //~^ match_single_binding
         _ => {
             let x = 29;
-            println!("x has a value of {}", x);
+            println!("x has a value of {x}");
         },
     }
     // Lint
@@ -81,24 +80,24 @@
     let p = Point { x: 0, y: 7 };
     match p {
         //~^ match_single_binding
-        Point { x, y } => println!("Coords: ({}, {})", x, y),
+        Point { x, y } => println!("Coords: ({x}, {y})"),
     }
     // Lint
     match p {
         //~^ match_single_binding
-        Point { x: x1, y: y1 } => println!("Coords: ({}, {})", x1, y1),
+        Point { x: x1, y: y1 } => println!("Coords: ({x1}, {y1})"),
     }
     // Lint
     let x = 5;
     match x {
         //~^ match_single_binding
-        ref r => println!("Got a reference to {}", r),
+        ref r => println!("Got a reference to {r}"),
     }
     // Lint
     let mut x = 5;
     match x {
         //~^ match_single_binding
-        ref mut mr => println!("Got a mutable reference to {}", mr),
+        ref mut mr => println!("Got a mutable reference to {mr}"),
     }
     // Lint
     let product = match coords() {
@@ -150,7 +149,7 @@
     val = match val.split_at(idx) {
         //~^ match_single_binding
         (pre, suf) => {
-            println!("{}", pre);
+            println!("{pre}");
             suf
         },
     };
@@ -273,7 +272,7 @@
         let x = 1;
         match (a, b, c) {
             //~^ match_single_binding
-            (x, y, z) => println!("{} {} {}", x, y, z),
+            (x, y, z) => println!("{x} {y} {z}"),
         }
         println!("x = {x}");
     }
@@ -281,7 +280,7 @@
     fn not_used_later(a: i32, b: i32, c: i32) {
         match (a, b, c) {
             //~^ match_single_binding
-            (x, y, z) => println!("{} {} {}", x, y, z),
+            (x, y, z) => println!("{x} {y} {z}"),
         }
     }
 
@@ -289,7 +288,7 @@
     fn not_used_later_but_shadowed(a: i32, b: i32, c: i32) {
         match (a, b, c) {
             //~^ match_single_binding
-            (x, y, z) => println!("{} {} {}", x, y, z),
+            (x, y, z) => println!("{x} {y} {z}"),
         }
         let x = 1;
         println!("x = {x}");
@@ -299,30 +298,30 @@
     fn not_used_later_but_shadowed_nested(a: i32, b: i32, c: i32) {
         match (a, b, c) {
             //~^ match_single_binding
-            (x, y, z) => println!("{} {} {}", x, y, z),
+            (x, y, z) => println!("{x} {x} {y}"),
         }
         if let (x, y, z) = (a, b, c) {
-            println!("{} {} {}", x, y, z)
+            println!("{x} {y} {z}")
         }
 
         {
             let x: i32 = 1;
             match (a, b, c) {
                 //~^ match_single_binding
-                (x, y, z) => println!("{} {} {}", x, y, z),
+                (x, y, z) => println!("{x} {y} {z}"),
             }
             if let (x, y, z) = (a, x, c) {
-                println!("{} {} {}", x, y, z)
+                println!("{x} {y} {z}")
             }
         }
 
         {
             match (a, b, c) {
                 //~^ match_single_binding
-                (x, y, z) => println!("{} {} {}", x, y, z),
+                (x, y, z) => println!("{x} {y} {z}"),
             }
             let fn_ = |y| {
-                println!("{} {} {}", a, b, y);
+                println!("{a} {b} {y}");
             };
             fn_(c);
         }
diff --git a/tests/ui/match_single_binding.stderr b/tests/ui/match_single_binding.stderr
index eea7177..82fc43a 100644
--- a/tests/ui/match_single_binding.stderr
+++ b/tests/ui/match_single_binding.stderr
@@ -1,10 +1,10 @@
 error: this match could be written as a `let` statement
-  --> tests/ui/match_single_binding.rs:33:5
+  --> tests/ui/match_single_binding.rs:32:5
    |
 LL | /     match (a, b, c) {
 LL | |
 LL | |         (x, y, z) => {
-LL | |             println!("{} {} {}", x, y, z);
+LL | |             println!("{x} {y} {z}");
 LL | |         },
 LL | |     }
    | |_____^
@@ -15,27 +15,27 @@
    |
 LL ~     let (x, y, z) = (a, b, c);
 LL +     {
-LL +         println!("{} {} {}", x, y, z);
+LL +         println!("{x} {y} {z}");
 LL +     }
    |
 
 error: this match could be written as a `let` statement
-  --> tests/ui/match_single_binding.rs:40:5
+  --> tests/ui/match_single_binding.rs:39:5
    |
 LL | /     match (a, b, c) {
 LL | |
-LL | |         (x, y, z) => println!("{} {} {}", x, y, z),
+LL | |         (x, y, z) => println!("{x} {y} {z}"),
 LL | |     }
    | |_____^
    |
 help: consider using a `let` statement
    |
 LL ~     let (x, y, z) = (a, b, c);
-LL +     println!("{} {} {}", x, y, z);
+LL +     println!("{x} {y} {z}");
    |
 
 error: this match could be replaced by its body itself
-  --> tests/ui/match_single_binding.rs:58:5
+  --> tests/ui/match_single_binding.rs:57:5
    |
 LL | /     match a {
 LL | |
@@ -44,13 +44,13 @@
    | |_____^ help: consider using the match body instead: `println!("whatever");`
 
 error: this match could be replaced by its body itself
-  --> tests/ui/match_single_binding.rs:63:5
+  --> tests/ui/match_single_binding.rs:62:5
    |
 LL | /     match a {
 LL | |
 LL | |         _ => {
 LL | |             let x = 29;
-LL | |             println!("x has a value of {}", x);
+LL | |             println!("x has a value of {x}");
 LL | |         },
 LL | |     }
    | |_____^
@@ -59,12 +59,12 @@
    |
 LL ~     {
 LL +         let x = 29;
-LL +         println!("x has a value of {}", x);
+LL +         println!("x has a value of {x}");
 LL +     }
    |
 
 error: this match could be replaced by its body itself
-  --> tests/ui/match_single_binding.rs:71:5
+  --> tests/ui/match_single_binding.rs:70:5
    |
 LL | /     match a {
 LL | |
@@ -86,67 +86,67 @@
    |
 
 error: this match could be written as a `let` statement
-  --> tests/ui/match_single_binding.rs:82:5
+  --> tests/ui/match_single_binding.rs:81:5
    |
 LL | /     match p {
 LL | |
-LL | |         Point { x, y } => println!("Coords: ({}, {})", x, y),
+LL | |         Point { x, y } => println!("Coords: ({x}, {y})"),
 LL | |     }
    | |_____^
    |
 help: consider using a `let` statement
    |
 LL ~     let Point { x, y } = p;
-LL +     println!("Coords: ({}, {})", x, y);
+LL +     println!("Coords: ({x}, {y})");
    |
 
 error: this match could be written as a `let` statement
-  --> tests/ui/match_single_binding.rs:87:5
+  --> tests/ui/match_single_binding.rs:86:5
    |
 LL | /     match p {
 LL | |
-LL | |         Point { x: x1, y: y1 } => println!("Coords: ({}, {})", x1, y1),
+LL | |         Point { x: x1, y: y1 } => println!("Coords: ({x1}, {y1})"),
 LL | |     }
    | |_____^
    |
 help: consider using a `let` statement
    |
 LL ~     let Point { x: x1, y: y1 } = p;
-LL +     println!("Coords: ({}, {})", x1, y1);
+LL +     println!("Coords: ({x1}, {y1})");
    |
 
 error: this match could be written as a `let` statement
-  --> tests/ui/match_single_binding.rs:93:5
+  --> tests/ui/match_single_binding.rs:92:5
    |
 LL | /     match x {
 LL | |
-LL | |         ref r => println!("Got a reference to {}", r),
+LL | |         ref r => println!("Got a reference to {r}"),
 LL | |     }
    | |_____^
    |
 help: consider using a `let` statement
    |
 LL ~     let ref r = x;
-LL +     println!("Got a reference to {}", r);
+LL +     println!("Got a reference to {r}");
    |
 
 error: this match could be written as a `let` statement
-  --> tests/ui/match_single_binding.rs:99:5
+  --> tests/ui/match_single_binding.rs:98:5
    |
 LL | /     match x {
 LL | |
-LL | |         ref mut mr => println!("Got a mutable reference to {}", mr),
+LL | |         ref mut mr => println!("Got a mutable reference to {mr}"),
 LL | |     }
    | |_____^
    |
 help: consider using a `let` statement
    |
 LL ~     let ref mut mr = x;
-LL +     println!("Got a mutable reference to {}", mr);
+LL +     println!("Got a mutable reference to {mr}");
    |
 
 error: this match could be written as a `let` statement
-  --> tests/ui/match_single_binding.rs:104:5
+  --> tests/ui/match_single_binding.rs:103:5
    |
 LL | /     let product = match coords() {
 LL | |
@@ -161,7 +161,7 @@
    |
 
 error: this match could be written as a `let` statement
-  --> tests/ui/match_single_binding.rs:113:18
+  --> tests/ui/match_single_binding.rs:112:18
    |
 LL |           .map(|i| match i.unwrap() {
    |  __________________^
@@ -179,7 +179,7 @@
    |
 
 error: this match could be replaced by its body itself
-  --> tests/ui/match_single_binding.rs:140:5
+  --> tests/ui/match_single_binding.rs:139:5
    |
 LL | /     match x {
 LL | |
@@ -189,12 +189,12 @@
    | |_____^ help: consider using the match body instead: `println!("Not an array index start")`
 
 error: this assignment could be simplified
-  --> tests/ui/match_single_binding.rs:150:5
+  --> tests/ui/match_single_binding.rs:149:5
    |
 LL | /     val = match val.split_at(idx) {
 LL | |
 LL | |         (pre, suf) => {
-LL | |             println!("{}", pre);
+LL | |             println!("{pre}");
 LL | |             suf
 LL | |         },
 LL | |     };
@@ -204,13 +204,13 @@
    |
 LL ~     let (pre, suf) = val.split_at(idx);
 LL +     val = {
-LL +         println!("{}", pre);
+LL +         println!("{pre}");
 LL +         suf
 LL ~     };
    |
 
 error: this match could be replaced by its scrutinee and body
-  --> tests/ui/match_single_binding.rs:164:16
+  --> tests/ui/match_single_binding.rs:163:16
    |
 LL |       let _ = || match side_effects() {
    |  ________________^
@@ -228,7 +228,7 @@
    |
 
 error: this match could be written as a `let` statement
-  --> tests/ui/match_single_binding.rs:171:5
+  --> tests/ui/match_single_binding.rs:170:5
    |
 LL | /     match r {
 LL | |
@@ -253,7 +253,7 @@
    |
 
 error: this match could be replaced by its body itself
-  --> tests/ui/match_single_binding.rs:185:5
+  --> tests/ui/match_single_binding.rs:184:5
    |
 LL | /     match 1 {
 LL | |
@@ -262,7 +262,7 @@
    | |_____^ help: consider using the match body instead: `();`
 
 error: this match could be replaced by its body itself
-  --> tests/ui/match_single_binding.rs:190:13
+  --> tests/ui/match_single_binding.rs:189:13
    |
 LL |       let a = match 1 {
    |  _____________^
@@ -272,7 +272,7 @@
    | |_____^ help: consider using the match body instead: `()`
 
 error: this match could be replaced by its body itself
-  --> tests/ui/match_single_binding.rs:195:5
+  --> tests/ui/match_single_binding.rs:194:5
    |
 LL | /     match 1 {
 LL | |
@@ -281,7 +281,7 @@
    | |_____^ help: consider using the match body instead: `side_effects();`
 
 error: this match could be replaced by its body itself
-  --> tests/ui/match_single_binding.rs:200:13
+  --> tests/ui/match_single_binding.rs:199:13
    |
 LL |       let b = match 1 {
    |  _____________^
@@ -291,7 +291,7 @@
    | |_____^ help: consider using the match body instead: `side_effects()`
 
 error: this match could be replaced by its body itself
-  --> tests/ui/match_single_binding.rs:205:5
+  --> tests/ui/match_single_binding.rs:204:5
    |
 LL | /     match 1 {
 LL | |
@@ -300,7 +300,7 @@
    | |_____^ help: consider using the match body instead: `println!("1");`
 
 error: this match could be replaced by its body itself
-  --> tests/ui/match_single_binding.rs:210:13
+  --> tests/ui/match_single_binding.rs:209:13
    |
 LL |       let c = match 1 {
    |  _____________^
@@ -310,7 +310,7 @@
    | |_____^ help: consider using the match body instead: `println!("1")`
 
 error: this match could be replaced by its body itself
-  --> tests/ui/match_single_binding.rs:216:9
+  --> tests/ui/match_single_binding.rs:215:9
    |
 LL | /         match 1 {
 LL | |
@@ -319,7 +319,7 @@
    | |_________^ help: consider using the match body instead: `()`
 
 error: this match could be replaced by its body itself
-  --> tests/ui/match_single_binding.rs:220:9
+  --> tests/ui/match_single_binding.rs:219:9
    |
 LL | /         match 1 {
 LL | |
@@ -328,7 +328,7 @@
    | |_________^ help: consider using the match body instead: `side_effects()`
 
 error: this match could be replaced by its body itself
-  --> tests/ui/match_single_binding.rs:224:9
+  --> tests/ui/match_single_binding.rs:223:9
    |
 LL | /         match 1 {
 LL | |
@@ -337,7 +337,7 @@
    | |_________^ help: consider using the match body instead: `println!("1")`
 
 error: this match could be replaced by its scrutinee and body
-  --> tests/ui/match_single_binding.rs:239:5
+  --> tests/ui/match_single_binding.rs:238:5
    |
 LL | /     match dbg!(3) {
 LL | |         _ => println!("here"),
@@ -351,7 +351,7 @@
    |
 
 error: this match could be written as a `let` statement
-  --> tests/ui/match_single_binding.rs:243:5
+  --> tests/ui/match_single_binding.rs:242:5
    |
 LL | /     match dbg!(3) {
 LL | |         id!(a) => println!("found {a}"),
@@ -365,7 +365,7 @@
    |
 
 error: this match could be written as a `let` statement
-  --> tests/ui/match_single_binding.rs:247:5
+  --> tests/ui/match_single_binding.rs:246:5
    |
 LL | /     let id!(_a) = match dbg!(3) {
 LL | |         id!(b) => dbg!(b + 1),
@@ -379,7 +379,7 @@
    |
 
 error: this match could be written as a `let` statement
-  --> tests/ui/match_single_binding.rs:255:21
+  --> tests/ui/match_single_binding.rs:254:21
    |
 LL |           inner: [(); match 1 {
    |  _____________________^
@@ -397,7 +397,7 @@
    |
 
 error: this match could be written as a `let` statement
-  --> tests/ui/match_single_binding.rs:263:13
+  --> tests/ui/match_single_binding.rs:262:13
    |
 LL | /             match 1 {
 LL | |
@@ -412,11 +412,11 @@
    |
 
 error: this match could be written as a `let` statement
-  --> tests/ui/match_single_binding.rs:274:9
+  --> tests/ui/match_single_binding.rs:273:9
    |
 LL | /         match (a, b, c) {
 LL | |
-LL | |             (x, y, z) => println!("{} {} {}", x, y, z),
+LL | |             (x, y, z) => println!("{x} {y} {z}"),
 LL | |         }
    | |_________^
    |
@@ -424,61 +424,61 @@
    |
 LL ~         {
 LL +             let (x, y, z) = (a, b, c);
-LL +             println!("{} {} {}", x, y, z);
+LL +             println!("{x} {y} {z}");
 LL +         }
    |
 
 error: this match could be written as a `let` statement
-  --> tests/ui/match_single_binding.rs:282:9
+  --> tests/ui/match_single_binding.rs:281:9
    |
 LL | /         match (a, b, c) {
 LL | |
-LL | |             (x, y, z) => println!("{} {} {}", x, y, z),
+LL | |             (x, y, z) => println!("{x} {y} {z}"),
 LL | |         }
    | |_________^
    |
 help: consider using a `let` statement
    |
 LL ~         let (x, y, z) = (a, b, c);
-LL +         println!("{} {} {}", x, y, z)
+LL +         println!("{x} {y} {z}")
    |
 
 error: this match could be written as a `let` statement
-  --> tests/ui/match_single_binding.rs:290:9
+  --> tests/ui/match_single_binding.rs:289:9
    |
 LL | /         match (a, b, c) {
 LL | |
-LL | |             (x, y, z) => println!("{} {} {}", x, y, z),
+LL | |             (x, y, z) => println!("{x} {y} {z}"),
 LL | |         }
    | |_________^
    |
 help: consider using a `let` statement
    |
 LL ~         let (x, y, z) = (a, b, c);
-LL +         println!("{} {} {}", x, y, z);
+LL +         println!("{x} {y} {z}");
    |
 
 error: this match could be written as a `let` statement
-  --> tests/ui/match_single_binding.rs:300:9
+  --> tests/ui/match_single_binding.rs:299:9
    |
 LL | /         match (a, b, c) {
 LL | |
-LL | |             (x, y, z) => println!("{} {} {}", x, y, z),
+LL | |             (x, y, z) => println!("{x} {x} {y}"),
 LL | |         }
    | |_________^
    |
 help: consider using a `let` statement
    |
 LL ~         let (x, y, z) = (a, b, c);
-LL +         println!("{} {} {}", x, y, z);
+LL +         println!("{x} {x} {y}");
    |
 
 error: this match could be written as a `let` statement
-  --> tests/ui/match_single_binding.rs:310:13
+  --> tests/ui/match_single_binding.rs:309:13
    |
 LL | /             match (a, b, c) {
 LL | |
-LL | |                 (x, y, z) => println!("{} {} {}", x, y, z),
+LL | |                 (x, y, z) => println!("{x} {y} {z}"),
 LL | |             }
    | |_____________^
    |
@@ -486,27 +486,27 @@
    |
 LL ~             {
 LL +                 let (x, y, z) = (a, b, c);
-LL +                 println!("{} {} {}", x, y, z);
+LL +                 println!("{x} {y} {z}");
 LL +             }
    |
 
 error: this match could be written as a `let` statement
-  --> tests/ui/match_single_binding.rs:320:13
+  --> tests/ui/match_single_binding.rs:319:13
    |
 LL | /             match (a, b, c) {
 LL | |
-LL | |                 (x, y, z) => println!("{} {} {}", x, y, z),
+LL | |                 (x, y, z) => println!("{x} {y} {z}"),
 LL | |             }
    | |_____________^
    |
 help: consider using a `let` statement
    |
 LL ~             let (x, y, z) = (a, b, c);
-LL +             println!("{} {} {}", x, y, z);
+LL +             println!("{x} {y} {z}");
    |
 
 error: this match could be replaced by its body itself
-  --> tests/ui/match_single_binding.rs:335:12
+  --> tests/ui/match_single_binding.rs:334:12
    |
 LL |           && match b {
    |  ____________^
@@ -516,7 +516,7 @@
    | |_________^ help: consider using the match body instead: `b < c`
 
 error: this match could be replaced by its body itself
-  --> tests/ui/match_single_binding.rs:341:12
+  --> tests/ui/match_single_binding.rs:340:12
    |
 LL |           && match (a, b) {
    |  ____________^
diff --git a/tests/ui/match_single_binding2.fixed b/tests/ui/match_single_binding2.fixed
index 988121f..f009874 100644
--- a/tests/ui/match_single_binding2.fixed
+++ b/tests/ui/match_single_binding2.fixed
@@ -1,6 +1,5 @@
 #![warn(clippy::match_single_binding)]
 #![allow(unused_variables)]
-#![allow(clippy::uninlined_format_args)]
 
 fn main() {
     // Lint (additional curly braces needed, see #6572)
@@ -29,7 +28,7 @@
         #[rustfmt::skip]
         Some((first, _second)) => {
             let (a, b) = get_tup();
-            println!("a {:?} and b {:?}", a, b)
+            println!("a {a:?} and b {b:?}")
         },
         None => println!("nothing"),
     }
diff --git a/tests/ui/match_single_binding2.rs b/tests/ui/match_single_binding2.rs
index a4fb2bd..5416f64 100644
--- a/tests/ui/match_single_binding2.rs
+++ b/tests/ui/match_single_binding2.rs
@@ -1,6 +1,5 @@
 #![warn(clippy::match_single_binding)]
 #![allow(unused_variables)]
-#![allow(clippy::uninlined_format_args)]
 
 fn main() {
     // Lint (additional curly braces needed, see #6572)
@@ -30,7 +29,7 @@
         Some((first, _second)) => {
             match get_tup() {
             //~^ match_single_binding
-                (a, b) => println!("a {:?} and b {:?}", a, b),
+                (a, b) => println!("a {a:?} and b {b:?}"),
             }
         },
         None => println!("nothing"),
diff --git a/tests/ui/match_single_binding2.stderr b/tests/ui/match_single_binding2.stderr
index a24cbe3..65b8aa6 100644
--- a/tests/ui/match_single_binding2.stderr
+++ b/tests/ui/match_single_binding2.stderr
@@ -1,5 +1,5 @@
 error: this match could be written as a `let` statement
-  --> tests/ui/match_single_binding2.rs:17:36
+  --> tests/ui/match_single_binding2.rs:16:36
    |
 LL |               Some((iter, _item)) => match iter.size_hint() {
    |  ____________________________________^
@@ -19,22 +19,22 @@
    |
 
 error: this match could be written as a `let` statement
-  --> tests/ui/match_single_binding2.rs:31:13
+  --> tests/ui/match_single_binding2.rs:30:13
    |
 LL | /             match get_tup() {
 LL | |
-LL | |                 (a, b) => println!("a {:?} and b {:?}", a, b),
+LL | |                 (a, b) => println!("a {a:?} and b {b:?}"),
 LL | |             }
    | |_____________^
    |
 help: consider using a `let` statement
    |
 LL ~             let (a, b) = get_tup();
-LL +             println!("a {:?} and b {:?}", a, b)
+LL +             println!("a {a:?} and b {b:?}")
    |
 
 error: this match could be replaced by its scrutinee and body
-  --> tests/ui/match_single_binding2.rs:43:5
+  --> tests/ui/match_single_binding2.rs:42:5
    |
 LL | /     match side_effects() {
 LL | |
@@ -49,7 +49,7 @@
    |
 
 error: this match could be replaced by its scrutinee and body
-  --> tests/ui/match_single_binding2.rs:51:5
+  --> tests/ui/match_single_binding2.rs:50:5
    |
 LL | /     match match x {
 LL | |
diff --git a/tests/ui/mem_replace.fixed b/tests/ui/mem_replace.fixed
index 870ef23..94ad1aa 100644
--- a/tests/ui/mem_replace.fixed
+++ b/tests/ui/mem_replace.fixed
@@ -179,3 +179,9 @@
     let mut an_option = Some(0);
     let replaced = mem::replace(&mut an_option, Some(1));
 }
+
+fn issue15785() {
+    let mut text = String::from("foo");
+    let replaced = std::mem::take(dbg!(&mut text));
+    //~^ mem_replace_with_default
+}
diff --git a/tests/ui/mem_replace.rs b/tests/ui/mem_replace.rs
index b4ed5ea..ac79660 100644
--- a/tests/ui/mem_replace.rs
+++ b/tests/ui/mem_replace.rs
@@ -179,3 +179,9 @@
     let mut an_option = Some(0);
     let replaced = mem::replace(&mut an_option, Some(1));
 }
+
+fn issue15785() {
+    let mut text = String::from("foo");
+    let replaced = std::mem::replace(dbg!(&mut text), String::default());
+    //~^ mem_replace_with_default
+}
diff --git a/tests/ui/mem_replace.stderr b/tests/ui/mem_replace.stderr
index fb4a367..104c985 100644
--- a/tests/ui/mem_replace.stderr
+++ b/tests/ui/mem_replace.stderr
@@ -181,5 +181,11 @@
 LL |     let replaced = mem::replace(if b { &mut opt1 } else { &mut opt2 }, Some(1));
    |                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider `Option::replace()` instead: `(if b { &mut opt1 } else { &mut opt2 }).replace(1)`
 
-error: aborting due to 29 previous errors
+error: replacing a value of type `T` with `T::default()` is better expressed using `std::mem::take`
+  --> tests/ui/mem_replace.rs:185:20
+   |
+LL |     let replaced = std::mem::replace(dbg!(&mut text), String::default());
+   |                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::mem::take(dbg!(&mut text))`
+
+error: aborting due to 30 previous errors
 
diff --git a/tests/ui/mut_mut.fixed b/tests/ui/mut_mut.fixed
new file mode 100644
index 0000000..f9a7f5d
--- /dev/null
+++ b/tests/ui/mut_mut.fixed
@@ -0,0 +1,92 @@
+//@aux-build:proc_macros.rs
+
+#![warn(clippy::mut_mut)]
+#![allow(unused)]
+#![allow(
+    clippy::no_effect,
+    clippy::uninlined_format_args,
+    clippy::unnecessary_operation,
+    clippy::needless_pass_by_ref_mut
+)]
+
+extern crate proc_macros;
+use proc_macros::{external, inline_macros};
+
+fn fun(x: &mut u32) {
+    //~^ mut_mut
+}
+
+fn less_fun(x: *mut *mut u32) {
+    let y = x;
+}
+
+macro_rules! mut_ptr {
+    ($p:expr) => {
+        &mut $p
+    };
+}
+
+#[allow(unused_mut, unused_variables)]
+#[inline_macros]
+fn main() {
+    let mut x = &mut 1u32;
+    //~^ mut_mut
+    {
+        let mut y = &mut *x;
+        //~^ mut_mut
+    }
+
+    {
+        let y: &mut u32 = &mut 2;
+        //~^ mut_mut
+        //~| mut_mut
+    }
+
+    {
+        let y: &mut u32 = &mut 2;
+        //~^ mut_mut
+        //~| mut_mut
+    }
+
+    let mut z = inline!(&mut $(&mut 3u32));
+}
+
+fn issue939() {
+    let array = [5, 6, 7, 8, 9];
+    let mut args = array.iter().skip(2);
+    for &arg in &mut args {
+        println!("{}", arg);
+    }
+
+    let args = &mut args;
+    for arg in args {
+        println!(":{}", arg);
+    }
+}
+
+fn issue6922() {
+    // do not lint from an external macro
+    external!(let mut_mut_ty: &mut &mut u32 = &mut &mut 1u32;);
+}
+
+mod issue9035 {
+    use std::fmt::Display;
+
+    struct Foo<'a> {
+        inner: &'a mut dyn Display,
+    }
+
+    impl Foo<'_> {
+        fn foo(&mut self) {
+            let hlp = &mut self.inner;
+            bar(hlp);
+        }
+    }
+
+    fn bar(_: &mut impl Display) {}
+}
+
+fn allow_works() {
+    #[allow(clippy::mut_mut)]
+    let _ = &mut &mut 1;
+}
diff --git a/tests/ui/mut_mut.rs b/tests/ui/mut_mut.rs
index bbcdbc8..bbec480 100644
--- a/tests/ui/mut_mut.rs
+++ b/tests/ui/mut_mut.rs
@@ -12,9 +12,8 @@
 extern crate proc_macros;
 use proc_macros::{external, inline_macros};
 
-fn fun(x: &mut &mut u32) -> bool {
+fn fun(x: &mut &mut u32) {
     //~^ mut_mut
-    **x > 0
 }
 
 fn less_fun(x: *mut *mut u32) {
@@ -37,23 +36,19 @@
         //~^ mut_mut
     }
 
-    if fun(x) {
+    {
         let y: &mut &mut u32 = &mut &mut 2;
         //~^ mut_mut
         //~| mut_mut
-        **y + **x;
     }
 
-    if fun(x) {
+    {
         let y: &mut &mut &mut u32 = &mut &mut &mut 2;
         //~^ mut_mut
         //~| mut_mut
-        //~| mut_mut
-        ***y + **x;
     }
 
     let mut z = inline!(&mut $(&mut 3u32));
-    //~^ mut_mut
 }
 
 fn issue939() {
diff --git a/tests/ui/mut_mut.stderr b/tests/ui/mut_mut.stderr
index 74b0c9b..85e9c56 100644
--- a/tests/ui/mut_mut.stderr
+++ b/tests/ui/mut_mut.stderr
@@ -1,61 +1,47 @@
-error: generally you want to avoid `&mut &mut _` if possible
+error: a type of form `&mut &mut _`
   --> tests/ui/mut_mut.rs:15:11
    |
-LL | fn fun(x: &mut &mut u32) -> bool {
-   |           ^^^^^^^^^^^^^
+LL | fn fun(x: &mut &mut u32) {
+   |           ^^^^^^^^^^^^^ help: remove the extra `&mut`: `&mut u32`
    |
    = note: `-D clippy::mut-mut` implied by `-D warnings`
    = help: to override `-D warnings` add `#[allow(clippy::mut_mut)]`
 
-error: generally you want to avoid `&mut &mut _` if possible
-  --> tests/ui/mut_mut.rs:33:17
+error: an expression of form `&mut &mut _`
+  --> tests/ui/mut_mut.rs:32:17
    |
 LL |     let mut x = &mut &mut 1u32;
-   |                 ^^^^^^^^^^^^^^
+   |                 ^^^^^^^^^^^^^^ help: remove the extra `&mut`: `&mut 1u32`
 
-error: generally you want to avoid `&mut &mut _` if possible
-  --> tests/ui/mut_mut.rs:55:25
-   |
-LL |     let mut z = inline!(&mut $(&mut 3u32));
-   |                         ^
-   |
-   = note: this error originates in the macro `__inline_mac_fn_main` (in Nightly builds, run with -Z macro-backtrace for more info)
-
-error: this expression mutably borrows a mutable reference. Consider reborrowing
-  --> tests/ui/mut_mut.rs:36:21
+error: this expression mutably borrows a mutable reference
+  --> tests/ui/mut_mut.rs:35:21
    |
 LL |         let mut y = &mut x;
-   |                     ^^^^^^
+   |                     ^^^^^^ help: reborrow instead: `&mut *x`
 
-error: generally you want to avoid `&mut &mut _` if possible
-  --> tests/ui/mut_mut.rs:41:32
+error: an expression of form `&mut &mut _`
+  --> tests/ui/mut_mut.rs:40:32
    |
 LL |         let y: &mut &mut u32 = &mut &mut 2;
-   |                                ^^^^^^^^^^^
+   |                                ^^^^^^^^^^^ help: remove the extra `&mut`: `&mut 2`
 
-error: generally you want to avoid `&mut &mut _` if possible
-  --> tests/ui/mut_mut.rs:41:16
+error: a type of form `&mut &mut _`
+  --> tests/ui/mut_mut.rs:40:16
    |
 LL |         let y: &mut &mut u32 = &mut &mut 2;
-   |                ^^^^^^^^^^^^^
+   |                ^^^^^^^^^^^^^ help: remove the extra `&mut`: `&mut u32`
 
-error: generally you want to avoid `&mut &mut _` if possible
-  --> tests/ui/mut_mut.rs:48:37
+error: an expression of form `&mut &mut _`
+  --> tests/ui/mut_mut.rs:46:37
    |
 LL |         let y: &mut &mut &mut u32 = &mut &mut &mut 2;
-   |                                     ^^^^^^^^^^^^^^^^
+   |                                     ^^^^^^^^^^^^^^^^ help: remove the extra `&mut`s: `&mut 2`
 
-error: generally you want to avoid `&mut &mut _` if possible
-  --> tests/ui/mut_mut.rs:48:16
+error: a type of form `&mut &mut _`
+  --> tests/ui/mut_mut.rs:46:16
    |
 LL |         let y: &mut &mut &mut u32 = &mut &mut &mut 2;
-   |                ^^^^^^^^^^^^^^^^^^
+   |                ^^^^^^^^^^^^^^^^^^ help: remove the extra `&mut`s: `&mut u32`
 
-error: generally you want to avoid `&mut &mut _` if possible
-  --> tests/ui/mut_mut.rs:48:21
-   |
-LL |         let y: &mut &mut &mut u32 = &mut &mut &mut 2;
-   |                     ^^^^^^^^^^^^^
-
-error: aborting due to 9 previous errors
+error: aborting due to 7 previous errors
 
diff --git a/tests/ui/mut_mut_unfixable.rs b/tests/ui/mut_mut_unfixable.rs
new file mode 100644
index 0000000..271cb7b
--- /dev/null
+++ b/tests/ui/mut_mut_unfixable.rs
@@ -0,0 +1,42 @@
+//@no-rustfix
+
+#![warn(clippy::mut_mut)]
+#![allow(unused)]
+#![expect(clippy::no_effect)]
+
+//! removing the extra `&mut`s will break the derefs
+
+fn fun(x: &mut &mut u32) -> bool {
+    //~^ mut_mut
+    **x > 0
+}
+
+fn main() {
+    let mut x = &mut &mut 1u32;
+    //~^ mut_mut
+    {
+        let mut y = &mut x;
+        //~^ mut_mut
+        ***y + **x;
+    }
+
+    if fun(x) {
+        let y = &mut &mut 2;
+        //~^ mut_mut
+        **y + **x;
+    }
+
+    if fun(x) {
+        let y = &mut &mut &mut 2;
+        //~^ mut_mut
+        ***y + **x;
+    }
+
+    if fun(x) {
+        // The lint will remove the extra `&mut`, but the result will still be a `&mut` of an expr
+        // of type `&mut _` (x), so the lint will fire again. That's because we've decided that
+        // doing both fixes in one run is not worth it, given how improbable code like this is.
+        let y = &mut &mut x;
+        //~^ mut_mut
+    }
+}
diff --git a/tests/ui/mut_mut_unfixable.stderr b/tests/ui/mut_mut_unfixable.stderr
new file mode 100644
index 0000000..cf66eb2
--- /dev/null
+++ b/tests/ui/mut_mut_unfixable.stderr
@@ -0,0 +1,41 @@
+error: a type of form `&mut &mut _`
+  --> tests/ui/mut_mut_unfixable.rs:9:11
+   |
+LL | fn fun(x: &mut &mut u32) -> bool {
+   |           ^^^^^^^^^^^^^ help: remove the extra `&mut`: `&mut u32`
+   |
+   = note: `-D clippy::mut-mut` implied by `-D warnings`
+   = help: to override `-D warnings` add `#[allow(clippy::mut_mut)]`
+
+error: an expression of form `&mut &mut _`
+  --> tests/ui/mut_mut_unfixable.rs:15:17
+   |
+LL |     let mut x = &mut &mut 1u32;
+   |                 ^^^^^^^^^^^^^^ help: remove the extra `&mut`: `&mut 1u32`
+
+error: this expression mutably borrows a mutable reference
+  --> tests/ui/mut_mut_unfixable.rs:18:21
+   |
+LL |         let mut y = &mut x;
+   |                     ^^^^^^ help: reborrow instead: `&mut *x`
+
+error: an expression of form `&mut &mut _`
+  --> tests/ui/mut_mut_unfixable.rs:24:17
+   |
+LL |         let y = &mut &mut 2;
+   |                 ^^^^^^^^^^^ help: remove the extra `&mut`: `&mut 2`
+
+error: an expression of form `&mut &mut _`
+  --> tests/ui/mut_mut_unfixable.rs:30:17
+   |
+LL |         let y = &mut &mut &mut 2;
+   |                 ^^^^^^^^^^^^^^^^ help: remove the extra `&mut`s: `&mut 2`
+
+error: an expression of form `&mut &mut _`
+  --> tests/ui/mut_mut_unfixable.rs:39:17
+   |
+LL |         let y = &mut &mut x;
+   |                 ^^^^^^^^^^^ help: remove the extra `&mut`: `&mut x`
+
+error: aborting due to 6 previous errors
+
diff --git a/tests/ui/new_without_default.fixed b/tests/ui/new_without_default.fixed
index 277c335cd..9a5e90b 100644
--- a/tests/ui/new_without_default.fixed
+++ b/tests/ui/new_without_default.fixed
@@ -1,5 +1,4 @@
 #![allow(
-    dead_code,
     clippy::missing_safety_doc,
     clippy::extra_unused_lifetimes,
     clippy::extra_unused_type_parameters,
@@ -322,3 +321,91 @@
         Self { _kv: None }
     }
 }
+
+// From issue #14552, but with `#[cfg]`s that are actually `true` in the uitest context
+
+pub struct NewWithCfg;
+#[cfg(not(test))]
+impl Default for NewWithCfg {
+    fn default() -> Self {
+        Self::new()
+    }
+}
+
+impl NewWithCfg {
+    #[cfg(not(test))]
+    pub fn new() -> Self {
+        //~^ new_without_default
+        unimplemented!()
+    }
+}
+
+pub struct NewWith2Cfgs;
+#[cfg(not(test))]
+#[cfg(panic = "unwind")]
+impl Default for NewWith2Cfgs {
+    fn default() -> Self {
+        Self::new()
+    }
+}
+
+impl NewWith2Cfgs {
+    #[cfg(not(test))]
+    #[cfg(panic = "unwind")]
+    pub fn new() -> Self {
+        //~^ new_without_default
+        unimplemented!()
+    }
+}
+
+pub struct NewWithExtraneous;
+impl Default for NewWithExtraneous {
+    fn default() -> Self {
+        Self::new()
+    }
+}
+
+impl NewWithExtraneous {
+    #[inline]
+    pub fn new() -> Self {
+        //~^ new_without_default
+        unimplemented!()
+    }
+}
+
+pub struct NewWithCfgAndExtraneous;
+#[cfg(not(test))]
+impl Default for NewWithCfgAndExtraneous {
+    fn default() -> Self {
+        Self::new()
+    }
+}
+
+impl NewWithCfgAndExtraneous {
+    #[cfg(not(test))]
+    #[inline]
+    pub fn new() -> Self {
+        //~^ new_without_default
+        unimplemented!()
+    }
+}
+
+mod issue15778 {
+    pub struct Foo(Vec<i32>);
+
+    impl Foo {
+        pub fn new() -> Self {
+            Self(Vec::new())
+        }
+    }
+
+    impl<'a> IntoIterator for &'a Foo {
+        type Item = &'a i32;
+
+        type IntoIter = std::slice::Iter<'a, i32>;
+
+        fn into_iter(self) -> Self::IntoIter {
+            self.0.as_slice().iter()
+        }
+    }
+}
diff --git a/tests/ui/new_without_default.rs b/tests/ui/new_without_default.rs
index f284489..f7466aa 100644
--- a/tests/ui/new_without_default.rs
+++ b/tests/ui/new_without_default.rs
@@ -1,5 +1,4 @@
 #![allow(
-    dead_code,
     clippy::missing_safety_doc,
     clippy::extra_unused_lifetimes,
     clippy::extra_unused_type_parameters,
@@ -265,3 +264,63 @@
         Self { _kv: None }
     }
 }
+
+// From issue #14552, but with `#[cfg]`s that are actually `true` in the uitest context
+
+pub struct NewWithCfg;
+impl NewWithCfg {
+    #[cfg(not(test))]
+    pub fn new() -> Self {
+        //~^ new_without_default
+        unimplemented!()
+    }
+}
+
+pub struct NewWith2Cfgs;
+impl NewWith2Cfgs {
+    #[cfg(not(test))]
+    #[cfg(panic = "unwind")]
+    pub fn new() -> Self {
+        //~^ new_without_default
+        unimplemented!()
+    }
+}
+
+pub struct NewWithExtraneous;
+impl NewWithExtraneous {
+    #[inline]
+    pub fn new() -> Self {
+        //~^ new_without_default
+        unimplemented!()
+    }
+}
+
+pub struct NewWithCfgAndExtraneous;
+impl NewWithCfgAndExtraneous {
+    #[cfg(not(test))]
+    #[inline]
+    pub fn new() -> Self {
+        //~^ new_without_default
+        unimplemented!()
+    }
+}
+
+mod issue15778 {
+    pub struct Foo(Vec<i32>);
+
+    impl Foo {
+        pub fn new() -> Self {
+            Self(Vec::new())
+        }
+    }
+
+    impl<'a> IntoIterator for &'a Foo {
+        type Item = &'a i32;
+
+        type IntoIter = std::slice::Iter<'a, i32>;
+
+        fn into_iter(self) -> Self::IntoIter {
+            self.0.as_slice().iter()
+        }
+    }
+}
diff --git a/tests/ui/new_without_default.stderr b/tests/ui/new_without_default.stderr
index 70a65ab..1e0d5e2 100644
--- a/tests/ui/new_without_default.stderr
+++ b/tests/ui/new_without_default.stderr
@@ -1,5 +1,5 @@
 error: you should consider adding a `Default` implementation for `Foo`
-  --> tests/ui/new_without_default.rs:13:5
+  --> tests/ui/new_without_default.rs:12:5
    |
 LL | /     pub fn new() -> Foo {
 LL | |
@@ -20,7 +20,7 @@
    |
 
 error: you should consider adding a `Default` implementation for `Bar`
-  --> tests/ui/new_without_default.rs:23:5
+  --> tests/ui/new_without_default.rs:22:5
    |
 LL | /     pub fn new() -> Self {
 LL | |
@@ -39,7 +39,7 @@
    |
 
 error: you should consider adding a `Default` implementation for `LtKo<'c>`
-  --> tests/ui/new_without_default.rs:89:5
+  --> tests/ui/new_without_default.rs:88:5
    |
 LL | /     pub fn new() -> LtKo<'c> {
 LL | |
@@ -58,7 +58,7 @@
    |
 
 error: you should consider adding a `Default` implementation for `Const`
-  --> tests/ui/new_without_default.rs:123:5
+  --> tests/ui/new_without_default.rs:122:5
    |
 LL | /     pub const fn new() -> Const {
 LL | |
@@ -76,7 +76,7 @@
    |
 
 error: you should consider adding a `Default` implementation for `NewNotEqualToDerive`
-  --> tests/ui/new_without_default.rs:184:5
+  --> tests/ui/new_without_default.rs:183:5
    |
 LL | /     pub fn new() -> Self {
 LL | |
@@ -95,7 +95,7 @@
    |
 
 error: you should consider adding a `Default` implementation for `FooGenerics<T>`
-  --> tests/ui/new_without_default.rs:194:5
+  --> tests/ui/new_without_default.rs:193:5
    |
 LL | /     pub fn new() -> Self {
 LL | |
@@ -114,7 +114,7 @@
    |
 
 error: you should consider adding a `Default` implementation for `BarGenerics<T>`
-  --> tests/ui/new_without_default.rs:203:5
+  --> tests/ui/new_without_default.rs:202:5
    |
 LL | /     pub fn new() -> Self {
 LL | |
@@ -133,7 +133,7 @@
    |
 
 error: you should consider adding a `Default` implementation for `Foo<T>`
-  --> tests/ui/new_without_default.rs:216:9
+  --> tests/ui/new_without_default.rs:215:9
    |
 LL | /         pub fn new() -> Self {
 LL | |
@@ -154,7 +154,7 @@
    |
 
 error: you should consider adding a `Default` implementation for `MyStruct<K, V>`
-  --> tests/ui/new_without_default.rs:263:5
+  --> tests/ui/new_without_default.rs:262:5
    |
 LL | /     pub fn new() -> Self {
 LL | |
@@ -174,5 +174,84 @@
 LL + }
    |
 
-error: aborting due to 9 previous errors
+error: you should consider adding a `Default` implementation for `NewWithCfg`
+  --> tests/ui/new_without_default.rs:273:5
+   |
+LL | /     pub fn new() -> Self {
+LL | |
+LL | |         unimplemented!()
+LL | |     }
+   | |_____^
+   |
+help: try adding this
+   |
+LL + #[cfg(not(test))]
+LL + impl Default for NewWithCfg {
+LL +     fn default() -> Self {
+LL +         Self::new()
+LL +     }
+LL + }
+LL | impl NewWithCfg {
+   |
+
+error: you should consider adding a `Default` implementation for `NewWith2Cfgs`
+  --> tests/ui/new_without_default.rs:283:5
+   |
+LL | /     pub fn new() -> Self {
+LL | |
+LL | |         unimplemented!()
+LL | |     }
+   | |_____^
+   |
+help: try adding this
+   |
+LL + #[cfg(not(test))]
+LL + #[cfg(panic = "unwind")]
+LL + impl Default for NewWith2Cfgs {
+LL +     fn default() -> Self {
+LL +         Self::new()
+LL +     }
+LL + }
+LL | impl NewWith2Cfgs {
+   |
+
+error: you should consider adding a `Default` implementation for `NewWithExtraneous`
+  --> tests/ui/new_without_default.rs:292:5
+   |
+LL | /     pub fn new() -> Self {
+LL | |
+LL | |         unimplemented!()
+LL | |     }
+   | |_____^
+   |
+help: try adding this
+   |
+LL + impl Default for NewWithExtraneous {
+LL +     fn default() -> Self {
+LL +         Self::new()
+LL +     }
+LL + }
+   |
+
+error: you should consider adding a `Default` implementation for `NewWithCfgAndExtraneous`
+  --> tests/ui/new_without_default.rs:302:5
+   |
+LL | /     pub fn new() -> Self {
+LL | |
+LL | |         unimplemented!()
+LL | |     }
+   | |_____^
+   |
+help: try adding this
+   |
+LL + #[cfg(not(test))]
+LL + impl Default for NewWithCfgAndExtraneous {
+LL +     fn default() -> Self {
+LL +         Self::new()
+LL +     }
+LL + }
+LL | impl NewWithCfgAndExtraneous {
+   |
+
+error: aborting due to 13 previous errors
 
diff --git a/tests/ui/should_impl_trait/method_list_1.stderr b/tests/ui/should_impl_trait/method_list_1.edition2015.stderr
similarity index 85%
rename from tests/ui/should_impl_trait/method_list_1.stderr
rename to tests/ui/should_impl_trait/method_list_1.edition2015.stderr
index 5609d6a..0312fa8 100644
--- a/tests/ui/should_impl_trait/method_list_1.stderr
+++ b/tests/ui/should_impl_trait/method_list_1.edition2015.stderr
@@ -1,5 +1,5 @@
 error: method `add` can be confused for the standard trait method `std::ops::Add::add`
-  --> tests/ui/should_impl_trait/method_list_1.rs:24:5
+  --> tests/ui/should_impl_trait/method_list_1.rs:27:5
    |
 LL | /     pub fn add(self, other: T) -> T {
 LL | |
@@ -13,7 +13,7 @@
    = help: to override `-D warnings` add `#[allow(clippy::should_implement_trait)]`
 
 error: method `as_mut` can be confused for the standard trait method `std::convert::AsMut::as_mut`
-  --> tests/ui/should_impl_trait/method_list_1.rs:30:5
+  --> tests/ui/should_impl_trait/method_list_1.rs:33:5
    |
 LL | /     pub fn as_mut(&mut self) -> &mut T {
 LL | |
@@ -25,7 +25,7 @@
    = help: consider implementing the trait `std::convert::AsMut` or choosing a less ambiguous method name
 
 error: method `as_ref` can be confused for the standard trait method `std::convert::AsRef::as_ref`
-  --> tests/ui/should_impl_trait/method_list_1.rs:36:5
+  --> tests/ui/should_impl_trait/method_list_1.rs:39:5
    |
 LL | /     pub fn as_ref(&self) -> &T {
 LL | |
@@ -37,7 +37,7 @@
    = help: consider implementing the trait `std::convert::AsRef` or choosing a less ambiguous method name
 
 error: method `bitand` can be confused for the standard trait method `std::ops::BitAnd::bitand`
-  --> tests/ui/should_impl_trait/method_list_1.rs:42:5
+  --> tests/ui/should_impl_trait/method_list_1.rs:45:5
    |
 LL | /     pub fn bitand(self, rhs: T) -> T {
 LL | |
@@ -49,7 +49,7 @@
    = help: consider implementing the trait `std::ops::BitAnd` or choosing a less ambiguous method name
 
 error: method `bitor` can be confused for the standard trait method `std::ops::BitOr::bitor`
-  --> tests/ui/should_impl_trait/method_list_1.rs:48:5
+  --> tests/ui/should_impl_trait/method_list_1.rs:51:5
    |
 LL | /     pub fn bitor(self, rhs: Self) -> Self {
 LL | |
@@ -61,7 +61,7 @@
    = help: consider implementing the trait `std::ops::BitOr` or choosing a less ambiguous method name
 
 error: method `bitxor` can be confused for the standard trait method `std::ops::BitXor::bitxor`
-  --> tests/ui/should_impl_trait/method_list_1.rs:54:5
+  --> tests/ui/should_impl_trait/method_list_1.rs:57:5
    |
 LL | /     pub fn bitxor(self, rhs: Self) -> Self {
 LL | |
@@ -73,7 +73,7 @@
    = help: consider implementing the trait `std::ops::BitXor` or choosing a less ambiguous method name
 
 error: method `borrow` can be confused for the standard trait method `std::borrow::Borrow::borrow`
-  --> tests/ui/should_impl_trait/method_list_1.rs:60:5
+  --> tests/ui/should_impl_trait/method_list_1.rs:63:5
    |
 LL | /     pub fn borrow(&self) -> &str {
 LL | |
@@ -85,7 +85,7 @@
    = help: consider implementing the trait `std::borrow::Borrow` or choosing a less ambiguous method name
 
 error: method `borrow_mut` can be confused for the standard trait method `std::borrow::BorrowMut::borrow_mut`
-  --> tests/ui/should_impl_trait/method_list_1.rs:66:5
+  --> tests/ui/should_impl_trait/method_list_1.rs:69:5
    |
 LL | /     pub fn borrow_mut(&mut self) -> &mut str {
 LL | |
@@ -97,7 +97,7 @@
    = help: consider implementing the trait `std::borrow::BorrowMut` or choosing a less ambiguous method name
 
 error: method `clone` can be confused for the standard trait method `std::clone::Clone::clone`
-  --> tests/ui/should_impl_trait/method_list_1.rs:72:5
+  --> tests/ui/should_impl_trait/method_list_1.rs:75:5
    |
 LL | /     pub fn clone(&self) -> Self {
 LL | |
@@ -109,7 +109,7 @@
    = help: consider implementing the trait `std::clone::Clone` or choosing a less ambiguous method name
 
 error: method `cmp` can be confused for the standard trait method `std::cmp::Ord::cmp`
-  --> tests/ui/should_impl_trait/method_list_1.rs:78:5
+  --> tests/ui/should_impl_trait/method_list_1.rs:81:5
    |
 LL | /     pub fn cmp(&self, other: &Self) -> Self {
 LL | |
@@ -121,7 +121,7 @@
    = help: consider implementing the trait `std::cmp::Ord` or choosing a less ambiguous method name
 
 error: method `default` can be confused for the standard trait method `std::default::Default::default`
-  --> tests/ui/should_impl_trait/method_list_1.rs:84:5
+  --> tests/ui/should_impl_trait/method_list_1.rs:87:5
    |
 LL | /     pub fn default() -> Self {
 LL | |
@@ -133,7 +133,7 @@
    = help: consider implementing the trait `std::default::Default` or choosing a less ambiguous method name
 
 error: method `deref` can be confused for the standard trait method `std::ops::Deref::deref`
-  --> tests/ui/should_impl_trait/method_list_1.rs:90:5
+  --> tests/ui/should_impl_trait/method_list_1.rs:93:5
    |
 LL | /     pub fn deref(&self) -> &Self {
 LL | |
@@ -145,7 +145,7 @@
    = help: consider implementing the trait `std::ops::Deref` or choosing a less ambiguous method name
 
 error: method `deref_mut` can be confused for the standard trait method `std::ops::DerefMut::deref_mut`
-  --> tests/ui/should_impl_trait/method_list_1.rs:96:5
+  --> tests/ui/should_impl_trait/method_list_1.rs:99:5
    |
 LL | /     pub fn deref_mut(&mut self) -> &mut Self {
 LL | |
@@ -157,7 +157,7 @@
    = help: consider implementing the trait `std::ops::DerefMut` or choosing a less ambiguous method name
 
 error: method `div` can be confused for the standard trait method `std::ops::Div::div`
-  --> tests/ui/should_impl_trait/method_list_1.rs:102:5
+  --> tests/ui/should_impl_trait/method_list_1.rs:105:5
    |
 LL | /     pub fn div(self, rhs: Self) -> Self {
 LL | |
@@ -169,7 +169,7 @@
    = help: consider implementing the trait `std::ops::Div` or choosing a less ambiguous method name
 
 error: method `drop` can be confused for the standard trait method `std::ops::Drop::drop`
-  --> tests/ui/should_impl_trait/method_list_1.rs:108:5
+  --> tests/ui/should_impl_trait/method_list_1.rs:111:5
    |
 LL | /     pub fn drop(&mut self) {
 LL | |
diff --git a/tests/ui/should_impl_trait/method_list_1.stderr b/tests/ui/should_impl_trait/method_list_1.edition2021.stderr
similarity index 85%
copy from tests/ui/should_impl_trait/method_list_1.stderr
copy to tests/ui/should_impl_trait/method_list_1.edition2021.stderr
index 5609d6a..0312fa8 100644
--- a/tests/ui/should_impl_trait/method_list_1.stderr
+++ b/tests/ui/should_impl_trait/method_list_1.edition2021.stderr
@@ -1,5 +1,5 @@
 error: method `add` can be confused for the standard trait method `std::ops::Add::add`
-  --> tests/ui/should_impl_trait/method_list_1.rs:24:5
+  --> tests/ui/should_impl_trait/method_list_1.rs:27:5
    |
 LL | /     pub fn add(self, other: T) -> T {
 LL | |
@@ -13,7 +13,7 @@
    = help: to override `-D warnings` add `#[allow(clippy::should_implement_trait)]`
 
 error: method `as_mut` can be confused for the standard trait method `std::convert::AsMut::as_mut`
-  --> tests/ui/should_impl_trait/method_list_1.rs:30:5
+  --> tests/ui/should_impl_trait/method_list_1.rs:33:5
    |
 LL | /     pub fn as_mut(&mut self) -> &mut T {
 LL | |
@@ -25,7 +25,7 @@
    = help: consider implementing the trait `std::convert::AsMut` or choosing a less ambiguous method name
 
 error: method `as_ref` can be confused for the standard trait method `std::convert::AsRef::as_ref`
-  --> tests/ui/should_impl_trait/method_list_1.rs:36:5
+  --> tests/ui/should_impl_trait/method_list_1.rs:39:5
    |
 LL | /     pub fn as_ref(&self) -> &T {
 LL | |
@@ -37,7 +37,7 @@
    = help: consider implementing the trait `std::convert::AsRef` or choosing a less ambiguous method name
 
 error: method `bitand` can be confused for the standard trait method `std::ops::BitAnd::bitand`
-  --> tests/ui/should_impl_trait/method_list_1.rs:42:5
+  --> tests/ui/should_impl_trait/method_list_1.rs:45:5
    |
 LL | /     pub fn bitand(self, rhs: T) -> T {
 LL | |
@@ -49,7 +49,7 @@
    = help: consider implementing the trait `std::ops::BitAnd` or choosing a less ambiguous method name
 
 error: method `bitor` can be confused for the standard trait method `std::ops::BitOr::bitor`
-  --> tests/ui/should_impl_trait/method_list_1.rs:48:5
+  --> tests/ui/should_impl_trait/method_list_1.rs:51:5
    |
 LL | /     pub fn bitor(self, rhs: Self) -> Self {
 LL | |
@@ -61,7 +61,7 @@
    = help: consider implementing the trait `std::ops::BitOr` or choosing a less ambiguous method name
 
 error: method `bitxor` can be confused for the standard trait method `std::ops::BitXor::bitxor`
-  --> tests/ui/should_impl_trait/method_list_1.rs:54:5
+  --> tests/ui/should_impl_trait/method_list_1.rs:57:5
    |
 LL | /     pub fn bitxor(self, rhs: Self) -> Self {
 LL | |
@@ -73,7 +73,7 @@
    = help: consider implementing the trait `std::ops::BitXor` or choosing a less ambiguous method name
 
 error: method `borrow` can be confused for the standard trait method `std::borrow::Borrow::borrow`
-  --> tests/ui/should_impl_trait/method_list_1.rs:60:5
+  --> tests/ui/should_impl_trait/method_list_1.rs:63:5
    |
 LL | /     pub fn borrow(&self) -> &str {
 LL | |
@@ -85,7 +85,7 @@
    = help: consider implementing the trait `std::borrow::Borrow` or choosing a less ambiguous method name
 
 error: method `borrow_mut` can be confused for the standard trait method `std::borrow::BorrowMut::borrow_mut`
-  --> tests/ui/should_impl_trait/method_list_1.rs:66:5
+  --> tests/ui/should_impl_trait/method_list_1.rs:69:5
    |
 LL | /     pub fn borrow_mut(&mut self) -> &mut str {
 LL | |
@@ -97,7 +97,7 @@
    = help: consider implementing the trait `std::borrow::BorrowMut` or choosing a less ambiguous method name
 
 error: method `clone` can be confused for the standard trait method `std::clone::Clone::clone`
-  --> tests/ui/should_impl_trait/method_list_1.rs:72:5
+  --> tests/ui/should_impl_trait/method_list_1.rs:75:5
    |
 LL | /     pub fn clone(&self) -> Self {
 LL | |
@@ -109,7 +109,7 @@
    = help: consider implementing the trait `std::clone::Clone` or choosing a less ambiguous method name
 
 error: method `cmp` can be confused for the standard trait method `std::cmp::Ord::cmp`
-  --> tests/ui/should_impl_trait/method_list_1.rs:78:5
+  --> tests/ui/should_impl_trait/method_list_1.rs:81:5
    |
 LL | /     pub fn cmp(&self, other: &Self) -> Self {
 LL | |
@@ -121,7 +121,7 @@
    = help: consider implementing the trait `std::cmp::Ord` or choosing a less ambiguous method name
 
 error: method `default` can be confused for the standard trait method `std::default::Default::default`
-  --> tests/ui/should_impl_trait/method_list_1.rs:84:5
+  --> tests/ui/should_impl_trait/method_list_1.rs:87:5
    |
 LL | /     pub fn default() -> Self {
 LL | |
@@ -133,7 +133,7 @@
    = help: consider implementing the trait `std::default::Default` or choosing a less ambiguous method name
 
 error: method `deref` can be confused for the standard trait method `std::ops::Deref::deref`
-  --> tests/ui/should_impl_trait/method_list_1.rs:90:5
+  --> tests/ui/should_impl_trait/method_list_1.rs:93:5
    |
 LL | /     pub fn deref(&self) -> &Self {
 LL | |
@@ -145,7 +145,7 @@
    = help: consider implementing the trait `std::ops::Deref` or choosing a less ambiguous method name
 
 error: method `deref_mut` can be confused for the standard trait method `std::ops::DerefMut::deref_mut`
-  --> tests/ui/should_impl_trait/method_list_1.rs:96:5
+  --> tests/ui/should_impl_trait/method_list_1.rs:99:5
    |
 LL | /     pub fn deref_mut(&mut self) -> &mut Self {
 LL | |
@@ -157,7 +157,7 @@
    = help: consider implementing the trait `std::ops::DerefMut` or choosing a less ambiguous method name
 
 error: method `div` can be confused for the standard trait method `std::ops::Div::div`
-  --> tests/ui/should_impl_trait/method_list_1.rs:102:5
+  --> tests/ui/should_impl_trait/method_list_1.rs:105:5
    |
 LL | /     pub fn div(self, rhs: Self) -> Self {
 LL | |
@@ -169,7 +169,7 @@
    = help: consider implementing the trait `std::ops::Div` or choosing a less ambiguous method name
 
 error: method `drop` can be confused for the standard trait method `std::ops::Drop::drop`
-  --> tests/ui/should_impl_trait/method_list_1.rs:108:5
+  --> tests/ui/should_impl_trait/method_list_1.rs:111:5
    |
 LL | /     pub fn drop(&mut self) {
 LL | |
diff --git a/tests/ui/should_impl_trait/method_list_1.rs b/tests/ui/should_impl_trait/method_list_1.rs
index e8de0e0..bbb04c0 100644
--- a/tests/ui/should_impl_trait/method_list_1.rs
+++ b/tests/ui/should_impl_trait/method_list_1.rs
@@ -1,3 +1,6 @@
+//@revisions: edition2015 edition2021
+//@[edition2015] edition:2015
+//@[edition2021] edition:2021
 #![allow(
     clippy::missing_errors_doc,
     clippy::needless_pass_by_value,
diff --git a/tests/ui/should_impl_trait/method_list_2.edition2015.stderr b/tests/ui/should_impl_trait/method_list_2.edition2015.stderr
new file mode 100644
index 0000000..2598159
--- /dev/null
+++ b/tests/ui/should_impl_trait/method_list_2.edition2015.stderr
@@ -0,0 +1,172 @@
+error: method `eq` can be confused for the standard trait method `std::cmp::PartialEq::eq`
+  --> tests/ui/should_impl_trait/method_list_2.rs:28:5
+   |
+LL | /     pub fn eq(&self, other: &Self) -> bool {
+LL | |
+LL | |
+LL | |         unimplemented!()
+LL | |     }
+   | |_____^
+   |
+   = help: consider implementing the trait `std::cmp::PartialEq` or choosing a less ambiguous method name
+   = note: `-D clippy::should-implement-trait` implied by `-D warnings`
+   = help: to override `-D warnings` add `#[allow(clippy::should_implement_trait)]`
+
+error: method `from_str` can be confused for the standard trait method `std::str::FromStr::from_str`
+  --> tests/ui/should_impl_trait/method_list_2.rs:40:5
+   |
+LL | /     pub fn from_str(s: &str) -> Result<Self, Self> {
+LL | |
+LL | |
+LL | |         unimplemented!()
+LL | |     }
+   | |_____^
+   |
+   = help: consider implementing the trait `std::str::FromStr` or choosing a less ambiguous method name
+
+error: method `hash` can be confused for the standard trait method `std::hash::Hash::hash`
+  --> tests/ui/should_impl_trait/method_list_2.rs:46:5
+   |
+LL | /     pub fn hash(&self, state: &mut T) {
+LL | |
+LL | |
+LL | |         unimplemented!()
+LL | |     }
+   | |_____^
+   |
+   = help: consider implementing the trait `std::hash::Hash` or choosing a less ambiguous method name
+
+error: method `index` can be confused for the standard trait method `std::ops::Index::index`
+  --> tests/ui/should_impl_trait/method_list_2.rs:52:5
+   |
+LL | /     pub fn index(&self, index: usize) -> &Self {
+LL | |
+LL | |
+LL | |         unimplemented!()
+LL | |     }
+   | |_____^
+   |
+   = help: consider implementing the trait `std::ops::Index` or choosing a less ambiguous method name
+
+error: method `index_mut` can be confused for the standard trait method `std::ops::IndexMut::index_mut`
+  --> tests/ui/should_impl_trait/method_list_2.rs:58:5
+   |
+LL | /     pub fn index_mut(&mut self, index: usize) -> &mut Self {
+LL | |
+LL | |
+LL | |         unimplemented!()
+LL | |     }
+   | |_____^
+   |
+   = help: consider implementing the trait `std::ops::IndexMut` or choosing a less ambiguous method name
+
+error: method `into_iter` can be confused for the standard trait method `std::iter::IntoIterator::into_iter`
+  --> tests/ui/should_impl_trait/method_list_2.rs:64:5
+   |
+LL | /     pub fn into_iter(self) -> Self {
+LL | |
+LL | |
+LL | |         unimplemented!()
+LL | |     }
+   | |_____^
+   |
+   = help: consider implementing the trait `std::iter::IntoIterator` or choosing a less ambiguous method name
+
+error: method `mul` can be confused for the standard trait method `std::ops::Mul::mul`
+  --> tests/ui/should_impl_trait/method_list_2.rs:70:5
+   |
+LL | /     pub fn mul(self, rhs: Self) -> Self {
+LL | |
+LL | |
+LL | |         unimplemented!()
+LL | |     }
+   | |_____^
+   |
+   = help: consider implementing the trait `std::ops::Mul` or choosing a less ambiguous method name
+
+error: method `neg` can be confused for the standard trait method `std::ops::Neg::neg`
+  --> tests/ui/should_impl_trait/method_list_2.rs:76:5
+   |
+LL | /     pub fn neg(self) -> Self {
+LL | |
+LL | |
+LL | |         unimplemented!()
+LL | |     }
+   | |_____^
+   |
+   = help: consider implementing the trait `std::ops::Neg` or choosing a less ambiguous method name
+
+error: method `next` can be confused for the standard trait method `std::iter::Iterator::next`
+  --> tests/ui/should_impl_trait/method_list_2.rs:82:5
+   |
+LL | /     pub fn next(&mut self) -> Option<Self> {
+LL | |
+LL | |
+LL | |         unimplemented!()
+LL | |     }
+   | |_____^
+   |
+   = help: consider implementing the trait `std::iter::Iterator` or choosing a less ambiguous method name
+
+error: method `not` can be confused for the standard trait method `std::ops::Not::not`
+  --> tests/ui/should_impl_trait/method_list_2.rs:88:5
+   |
+LL | /     pub fn not(self) -> Self {
+LL | |
+LL | |
+LL | |         unimplemented!()
+LL | |     }
+   | |_____^
+   |
+   = help: consider implementing the trait `std::ops::Not` or choosing a less ambiguous method name
+
+error: method `rem` can be confused for the standard trait method `std::ops::Rem::rem`
+  --> tests/ui/should_impl_trait/method_list_2.rs:94:5
+   |
+LL | /     pub fn rem(self, rhs: Self) -> Self {
+LL | |
+LL | |
+LL | |         unimplemented!()
+LL | |     }
+   | |_____^
+   |
+   = help: consider implementing the trait `std::ops::Rem` or choosing a less ambiguous method name
+
+error: method `shl` can be confused for the standard trait method `std::ops::Shl::shl`
+  --> tests/ui/should_impl_trait/method_list_2.rs:100:5
+   |
+LL | /     pub fn shl(self, rhs: Self) -> Self {
+LL | |
+LL | |
+LL | |         unimplemented!()
+LL | |     }
+   | |_____^
+   |
+   = help: consider implementing the trait `std::ops::Shl` or choosing a less ambiguous method name
+
+error: method `shr` can be confused for the standard trait method `std::ops::Shr::shr`
+  --> tests/ui/should_impl_trait/method_list_2.rs:106:5
+   |
+LL | /     pub fn shr(self, rhs: Self) -> Self {
+LL | |
+LL | |
+LL | |         unimplemented!()
+LL | |     }
+   | |_____^
+   |
+   = help: consider implementing the trait `std::ops::Shr` or choosing a less ambiguous method name
+
+error: method `sub` can be confused for the standard trait method `std::ops::Sub::sub`
+  --> tests/ui/should_impl_trait/method_list_2.rs:112:5
+   |
+LL | /     pub fn sub(self, rhs: Self) -> Self {
+LL | |
+LL | |
+LL | |         unimplemented!()
+LL | |     }
+   | |_____^
+   |
+   = help: consider implementing the trait `std::ops::Sub` or choosing a less ambiguous method name
+
+error: aborting due to 14 previous errors
+
diff --git a/tests/ui/should_impl_trait/method_list_2.edition2021.stderr b/tests/ui/should_impl_trait/method_list_2.edition2021.stderr
new file mode 100644
index 0000000..2f90b61
--- /dev/null
+++ b/tests/ui/should_impl_trait/method_list_2.edition2021.stderr
@@ -0,0 +1,184 @@
+error: method `eq` can be confused for the standard trait method `std::cmp::PartialEq::eq`
+  --> tests/ui/should_impl_trait/method_list_2.rs:28:5
+   |
+LL | /     pub fn eq(&self, other: &Self) -> bool {
+LL | |
+LL | |
+LL | |         unimplemented!()
+LL | |     }
+   | |_____^
+   |
+   = help: consider implementing the trait `std::cmp::PartialEq` or choosing a less ambiguous method name
+   = note: `-D clippy::should-implement-trait` implied by `-D warnings`
+   = help: to override `-D warnings` add `#[allow(clippy::should_implement_trait)]`
+
+error: method `from_iter` can be confused for the standard trait method `std::iter::FromIterator::from_iter`
+  --> tests/ui/should_impl_trait/method_list_2.rs:34:5
+   |
+LL | /     pub fn from_iter<T>(iter: T) -> Self {
+LL | |
+LL | |
+LL | |         unimplemented!()
+LL | |     }
+   | |_____^
+   |
+   = help: consider implementing the trait `std::iter::FromIterator` or choosing a less ambiguous method name
+
+error: method `from_str` can be confused for the standard trait method `std::str::FromStr::from_str`
+  --> tests/ui/should_impl_trait/method_list_2.rs:40:5
+   |
+LL | /     pub fn from_str(s: &str) -> Result<Self, Self> {
+LL | |
+LL | |
+LL | |         unimplemented!()
+LL | |     }
+   | |_____^
+   |
+   = help: consider implementing the trait `std::str::FromStr` or choosing a less ambiguous method name
+
+error: method `hash` can be confused for the standard trait method `std::hash::Hash::hash`
+  --> tests/ui/should_impl_trait/method_list_2.rs:46:5
+   |
+LL | /     pub fn hash(&self, state: &mut T) {
+LL | |
+LL | |
+LL | |         unimplemented!()
+LL | |     }
+   | |_____^
+   |
+   = help: consider implementing the trait `std::hash::Hash` or choosing a less ambiguous method name
+
+error: method `index` can be confused for the standard trait method `std::ops::Index::index`
+  --> tests/ui/should_impl_trait/method_list_2.rs:52:5
+   |
+LL | /     pub fn index(&self, index: usize) -> &Self {
+LL | |
+LL | |
+LL | |         unimplemented!()
+LL | |     }
+   | |_____^
+   |
+   = help: consider implementing the trait `std::ops::Index` or choosing a less ambiguous method name
+
+error: method `index_mut` can be confused for the standard trait method `std::ops::IndexMut::index_mut`
+  --> tests/ui/should_impl_trait/method_list_2.rs:58:5
+   |
+LL | /     pub fn index_mut(&mut self, index: usize) -> &mut Self {
+LL | |
+LL | |
+LL | |         unimplemented!()
+LL | |     }
+   | |_____^
+   |
+   = help: consider implementing the trait `std::ops::IndexMut` or choosing a less ambiguous method name
+
+error: method `into_iter` can be confused for the standard trait method `std::iter::IntoIterator::into_iter`
+  --> tests/ui/should_impl_trait/method_list_2.rs:64:5
+   |
+LL | /     pub fn into_iter(self) -> Self {
+LL | |
+LL | |
+LL | |         unimplemented!()
+LL | |     }
+   | |_____^
+   |
+   = help: consider implementing the trait `std::iter::IntoIterator` or choosing a less ambiguous method name
+
+error: method `mul` can be confused for the standard trait method `std::ops::Mul::mul`
+  --> tests/ui/should_impl_trait/method_list_2.rs:70:5
+   |
+LL | /     pub fn mul(self, rhs: Self) -> Self {
+LL | |
+LL | |
+LL | |         unimplemented!()
+LL | |     }
+   | |_____^
+   |
+   = help: consider implementing the trait `std::ops::Mul` or choosing a less ambiguous method name
+
+error: method `neg` can be confused for the standard trait method `std::ops::Neg::neg`
+  --> tests/ui/should_impl_trait/method_list_2.rs:76:5
+   |
+LL | /     pub fn neg(self) -> Self {
+LL | |
+LL | |
+LL | |         unimplemented!()
+LL | |     }
+   | |_____^
+   |
+   = help: consider implementing the trait `std::ops::Neg` or choosing a less ambiguous method name
+
+error: method `next` can be confused for the standard trait method `std::iter::Iterator::next`
+  --> tests/ui/should_impl_trait/method_list_2.rs:82:5
+   |
+LL | /     pub fn next(&mut self) -> Option<Self> {
+LL | |
+LL | |
+LL | |         unimplemented!()
+LL | |     }
+   | |_____^
+   |
+   = help: consider implementing the trait `std::iter::Iterator` or choosing a less ambiguous method name
+
+error: method `not` can be confused for the standard trait method `std::ops::Not::not`
+  --> tests/ui/should_impl_trait/method_list_2.rs:88:5
+   |
+LL | /     pub fn not(self) -> Self {
+LL | |
+LL | |
+LL | |         unimplemented!()
+LL | |     }
+   | |_____^
+   |
+   = help: consider implementing the trait `std::ops::Not` or choosing a less ambiguous method name
+
+error: method `rem` can be confused for the standard trait method `std::ops::Rem::rem`
+  --> tests/ui/should_impl_trait/method_list_2.rs:94:5
+   |
+LL | /     pub fn rem(self, rhs: Self) -> Self {
+LL | |
+LL | |
+LL | |         unimplemented!()
+LL | |     }
+   | |_____^
+   |
+   = help: consider implementing the trait `std::ops::Rem` or choosing a less ambiguous method name
+
+error: method `shl` can be confused for the standard trait method `std::ops::Shl::shl`
+  --> tests/ui/should_impl_trait/method_list_2.rs:100:5
+   |
+LL | /     pub fn shl(self, rhs: Self) -> Self {
+LL | |
+LL | |
+LL | |         unimplemented!()
+LL | |     }
+   | |_____^
+   |
+   = help: consider implementing the trait `std::ops::Shl` or choosing a less ambiguous method name
+
+error: method `shr` can be confused for the standard trait method `std::ops::Shr::shr`
+  --> tests/ui/should_impl_trait/method_list_2.rs:106:5
+   |
+LL | /     pub fn shr(self, rhs: Self) -> Self {
+LL | |
+LL | |
+LL | |         unimplemented!()
+LL | |     }
+   | |_____^
+   |
+   = help: consider implementing the trait `std::ops::Shr` or choosing a less ambiguous method name
+
+error: method `sub` can be confused for the standard trait method `std::ops::Sub::sub`
+  --> tests/ui/should_impl_trait/method_list_2.rs:112:5
+   |
+LL | /     pub fn sub(self, rhs: Self) -> Self {
+LL | |
+LL | |
+LL | |         unimplemented!()
+LL | |     }
+   | |_____^
+   |
+   = help: consider implementing the trait `std::ops::Sub` or choosing a less ambiguous method name
+
+error: aborting due to 15 previous errors
+
diff --git a/tests/ui/should_impl_trait/method_list_2.rs b/tests/ui/should_impl_trait/method_list_2.rs
index 1f25ab3..4dfbe7e 100644
--- a/tests/ui/should_impl_trait/method_list_2.rs
+++ b/tests/ui/should_impl_trait/method_list_2.rs
@@ -1,3 +1,6 @@
+//@revisions: edition2015 edition2021
+//@[edition2015] edition:2015
+//@[edition2021] edition:2021
 #![allow(
     clippy::missing_errors_doc,
     clippy::needless_pass_by_value,
@@ -29,7 +32,7 @@
     }
 
     pub fn from_iter<T>(iter: T) -> Self {
-        //~^ should_implement_trait
+        //~[edition2021]^ should_implement_trait
 
         unimplemented!()
     }