about summary refs log tree commit diff
path: root/clippy_lints/src
diff options
context:
space:
mode:
Diffstat (limited to 'clippy_lints/src')
-rw-r--r--clippy_lints/src/assertions_on_constants.rs120
-rw-r--r--clippy_lints/src/attrs.rs18
-rw-r--r--clippy_lints/src/bool_assert_comparison.rs75
-rw-r--r--clippy_lints/src/borrow_as_ptr.rs97
-rw-r--r--clippy_lints/src/case_sensitive_file_extension_comparisons.rs2
-rw-r--r--clippy_lints/src/casts/cast_ptr_alignment.rs2
-rw-r--r--clippy_lints/src/casts/cast_ref_to_mut.rs2
-rw-r--r--clippy_lints/src/casts/char_lit_as_u8.rs2
-rw-r--r--clippy_lints/src/casts/ptr_as_ptr.rs2
-rw-r--r--clippy_lints/src/copies.rs14
-rw-r--r--clippy_lints/src/default.rs4
-rw-r--r--clippy_lints/src/default_numeric_fallback.rs2
-rw-r--r--clippy_lints/src/dereference.rs10
-rw-r--r--clippy_lints/src/disallowed_methods.rs34
-rw-r--r--clippy_lints/src/disallowed_types.rs5
-rw-r--r--clippy_lints/src/doc.rs33
-rw-r--r--clippy_lints/src/entry.rs10
-rw-r--r--clippy_lints/src/eq_op.rs45
-rw-r--r--clippy_lints/src/equatable_if_let.rs2
-rw-r--r--clippy_lints/src/erasing_op.rs32
-rw-r--r--clippy_lints/src/eta_reduction.rs5
-rw-r--r--clippy_lints/src/explicit_write.rs6
-rw-r--r--clippy_lints/src/fallible_impl_from.rs15
-rw-r--r--clippy_lints/src/format.rs33
-rw-r--r--clippy_lints/src/format_args.rs53
-rw-r--r--clippy_lints/src/from_over_into.rs2
-rw-r--r--clippy_lints/src/from_str_radix_10.rs2
-rw-r--r--clippy_lints/src/functions/must_use.rs6
-rw-r--r--clippy_lints/src/functions/not_unsafe_ptr_arg_deref.rs6
-rw-r--r--clippy_lints/src/functions/result_unit_err.rs6
-rw-r--r--clippy_lints/src/functions/too_many_arguments.rs12
-rw-r--r--clippy_lints/src/functions/too_many_lines.rs4
-rw-r--r--clippy_lints/src/if_then_some_else_none.rs2
-rw-r--r--clippy_lints/src/implicit_return.rs4
-rw-r--r--clippy_lints/src/inconsistent_struct_constructor.rs2
-rw-r--r--clippy_lints/src/index_refutable_slice.rs2
-rw-r--r--clippy_lints/src/init_numbered_fields.rs3
-rw-r--r--clippy_lints/src/iter_not_returning_iterator.rs67
-rw-r--r--clippy_lints/src/len_zero.rs2
-rw-r--r--clippy_lints/src/lib.register_all.rs4
-rw-r--r--clippy_lints/src/lib.register_lints.rs31
-rw-r--r--clippy_lints/src/lib.register_nursery.rs3
-rw-r--r--clippy_lints/src/lib.register_pedantic.rs1
-rw-r--r--clippy_lints/src/lib.register_perf.rs1
-rw-r--r--clippy_lints/src/lib.register_restriction.rs1
-rw-r--r--clippy_lints/src/lib.register_style.rs3
-rw-r--r--clippy_lints/src/lib.rs20
-rw-r--r--clippy_lints/src/loops/empty_loop.rs2
-rw-r--r--clippy_lints/src/loops/explicit_into_iter_loop.rs2
-rw-r--r--clippy_lints/src/loops/manual_memcpy.rs37
-rw-r--r--clippy_lints/src/loops/mut_range_bound.rs2
-rw-r--r--clippy_lints/src/loops/needless_collect.rs4
-rw-r--r--clippy_lints/src/loops/never_loop.rs4
-rw-r--r--clippy_lints/src/loops/while_let_loop.rs2
-rw-r--r--clippy_lints/src/loops/while_let_on_iterator.rs49
-rw-r--r--clippy_lints/src/macro_use.rs13
-rw-r--r--clippy_lints/src/manual_assert.rs70
-rw-r--r--clippy_lints/src/manual_bits.rs107
-rw-r--r--clippy_lints/src/manual_map.rs17
-rw-r--r--clippy_lints/src/manual_ok_or.rs2
-rw-r--r--clippy_lints/src/manual_unwrap_or.rs2
-rw-r--r--clippy_lints/src/match_str_case_mismatch.rs2
-rw-r--r--clippy_lints/src/matches.rs36
-rw-r--r--clippy_lints/src/methods/expect_fun_call.rs21
-rw-r--r--clippy_lints/src/methods/from_iter_instead_of_collect.rs2
-rw-r--r--clippy_lints/src/methods/mod.rs54
-rw-r--r--clippy_lints/src/methods/str_splitn.rs4
-rw-r--r--clippy_lints/src/methods/unnecessary_iter_cloned.rs27
-rw-r--r--clippy_lints/src/methods/unnecessary_to_owned.rs42
-rw-r--r--clippy_lints/src/misc.rs2
-rw-r--r--clippy_lints/src/mutable_debug_assertion.rs42
-rw-r--r--clippy_lints/src/mutex_atomic.rs2
-rw-r--r--clippy_lints/src/needless_for_each.rs2
-rw-r--r--clippy_lints/src/needless_late_init.rs2
-rw-r--r--clippy_lints/src/no_effect.rs4
-rw-r--r--clippy_lints/src/non_octal_unix_permissions.rs2
-rw-r--r--clippy_lints/src/octal_escapes.rs4
-rw-r--r--clippy_lints/src/panic_in_result_fn.rs32
-rw-r--r--clippy_lints/src/panic_unimplemented.rs56
-rw-r--r--clippy_lints/src/ptr_eq.rs2
-rw-r--r--clippy_lints/src/redundant_clone.rs4
-rw-r--r--clippy_lints/src/redundant_slicing.rs2
-rw-r--r--clippy_lints/src/reference.rs1
-rw-r--r--clippy_lints/src/return_self_not_must_use.rs38
-rw-r--r--clippy_lints/src/semicolon_if_nothing_returned.rs2
-rw-r--r--clippy_lints/src/single_char_lifetime_names.rs63
-rw-r--r--clippy_lints/src/size_of_in_element_count.rs7
-rw-r--r--clippy_lints/src/strings.rs4
-rw-r--r--clippy_lints/src/strlen_on_c_strings.rs2
-rw-r--r--clippy_lints/src/suspicious_operation_groupings.rs4
-rw-r--r--clippy_lints/src/trailing_empty_array.rs5
-rw-r--r--clippy_lints/src/trait_bounds.rs92
-rw-r--r--clippy_lints/src/types/mod.rs5
-rw-r--r--clippy_lints/src/undocumented_unsafe_blocks.rs4
-rw-r--r--clippy_lints/src/undropped_manually_drops.rs2
-rw-r--r--clippy_lints/src/uninit_vec.rs4
-rw-r--r--clippy_lints/src/unit_hash.rs2
-rw-r--r--clippy_lints/src/unit_types/unit_cmp.rs40
-rw-r--r--clippy_lints/src/unused_io_amount.rs89
-rw-r--r--clippy_lints/src/utils/author.rs2
-rw-r--r--clippy_lints/src/utils/conf.rs10
-rw-r--r--clippy_lints/src/utils/inspector.rs4
-rw-r--r--clippy_lints/src/utils/internal_lints.rs30
-rw-r--r--clippy_lints/src/utils/internal_lints/metadata_collector.rs15
-rw-r--r--clippy_lints/src/utils/mod.rs2
-rw-r--r--clippy_lints/src/vec_init_then_push.rs2
106 files changed, 1156 insertions, 737 deletions
diff --git a/clippy_lints/src/assertions_on_constants.rs b/clippy_lints/src/assertions_on_constants.rs
index b7f414742f1..c82837746bd 100644
--- a/clippy_lints/src/assertions_on_constants.rs
+++ b/clippy_lints/src/assertions_on_constants.rs
@@ -1,12 +1,10 @@
 use clippy_utils::consts::{constant, Constant};
 use clippy_utils::diagnostics::span_lint_and_help;
-use clippy_utils::higher;
-use clippy_utils::source::snippet_opt;
-use clippy_utils::{is_direct_expn_of, is_expn_of, match_panic_call, peel_blocks};
-use if_chain::if_chain;
-use rustc_hir::{Expr, ExprKind, UnOp};
+use clippy_utils::macros::{find_assert_args, root_macro_call_first_node, PanicExpn};
+use rustc_hir::Expr;
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_span::sym;
 
 declare_clippy_lint! {
     /// ### What it does
@@ -36,107 +34,39 @@ declare_lint_pass!(AssertionsOnConstants => [ASSERTIONS_ON_CONSTANTS]);
 
 impl<'tcx> LateLintPass<'tcx> for AssertionsOnConstants {
     fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) {
-        let lint_true = |is_debug: bool| {
-            span_lint_and_help(
-                cx,
-                ASSERTIONS_ON_CONSTANTS,
-                e.span,
-                if is_debug {
-                    "`debug_assert!(true)` will be optimized out by the compiler"
-                } else {
-                    "`assert!(true)` will be optimized out by the compiler"
-                },
-                None,
-                "remove it",
-            );
+        let Some(macro_call) = root_macro_call_first_node(cx, e) else { return };
+        let is_debug = match cx.tcx.get_diagnostic_name(macro_call.def_id) {
+            Some(sym::debug_assert_macro) => true,
+            Some(sym::assert_macro) => false,
+            _ => return,
         };
-        let lint_false_without_message = || {
+        let Some((condition, panic_expn)) = find_assert_args(cx, e, macro_call.expn) else { return };
+        let Some((Constant::Bool(val), _)) = constant(cx, cx.typeck_results(), condition) else { return };
+        if val {
             span_lint_and_help(
                 cx,
                 ASSERTIONS_ON_CONSTANTS,
-                e.span,
-                "`assert!(false)` should probably be replaced",
+                macro_call.span,
+                &format!(
+                    "`{}!(true)` will be optimized out by the compiler",
+                    cx.tcx.item_name(macro_call.def_id)
+                ),
                 None,
-                "use `panic!()` or `unreachable!()`",
+                "remove it",
             );
-        };
-        let lint_false_with_message = |panic_message: String| {
+        } else if !is_debug {
+            let (assert_arg, panic_arg) = match panic_expn {
+                PanicExpn::Empty => ("", ""),
+                _ => (", ..", ".."),
+            };
             span_lint_and_help(
                 cx,
                 ASSERTIONS_ON_CONSTANTS,
-                e.span,
-                &format!("`assert!(false, {})` should probably be replaced", panic_message),
+                macro_call.span,
+                &format!("`assert!(false{})` should probably be replaced", assert_arg),
                 None,
-                &format!("use `panic!({})` or `unreachable!({})`", panic_message, panic_message),
+                &format!("use `panic!({})` or `unreachable!({0})`", panic_arg),
             );
-        };
-
-        if let Some(debug_assert_span) = is_expn_of(e.span, "debug_assert") {
-            if debug_assert_span.from_expansion() {
-                return;
-            }
-            if_chain! {
-                if let ExprKind::Unary(_, lit) = e.kind;
-                if let Some((Constant::Bool(is_true), _)) = constant(cx, cx.typeck_results(), lit);
-                if is_true;
-                then {
-                    lint_true(true);
-                }
-            };
-        } else if let Some(assert_span) = is_direct_expn_of(e.span, "assert") {
-            if assert_span.from_expansion() {
-                return;
-            }
-            if let Some(assert_match) = match_assert_with_message(cx, e) {
-                match assert_match {
-                    // matched assert but not message
-                    AssertKind::WithoutMessage(false) => lint_false_without_message(),
-                    AssertKind::WithoutMessage(true) | AssertKind::WithMessage(_, true) => lint_true(false),
-                    AssertKind::WithMessage(panic_message, false) => lint_false_with_message(panic_message),
-                };
-            }
-        }
-    }
-}
-
-/// Result of calling `match_assert_with_message`.
-enum AssertKind {
-    WithMessage(String, bool),
-    WithoutMessage(bool),
-}
-
-/// Check if the expression matches
-///
-/// ```rust,ignore
-/// if !c {
-///   {
-///     ::std::rt::begin_panic(message, _)
-///   }
-/// }
-/// ```
-///
-/// where `message` is any expression and `c` is a constant bool.
-fn match_assert_with_message<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> Option<AssertKind> {
-    if_chain! {
-        if let Some(higher::If { cond, then, .. }) = higher::If::hir(expr);
-        if let ExprKind::Unary(UnOp::Not, expr) = cond.kind;
-        // bind the first argument of the `assert!` macro
-        if let Some((Constant::Bool(is_true), _)) = constant(cx, cx.typeck_results(), expr);
-        let begin_panic_call = peel_blocks(then);
-        // function call
-        if let Some(arg) = match_panic_call(cx, begin_panic_call);
-        // bind the second argument of the `assert!` macro if it exists
-        if let panic_message = snippet_opt(cx, arg.span);
-        // second argument of begin_panic is irrelevant
-        // as is the second match arm
-        then {
-            // an empty message occurs when it was generated by the macro
-            // (and not passed by the user)
-            return panic_message
-                .filter(|msg| !msg.is_empty())
-                .map(|msg| AssertKind::WithMessage(msg, is_true))
-                .or(Some(AssertKind::WithoutMessage(is_true)));
         }
     }
-    None
 }
diff --git a/clippy_lints/src/attrs.rs b/clippy_lints/src/attrs.rs
index 0629674307b..a58d12ddd6b 100644
--- a/clippy_lints/src/attrs.rs
+++ b/clippy_lints/src/attrs.rs
@@ -1,9 +1,10 @@
 //! checks for attributes
 
 use clippy_utils::diagnostics::{span_lint, span_lint_and_help, span_lint_and_sugg, span_lint_and_then};
+use clippy_utils::macros::{is_panic, macro_backtrace};
 use clippy_utils::msrvs;
 use clippy_utils::source::{first_line_of_span, is_present_in_source, snippet_opt, without_block_comments};
-use clippy_utils::{extract_msrv_attr, match_panic_def_id, meets_msrv};
+use clippy_utils::{extract_msrv_attr, meets_msrv};
 use if_chain::if_chain;
 use rustc_ast::{AttrKind, AttrStyle, Attribute, Lit, LitKind, MetaItemKind, NestedMetaItem};
 use rustc_errors::Applicability;
@@ -443,20 +444,15 @@ fn is_relevant_block(cx: &LateContext<'_>, typeck_results: &ty::TypeckResults<'_
 }
 
 fn is_relevant_expr(cx: &LateContext<'_>, typeck_results: &ty::TypeckResults<'_>, expr: &Expr<'_>) -> bool {
+    if macro_backtrace(expr.span).last().map_or(false, |macro_call| {
+        is_panic(cx, macro_call.def_id) || cx.tcx.item_name(macro_call.def_id) == sym::unreachable
+    }) {
+        return false;
+    }
     match &expr.kind {
         ExprKind::Block(block, _) => is_relevant_block(cx, typeck_results, block),
         ExprKind::Ret(Some(e)) => is_relevant_expr(cx, typeck_results, e),
         ExprKind::Ret(None) | ExprKind::Break(_, None) => false,
-        ExprKind::Call(path_expr, _) => {
-            if let ExprKind::Path(qpath) = &path_expr.kind {
-                typeck_results
-                    .qpath_res(qpath, path_expr.hir_id)
-                    .opt_def_id()
-                    .map_or(true, |fun_id| !match_panic_def_id(cx, fun_id))
-            } else {
-                true
-            }
-        },
         _ => true,
     }
 }
diff --git a/clippy_lints/src/bool_assert_comparison.rs b/clippy_lints/src/bool_assert_comparison.rs
index d0b8c52a36a..c50e214be28 100644
--- a/clippy_lints/src/bool_assert_comparison.rs
+++ b/clippy_lints/src/bool_assert_comparison.rs
@@ -1,4 +1,5 @@
-use clippy_utils::{diagnostics::span_lint_and_sugg, higher, is_direct_expn_of, ty::implements_trait};
+use clippy_utils::macros::{find_assert_eq_args, root_macro_call_first_node};
+use clippy_utils::{diagnostics::span_lint_and_sugg, ty::implements_trait};
 use rustc_ast::ast::LitKind;
 use rustc_errors::Applicability;
 use rustc_hir::{Expr, ExprKind, Lit};
@@ -41,7 +42,7 @@ fn is_bool_lit(e: &Expr<'_>) -> bool {
     ) && !e.span.from_expansion()
 }
 
-fn is_impl_not_trait_with_bool_out(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) -> bool {
+fn is_impl_not_trait_with_bool_out(cx: &LateContext<'_>, e: &Expr<'_>) -> bool {
     let ty = cx.typeck_results().expr_ty(e);
 
     cx.tcx
@@ -66,44 +67,40 @@ fn is_impl_not_trait_with_bool_out(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) ->
 
 impl<'tcx> LateLintPass<'tcx> for BoolAssertComparison {
     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
-        let macros = ["assert_eq", "debug_assert_eq"];
-        let inverted_macros = ["assert_ne", "debug_assert_ne"];
-
-        for mac in macros.iter().chain(inverted_macros.iter()) {
-            if let Some(span) = is_direct_expn_of(expr.span, mac) {
-                if let Some(args) = higher::extract_assert_macro_args(expr) {
-                    if let [a, b, ..] = args[..] {
-                        let nb_bool_args = usize::from(is_bool_lit(a)) + usize::from(is_bool_lit(b));
-
-                        if nb_bool_args != 1 {
-                            // If there are two boolean arguments, we definitely don't understand
-                            // what's going on, so better leave things as is...
-                            //
-                            // Or there is simply no boolean and then we can leave things as is!
-                            return;
-                        }
-
-                        if !is_impl_not_trait_with_bool_out(cx, a) || !is_impl_not_trait_with_bool_out(cx, b) {
-                            // At this point the expression which is not a boolean
-                            // literal does not implement Not trait with a bool output,
-                            // so we cannot suggest to rewrite our code
-                            return;
-                        }
+        let Some(macro_call) = root_macro_call_first_node(cx, expr) else { return };
+        let macro_name = cx.tcx.item_name(macro_call.def_id);
+        if !matches!(
+            macro_name.as_str(),
+            "assert_eq" | "debug_assert_eq" | "assert_ne" | "debug_assert_ne"
+        ) {
+            return;
+        }
+        let Some ((a, b, _)) = find_assert_eq_args(cx, expr, macro_call.expn) else { return };
+        if !(is_bool_lit(a) ^ is_bool_lit(b)) {
+            // If there are two boolean arguments, we definitely don't understand
+            // what's going on, so better leave things as is...
+            //
+            // Or there is simply no boolean and then we can leave things as is!
+            return;
+        }
 
-                        let non_eq_mac = &mac[..mac.len() - 3];
-                        span_lint_and_sugg(
-                            cx,
-                            BOOL_ASSERT_COMPARISON,
-                            span,
-                            &format!("used `{}!` with a literal bool", mac),
-                            "replace it with",
-                            format!("{}!(..)", non_eq_mac),
-                            Applicability::MaybeIncorrect,
-                        );
-                        return;
-                    }
-                }
-            }
+        if !is_impl_not_trait_with_bool_out(cx, a) || !is_impl_not_trait_with_bool_out(cx, b) {
+            // At this point the expression which is not a boolean
+            // literal does not implement Not trait with a bool output,
+            // so we cannot suggest to rewrite our code
+            return;
         }
+
+        let macro_name = macro_name.as_str();
+        let non_eq_mac = &macro_name[..macro_name.len() - 3];
+        span_lint_and_sugg(
+            cx,
+            BOOL_ASSERT_COMPARISON,
+            macro_call.span,
+            &format!("used `{}!` with a literal bool", macro_name),
+            "replace it with",
+            format!("{}!(..)", non_eq_mac),
+            Applicability::MaybeIncorrect,
+        );
     }
 }
diff --git a/clippy_lints/src/borrow_as_ptr.rs b/clippy_lints/src/borrow_as_ptr.rs
new file mode 100644
index 00000000000..b8f5217af2b
--- /dev/null
+++ b/clippy_lints/src/borrow_as_ptr.rs
@@ -0,0 +1,97 @@
+use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::is_no_std_crate;
+use clippy_utils::source::snippet_opt;
+use clippy_utils::{meets_msrv, msrvs};
+use if_chain::if_chain;
+use rustc_errors::Applicability;
+use rustc_hir::{BorrowKind, Expr, ExprKind, Mutability, TyKind};
+use rustc_lint::{LateContext, LateLintPass};
+use rustc_semver::RustcVersion;
+use rustc_session::{declare_tool_lint, impl_lint_pass};
+
+declare_clippy_lint! {
+    /// ### What it does
+    /// Checks for the usage of `&expr as *const T` or
+    /// `&mut expr as *mut T`, and suggest using `ptr::addr_of` or
+    /// `ptr::addr_of_mut` instead.
+    ///
+    /// ### Why is this bad?
+    /// This would improve readability and avoid creating a reference
+    /// that points to an uninitialized value or unaligned place.
+    /// Read the `ptr::addr_of` docs for more information.
+    ///
+    /// ### Example
+    /// ```rust
+    /// let val = 1;
+    /// let p = &val as *const i32;
+    ///
+    /// let mut val_mut = 1;
+    /// let p_mut = &mut val_mut as *mut i32;
+    /// ```
+    /// Use instead:
+    /// ```rust
+    /// let val = 1;
+    /// let p = std::ptr::addr_of!(val);
+    ///
+    /// let mut val_mut = 1;
+    /// let p_mut = std::ptr::addr_of_mut!(val_mut);
+    /// ```
+    #[clippy::version = "1.60.0"]
+    pub BORROW_AS_PTR,
+    pedantic,
+    "borrowing just to cast to a raw pointer"
+}
+
+impl_lint_pass!(BorrowAsPtr => [BORROW_AS_PTR]);
+
+pub struct BorrowAsPtr {
+    msrv: Option<RustcVersion>,
+}
+
+impl BorrowAsPtr {
+    #[must_use]
+    pub fn new(msrv: Option<RustcVersion>) -> Self {
+        Self { msrv }
+    }
+}
+
+impl<'tcx> LateLintPass<'tcx> for BorrowAsPtr {
+    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
+        if !meets_msrv(self.msrv.as_ref(), &msrvs::BORROW_AS_PTR) {
+            return;
+        }
+
+        if expr.span.from_expansion() {
+            return;
+        }
+
+        if_chain! {
+            if let ExprKind::Cast(left_expr, ty) = &expr.kind;
+            if let TyKind::Ptr(_) = ty.kind;
+            if let ExprKind::AddrOf(BorrowKind::Ref, mutability, e) = &left_expr.kind;
+
+            then {
+                let core_or_std = if is_no_std_crate(cx) { "core" } else { "std" };
+                let macro_name = match mutability {
+                    Mutability::Not => "addr_of",
+                    Mutability::Mut => "addr_of_mut",
+                };
+
+                span_lint_and_sugg(
+                    cx,
+                    BORROW_AS_PTR,
+                    expr.span,
+                    "borrow as raw pointer",
+                    "try",
+                    format!(
+                        "{}::ptr::{}!({})",
+                        core_or_std,
+                        macro_name,
+                        snippet_opt(cx, e.span).unwrap()
+                    ),
+                    Applicability::MachineApplicable,
+                );
+            }
+        }
+    }
+}
diff --git a/clippy_lints/src/case_sensitive_file_extension_comparisons.rs b/clippy_lints/src/case_sensitive_file_extension_comparisons.rs
index 3f286dd9e2f..e8f39cd3709 100644
--- a/clippy_lints/src/case_sensitive_file_extension_comparisons.rs
+++ b/clippy_lints/src/case_sensitive_file_extension_comparisons.rs
@@ -67,7 +67,7 @@ fn check_case_sensitive_file_extension_comparison(ctx: &LateContext<'_>, expr: &
     None
 }
 
-impl LateLintPass<'tcx> for CaseSensitiveFileExtensionComparisons {
+impl<'tcx> LateLintPass<'tcx> for CaseSensitiveFileExtensionComparisons {
     fn check_expr(&mut self, ctx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) {
         if let Some(span) = check_case_sensitive_file_extension_comparison(ctx, expr) {
             span_lint_and_help(
diff --git a/clippy_lints/src/casts/cast_ptr_alignment.rs b/clippy_lints/src/casts/cast_ptr_alignment.rs
index 248b35b024e..b9de5510455 100644
--- a/clippy_lints/src/casts/cast_ptr_alignment.rs
+++ b/clippy_lints/src/casts/cast_ptr_alignment.rs
@@ -9,7 +9,7 @@ use rustc_span::symbol::sym;
 
 use super::CAST_PTR_ALIGNMENT;
 
-pub(super) fn check(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
+pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>) {
     if let ExprKind::Cast(cast_expr, cast_to) = expr.kind {
         if is_hir_ty_cfg_dependant(cx, cast_to) {
             return;
diff --git a/clippy_lints/src/casts/cast_ref_to_mut.rs b/clippy_lints/src/casts/cast_ref_to_mut.rs
index d9bf1ea58b9..15f2f81f407 100644
--- a/clippy_lints/src/casts/cast_ref_to_mut.rs
+++ b/clippy_lints/src/casts/cast_ref_to_mut.rs
@@ -6,7 +6,7 @@ use rustc_middle::ty;
 
 use super::CAST_REF_TO_MUT;
 
-pub(super) fn check(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
+pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>) {
     if_chain! {
         if let ExprKind::Unary(UnOp::Deref, e) = &expr.kind;
         if let ExprKind::Cast(e, t) = &e.kind;
diff --git a/clippy_lints/src/casts/char_lit_as_u8.rs b/clippy_lints/src/casts/char_lit_as_u8.rs
index 099a0de881f..7cc406018db 100644
--- a/clippy_lints/src/casts/char_lit_as_u8.rs
+++ b/clippy_lints/src/casts/char_lit_as_u8.rs
@@ -9,7 +9,7 @@ use rustc_middle::ty::{self, UintTy};
 
 use super::CHAR_LIT_AS_U8;
 
-pub(super) fn check(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
+pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>) {
     if_chain! {
         if let ExprKind::Cast(e, _) = &expr.kind;
         if let ExprKind::Lit(l) = &e.kind;
diff --git a/clippy_lints/src/casts/ptr_as_ptr.rs b/clippy_lints/src/casts/ptr_as_ptr.rs
index 3132d3a5cf0..fb04f93fbcf 100644
--- a/clippy_lints/src/casts/ptr_as_ptr.rs
+++ b/clippy_lints/src/casts/ptr_as_ptr.rs
@@ -12,7 +12,7 @@ use rustc_semver::RustcVersion;
 
 use super::PTR_AS_PTR;
 
-pub(super) fn check(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, msrv: &Option<RustcVersion>) {
+pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, msrv: &Option<RustcVersion>) {
     if !meets_msrv(msrv.as_ref(), &msrvs::POINTER_CAST) {
         return;
     }
diff --git a/clippy_lints/src/copies.rs b/clippy_lints/src/copies.rs
index d07bc23235b..73ce656ad15 100644
--- a/clippy_lints/src/copies.rs
+++ b/clippy_lints/src/copies.rs
@@ -316,7 +316,7 @@ struct BlockEqual {
 
 /// This function can also trigger the `IF_SAME_THEN_ELSE` in which case it'll return `None` to
 /// abort any further processing and avoid duplicate lint triggers.
-fn scan_block_for_eq(cx: &LateContext<'tcx>, blocks: &[&Block<'tcx>]) -> Option<BlockEqual> {
+fn scan_block_for_eq(cx: &LateContext<'_>, blocks: &[&Block<'_>]) -> Option<BlockEqual> {
     let mut start_eq = usize::MAX;
     let mut end_eq = usize::MAX;
     let mut expr_eq = true;
@@ -385,11 +385,7 @@ fn scan_block_for_eq(cx: &LateContext<'tcx>, blocks: &[&Block<'tcx>]) -> Option<
     })
 }
 
-fn check_for_warn_of_moved_symbol(
-    cx: &LateContext<'tcx>,
-    symbols: &FxHashSet<Symbol>,
-    if_expr: &'tcx Expr<'_>,
-) -> bool {
+fn check_for_warn_of_moved_symbol(cx: &LateContext<'_>, symbols: &FxHashSet<Symbol>, if_expr: &Expr<'_>) -> bool {
     get_enclosing_block(cx, if_expr.hir_id).map_or(false, |block| {
         let ignore_span = block.span.shrink_to_lo().to(if_expr.span);
 
@@ -419,13 +415,13 @@ fn check_for_warn_of_moved_symbol(
 }
 
 fn emit_branches_sharing_code_lint(
-    cx: &LateContext<'tcx>,
+    cx: &LateContext<'_>,
     start_stmts: usize,
     end_stmts: usize,
     lint_end: bool,
     warn_about_moved_symbol: bool,
-    blocks: &[&Block<'tcx>],
-    if_expr: &'tcx Expr<'_>,
+    blocks: &[&Block<'_>],
+    if_expr: &Expr<'_>,
 ) {
     if start_stmts == 0 && !lint_end {
         return;
diff --git a/clippy_lints/src/default.rs b/clippy_lints/src/default.rs
index 6422f5aabe5..3070588483c 100644
--- a/clippy_lints/src/default.rs
+++ b/clippy_lints/src/default.rs
@@ -77,7 +77,7 @@ pub struct Default {
 
 impl_lint_pass!(Default => [DEFAULT_TRAIT_ACCESS, FIELD_REASSIGN_WITH_DEFAULT]);
 
-impl LateLintPass<'_> for Default {
+impl<'tcx> LateLintPass<'tcx> for Default {
     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
         if_chain! {
             if !expr.span.from_expansion();
@@ -110,7 +110,7 @@ impl LateLintPass<'_> for Default {
     }
 
     #[allow(clippy::too_many_lines)]
-    fn check_block<'tcx>(&mut self, cx: &LateContext<'tcx>, block: &Block<'tcx>) {
+    fn check_block(&mut self, cx: &LateContext<'tcx>, block: &Block<'tcx>) {
         // start from the `let mut _ = _::default();` and look at all the following
         // statements, see if they re-assign the fields of the binding
         let stmts_head = match block.stmts {
diff --git a/clippy_lints/src/default_numeric_fallback.rs b/clippy_lints/src/default_numeric_fallback.rs
index 15215ac15cd..66b5f49817d 100644
--- a/clippy_lints/src/default_numeric_fallback.rs
+++ b/clippy_lints/src/default_numeric_fallback.rs
@@ -54,7 +54,7 @@ declare_clippy_lint! {
 
 declare_lint_pass!(DefaultNumericFallback => [DEFAULT_NUMERIC_FALLBACK]);
 
-impl LateLintPass<'_> for DefaultNumericFallback {
+impl<'tcx> LateLintPass<'tcx> for DefaultNumericFallback {
     fn check_body(&mut self, cx: &LateContext<'tcx>, body: &'tcx Body<'_>) {
         let mut visitor = NumericFallbackVisitor::new(cx);
         visitor.visit_body(body);
diff --git a/clippy_lints/src/dereference.rs b/clippy_lints/src/dereference.rs
index fa2b348591b..bf077a212fd 100644
--- a/clippy_lints/src/dereference.rs
+++ b/clippy_lints/src/dereference.rs
@@ -355,7 +355,7 @@ impl<'tcx> LateLintPass<'tcx> for Dereferencing {
     }
 }
 
-fn try_parse_ref_op(
+fn try_parse_ref_op<'tcx>(
     tcx: TyCtxt<'tcx>,
     typeck: &'tcx TypeckResults<'_>,
     expr: &'tcx Expr<'_>,
@@ -387,7 +387,7 @@ fn try_parse_ref_op(
 
 // Checks whether the type for a deref call actually changed the type, not just the mutability of
 // the reference.
-fn deref_method_same_type(result_ty: Ty<'tcx>, arg_ty: Ty<'tcx>) -> bool {
+fn deref_method_same_type(result_ty: Ty<'_>, arg_ty: Ty<'_>) -> bool {
     match (result_ty.kind(), arg_ty.kind()) {
         (ty::Ref(_, result_ty, _), ty::Ref(_, arg_ty, _)) => TyS::same_type(result_ty, arg_ty),
 
@@ -457,7 +457,7 @@ fn is_linted_explicit_deref_position(parent: Option<Node<'_>>, child_id: HirId,
 }
 
 /// Adjustments are sometimes made in the parent block rather than the expression itself.
-fn find_adjustments(
+fn find_adjustments<'tcx>(
     tcx: TyCtxt<'tcx>,
     typeck: &'tcx TypeckResults<'_>,
     expr: &'tcx Expr<'_>,
@@ -499,7 +499,7 @@ fn find_adjustments(
 }
 
 #[allow(clippy::needless_pass_by_value)]
-fn report(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, state: State, data: StateData) {
+fn report(cx: &LateContext<'_>, expr: &Expr<'_>, state: State, data: StateData) {
     match state {
         State::DerefMethod {
             ty_changed_count,
@@ -568,7 +568,7 @@ fn report(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, state: State, data: Stat
 }
 
 impl Dereferencing {
-    fn check_local_usage(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>, local: HirId) {
+    fn check_local_usage(&mut self, cx: &LateContext<'_>, e: &Expr<'_>, local: HirId) {
         if let Some(outer_pat) = self.ref_locals.get_mut(&local) {
             if let Some(pat) = outer_pat {
                 // Check for auto-deref
diff --git a/clippy_lints/src/disallowed_methods.rs b/clippy_lints/src/disallowed_methods.rs
index 6d4065907fb..73c00d97020 100644
--- a/clippy_lints/src/disallowed_methods.rs
+++ b/clippy_lints/src/disallowed_methods.rs
@@ -11,6 +11,9 @@ declare_clippy_lint! {
     /// ### What it does
     /// Denies the configured methods and functions in clippy.toml
     ///
+    /// Note: Even though this lint is warn-by-default, it will only trigger if
+    /// methods are defined in the clippy.toml file.
+    ///
     /// ### Why is this bad?
     /// Some methods are undesirable in certain contexts, and it's beneficial to
     /// lint for them as needed.
@@ -49,14 +52,14 @@ declare_clippy_lint! {
     /// ```
     #[clippy::version = "1.49.0"]
     pub DISALLOWED_METHODS,
-    nursery,
+    style,
     "use of a disallowed method call"
 }
 
 #[derive(Clone, Debug)]
 pub struct DisallowedMethods {
     conf_disallowed: Vec<conf::DisallowedMethod>,
-    disallowed: DefIdMap<Option<String>>,
+    disallowed: DefIdMap<usize>,
 }
 
 impl DisallowedMethods {
@@ -72,17 +75,10 @@ impl_lint_pass!(DisallowedMethods => [DISALLOWED_METHODS]);
 
 impl<'tcx> LateLintPass<'tcx> for DisallowedMethods {
     fn check_crate(&mut self, cx: &LateContext<'_>) {
-        for conf in &self.conf_disallowed {
-            let (path, reason) = match conf {
-                conf::DisallowedMethod::Simple(path) => (path, None),
-                conf::DisallowedMethod::WithReason { path, reason } => (
-                    path,
-                    reason.as_ref().map(|reason| format!("{} (from clippy.toml)", reason)),
-                ),
-            };
-            let segs: Vec<_> = path.split("::").collect();
+        for (index, conf) in self.conf_disallowed.iter().enumerate() {
+            let segs: Vec<_> = conf.path().split("::").collect();
             if let Res::Def(_, id) = clippy_utils::path_to_res(cx, &segs) {
-                self.disallowed.insert(id, reason);
+                self.disallowed.insert(id, index);
             }
         }
     }
@@ -92,15 +88,17 @@ impl<'tcx> LateLintPass<'tcx> for DisallowedMethods {
             Some(def_id) => def_id,
             None => return,
         };
-        let reason = match self.disallowed.get(&def_id) {
-            Some(reason) => reason,
+        let conf = match self.disallowed.get(&def_id) {
+            Some(&index) => &self.conf_disallowed[index],
             None => return,
         };
-        let func_path = cx.tcx.def_path_str(def_id);
-        let msg = format!("use of a disallowed method `{}`", func_path);
+        let msg = format!("use of a disallowed method `{}`", conf.path());
         span_lint_and_then(cx, DISALLOWED_METHODS, expr.span, &msg, |diag| {
-            if let Some(reason) = reason {
-                diag.note(reason);
+            if let conf::DisallowedMethod::WithReason {
+                reason: Some(reason), ..
+            } = conf
+            {
+                diag.note(&format!("{} (from clippy.toml)", reason));
             }
         });
     }
diff --git a/clippy_lints/src/disallowed_types.rs b/clippy_lints/src/disallowed_types.rs
index eaed4032713..ea4b49b46fe 100644
--- a/clippy_lints/src/disallowed_types.rs
+++ b/clippy_lints/src/disallowed_types.rs
@@ -14,6 +14,9 @@ declare_clippy_lint! {
     /// ### What it does
     /// Denies the configured types in clippy.toml.
     ///
+    /// Note: Even though this lint is warn-by-default, it will only trigger if
+    /// types are defined in the clippy.toml file.
+    ///
     /// ### Why is this bad?
     /// Some types are undesirable in certain contexts.
     ///
@@ -44,7 +47,7 @@ declare_clippy_lint! {
     /// ```
     #[clippy::version = "1.55.0"]
     pub DISALLOWED_TYPES,
-    nursery,
+    style,
     "use of disallowed types"
 }
 #[derive(Clone, Debug)]
diff --git a/clippy_lints/src/doc.rs b/clippy_lints/src/doc.rs
index 7c271773357..cb7d5ac7394 100644
--- a/clippy_lints/src/doc.rs
+++ b/clippy_lints/src/doc.rs
@@ -1,8 +1,9 @@
 use clippy_utils::attrs::is_doc_hidden;
 use clippy_utils::diagnostics::{span_lint, span_lint_and_help, span_lint_and_note, span_lint_and_then};
+use clippy_utils::macros::{is_panic, root_macro_call_first_node};
 use clippy_utils::source::{first_line_of_span, snippet_with_applicability};
 use clippy_utils::ty::{implements_trait, is_type_diagnostic_item};
-use clippy_utils::{is_entrypoint_fn, is_expn_of, match_panic_def_id, method_chain_args, return_ty};
+use clippy_utils::{is_entrypoint_fn, method_chain_args, return_ty};
 use if_chain::if_chain;
 use itertools::Itertools;
 use rustc_ast::ast::{Async, AttrKind, Attribute, Fn, FnRetTy, ItemKind};
@@ -13,7 +14,7 @@ use rustc_errors::emitter::EmitterWriter;
 use rustc_errors::{Applicability, Handler, SuggestionStyle};
 use rustc_hir as hir;
 use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor};
-use rustc_hir::{AnonConst, Expr, ExprKind, QPath};
+use rustc_hir::{AnonConst, Expr};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::hir::map::Map;
 use rustc_middle::lint::in_external_macro;
@@ -805,24 +806,17 @@ impl<'a, 'tcx> Visitor<'tcx> for FindPanicUnwrap<'a, 'tcx> {
             return;
         }
 
-        // check for `begin_panic`
-        if_chain! {
-            if let ExprKind::Call(func_expr, _) = expr.kind;
-            if let ExprKind::Path(QPath::Resolved(_, path)) = func_expr.kind;
-            if let Some(path_def_id) = path.res.opt_def_id();
-            if match_panic_def_id(self.cx, path_def_id);
-            if is_expn_of(expr.span, "unreachable").is_none();
-            if !is_expn_of_debug_assertions(expr.span);
-            then {
-                self.panic_span = Some(expr.span);
+        if let Some(macro_call) = root_macro_call_first_node(self.cx, expr) {
+            if is_panic(self.cx, macro_call.def_id)
+                || matches!(
+                    self.cx.tcx.item_name(macro_call.def_id).as_str(),
+                    "assert" | "assert_eq" | "assert_ne" | "todo"
+                )
+            {
+                self.panic_span = Some(macro_call.span);
             }
         }
 
-        // check for `assert_eq` or `assert_ne`
-        if is_expn_of(expr.span, "assert_eq").is_some() || is_expn_of(expr.span, "assert_ne").is_some() {
-            self.panic_span = Some(expr.span);
-        }
-
         // check for `unwrap`
         if let Some(arglists) = method_chain_args(expr, &["unwrap"]) {
             let receiver_ty = self.typeck_results.expr_ty(&arglists[0][0]).peel_refs();
@@ -844,8 +838,3 @@ impl<'a, 'tcx> Visitor<'tcx> for FindPanicUnwrap<'a, 'tcx> {
         NestedVisitorMap::OnlyBodies(self.cx.tcx.hir())
     }
 }
-
-fn is_expn_of_debug_assertions(span: Span) -> bool {
-    const MACRO_NAMES: &[&str] = &["debug_assert", "debug_assert_eq", "debug_assert_ne"];
-    MACRO_NAMES.iter().any(|name| is_expn_of(span, name).is_some())
-}
diff --git a/clippy_lints/src/entry.rs b/clippy_lints/src/entry.rs
index 3d92eb16870..3ce239273e2 100644
--- a/clippy_lints/src/entry.rs
+++ b/clippy_lints/src/entry.rs
@@ -233,7 +233,7 @@ struct ContainsExpr<'tcx> {
     key: &'tcx Expr<'tcx>,
     call_ctxt: SyntaxContext,
 }
-fn try_parse_contains(cx: &LateContext<'_>, expr: &'tcx Expr<'_>) -> Option<(MapType, ContainsExpr<'tcx>)> {
+fn try_parse_contains<'tcx>(cx: &LateContext<'_>, expr: &'tcx Expr<'_>) -> Option<(MapType, ContainsExpr<'tcx>)> {
     let mut negated = false;
     let expr = peel_hir_expr_while(expr, |e| match e.kind {
         ExprKind::Unary(UnOp::Not, e) => {
@@ -280,7 +280,7 @@ struct InsertExpr<'tcx> {
     key: &'tcx Expr<'tcx>,
     value: &'tcx Expr<'tcx>,
 }
-fn try_parse_insert(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> Option<InsertExpr<'tcx>> {
+fn try_parse_insert<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> Option<InsertExpr<'tcx>> {
     if let ExprKind::MethodCall(_, _, [map, key, value], _) = expr.kind {
         let id = cx.typeck_results().type_dependent_def_id(expr.hir_id)?;
         if match_def_path(cx, id, &paths::BTREEMAP_INSERT) || match_def_path(cx, id, &paths::HASHMAP_INSERT) {
@@ -301,7 +301,7 @@ enum Edit<'tcx> {
     /// An insertion into the map.
     Insertion(Insertion<'tcx>),
 }
-impl Edit<'tcx> {
+impl<'tcx> Edit<'tcx> {
     fn as_insertion(self) -> Option<Insertion<'tcx>> {
         if let Self::Insertion(i) = self { Some(i) } else { None }
     }
@@ -532,7 +532,7 @@ struct InsertSearchResults<'tcx> {
     allow_insert_closure: bool,
     is_single_insert: bool,
 }
-impl InsertSearchResults<'tcx> {
+impl<'tcx> InsertSearchResults<'tcx> {
     fn as_single_insertion(&self) -> Option<Insertion<'tcx>> {
         self.is_single_insert.then(|| self.edits[0].as_insertion().unwrap())
     }
@@ -633,7 +633,7 @@ impl InsertSearchResults<'tcx> {
     }
 }
 
-fn find_insert_calls(
+fn find_insert_calls<'tcx>(
     cx: &LateContext<'tcx>,
     contains_expr: &ContainsExpr<'tcx>,
     expr: &'tcx Expr<'_>,
diff --git a/clippy_lints/src/eq_op.rs b/clippy_lints/src/eq_op.rs
index 10123460527..df75b815436 100644
--- a/clippy_lints/src/eq_op.rs
+++ b/clippy_lints/src/eq_op.rs
@@ -1,10 +1,11 @@
 use clippy_utils::diagnostics::{multispan_sugg, span_lint, span_lint_and_then};
+use clippy_utils::macros::{find_assert_eq_args, first_node_macro_backtrace};
 use clippy_utils::source::snippet;
 use clippy_utils::ty::{implements_trait, is_copy};
-use clippy_utils::{ast_utils::is_useless_with_eq_exprs, eq_expr_value, higher, is_expn_of, is_in_test_function};
+use clippy_utils::{ast_utils::is_useless_with_eq_exprs, eq_expr_value, is_in_test_function};
 use if_chain::if_chain;
 use rustc_errors::Applicability;
-use rustc_hir::{BinOpKind, BorrowKind, Expr, ExprKind, StmtKind};
+use rustc_hir::{BinOpKind, BorrowKind, Expr, ExprKind};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_session::{declare_lint_pass, declare_tool_lint};
 
@@ -68,32 +69,26 @@ declare_clippy_lint! {
 
 declare_lint_pass!(EqOp => [EQ_OP, OP_REF]);
 
-const ASSERT_MACRO_NAMES: [&str; 4] = ["assert_eq", "assert_ne", "debug_assert_eq", "debug_assert_ne"];
-
 impl<'tcx> LateLintPass<'tcx> for EqOp {
     #[allow(clippy::similar_names, clippy::too_many_lines)]
     fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) {
-        if let ExprKind::Block(block, _) = e.kind {
-            for stmt in block.stmts {
-                for amn in &ASSERT_MACRO_NAMES {
-                    if_chain! {
-                        if is_expn_of(stmt.span, amn).is_some();
-                        if let StmtKind::Semi(matchexpr) = stmt.kind;
-                        if let Some(macro_args) = higher::extract_assert_macro_args(matchexpr);
-                        if macro_args.len() == 2;
-                        let (lhs, rhs) = (macro_args[0], macro_args[1]);
-                        if eq_expr_value(cx, lhs, rhs);
-                        if !is_in_test_function(cx.tcx, e.hir_id);
-                        then {
-                            span_lint(
-                                cx,
-                                EQ_OP,
-                                lhs.span.to(rhs.span),
-                                &format!("identical args used in this `{}!` macro call", amn),
-                            );
-                        }
-                    }
-                }
+        if_chain! {
+            if let Some((macro_call, macro_name)) = first_node_macro_backtrace(cx, e).find_map(|macro_call| {
+                let name = cx.tcx.item_name(macro_call.def_id);
+                matches!(name.as_str(), "assert_eq" | "assert_ne" | "debug_assert_eq" | "debug_assert_ne")
+                    .then(|| (macro_call, name))
+            });
+            if let Some((lhs, rhs, _)) = find_assert_eq_args(cx, e, macro_call.expn);
+            if eq_expr_value(cx, lhs, rhs);
+            if macro_call.is_local();
+            if !is_in_test_function(cx.tcx, e.hir_id);
+            then {
+                span_lint(
+                    cx,
+                    EQ_OP,
+                    lhs.span.to(rhs.span),
+                    &format!("identical args used in this `{}!` macro call", macro_name),
+                );
             }
         }
         if let ExprKind::Binary(op, left, right) = e.kind {
diff --git a/clippy_lints/src/equatable_if_let.rs b/clippy_lints/src/equatable_if_let.rs
index 06d128f5527..cf47e581ccb 100644
--- a/clippy_lints/src/equatable_if_let.rs
+++ b/clippy_lints/src/equatable_if_let.rs
@@ -56,7 +56,7 @@ fn unary_pattern(pat: &Pat<'_>) -> bool {
     }
 }
 
-fn is_structural_partial_eq(cx: &LateContext<'tcx>, ty: Ty<'tcx>, other: Ty<'tcx>) -> bool {
+fn is_structural_partial_eq<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>, other: Ty<'tcx>) -> bool {
     if let Some(def_id) = cx.tcx.lang_items().eq_trait() {
         implements_trait(cx, ty, def_id, &[other.into()])
     } else {
diff --git a/clippy_lints/src/erasing_op.rs b/clippy_lints/src/erasing_op.rs
index d49cec26be5..c1a84973c42 100644
--- a/clippy_lints/src/erasing_op.rs
+++ b/clippy_lints/src/erasing_op.rs
@@ -1,9 +1,11 @@
 use clippy_utils::consts::{constant_simple, Constant};
 use clippy_utils::diagnostics::span_lint;
+use clippy_utils::ty::same_type_and_consts;
+
 use rustc_hir::{BinOpKind, Expr, ExprKind};
 use rustc_lint::{LateContext, LateLintPass};
+use rustc_middle::ty::TypeckResults;
 use rustc_session::{declare_lint_pass, declare_tool_lint};
-use rustc_span::source_map::Span;
 
 declare_clippy_lint! {
     /// ### What it does
@@ -35,24 +37,40 @@ impl<'tcx> LateLintPass<'tcx> for ErasingOp {
             return;
         }
         if let ExprKind::Binary(ref cmp, left, right) = e.kind {
+            let tck = cx.typeck_results();
             match cmp.node {
                 BinOpKind::Mul | BinOpKind::BitAnd => {
-                    check(cx, left, e.span);
-                    check(cx, right, e.span);
+                    check(cx, tck, left, right, e);
+                    check(cx, tck, right, left, e);
                 },
-                BinOpKind::Div => check(cx, left, e.span),
+                BinOpKind::Div => check(cx, tck, left, right, e),
                 _ => (),
             }
         }
     }
 }
 
-fn check(cx: &LateContext<'_>, e: &Expr<'_>, span: Span) {
-    if constant_simple(cx, cx.typeck_results(), e) == Some(Constant::Int(0)) {
+fn different_types(tck: &TypeckResults<'_>, input: &Expr<'_>, output: &Expr<'_>) -> bool {
+    let input_ty = tck.expr_ty(input).peel_refs();
+    let output_ty = tck.expr_ty(output).peel_refs();
+    !same_type_and_consts(input_ty, output_ty)
+}
+
+fn check<'tcx>(
+    cx: &LateContext<'tcx>,
+    tck: &TypeckResults<'tcx>,
+    op: &Expr<'tcx>,
+    other: &Expr<'tcx>,
+    parent: &Expr<'tcx>,
+) {
+    if constant_simple(cx, tck, op) == Some(Constant::Int(0)) {
+        if different_types(tck, other, parent) {
+            return;
+        }
         span_lint(
             cx,
             ERASING_OP,
-            span,
+            parent.span,
             "this operation will always return zero. This is likely not the intended outcome",
         );
     }
diff --git a/clippy_lints/src/eta_reduction.rs b/clippy_lints/src/eta_reduction.rs
index 5a4b4247104..b22515a3907 100644
--- a/clippy_lints/src/eta_reduction.rs
+++ b/clippy_lints/src/eta_reduction.rs
@@ -1,6 +1,7 @@
 use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then};
 use clippy_utils::higher::VecArgs;
 use clippy_utils::source::snippet_opt;
+use clippy_utils::ty::is_type_diagnostic_item;
 use clippy_utils::usage::local_used_after_expr;
 use clippy_utils::{get_enclosing_loop_or_closure, higher, path_to_local, path_to_local_id};
 use if_chain::if_chain;
@@ -12,6 +13,7 @@ use rustc_middle::ty::adjustment::{Adjust, Adjustment, AutoBorrow};
 use rustc_middle::ty::subst::Subst;
 use rustc_middle::ty::{self, ClosureKind, Ty, TypeFoldable};
 use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_span::symbol::sym;
 
 declare_clippy_lint! {
     /// ### What it does
@@ -113,6 +115,9 @@ impl<'tcx> LateLintPass<'tcx> for EtaReduction {
             // A type param function ref like `T::f` is not 'static, however
             // it is if cast like `T::f as fn()`. This seems like a rustc bug.
             if !substs.types().any(|t| matches!(t.kind(), ty::Param(_)));
+            let callee_ty_unadjusted = cx.typeck_results().expr_ty(callee).peel_refs();
+            if !is_type_diagnostic_item(cx, callee_ty_unadjusted, sym::Arc);
+            if !is_type_diagnostic_item(cx, callee_ty_unadjusted, sym::Rc);
             then {
                 span_lint_and_then(cx, REDUNDANT_CLOSURE, expr.span, "redundant closure", |diag| {
                     if let Some(mut snippet) = snippet_opt(cx, callee.span) {
diff --git a/clippy_lints/src/explicit_write.rs b/clippy_lints/src/explicit_write.rs
index 6b327b9ce17..98e5234e0aa 100644
--- a/clippy_lints/src/explicit_write.rs
+++ b/clippy_lints/src/explicit_write.rs
@@ -1,5 +1,5 @@
 use clippy_utils::diagnostics::{span_lint_and_help, span_lint_and_sugg};
-use clippy_utils::higher::FormatArgsExpn;
+use clippy_utils::macros::FormatArgsExpn;
 use clippy_utils::{is_expn_of, match_function_call, paths};
 use if_chain::if_chain;
 use rustc_errors::Applicability;
@@ -48,7 +48,7 @@ impl<'tcx> LateLintPass<'tcx> for ExplicitWrite {
             } else {
                 None
             };
-            if let Some(format_args) = FormatArgsExpn::parse(write_arg);
+            if let Some(format_args) = FormatArgsExpn::parse(cx, write_arg);
             then {
                 let calling_macro =
                     // ordering is important here, since `writeln!` uses `write!` internally
@@ -80,7 +80,7 @@ impl<'tcx> LateLintPass<'tcx> for ExplicitWrite {
                     )
                 };
                 let msg = format!("use of `{}.unwrap()`", used);
-                if let [write_output] = *format_args.format_string_symbols {
+                if let [write_output] = *format_args.format_string_parts {
                     let mut write_output = write_output.to_string();
                     if write_output.ends_with('\n') {
                         write_output.pop();
diff --git a/clippy_lints/src/fallible_impl_from.rs b/clippy_lints/src/fallible_impl_from.rs
index 05d300058cf..02f1baf27fa 100644
--- a/clippy_lints/src/fallible_impl_from.rs
+++ b/clippy_lints/src/fallible_impl_from.rs
@@ -1,6 +1,7 @@
 use clippy_utils::diagnostics::span_lint_and_then;
+use clippy_utils::macros::{is_panic, root_macro_call_first_node};
+use clippy_utils::method_chain_args;
 use clippy_utils::ty::is_type_diagnostic_item;
-use clippy_utils::{is_expn_of, match_panic_def_id, method_chain_args};
 use if_chain::if_chain;
 use rustc_hir as hir;
 use rustc_lint::{LateContext, LateLintPass};
@@ -68,7 +69,7 @@ impl<'tcx> LateLintPass<'tcx> for FallibleImplFrom {
 
 fn lint_impl_body<'tcx>(cx: &LateContext<'tcx>, impl_span: Span, impl_items: &[hir::ImplItemRef]) {
     use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor};
-    use rustc_hir::{Expr, ExprKind, ImplItemKind, QPath};
+    use rustc_hir::{Expr, ImplItemKind};
 
     struct FindPanicUnwrap<'a, 'tcx> {
         lcx: &'a LateContext<'tcx>,
@@ -80,14 +81,8 @@ fn lint_impl_body<'tcx>(cx: &LateContext<'tcx>, impl_span: Span, impl_items: &[h
         type Map = Map<'tcx>;
 
         fn visit_expr(&mut self, expr: &'tcx Expr<'_>) {
-            // check for `begin_panic`
-            if_chain! {
-                if let ExprKind::Call(func_expr, _) = expr.kind;
-                if let ExprKind::Path(QPath::Resolved(_, path)) = func_expr.kind;
-                if let Some(path_def_id) = path.res.opt_def_id();
-                if match_panic_def_id(self.lcx, path_def_id);
-                if is_expn_of(expr.span, "unreachable").is_none();
-                then {
+            if let Some(macro_call) = root_macro_call_first_node(self.lcx, expr) {
+                if is_panic(self.lcx, macro_call.def_id) {
                     self.result.push(expr.span);
                 }
             }
diff --git a/clippy_lints/src/format.rs b/clippy_lints/src/format.rs
index 3f043e5f2f1..688d8f8630f 100644
--- a/clippy_lints/src/format.rs
+++ b/clippy_lints/src/format.rs
@@ -1,5 +1,5 @@
 use clippy_utils::diagnostics::span_lint_and_sugg;
-use clippy_utils::higher::FormatExpn;
+use clippy_utils::macros::{root_macro_call_first_node, FormatArgsExpn};
 use clippy_utils::source::{snippet_opt, snippet_with_applicability};
 use clippy_utils::sugg::Sugg;
 use if_chain::if_chain;
@@ -43,38 +43,41 @@ declare_lint_pass!(UselessFormat => [USELESS_FORMAT]);
 
 impl<'tcx> LateLintPass<'tcx> for UselessFormat {
     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
-        let FormatExpn { call_site, format_args } = match FormatExpn::parse(expr) {
-            Some(e) if !e.call_site.from_expansion() => e,
-            _ => return,
+        let (format_args, call_site) = if_chain! {
+            if let Some(macro_call) = root_macro_call_first_node(cx, expr);
+            if cx.tcx.is_diagnostic_item(sym::format_macro, macro_call.def_id);
+            if let Some(format_args) = FormatArgsExpn::find_nested(cx, expr, macro_call.expn);
+            then {
+                (format_args, macro_call.span)
+            } else {
+                return
+            }
         };
 
         let mut applicability = Applicability::MachineApplicable;
         if format_args.value_args.is_empty() {
-            if format_args.format_string_parts.is_empty() {
-                span_useless_format_empty(cx, call_site, "String::new()".to_owned(), applicability);
-            } else {
-                if_chain! {
-                    if let [e] = &*format_args.format_string_parts;
-                    if let ExprKind::Lit(lit) = &e.kind;
-                    if let Some(s_src) = snippet_opt(cx, lit.span);
-                    then {
+            match *format_args.format_string_parts {
+                [] => span_useless_format_empty(cx, call_site, "String::new()".to_owned(), applicability),
+                [_] => {
+                    if let Some(s_src) = snippet_opt(cx, format_args.format_string_span) {
                         // Simulate macro expansion, converting {{ and }} to { and }.
                         let s_expand = s_src.replace("{{", "{").replace("}}", "}");
                         let sugg = format!("{}.to_string()", s_expand);
                         span_useless_format(cx, call_site, sugg, applicability);
                     }
-                }
+                },
+                [..] => {},
             }
         } else if let [value] = *format_args.value_args {
             if_chain! {
-                if format_args.format_string_symbols == [kw::Empty];
+                if format_args.format_string_parts == [kw::Empty];
                 if match cx.typeck_results().expr_ty(value).peel_refs().kind() {
                     ty::Adt(adt, _) => cx.tcx.is_diagnostic_item(sym::String, adt.did),
                     ty::Str => true,
                     _ => false,
                 };
                 if let Some(args) = format_args.args();
-                if args.iter().all(|arg| arg.is_display() && !arg.has_string_formatting());
+                if args.iter().all(|arg| arg.format_trait == sym::Display && !arg.has_string_formatting());
                 then {
                     let is_new_string = match value.kind {
                         ExprKind::Binary(..) => true,
diff --git a/clippy_lints/src/format_args.rs b/clippy_lints/src/format_args.rs
index f0e1a67dcdd..ae423d799d7 100644
--- a/clippy_lints/src/format_args.rs
+++ b/clippy_lints/src/format_args.rs
@@ -1,5 +1,5 @@
 use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then};
-use clippy_utils::higher::{FormatArgsArg, FormatArgsExpn, FormatExpn};
+use clippy_utils::macros::{FormatArgsArg, FormatArgsExpn};
 use clippy_utils::source::snippet_opt;
 use clippy_utils::ty::implements_trait;
 use clippy_utils::{is_diag_trait_item, match_def_path, paths};
@@ -83,7 +83,7 @@ const FORMAT_MACRO_DIAG_ITEMS: &[Symbol] = &[sym::format_macro, sym::std_panic_m
 impl<'tcx> LateLintPass<'tcx> for FormatArgs {
     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) {
         if_chain! {
-            if let Some(format_args) = FormatArgsExpn::parse(expr);
+            if let Some(format_args) = FormatArgsExpn::parse(cx, expr);
             let expr_expn_data = expr.span.ctxt().outer_expn_data();
             let outermost_expn_data = outermost_expn_data(expr_expn_data);
             if let Some(macro_def_id) = outermost_expn_data.macro_def_id;
@@ -97,7 +97,7 @@ impl<'tcx> LateLintPass<'tcx> for FormatArgs {
             if let Some(args) = format_args.args();
             then {
                 for (i, arg) in args.iter().enumerate() {
-                    if !arg.is_display() {
+                    if arg.format_trait != sym::Display {
                         continue;
                     }
                     if arg.has_string_formatting() {
@@ -106,8 +106,8 @@ impl<'tcx> LateLintPass<'tcx> for FormatArgs {
                     if is_aliased(&args, i) {
                         continue;
                     }
-                    check_format_in_format_args(cx, outermost_expn_data.call_site, name, arg);
-                    check_to_string_in_format_args(cx, name, arg);
+                    check_format_in_format_args(cx, outermost_expn_data.call_site, name, arg.value);
+                    check_to_string_in_format_args(cx, name, arg.value);
                 }
             }
         }
@@ -122,30 +122,31 @@ fn outermost_expn_data(expn_data: ExpnData) -> ExpnData {
     }
 }
 
-fn check_format_in_format_args(cx: &LateContext<'_>, call_site: Span, name: Symbol, arg: &FormatArgsArg<'_>) {
-    if_chain! {
-        if FormatExpn::parse(arg.value).is_some();
-        if !arg.value.span.ctxt().outer_expn_data().call_site.from_expansion();
-        then {
-            span_lint_and_then(
-                cx,
-                FORMAT_IN_FORMAT_ARGS,
-                call_site,
-                &format!("`format!` in `{}!` args", name),
-                |diag| {
-                    diag.help(&format!(
-                        "combine the `format!(..)` arguments with the outer `{}!(..)` call",
-                        name
-                    ));
-                    diag.help("or consider changing `format!` to `format_args!`");
-                },
-            );
-        }
+fn check_format_in_format_args(cx: &LateContext<'_>, call_site: Span, name: Symbol, arg: &Expr<'_>) {
+    let expn_data = arg.span.ctxt().outer_expn_data();
+    if expn_data.call_site.from_expansion() {
+        return;
+    }
+    let Some(mac_id) = expn_data.macro_def_id else { return };
+    if !cx.tcx.is_diagnostic_item(sym::format_macro, mac_id) {
+        return;
     }
+    span_lint_and_then(
+        cx,
+        FORMAT_IN_FORMAT_ARGS,
+        call_site,
+        &format!("`format!` in `{}!` args", name),
+        |diag| {
+            diag.help(&format!(
+                "combine the `format!(..)` arguments with the outer `{}!(..)` call",
+                name
+            ));
+            diag.help("or consider changing `format!` to `format_args!`");
+        },
+    );
 }
 
-fn check_to_string_in_format_args<'tcx>(cx: &LateContext<'tcx>, name: Symbol, arg: &FormatArgsArg<'tcx>) {
-    let value = arg.value;
+fn check_to_string_in_format_args(cx: &LateContext<'_>, name: Symbol, value: &Expr<'_>) {
     if_chain! {
         if !value.span.from_expansion();
         if let ExprKind::MethodCall(_, _, [receiver], _) = value.kind;
diff --git a/clippy_lints/src/from_over_into.rs b/clippy_lints/src/from_over_into.rs
index 866ff216f84..5ece2cc5ac4 100644
--- a/clippy_lints/src/from_over_into.rs
+++ b/clippy_lints/src/from_over_into.rs
@@ -53,7 +53,7 @@ impl FromOverInto {
 
 impl_lint_pass!(FromOverInto => [FROM_OVER_INTO]);
 
-impl LateLintPass<'_> for FromOverInto {
+impl<'tcx> LateLintPass<'tcx> for FromOverInto {
     fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::Item<'_>) {
         if !meets_msrv(self.msrv.as_ref(), &msrvs::RE_REBALANCING_COHERENCE) {
             return;
diff --git a/clippy_lints/src/from_str_radix_10.rs b/clippy_lints/src/from_str_radix_10.rs
index 73e800073b0..57b07513205 100644
--- a/clippy_lints/src/from_str_radix_10.rs
+++ b/clippy_lints/src/from_str_radix_10.rs
@@ -43,7 +43,7 @@ declare_clippy_lint! {
 
 declare_lint_pass!(FromStrRadix10 => [FROM_STR_RADIX_10]);
 
-impl LateLintPass<'tcx> for FromStrRadix10 {
+impl<'tcx> LateLintPass<'tcx> for FromStrRadix10 {
     fn check_expr(&mut self, cx: &LateContext<'tcx>, exp: &Expr<'tcx>) {
         if_chain! {
             if let ExprKind::Call(maybe_path, arguments) = &exp.kind;
diff --git a/clippy_lints/src/functions/must_use.rs b/clippy_lints/src/functions/must_use.rs
index 77d08081c07..f2b4aefaead 100644
--- a/clippy_lints/src/functions/must_use.rs
+++ b/clippy_lints/src/functions/must_use.rs
@@ -18,7 +18,7 @@ use clippy_utils::{match_def_path, must_use_attr, return_ty, trait_ref_of_method
 
 use super::{DOUBLE_MUST_USE, MUST_USE_CANDIDATE, MUST_USE_UNIT};
 
-pub(super) fn check_item(cx: &LateContext<'tcx>, item: &'tcx hir::Item<'_>) {
+pub(super) fn check_item<'tcx>(cx: &LateContext<'tcx>, item: &'tcx hir::Item<'_>) {
     let attrs = cx.tcx.hir().attrs(item.hir_id());
     let attr = must_use_attr(attrs);
     if let hir::ItemKind::Fn(ref sig, ref _generics, ref body_id) = item.kind {
@@ -40,7 +40,7 @@ pub(super) fn check_item(cx: &LateContext<'tcx>, item: &'tcx hir::Item<'_>) {
     }
 }
 
-pub(super) fn check_impl_item(cx: &LateContext<'tcx>, item: &'tcx hir::ImplItem<'_>) {
+pub(super) fn check_impl_item<'tcx>(cx: &LateContext<'tcx>, item: &'tcx hir::ImplItem<'_>) {
     if let hir::ImplItemKind::Fn(ref sig, ref body_id) = item.kind {
         let is_public = cx.access_levels.is_exported(item.def_id);
         let fn_header_span = item.span.with_hi(sig.decl.output.span().hi());
@@ -62,7 +62,7 @@ pub(super) fn check_impl_item(cx: &LateContext<'tcx>, item: &'tcx hir::ImplItem<
     }
 }
 
-pub(super) fn check_trait_item(cx: &LateContext<'tcx>, item: &'tcx hir::TraitItem<'_>) {
+pub(super) fn check_trait_item<'tcx>(cx: &LateContext<'tcx>, item: &'tcx hir::TraitItem<'_>) {
     if let hir::TraitItemKind::Fn(ref sig, ref eid) = item.kind {
         let is_public = cx.access_levels.is_exported(item.def_id);
         let fn_header_span = item.span.with_hi(sig.decl.output.span().hi());
diff --git a/clippy_lints/src/functions/not_unsafe_ptr_arg_deref.rs b/clippy_lints/src/functions/not_unsafe_ptr_arg_deref.rs
index f83789bb219..6d829a18b2e 100644
--- a/clippy_lints/src/functions/not_unsafe_ptr_arg_deref.rs
+++ b/clippy_lints/src/functions/not_unsafe_ptr_arg_deref.rs
@@ -9,7 +9,7 @@ use clippy_utils::{iter_input_pats, path_to_local};
 
 use super::NOT_UNSAFE_PTR_ARG_DEREF;
 
-pub(super) fn check_fn(
+pub(super) fn check_fn<'tcx>(
     cx: &LateContext<'tcx>,
     kind: intravisit::FnKind<'tcx>,
     decl: &'tcx hir::FnDecl<'tcx>,
@@ -25,14 +25,14 @@ pub(super) fn check_fn(
     check_raw_ptr(cx, unsafety, decl, body, cx.tcx.hir().local_def_id(hir_id));
 }
 
-pub(super) fn check_trait_item(cx: &LateContext<'tcx>, item: &'tcx hir::TraitItem<'_>) {
+pub(super) fn check_trait_item<'tcx>(cx: &LateContext<'tcx>, item: &'tcx hir::TraitItem<'_>) {
     if let hir::TraitItemKind::Fn(ref sig, hir::TraitFn::Provided(eid)) = item.kind {
         let body = cx.tcx.hir().body(eid);
         check_raw_ptr(cx, sig.header.unsafety, sig.decl, body, item.def_id);
     }
 }
 
-fn check_raw_ptr(
+fn check_raw_ptr<'tcx>(
     cx: &LateContext<'tcx>,
     unsafety: hir::Unsafety,
     decl: &'tcx hir::FnDecl<'tcx>,
diff --git a/clippy_lints/src/functions/result_unit_err.rs b/clippy_lints/src/functions/result_unit_err.rs
index 71f6f87ae60..73f08a04989 100644
--- a/clippy_lints/src/functions/result_unit_err.rs
+++ b/clippy_lints/src/functions/result_unit_err.rs
@@ -13,7 +13,7 @@ use clippy_utils::ty::is_type_diagnostic_item;
 
 use super::RESULT_UNIT_ERR;
 
-pub(super) fn check_item(cx: &LateContext<'tcx>, item: &'tcx hir::Item<'_>) {
+pub(super) fn check_item(cx: &LateContext<'_>, item: &hir::Item<'_>) {
     if let hir::ItemKind::Fn(ref sig, ref _generics, _) = item.kind {
         let is_public = cx.access_levels.is_exported(item.def_id);
         let fn_header_span = item.span.with_hi(sig.decl.output.span().hi());
@@ -23,7 +23,7 @@ pub(super) fn check_item(cx: &LateContext<'tcx>, item: &'tcx hir::Item<'_>) {
     }
 }
 
-pub(super) fn check_impl_item(cx: &LateContext<'tcx>, item: &'tcx hir::ImplItem<'_>) {
+pub(super) fn check_impl_item(cx: &LateContext<'_>, item: &hir::ImplItem<'_>) {
     if let hir::ImplItemKind::Fn(ref sig, _) = item.kind {
         let is_public = cx.access_levels.is_exported(item.def_id);
         let fn_header_span = item.span.with_hi(sig.decl.output.span().hi());
@@ -33,7 +33,7 @@ pub(super) fn check_impl_item(cx: &LateContext<'tcx>, item: &'tcx hir::ImplItem<
     }
 }
 
-pub(super) fn check_trait_item(cx: &LateContext<'tcx>, item: &'tcx hir::TraitItem<'_>) {
+pub(super) fn check_trait_item(cx: &LateContext<'_>, item: &hir::TraitItem<'_>) {
     if let hir::TraitItemKind::Fn(ref sig, _) = item.kind {
         let is_public = cx.access_levels.is_exported(item.def_id);
         let fn_header_span = item.span.with_hi(sig.decl.output.span().hi());
diff --git a/clippy_lints/src/functions/too_many_arguments.rs b/clippy_lints/src/functions/too_many_arguments.rs
index 63a14d8d4cd..3af960491ed 100644
--- a/clippy_lints/src/functions/too_many_arguments.rs
+++ b/clippy_lints/src/functions/too_many_arguments.rs
@@ -9,9 +9,9 @@ use clippy_utils::is_trait_impl_item;
 use super::TOO_MANY_ARGUMENTS;
 
 pub(super) fn check_fn(
-    cx: &LateContext<'tcx>,
-    kind: intravisit::FnKind<'tcx>,
-    decl: &'tcx hir::FnDecl<'_>,
+    cx: &LateContext<'_>,
+    kind: intravisit::FnKind<'_>,
+    decl: &hir::FnDecl<'_>,
     span: Span,
     hir_id: hir::HirId,
     too_many_arguments_threshold: u64,
@@ -39,11 +39,7 @@ pub(super) fn check_fn(
     }
 }
 
-pub(super) fn check_trait_item(
-    cx: &LateContext<'tcx>,
-    item: &'tcx hir::TraitItem<'_>,
-    too_many_arguments_threshold: u64,
-) {
+pub(super) fn check_trait_item(cx: &LateContext<'_>, item: &hir::TraitItem<'_>, too_many_arguments_threshold: u64) {
     if let hir::TraitItemKind::Fn(ref sig, _) = item.kind {
         // don't lint extern functions decls, it's not their fault
         if sig.header.abi == Abi::Rust {
diff --git a/clippy_lints/src/functions/too_many_lines.rs b/clippy_lints/src/functions/too_many_lines.rs
index 65efbbab41a..54bdea7ea25 100644
--- a/clippy_lints/src/functions/too_many_lines.rs
+++ b/clippy_lints/src/functions/too_many_lines.rs
@@ -11,9 +11,9 @@ use super::TOO_MANY_LINES;
 
 pub(super) fn check_fn(
     cx: &LateContext<'_>,
-    kind: FnKind<'tcx>,
+    kind: FnKind<'_>,
     span: Span,
-    body: &'tcx hir::Body<'_>,
+    body: &hir::Body<'_>,
     too_many_lines_threshold: u64,
 ) {
     // Closures must be contained in a parent body, which will be checked for `too_many_lines`.
diff --git a/clippy_lints/src/if_then_some_else_none.rs b/clippy_lints/src/if_then_some_else_none.rs
index 16e5c5ca603..9525c163ece 100644
--- a/clippy_lints/src/if_then_some_else_none.rs
+++ b/clippy_lints/src/if_then_some_else_none.rs
@@ -55,7 +55,7 @@ impl IfThenSomeElseNone {
 
 impl_lint_pass!(IfThenSomeElseNone => [IF_THEN_SOME_ELSE_NONE]);
 
-impl LateLintPass<'_> for IfThenSomeElseNone {
+impl<'tcx> LateLintPass<'tcx> for IfThenSomeElseNone {
     fn check_expr(&mut self, cx: &LateContext<'_>, expr: &'tcx Expr<'_>) {
         if !meets_msrv(self.msrv.as_ref(), &msrvs::BOOL_THEN) {
             return;
diff --git a/clippy_lints/src/implicit_return.rs b/clippy_lints/src/implicit_return.rs
index 07caeada80d..d650d6e9a85 100644
--- a/clippy_lints/src/implicit_return.rs
+++ b/clippy_lints/src/implicit_return.rs
@@ -94,8 +94,8 @@ fn get_call_site(span: Span, ctxt: SyntaxContext) -> Option<Span> {
 }
 
 fn lint_implicit_returns(
-    cx: &LateContext<'tcx>,
-    expr: &'tcx Expr<'_>,
+    cx: &LateContext<'_>,
+    expr: &Expr<'_>,
     // The context of the function body.
     ctxt: SyntaxContext,
     // Whether the expression is from a macro expansion.
diff --git a/clippy_lints/src/inconsistent_struct_constructor.rs b/clippy_lints/src/inconsistent_struct_constructor.rs
index 388bb3727f9..3d44a669d8f 100644
--- a/clippy_lints/src/inconsistent_struct_constructor.rs
+++ b/clippy_lints/src/inconsistent_struct_constructor.rs
@@ -63,7 +63,7 @@ declare_clippy_lint! {
 
 declare_lint_pass!(InconsistentStructConstructor => [INCONSISTENT_STRUCT_CONSTRUCTOR]);
 
-impl LateLintPass<'_> for InconsistentStructConstructor {
+impl<'tcx> LateLintPass<'tcx> for InconsistentStructConstructor {
     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>) {
         if_chain! {
             if !expr.span.from_expansion();
diff --git a/clippy_lints/src/index_refutable_slice.rs b/clippy_lints/src/index_refutable_slice.rs
index 69f1c90beec..073313e2bad 100644
--- a/clippy_lints/src/index_refutable_slice.rs
+++ b/clippy_lints/src/index_refutable_slice.rs
@@ -69,7 +69,7 @@ impl IndexRefutableSlice {
 
 impl_lint_pass!(IndexRefutableSlice => [INDEX_REFUTABLE_SLICE]);
 
-impl LateLintPass<'_> for IndexRefutableSlice {
+impl<'tcx> LateLintPass<'tcx> for IndexRefutableSlice {
     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>) {
         if_chain! {
             if !expr.span.from_expansion() || is_expn_of(expr.span, "if_chain").is_some();
diff --git a/clippy_lints/src/init_numbered_fields.rs b/clippy_lints/src/init_numbered_fields.rs
index 5fe6725b581..9284e002409 100644
--- a/clippy_lints/src/init_numbered_fields.rs
+++ b/clippy_lints/src/init_numbered_fields.rs
@@ -1,5 +1,4 @@
 use clippy_utils::diagnostics::span_lint_and_sugg;
-use clippy_utils::in_macro;
 use clippy_utils::source::snippet_with_applicability;
 use rustc_errors::Applicability;
 use rustc_hir::{Expr, ExprKind};
@@ -46,7 +45,7 @@ impl<'tcx> LateLintPass<'tcx> for NumberedFields {
     fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) {
         if let ExprKind::Struct(path, fields, None) = e.kind {
             if !fields.is_empty()
-                && !in_macro(e.span)
+                && !e.span.from_expansion()
                 && fields
                     .iter()
                     .all(|f| f.ident.as_str().as_bytes().iter().all(u8::is_ascii_digit))
diff --git a/clippy_lints/src/iter_not_returning_iterator.rs b/clippy_lints/src/iter_not_returning_iterator.rs
index 0af6b3b7d46..d3bdc819a9f 100644
--- a/clippy_lints/src/iter_not_returning_iterator.rs
+++ b/clippy_lints/src/iter_not_returning_iterator.rs
@@ -1,8 +1,7 @@
-use clippy_utils::{diagnostics::span_lint, return_ty, ty::implements_trait};
-use rustc_hir::{ImplItem, ImplItemKind};
+use clippy_utils::{diagnostics::span_lint, get_parent_node, ty::implements_trait};
+use rustc_hir::{def_id::LocalDefId, FnSig, ImplItem, ImplItemKind, Item, ItemKind, Node, TraitItem, TraitItemKind};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_session::{declare_lint_pass, declare_tool_lint};
-use rustc_span::symbol::kw;
 use rustc_span::symbol::sym;
 
 declare_clippy_lint! {
@@ -40,26 +39,52 @@ declare_clippy_lint! {
 
 declare_lint_pass!(IterNotReturningIterator => [ITER_NOT_RETURNING_ITERATOR]);
 
-impl LateLintPass<'_> for IterNotReturningIterator {
-    fn check_impl_item(&mut self, cx: &LateContext<'tcx>, impl_item: &'tcx ImplItem<'tcx>) {
-        let name = impl_item.ident.name.as_str();
-        if_chain! {
-            if let ImplItemKind::Fn(fn_sig, _) = &impl_item.kind;
-            let ret_ty = return_ty(cx, impl_item.hir_id());
-            if matches!(name, "iter" | "iter_mut");
-            if let [param] = cx.tcx.fn_arg_names(impl_item.def_id);
-            if param.name == kw::SelfLower;
-            if let Some(iter_trait_id) = cx.tcx.get_diagnostic_item(sym::Iterator);
-            if !implements_trait(cx, ret_ty, iter_trait_id, &[]);
+impl<'tcx> LateLintPass<'tcx> for IterNotReturningIterator {
+    fn check_trait_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx TraitItem<'_>) {
+        let name = item.ident.name.as_str();
+        if matches!(name, "iter" | "iter_mut") {
+            if let TraitItemKind::Fn(fn_sig, _) = &item.kind {
+                check_sig(cx, name, fn_sig, item.def_id);
+            }
+        }
+    }
 
-            then {
-                span_lint(
-                    cx,
-                    ITER_NOT_RETURNING_ITERATOR,
-                    fn_sig.span,
-                    &format!("this method is named `{}` but its return type does not implement `Iterator`", name),
-                );
+    fn check_impl_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx ImplItem<'tcx>) {
+        let name = item.ident.name.as_str();
+        if matches!(name, "iter" | "iter_mut")
+            && !matches!(
+                get_parent_node(cx.tcx, item.hir_id()),
+                Some(Node::Item(Item { kind: ItemKind::Impl(i), .. })) if i.of_trait.is_some()
+            )
+        {
+            if let ImplItemKind::Fn(fn_sig, _) = &item.kind {
+                check_sig(cx, name, fn_sig, item.def_id);
             }
         }
     }
 }
+
+fn check_sig(cx: &LateContext<'_>, name: &str, sig: &FnSig<'_>, fn_id: LocalDefId) {
+    if sig.decl.implicit_self.has_implicit_self() {
+        let ret_ty = cx.tcx.fn_sig(fn_id).skip_binder().output();
+        let ret_ty = cx
+            .tcx
+            .try_normalize_erasing_regions(cx.param_env, ret_ty)
+            .unwrap_or(ret_ty);
+        if cx
+            .tcx
+            .get_diagnostic_item(sym::Iterator)
+            .map_or(false, |iter_id| !implements_trait(cx, ret_ty, iter_id, &[]))
+        {
+            span_lint(
+                cx,
+                ITER_NOT_RETURNING_ITERATOR,
+                sig.span,
+                &format!(
+                    "this method is named `{}` but its return type does not implement `Iterator`",
+                    name
+                ),
+            );
+        }
+    }
+}
diff --git a/clippy_lints/src/len_zero.rs b/clippy_lints/src/len_zero.rs
index 64f6d62fbdc..e1168c3f602 100644
--- a/clippy_lints/src/len_zero.rs
+++ b/clippy_lints/src/len_zero.rs
@@ -245,7 +245,7 @@ enum LenOutput<'tcx> {
     Option(DefId),
     Result(DefId, Ty<'tcx>),
 }
-fn parse_len_output(cx: &LateContext<'_>, sig: FnSig<'tcx>) -> Option<LenOutput<'tcx>> {
+fn parse_len_output<'tcx>(cx: &LateContext<'_>, sig: FnSig<'tcx>) -> Option<LenOutput<'tcx>> {
     match *sig.output().kind() {
         ty::Int(_) | ty::Uint(_) => Some(LenOutput::Integral),
         ty::Adt(adt, subs) if cx.tcx.is_diagnostic_item(sym::Option, adt.did) => {
diff --git a/clippy_lints/src/lib.register_all.rs b/clippy_lints/src/lib.register_all.rs
index 944411087e9..26fb4259952 100644
--- a/clippy_lints/src/lib.register_all.rs
+++ b/clippy_lints/src/lib.register_all.rs
@@ -37,6 +37,8 @@ store.register_group(true, "clippy::all", Some("clippy_all"), vec![
     LintId::of(derivable_impls::DERIVABLE_IMPLS),
     LintId::of(derive::DERIVE_HASH_XOR_EQ),
     LintId::of(derive::DERIVE_ORD_XOR_PARTIAL_ORD),
+    LintId::of(disallowed_methods::DISALLOWED_METHODS),
+    LintId::of(disallowed_types::DISALLOWED_TYPES),
     LintId::of(doc::MISSING_SAFETY_DOC),
     LintId::of(doc::NEEDLESS_DOCTEST_MAIN),
     LintId::of(double_comparison::DOUBLE_COMPARISONS),
@@ -113,6 +115,7 @@ store.register_group(true, "clippy::all", Some("clippy_all"), vec![
     LintId::of(loops::WHILE_LET_ON_ITERATOR),
     LintId::of(main_recursion::MAIN_RECURSION),
     LintId::of(manual_async_fn::MANUAL_ASYNC_FN),
+    LintId::of(manual_bits::MANUAL_BITS),
     LintId::of(manual_map::MANUAL_MAP),
     LintId::of(manual_non_exhaustive::MANUAL_NON_EXHAUSTIVE),
     LintId::of(manual_strip::MANUAL_STRIP),
@@ -204,7 +207,6 @@ store.register_group(true, "clippy::all", Some("clippy_all"), vec![
     LintId::of(mut_key::MUTABLE_KEY_TYPE),
     LintId::of(mut_mutex_lock::MUT_MUTEX_LOCK),
     LintId::of(mut_reference::UNNECESSARY_MUT_PASSED),
-    LintId::of(mutex_atomic::MUTEX_ATOMIC),
     LintId::of(needless_arbitrary_self_type::NEEDLESS_ARBITRARY_SELF_TYPE),
     LintId::of(needless_bool::BOOL_COMPARISON),
     LintId::of(needless_bool::NEEDLESS_BOOL),
diff --git a/clippy_lints/src/lib.register_lints.rs b/clippy_lints/src/lib.register_lints.rs
index 002122793f3..746bdb19c3d 100644
--- a/clippy_lints/src/lib.register_lints.rs
+++ b/clippy_lints/src/lib.register_lints.rs
@@ -3,33 +3,33 @@
 // Manual edits will be overwritten.
 
 store.register_lints(&[
-    #[cfg(feature = "internal-lints")]
+    #[cfg(feature = "internal")]
     utils::internal_lints::CLIPPY_LINTS_INTERNAL,
-    #[cfg(feature = "internal-lints")]
+    #[cfg(feature = "internal")]
     utils::internal_lints::COLLAPSIBLE_SPAN_LINT_CALLS,
-    #[cfg(feature = "internal-lints")]
+    #[cfg(feature = "internal")]
     utils::internal_lints::COMPILER_LINT_FUNCTIONS,
-    #[cfg(feature = "internal-lints")]
+    #[cfg(feature = "internal")]
     utils::internal_lints::DEFAULT_LINT,
-    #[cfg(feature = "internal-lints")]
+    #[cfg(feature = "internal")]
     utils::internal_lints::IF_CHAIN_STYLE,
-    #[cfg(feature = "internal-lints")]
+    #[cfg(feature = "internal")]
     utils::internal_lints::INTERNING_DEFINED_SYMBOL,
-    #[cfg(feature = "internal-lints")]
+    #[cfg(feature = "internal")]
     utils::internal_lints::INVALID_CLIPPY_VERSION_ATTRIBUTE,
-    #[cfg(feature = "internal-lints")]
+    #[cfg(feature = "internal")]
     utils::internal_lints::INVALID_PATHS,
-    #[cfg(feature = "internal-lints")]
+    #[cfg(feature = "internal")]
     utils::internal_lints::LINT_WITHOUT_LINT_PASS,
-    #[cfg(feature = "internal-lints")]
+    #[cfg(feature = "internal")]
     utils::internal_lints::MATCH_TYPE_ON_DIAGNOSTIC_ITEM,
-    #[cfg(feature = "internal-lints")]
+    #[cfg(feature = "internal")]
     utils::internal_lints::MISSING_CLIPPY_VERSION_ATTRIBUTE,
-    #[cfg(feature = "internal-lints")]
+    #[cfg(feature = "internal")]
     utils::internal_lints::OUTER_EXPN_EXPN_DATA,
-    #[cfg(feature = "internal-lints")]
+    #[cfg(feature = "internal")]
     utils::internal_lints::PRODUCE_ICE,
-    #[cfg(feature = "internal-lints")]
+    #[cfg(feature = "internal")]
     utils::internal_lints::UNNECESSARY_SYMBOL_STR,
     absurd_extreme_comparisons::ABSURD_EXTREME_COMPARISONS,
     approx_const::APPROX_CONSTANT,
@@ -59,6 +59,7 @@ store.register_lints(&[
     bool_assert_comparison::BOOL_ASSERT_COMPARISON,
     booleans::LOGIC_BUG,
     booleans::NONMINIMAL_BOOL,
+    borrow_as_ptr::BORROW_AS_PTR,
     bytecount::NAIVE_BYTECOUNT,
     cargo_common_metadata::CARGO_COMMON_METADATA,
     case_sensitive_file_extension_comparisons::CASE_SENSITIVE_FILE_EXTENSION_COMPARISONS,
@@ -225,6 +226,7 @@ store.register_lints(&[
     main_recursion::MAIN_RECURSION,
     manual_assert::MANUAL_ASSERT,
     manual_async_fn::MANUAL_ASYNC_FN,
+    manual_bits::MANUAL_BITS,
     manual_map::MANUAL_MAP,
     manual_non_exhaustive::MANUAL_NON_EXHAUSTIVE,
     manual_ok_or::MANUAL_OK_OR,
@@ -435,6 +437,7 @@ store.register_lints(&[
     shadow::SHADOW_REUSE,
     shadow::SHADOW_SAME,
     shadow::SHADOW_UNRELATED,
+    single_char_lifetime_names::SINGLE_CHAR_LIFETIME_NAMES,
     single_component_path_imports::SINGLE_COMPONENT_PATH_IMPORTS,
     size_of_in_element_count::SIZE_OF_IN_ELEMENT_COUNT,
     slow_vector_initialization::SLOW_VECTOR_INITIALIZATION,
diff --git a/clippy_lints/src/lib.register_nursery.rs b/clippy_lints/src/lib.register_nursery.rs
index e3cf0670018..a7353790100 100644
--- a/clippy_lints/src/lib.register_nursery.rs
+++ b/clippy_lints/src/lib.register_nursery.rs
@@ -6,8 +6,6 @@ store.register_group(true, "clippy::nursery", Some("clippy_nursery"), vec![
     LintId::of(attrs::EMPTY_LINE_AFTER_OUTER_ATTR),
     LintId::of(cognitive_complexity::COGNITIVE_COMPLEXITY),
     LintId::of(copies::BRANCHES_SHARING_CODE),
-    LintId::of(disallowed_methods::DISALLOWED_METHODS),
-    LintId::of(disallowed_types::DISALLOWED_TYPES),
     LintId::of(equatable_if_let::EQUATABLE_IF_LET),
     LintId::of(fallible_impl_from::FALLIBLE_IMPL_FROM),
     LintId::of(floating_point_arithmetic::IMPRECISE_FLOPS),
@@ -17,6 +15,7 @@ store.register_group(true, "clippy::nursery", Some("clippy_nursery"), vec![
     LintId::of(let_if_seq::USELESS_LET_IF_SEQ),
     LintId::of(missing_const_for_fn::MISSING_CONST_FOR_FN),
     LintId::of(mutable_debug_assertion::DEBUG_ASSERT_WITH_MUT_CALL),
+    LintId::of(mutex_atomic::MUTEX_ATOMIC),
     LintId::of(mutex_atomic::MUTEX_INTEGER),
     LintId::of(non_send_fields_in_send_ty::NON_SEND_FIELDS_IN_SEND_TY),
     LintId::of(nonstandard_macro_braces::NONSTANDARD_MACRO_BRACES),
diff --git a/clippy_lints/src/lib.register_pedantic.rs b/clippy_lints/src/lib.register_pedantic.rs
index 70a4a624378..1744b7c8250 100644
--- a/clippy_lints/src/lib.register_pedantic.rs
+++ b/clippy_lints/src/lib.register_pedantic.rs
@@ -7,6 +7,7 @@ store.register_group(true, "clippy::pedantic", Some("clippy_pedantic"), vec![
     LintId::of(await_holding_invalid::AWAIT_HOLDING_LOCK),
     LintId::of(await_holding_invalid::AWAIT_HOLDING_REFCELL_REF),
     LintId::of(bit_mask::VERBOSE_BIT_MASK),
+    LintId::of(borrow_as_ptr::BORROW_AS_PTR),
     LintId::of(bytecount::NAIVE_BYTECOUNT),
     LintId::of(case_sensitive_file_extension_comparisons::CASE_SENSITIVE_FILE_EXTENSION_COMPARISONS),
     LintId::of(casts::CAST_LOSSLESS),
diff --git a/clippy_lints/src/lib.register_perf.rs b/clippy_lints/src/lib.register_perf.rs
index 2ea0b696f1f..f9ffd4cf829 100644
--- a/clippy_lints/src/lib.register_perf.rs
+++ b/clippy_lints/src/lib.register_perf.rs
@@ -19,7 +19,6 @@ store.register_group(true, "clippy::perf", Some("clippy_perf"), vec![
     LintId::of(methods::SINGLE_CHAR_PATTERN),
     LintId::of(methods::UNNECESSARY_TO_OWNED),
     LintId::of(misc::CMP_OWNED),
-    LintId::of(mutex_atomic::MUTEX_ATOMIC),
     LintId::of(redundant_clone::REDUNDANT_CLONE),
     LintId::of(slow_vector_initialization::SLOW_VECTOR_INITIALIZATION),
     LintId::of(stable_sort_primitive::STABLE_SORT_PRIMITIVE),
diff --git a/clippy_lints/src/lib.register_restriction.rs b/clippy_lints/src/lib.register_restriction.rs
index eab389a9bd8..e7e2798da7d 100644
--- a/clippy_lints/src/lib.register_restriction.rs
+++ b/clippy_lints/src/lib.register_restriction.rs
@@ -54,6 +54,7 @@ store.register_group(true, "clippy::restriction", Some("clippy_restriction"), ve
     LintId::of(shadow::SHADOW_REUSE),
     LintId::of(shadow::SHADOW_SAME),
     LintId::of(shadow::SHADOW_UNRELATED),
+    LintId::of(single_char_lifetime_names::SINGLE_CHAR_LIFETIME_NAMES),
     LintId::of(strings::STRING_ADD),
     LintId::of(strings::STRING_SLICE),
     LintId::of(strings::STRING_TO_STRING),
diff --git a/clippy_lints/src/lib.register_style.rs b/clippy_lints/src/lib.register_style.rs
index 1a0b869d40a..05211476ff2 100644
--- a/clippy_lints/src/lib.register_style.rs
+++ b/clippy_lints/src/lib.register_style.rs
@@ -16,6 +16,8 @@ store.register_group(true, "clippy::style", Some("clippy_style"), vec![
     LintId::of(comparison_chain::COMPARISON_CHAIN),
     LintId::of(default::FIELD_REASSIGN_WITH_DEFAULT),
     LintId::of(dereference::NEEDLESS_BORROW),
+    LintId::of(disallowed_methods::DISALLOWED_METHODS),
+    LintId::of(disallowed_types::DISALLOWED_TYPES),
     LintId::of(doc::MISSING_SAFETY_DOC),
     LintId::of(doc::NEEDLESS_DOCTEST_MAIN),
     LintId::of(enum_variants::ENUM_VARIANT_NAMES),
@@ -41,6 +43,7 @@ store.register_group(true, "clippy::style", Some("clippy_style"), vec![
     LintId::of(loops::WHILE_LET_ON_ITERATOR),
     LintId::of(main_recursion::MAIN_RECURSION),
     LintId::of(manual_async_fn::MANUAL_ASYNC_FN),
+    LintId::of(manual_bits::MANUAL_BITS),
     LintId::of(manual_map::MANUAL_MAP),
     LintId::of(manual_non_exhaustive::MANUAL_NON_EXHAUSTIVE),
     LintId::of(map_clone::MAP_CLONE),
diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs
index d4687a1e287..79e9882fef4 100644
--- a/clippy_lints/src/lib.rs
+++ b/clippy_lints/src/lib.rs
@@ -4,7 +4,6 @@
 #![feature(box_patterns)]
 #![feature(control_flow_enum)]
 #![feature(drain_filter)]
-#![feature(in_band_lifetimes)]
 #![feature(iter_intersperse)]
 #![feature(let_else)]
 #![feature(once_cell)]
@@ -153,12 +152,9 @@ macro_rules! declare_clippy_lint {
     };
 }
 
-#[cfg(feature = "metadata-collector-lint")]
+#[cfg(feature = "internal")]
 mod deprecated_lints;
-#[cfg_attr(
-    any(feature = "internal-lints", feature = "metadata-collector-lint"),
-    allow(clippy::missing_clippy_version_attribute)
-)]
+#[cfg_attr(feature = "internal", allow(clippy::missing_clippy_version_attribute))]
 mod utils;
 
 // begin lints modules, do not remove this comment, it’s used in `update_lints`
@@ -177,6 +173,7 @@ mod blacklisted_name;
 mod blocks_in_if_conditions;
 mod bool_assert_comparison;
 mod booleans;
+mod borrow_as_ptr;
 mod bytecount;
 mod cargo_common_metadata;
 mod case_sensitive_file_extension_comparisons;
@@ -264,6 +261,7 @@ mod macro_use;
 mod main_recursion;
 mod manual_assert;
 mod manual_async_fn;
+mod manual_bits;
 mod manual_map;
 mod manual_non_exhaustive;
 mod manual_ok_or;
@@ -351,6 +349,7 @@ mod self_named_constructors;
 mod semicolon_if_nothing_returned;
 mod serde_api;
 mod shadow;
+mod single_char_lifetime_names;
 mod single_component_path_imports;
 mod size_of_in_element_count;
 mod slow_vector_initialization;
@@ -471,7 +470,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
     include!("lib.register_restriction.rs");
     include!("lib.register_pedantic.rs");
 
-    #[cfg(feature = "internal-lints")]
+    #[cfg(feature = "internal")]
     include!("lib.register_internal.rs");
 
     include!("lib.register_all.rs");
@@ -483,7 +482,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
     include!("lib.register_cargo.rs");
     include!("lib.register_nursery.rs");
 
-    #[cfg(feature = "metadata-collector-lint")]
+    #[cfg(feature = "internal")]
     {
         if std::env::var("ENABLE_METADATA_COLLECTION").eq(&Ok("1".to_string())) {
             store.register_late_pass(|| Box::new(utils::internal_lints::metadata_collector::MetadataCollector::new()));
@@ -492,7 +491,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
     }
 
     // all the internal lints
-    #[cfg(feature = "internal-lints")]
+    #[cfg(feature = "internal")]
     {
         store.register_early_pass(|| Box::new(utils::internal_lints::ClippyLintsInternal));
         store.register_early_pass(|| Box::new(utils::internal_lints::ProduceIce));
@@ -858,6 +857,9 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
     store.register_late_pass(|| Box::new(needless_late_init::NeedlessLateInit));
     store.register_late_pass(|| Box::new(return_self_not_must_use::ReturnSelfNotMustUse));
     store.register_late_pass(|| Box::new(init_numbered_fields::NumberedFields));
+    store.register_early_pass(|| Box::new(single_char_lifetime_names::SingleCharLifetimeNames));
+    store.register_late_pass(move || Box::new(borrow_as_ptr::BorrowAsPtr::new(msrv)));
+    store.register_late_pass(move || Box::new(manual_bits::ManualBits::new(msrv)));
     // add lints here, do not remove this comment, it's used in `new_lint`
 }
 
diff --git a/clippy_lints/src/loops/empty_loop.rs b/clippy_lints/src/loops/empty_loop.rs
index dda09fecdf9..823cf0f4322 100644
--- a/clippy_lints/src/loops/empty_loop.rs
+++ b/clippy_lints/src/loops/empty_loop.rs
@@ -5,7 +5,7 @@ use clippy_utils::{is_in_panic_handler, is_no_std_crate};
 use rustc_hir::{Block, Expr};
 use rustc_lint::LateContext;
 
-pub(super) fn check(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, loop_block: &'tcx Block<'_>) {
+pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, loop_block: &Block<'_>) {
     if loop_block.stmts.is_empty() && loop_block.expr.is_none() && !is_in_panic_handler(cx, expr) {
         let msg = "empty `loop {}` wastes CPU cycles";
         let help = if is_no_std_crate(cx) {
diff --git a/clippy_lints/src/loops/explicit_into_iter_loop.rs b/clippy_lints/src/loops/explicit_into_iter_loop.rs
index 1bab0d99b69..17246cc5426 100644
--- a/clippy_lints/src/loops/explicit_into_iter_loop.rs
+++ b/clippy_lints/src/loops/explicit_into_iter_loop.rs
@@ -8,7 +8,7 @@ use rustc_lint::LateContext;
 use rustc_middle::ty::TyS;
 use rustc_span::symbol::sym;
 
-pub(super) fn check(cx: &LateContext<'_>, self_arg: &'hir Expr<'hir>, call_expr: &Expr<'_>) {
+pub(super) fn check(cx: &LateContext<'_>, self_arg: &Expr<'_>, call_expr: &Expr<'_>) {
     let self_ty = cx.typeck_results().expr_ty(self_arg);
     let self_ty_adjusted = cx.typeck_results().expr_ty_adjusted(self_arg);
     if !(TyS::same_type(self_ty, self_ty_adjusted) && is_trait_method(cx, call_expr, sym::IntoIterator)) {
diff --git a/clippy_lints/src/loops/manual_memcpy.rs b/clippy_lints/src/loops/manual_memcpy.rs
index c62fa5e998b..48c4015e07b 100644
--- a/clippy_lints/src/loops/manual_memcpy.rs
+++ b/clippy_lints/src/loops/manual_memcpy.rs
@@ -2,7 +2,7 @@ use super::{IncrementVisitor, InitializeVisitor, MANUAL_MEMCPY};
 use clippy_utils::diagnostics::span_lint_and_sugg;
 use clippy_utils::source::snippet;
 use clippy_utils::sugg::Sugg;
-use clippy_utils::ty::is_type_diagnostic_item;
+use clippy_utils::ty::is_copy;
 use clippy_utils::{get_enclosing_block, higher, path_to_local, sugg};
 use if_chain::if_chain;
 use rustc_ast::ast;
@@ -62,15 +62,15 @@ pub(super) fn check<'tcx>(
                         if_chain! {
                             if let ExprKind::Index(base_left, idx_left) = lhs.kind;
                             if let ExprKind::Index(base_right, idx_right) = rhs.kind;
-                            if is_slice_like(cx, cx.typeck_results().expr_ty(base_left));
-                            if is_slice_like(cx, cx.typeck_results().expr_ty(base_right));
+                            if let Some(ty) = get_slice_like_element_ty(cx, cx.typeck_results().expr_ty(base_left));
+                            if get_slice_like_element_ty(cx, cx.typeck_results().expr_ty(base_right)).is_some();
                             if let Some((start_left, offset_left)) = get_details_from_idx(cx, idx_left, &starts);
                             if let Some((start_right, offset_right)) = get_details_from_idx(cx, idx_right, &starts);
 
                             // Source and destination must be different
                             if path_to_local(base_left) != path_to_local(base_right);
                             then {
-                                Some((IndexExpr { base: base_left, idx: start_left, idx_offset: offset_left },
+                                Some((ty, IndexExpr { base: base_left, idx: start_left, idx_offset: offset_left },
                                     IndexExpr { base: base_right, idx: start_right, idx_offset: offset_right }))
                             } else {
                                 None
@@ -78,7 +78,7 @@ pub(super) fn check<'tcx>(
                         }
                     })
                 })
-                .map(|o| o.map(|(dst, src)| build_manual_memcpy_suggestion(cx, start, end, limits, &dst, &src)))
+                .map(|o| o.map(|(ty, dst, src)| build_manual_memcpy_suggestion(cx, start, end, limits, ty, &dst, &src)))
                 .collect::<Option<Vec<_>>>()
                 .filter(|v| !v.is_empty())
                 .map(|v| v.join("\n    "));
@@ -105,6 +105,7 @@ fn build_manual_memcpy_suggestion<'tcx>(
     start: &Expr<'_>,
     end: &Expr<'_>,
     limits: ast::RangeLimits,
+    elem_ty: Ty<'tcx>,
     dst: &IndexExpr<'_>,
     src: &IndexExpr<'_>,
 ) -> String {
@@ -187,9 +188,16 @@ fn build_manual_memcpy_suggestion<'tcx>(
         .into()
     };
 
+    let method_str = if is_copy(cx, elem_ty) {
+        "copy_from_slice"
+    } else {
+        "clone_from_slice"
+    };
+
     format!(
-        "{}.clone_from_slice(&{}[{}..{}]);",
+        "{}.{}(&{}[{}..{}]);",
         dst,
+        method_str,
         src_base_str,
         src_offset.maybe_par(),
         src_limit.maybe_par()
@@ -203,7 +211,7 @@ fn build_manual_memcpy_suggestion<'tcx>(
 #[derive(Clone)]
 struct MinifyingSugg<'a>(Sugg<'a>);
 
-impl Display for MinifyingSugg<'a> {
+impl<'a> Display for MinifyingSugg<'a> {
     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
         self.0.fmt(f)
     }
@@ -324,14 +332,13 @@ struct Start<'hir> {
     kind: StartKind<'hir>,
 }
 
-fn is_slice_like<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'_>) -> bool {
-    let is_slice = match ty.kind() {
-        ty::Ref(_, subty, _) => is_slice_like(cx, subty),
-        ty::Slice(..) | ty::Array(..) => true,
-        _ => false,
-    };
-
-    is_slice || is_type_diagnostic_item(cx, ty, sym::Vec) || is_type_diagnostic_item(cx, ty, sym::VecDeque)
+fn get_slice_like_element_ty<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> Option<Ty<'tcx>> {
+    match ty.kind() {
+        ty::Adt(adt, subs) if cx.tcx.is_diagnostic_item(sym::Vec, adt.did) => Some(subs.type_at(0)),
+        ty::Ref(_, subty, _) => get_slice_like_element_ty(cx, subty),
+        ty::Slice(ty) | ty::Array(ty, _) => Some(ty),
+        _ => None,
+    }
 }
 
 fn fetch_cloned_expr<'tcx>(expr: &'tcx Expr<'tcx>) -> &'tcx Expr<'tcx> {
diff --git a/clippy_lints/src/loops/mut_range_bound.rs b/clippy_lints/src/loops/mut_range_bound.rs
index aedf0844937..37a57d8feb1 100644
--- a/clippy_lints/src/loops/mut_range_bound.rs
+++ b/clippy_lints/src/loops/mut_range_bound.rs
@@ -147,7 +147,7 @@ impl BreakAfterExprVisitor {
     }
 }
 
-impl intravisit::Visitor<'tcx> for BreakAfterExprVisitor {
+impl<'tcx> intravisit::Visitor<'tcx> for BreakAfterExprVisitor {
     type Map = Map<'tcx>;
 
     fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
diff --git a/clippy_lints/src/loops/needless_collect.rs b/clippy_lints/src/loops/needless_collect.rs
index ba895f35faa..6248680aa62 100644
--- a/clippy_lints/src/loops/needless_collect.rs
+++ b/clippy_lints/src/loops/needless_collect.rs
@@ -339,8 +339,8 @@ fn detect_iter_and_into_iters<'tcx: 'a, 'a>(
     }
 }
 
-fn get_captured_ids(cx: &LateContext<'tcx>, ty: &'_ TyS<'_>) -> HirIdSet {
-    fn get_captured_ids_recursive(cx: &LateContext<'tcx>, ty: &'_ TyS<'_>, set: &mut HirIdSet) {
+fn get_captured_ids(cx: &LateContext<'_>, ty: &'_ TyS<'_>) -> HirIdSet {
+    fn get_captured_ids_recursive(cx: &LateContext<'_>, ty: &'_ TyS<'_>, set: &mut HirIdSet) {
         match ty.kind() {
             ty::Adt(_, generics) => {
                 for generic in *generics {
diff --git a/clippy_lints/src/loops/never_loop.rs b/clippy_lints/src/loops/never_loop.rs
index a3aa6be6afd..bb1b3e2a1ec 100644
--- a/clippy_lints/src/loops/never_loop.rs
+++ b/clippy_lints/src/loops/never_loop.rs
@@ -10,8 +10,8 @@ use rustc_span::Span;
 use std::iter::{once, Iterator};
 
 pub(super) fn check(
-    cx: &LateContext<'tcx>,
-    block: &'tcx Block<'_>,
+    cx: &LateContext<'_>,
+    block: &Block<'_>,
     loop_id: HirId,
     span: Span,
     for_loop: Option<&ForLoop<'_>>,
diff --git a/clippy_lints/src/loops/while_let_loop.rs b/clippy_lints/src/loops/while_let_loop.rs
index 4dcd5c87722..8f57df0be6b 100644
--- a/clippy_lints/src/loops/while_let_loop.rs
+++ b/clippy_lints/src/loops/while_let_loop.rs
@@ -7,7 +7,7 @@ use rustc_hir::{Block, Expr, ExprKind, MatchSource, Pat, StmtKind};
 use rustc_lint::{LateContext, LintContext};
 use rustc_middle::lint::in_external_macro;
 
-pub(super) fn check(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, loop_block: &'tcx Block<'_>) {
+pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, loop_block: &'tcx Block<'_>) {
     // extract the expression from the first statement (if any) in a block
     let inner_stmt_expr = extract_expr_from_first_stmt(loop_block);
     // or extract the first expression (if any) from the block
diff --git a/clippy_lints/src/loops/while_let_on_iterator.rs b/clippy_lints/src/loops/while_let_on_iterator.rs
index b390476a664..750328d1d01 100644
--- a/clippy_lints/src/loops/while_let_on_iterator.rs
+++ b/clippy_lints/src/loops/while_let_on_iterator.rs
@@ -8,12 +8,13 @@ use clippy_utils::{
 use if_chain::if_chain;
 use rustc_errors::Applicability;
 use rustc_hir::intravisit::{walk_expr, ErasedMap, NestedVisitorMap, Visitor};
-use rustc_hir::{def::Res, Expr, ExprKind, HirId, Local, PatKind, QPath, UnOp};
+use rustc_hir::{def::Res, Expr, ExprKind, HirId, Local, Mutability, PatKind, QPath, UnOp};
 use rustc_lint::LateContext;
-use rustc_span::{symbol::sym, Span, Symbol};
+use rustc_middle::ty::adjustment::Adjust;
+use rustc_span::{symbol::sym, Symbol};
 
-pub(super) fn check(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
-    let (scrutinee_expr, iter_expr, some_pat, loop_expr) = if_chain! {
+pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
+    let (scrutinee_expr, iter_expr_struct, iter_expr, some_pat, loop_expr) = if_chain! {
         if let Some(higher::WhileLet { if_then, let_pat, let_expr }) = higher::WhileLet::hir(expr);
         // check for `Some(..)` pattern
         if let PatKind::TupleStruct(QPath::Resolved(None, pat_path), some_pat, _) = let_pat.kind;
@@ -27,7 +28,7 @@ pub(super) fn check(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
         // get the loop containing the match expression
         if !uses_iter(cx, &iter_expr_struct, if_then);
         then {
-            (let_expr, iter_expr_struct, some_pat, expr)
+            (let_expr, iter_expr_struct, iter_expr, some_pat, expr)
         } else {
             return;
         }
@@ -47,7 +48,11 @@ pub(super) fn check(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
     // If the iterator is a field or the iterator is accessed after the loop is complete it needs to be
     // borrowed mutably. TODO: If the struct can be partially moved from and the struct isn't used
     // afterwards a mutable borrow of a field isn't necessary.
-    let by_ref = if !iter_expr.fields.is_empty() || needs_mutable_borrow(cx, &iter_expr, loop_expr) {
+    let by_ref = if cx.typeck_results().expr_ty(iter_expr).ref_mutability() == Some(Mutability::Mut)
+        || !iter_expr_struct.can_move
+        || !iter_expr_struct.fields.is_empty()
+        || needs_mutable_borrow(cx, &iter_expr_struct, loop_expr)
+    {
         ".by_ref()"
     } else {
         ""
@@ -67,26 +72,36 @@ pub(super) fn check(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
 
 #[derive(Debug)]
 struct IterExpr {
-    /// The span of the whole expression, not just the path and fields stored here.
-    span: Span,
     /// The fields used, in order of child to parent.
     fields: Vec<Symbol>,
     /// The path being used.
     path: Res,
+    /// Whether or not the iterator can be moved.
+    can_move: bool,
 }
 
 /// Parses any expression to find out which field of which variable is used. Will return `None` if
 /// the expression might have side effects.
 fn try_parse_iter_expr(cx: &LateContext<'_>, mut e: &Expr<'_>) -> Option<IterExpr> {
-    let span = e.span;
     let mut fields = Vec::new();
+    let mut can_move = true;
     loop {
+        if cx
+            .typeck_results()
+            .expr_adjustments(e)
+            .iter()
+            .any(|a| matches!(a.kind, Adjust::Deref(Some(..))))
+        {
+            // Custom deref impls need to borrow the whole value as it's captured by reference
+            can_move = false;
+            fields.clear();
+        }
         match e.kind {
             ExprKind::Path(ref path) => {
                 break Some(IterExpr {
-                    span,
                     fields,
                     path: cx.qpath_res(path, e.hir_id),
+                    can_move,
                 });
             },
             ExprKind::Field(base, name) => {
@@ -99,10 +114,12 @@ fn try_parse_iter_expr(cx: &LateContext<'_>, mut e: &Expr<'_>) -> Option<IterExp
             // Shouldn't have side effects, but there's no way to trace which field is used. So forget which fields have
             // already been seen.
             ExprKind::Index(base, idx) if !idx.can_have_side_effects() => {
+                can_move = false;
                 fields.clear();
                 e = base;
             },
             ExprKind::Unary(UnOp::Deref, base) => {
+                can_move = false;
                 fields.clear();
                 e = base;
             },
@@ -174,7 +191,7 @@ fn is_expr_same_child_or_parent_field(cx: &LateContext<'_>, expr: &Expr<'_>, fie
 
 /// Strips off all field and path expressions. This will return true if a field or path has been
 /// skipped. Used to skip them after failing to check for equality.
-fn skip_fields_and_path(expr: &'tcx Expr<'_>) -> (Option<&'tcx Expr<'tcx>>, bool) {
+fn skip_fields_and_path<'tcx>(expr: &'tcx Expr<'_>) -> (Option<&'tcx Expr<'tcx>>, bool) {
     let mut e = expr;
     let e = loop {
         match e.kind {
@@ -187,13 +204,13 @@ fn skip_fields_and_path(expr: &'tcx Expr<'_>) -> (Option<&'tcx Expr<'tcx>>, bool
 }
 
 /// Checks if the given expression uses the iterator.
-fn uses_iter(cx: &LateContext<'tcx>, iter_expr: &IterExpr, container: &'tcx Expr<'_>) -> bool {
+fn uses_iter<'tcx>(cx: &LateContext<'tcx>, iter_expr: &IterExpr, container: &'tcx Expr<'_>) -> bool {
     struct V<'a, 'b, 'tcx> {
         cx: &'a LateContext<'tcx>,
         iter_expr: &'b IterExpr,
         uses_iter: bool,
     }
-    impl Visitor<'tcx> for V<'_, '_, 'tcx> {
+    impl<'tcx> Visitor<'tcx> for V<'_, '_, 'tcx> {
         type Map = ErasedMap<'tcx>;
         fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
             NestedVisitorMap::None
@@ -228,7 +245,7 @@ fn uses_iter(cx: &LateContext<'tcx>, iter_expr: &IterExpr, container: &'tcx Expr
 }
 
 #[allow(clippy::too_many_lines)]
-fn needs_mutable_borrow(cx: &LateContext<'tcx>, iter_expr: &IterExpr, loop_expr: &'tcx Expr<'_>) -> bool {
+fn needs_mutable_borrow(cx: &LateContext<'_>, iter_expr: &IterExpr, loop_expr: &Expr<'_>) -> bool {
     struct AfterLoopVisitor<'a, 'b, 'tcx> {
         cx: &'a LateContext<'tcx>,
         iter_expr: &'b IterExpr,
@@ -236,7 +253,7 @@ fn needs_mutable_borrow(cx: &LateContext<'tcx>, iter_expr: &IterExpr, loop_expr:
         after_loop: bool,
         used_iter: bool,
     }
-    impl Visitor<'tcx> for AfterLoopVisitor<'_, '_, 'tcx> {
+    impl<'tcx> Visitor<'tcx> for AfterLoopVisitor<'_, '_, 'tcx> {
         type Map = ErasedMap<'tcx>;
         fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
             NestedVisitorMap::None
@@ -275,7 +292,7 @@ fn needs_mutable_borrow(cx: &LateContext<'tcx>, iter_expr: &IterExpr, loop_expr:
         found_local: bool,
         used_after: bool,
     }
-    impl Visitor<'tcx> for NestedLoopVisitor<'a, 'b, 'tcx> {
+    impl<'a, 'b, 'tcx> Visitor<'tcx> for NestedLoopVisitor<'a, 'b, 'tcx> {
         type Map = ErasedMap<'tcx>;
 
         fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
diff --git a/clippy_lints/src/macro_use.rs b/clippy_lints/src/macro_use.rs
index 41f5a913b31..ca1ccb93bf3 100644
--- a/clippy_lints/src/macro_use.rs
+++ b/clippy_lints/src/macro_use.rs
@@ -1,5 +1,4 @@
 use clippy_utils::diagnostics::span_lint_and_sugg;
-use clippy_utils::in_macro;
 use clippy_utils::source::snippet;
 use hir::def::{DefKind, Res};
 use if_chain::if_chain;
@@ -104,34 +103,34 @@ impl<'tcx> LateLintPass<'tcx> for MacroUseImports {
                     }
                 }
             } else {
-                if in_macro(item.span) {
+                if item.span.from_expansion() {
                     self.push_unique_macro_pat_ty(cx, item.span);
                 }
             }
         }
     }
     fn check_attribute(&mut self, cx: &LateContext<'_>, attr: &ast::Attribute) {
-        if in_macro(attr.span) {
+        if attr.span.from_expansion() {
             self.push_unique_macro(cx, attr.span);
         }
     }
     fn check_expr(&mut self, cx: &LateContext<'_>, expr: &hir::Expr<'_>) {
-        if in_macro(expr.span) {
+        if expr.span.from_expansion() {
             self.push_unique_macro(cx, expr.span);
         }
     }
     fn check_stmt(&mut self, cx: &LateContext<'_>, stmt: &hir::Stmt<'_>) {
-        if in_macro(stmt.span) {
+        if stmt.span.from_expansion() {
             self.push_unique_macro(cx, stmt.span);
         }
     }
     fn check_pat(&mut self, cx: &LateContext<'_>, pat: &hir::Pat<'_>) {
-        if in_macro(pat.span) {
+        if pat.span.from_expansion() {
             self.push_unique_macro_pat_ty(cx, pat.span);
         }
     }
     fn check_ty(&mut self, cx: &LateContext<'_>, ty: &hir::Ty<'_>) {
-        if in_macro(ty.span) {
+        if ty.span.from_expansion() {
             self.push_unique_macro_pat_ty(cx, ty.span);
         }
     }
diff --git a/clippy_lints/src/manual_assert.rs b/clippy_lints/src/manual_assert.rs
index 5a2a965716c..26b53ab5d68 100644
--- a/clippy_lints/src/manual_assert.rs
+++ b/clippy_lints/src/manual_assert.rs
@@ -1,11 +1,12 @@
 use clippy_utils::diagnostics::span_lint_and_sugg;
-use clippy_utils::higher::PanicExpn;
+use clippy_utils::macros::{root_macro_call, FormatArgsExpn};
 use clippy_utils::source::snippet_with_applicability;
-use clippy_utils::{is_expn_of, sugg};
+use clippy_utils::{peel_blocks_with_stmt, sugg};
 use rustc_errors::Applicability;
-use rustc_hir::{Block, Expr, ExprKind, StmtKind, UnOp};
+use rustc_hir::{Expr, ExprKind, UnOp};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_span::sym;
 
 declare_clippy_lint! {
     /// ### What it does
@@ -34,65 +35,34 @@ declare_clippy_lint! {
 
 declare_lint_pass!(ManualAssert => [MANUAL_ASSERT]);
 
-impl LateLintPass<'_> for ManualAssert {
-    fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) {
+impl<'tcx> LateLintPass<'tcx> for ManualAssert {
+    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &Expr<'tcx>) {
         if_chain! {
-            if let Expr {
-                kind: ExprKind:: If(cond, Expr {
-                    kind: ExprKind::Block(
-                        Block {
-                            stmts: [stmt],
-                            ..
-                        },
-                        _),
-                    ..
-                }, None),
-                ..
-            } = &expr;
-            if is_expn_of(stmt.span, "panic").is_some();
+            if let ExprKind::If(cond, then, None) = expr.kind;
             if !matches!(cond.kind, ExprKind::Let(_));
-            if let StmtKind::Semi(semi) = stmt.kind;
+            if !expr.span.from_expansion();
+            let then = peel_blocks_with_stmt(then);
+            if let Some(macro_call) = root_macro_call(then.span);
+            if cx.tcx.item_name(macro_call.def_id) == sym::panic;
             if !cx.tcx.sess.source_map().is_multiline(cond.span);
-
+            if let Some(format_args) = FormatArgsExpn::find_nested(cx, then, macro_call.expn);
             then {
-                let call = if_chain! {
-                    if let ExprKind::Block(block, _) = semi.kind;
-                    if let Some(init) = block.expr;
-                    then {
-                        init
-                    } else {
-                        semi
-                    }
-                };
-                let span = if let Some(panic_expn) = PanicExpn::parse(call) {
-                    match *panic_expn.format_args.value_args {
-                        [] => panic_expn.format_args.format_string_span,
-                        [.., last] => panic_expn.format_args.format_string_span.to(last.span),
-                    }
-                } else if let ExprKind::Call(_, [format_args]) = call.kind {
-                    format_args.span
-                } else {
-                    return
-                };
                 let mut applicability = Applicability::MachineApplicable;
-                let sugg = snippet_with_applicability(cx, span, "..", &mut applicability);
-                let cond_sugg = if let ExprKind::DropTemps(e, ..) = cond.kind {
-                    if let Expr{kind: ExprKind::Unary(UnOp::Not, not_expr), ..} = e {
-                         sugg::Sugg::hir_with_applicability(cx, not_expr, "..", &mut applicability).maybe_par().to_string()
-                    } else {
-                       format!("!{}", sugg::Sugg::hir_with_applicability(cx, e, "..", &mut applicability).maybe_par())
-                    }
-                } else {
-                   format!("!{}", sugg::Sugg::hir_with_applicability(cx, cond, "..", &mut applicability).maybe_par())
+                let format_args_snip = snippet_with_applicability(cx, format_args.inputs_span(), "..", &mut applicability);
+                let cond = cond.peel_drop_temps();
+                let (cond, not) = match cond.kind {
+                    ExprKind::Unary(UnOp::Not, e) => (e, ""),
+                    _ => (cond, "!"),
                 };
-
+                let cond_sugg = sugg::Sugg::hir_with_applicability(cx, cond, "..", &mut applicability).maybe_par();
+                let sugg = format!("assert!({not}{cond_sugg}, {format_args_snip});");
                 span_lint_and_sugg(
                     cx,
                     MANUAL_ASSERT,
                     expr.span,
                     "only a `panic!` in `if`-then statement",
                     "try",
-                    format!("assert!({}, {});", cond_sugg, sugg),
+                    sugg,
                     Applicability::MachineApplicable,
                 );
             }
diff --git a/clippy_lints/src/manual_bits.rs b/clippy_lints/src/manual_bits.rs
new file mode 100644
index 00000000000..50bf2527e39
--- /dev/null
+++ b/clippy_lints/src/manual_bits.rs
@@ -0,0 +1,107 @@
+use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::source::snippet_opt;
+use clippy_utils::{match_def_path, meets_msrv, msrvs, paths};
+use rustc_ast::ast::LitKind;
+use rustc_errors::Applicability;
+use rustc_hir::{BinOpKind, Expr, ExprKind, GenericArg, QPath};
+use rustc_lint::{LateContext, LateLintPass};
+use rustc_middle::ty::{self, Ty};
+use rustc_semver::RustcVersion;
+use rustc_session::{declare_tool_lint, impl_lint_pass};
+
+declare_clippy_lint! {
+    /// ### What it does
+    /// Checks for uses of `std::mem::size_of::<T>() * 8` when
+    /// `T::BITS` is available.
+    ///
+    /// ### Why is this bad?
+    /// Can be written as the shorter `T::BITS`.
+    ///
+    /// ### Example
+    /// ```rust
+    /// std::mem::size_of::<usize>() * 8;
+    /// ```
+    /// Use instead:
+    /// ```rust
+    /// usize::BITS;
+    /// ```
+    #[clippy::version = "1.60.0"]
+    pub MANUAL_BITS,
+    style,
+    "manual implementation of `size_of::<T>() * 8` can be simplified with `T::BITS`"
+}
+
+#[derive(Clone)]
+pub struct ManualBits {
+    msrv: Option<RustcVersion>,
+}
+
+impl ManualBits {
+    #[must_use]
+    pub fn new(msrv: Option<RustcVersion>) -> Self {
+        Self { msrv }
+    }
+}
+
+impl_lint_pass!(ManualBits => [MANUAL_BITS]);
+
+impl<'tcx> LateLintPass<'tcx> for ManualBits {
+    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
+        if !meets_msrv(self.msrv.as_ref(), &msrvs::MANUAL_BITS) {
+            return;
+        }
+
+        if_chain! {
+            if let ExprKind::Binary(bin_op, left_expr, right_expr) = expr.kind;
+            if let BinOpKind::Mul = &bin_op.node;
+            if let Some((real_ty, resolved_ty, other_expr)) = get_one_size_of_ty(cx, left_expr, right_expr);
+            if matches!(resolved_ty.kind(), ty::Int(_) | ty::Uint(_));
+            if let ExprKind::Lit(lit) = &other_expr.kind;
+            if let LitKind::Int(8, _) = lit.node;
+
+            then {
+                span_lint_and_sugg(
+                    cx,
+                    MANUAL_BITS,
+                    expr.span,
+                    "usage of `mem::size_of::<T>()` to obtain the size of `T` in bits",
+                    "consider using",
+                    format!("{}::BITS", snippet_opt(cx, real_ty.span).unwrap()),
+                    Applicability::MachineApplicable,
+                );
+            }
+        }
+    }
+}
+
+fn get_one_size_of_ty<'tcx>(
+    cx: &LateContext<'tcx>,
+    expr1: &'tcx Expr<'_>,
+    expr2: &'tcx Expr<'_>,
+) -> Option<(&'tcx rustc_hir::Ty<'tcx>, Ty<'tcx>, &'tcx Expr<'tcx>)> {
+    match (get_size_of_ty(cx, expr1), get_size_of_ty(cx, expr2)) {
+        (Some((real_ty, resolved_ty)), None) => Some((real_ty, resolved_ty, expr2)),
+        (None, Some((real_ty, resolved_ty))) => Some((real_ty, resolved_ty, expr1)),
+        _ => None,
+    }
+}
+
+fn get_size_of_ty<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> Option<(&'tcx rustc_hir::Ty<'tcx>, Ty<'tcx>)> {
+    if_chain! {
+        if let ExprKind::Call(count_func, _func_args) = expr.kind;
+        if let ExprKind::Path(ref count_func_qpath) = count_func.kind;
+
+        if let QPath::Resolved(_, count_func_path) = count_func_qpath;
+        if let Some(segment_zero) = count_func_path.segments.get(0);
+        if let Some(args) = segment_zero.args;
+        if let Some(GenericArg::Type(real_ty)) = args.args.get(0);
+
+        if let Some(def_id) = cx.qpath_res(count_func_qpath, count_func.hir_id).opt_def_id();
+        if match_def_path(cx, def_id, &paths::MEM_SIZE_OF);
+        then {
+            cx.typeck_results().node_substs(count_func.hir_id).types().next().map(|resolved_ty| (real_ty, resolved_ty))
+        } else {
+            None
+        }
+    }
+}
diff --git a/clippy_lints/src/manual_map.rs b/clippy_lints/src/manual_map.rs
index 34a70ca76c6..8475e367b09 100644
--- a/clippy_lints/src/manual_map.rs
+++ b/clippy_lints/src/manual_map.rs
@@ -45,7 +45,7 @@ declare_clippy_lint! {
 
 declare_lint_pass!(ManualMap => [MANUAL_MAP]);
 
-impl LateLintPass<'_> for ManualMap {
+impl<'tcx> LateLintPass<'tcx> for ManualMap {
     #[allow(clippy::too_many_lines)]
     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
         let (scrutinee, then_pat, then_body, else_pat, else_body) = match IfLetOrMatch::parse(cx, expr) {
@@ -219,7 +219,7 @@ impl LateLintPass<'_> for ManualMap {
 
 // Checks whether the expression could be passed as a function, or whether a closure is needed.
 // Returns the function to be passed to `map` if it exists.
-fn can_pass_as_func(cx: &LateContext<'tcx>, binding: HirId, expr: &'tcx Expr<'_>) -> Option<&'tcx Expr<'tcx>> {
+fn can_pass_as_func<'tcx>(cx: &LateContext<'tcx>, binding: HirId, expr: &'tcx Expr<'_>) -> Option<&'tcx Expr<'tcx>> {
     match expr.kind {
         ExprKind::Call(func, [arg])
             if path_to_local_id(arg, binding)
@@ -251,8 +251,13 @@ struct SomeExpr<'tcx> {
 
 // Try to parse into a recognized `Option` pattern.
 // i.e. `_`, `None`, `Some(..)`, or a reference to any of those.
-fn try_parse_pattern(cx: &LateContext<'tcx>, pat: &'tcx Pat<'_>, ctxt: SyntaxContext) -> Option<OptionPat<'tcx>> {
-    fn f(cx: &LateContext<'tcx>, pat: &'tcx Pat<'_>, ref_count: usize, ctxt: SyntaxContext) -> Option<OptionPat<'tcx>> {
+fn try_parse_pattern<'tcx>(cx: &LateContext<'tcx>, pat: &'tcx Pat<'_>, ctxt: SyntaxContext) -> Option<OptionPat<'tcx>> {
+    fn f<'tcx>(
+        cx: &LateContext<'tcx>,
+        pat: &'tcx Pat<'_>,
+        ref_count: usize,
+        ctxt: SyntaxContext,
+    ) -> Option<OptionPat<'tcx>> {
         match pat.kind {
             PatKind::Wild => Some(OptionPat::Wild),
             PatKind::Ref(pat, _) => f(cx, pat, ref_count + 1, ctxt),
@@ -269,7 +274,7 @@ fn try_parse_pattern(cx: &LateContext<'tcx>, pat: &'tcx Pat<'_>, ctxt: SyntaxCon
 }
 
 // Checks for an expression wrapped by the `Some` constructor. Returns the contained expression.
-fn get_some_expr(
+fn get_some_expr<'tcx>(
     cx: &LateContext<'tcx>,
     expr: &'tcx Expr<'_>,
     needs_unsafe_block: bool,
@@ -306,6 +311,6 @@ fn get_some_expr(
 }
 
 // Checks for the `None` value.
-fn is_none_expr(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> bool {
+fn is_none_expr(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
     matches!(peel_blocks(expr).kind, ExprKind::Path(ref qpath) if is_lang_ctor(cx, qpath, OptionNone))
 }
diff --git a/clippy_lints/src/manual_ok_or.rs b/clippy_lints/src/manual_ok_or.rs
index b60e2dc366b..bd083e3e9e2 100644
--- a/clippy_lints/src/manual_ok_or.rs
+++ b/clippy_lints/src/manual_ok_or.rs
@@ -40,7 +40,7 @@ declare_clippy_lint! {
 
 declare_lint_pass!(ManualOkOr => [MANUAL_OK_OR]);
 
-impl LateLintPass<'_> for ManualOkOr {
+impl<'tcx> LateLintPass<'tcx> for ManualOkOr {
     fn check_expr(&mut self, cx: &LateContext<'tcx>, scrutinee: &'tcx Expr<'tcx>) {
         if in_external_macro(cx.sess(), scrutinee.span) {
             return;
diff --git a/clippy_lints/src/manual_unwrap_or.rs b/clippy_lints/src/manual_unwrap_or.rs
index aac3c6e0de2..b3a91d9f18f 100644
--- a/clippy_lints/src/manual_unwrap_or.rs
+++ b/clippy_lints/src/manual_unwrap_or.rs
@@ -43,7 +43,7 @@ declare_clippy_lint! {
 
 declare_lint_pass!(ManualUnwrapOr => [MANUAL_UNWRAP_OR]);
 
-impl LateLintPass<'_> for ManualUnwrapOr {
+impl<'tcx> LateLintPass<'tcx> for ManualUnwrapOr {
     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) {
         if in_external_macro(cx.sess(), expr.span) || in_constant(cx, expr.hir_id) {
             return;
diff --git a/clippy_lints/src/match_str_case_mismatch.rs b/clippy_lints/src/match_str_case_mismatch.rs
index 2c0fc218ca0..1fc7eb72142 100644
--- a/clippy_lints/src/match_str_case_mismatch.rs
+++ b/clippy_lints/src/match_str_case_mismatch.rs
@@ -55,7 +55,7 @@ enum CaseMethod {
     AsciiUppercase,
 }
 
-impl LateLintPass<'_> for MatchStrCaseMismatch {
+impl<'tcx> LateLintPass<'tcx> for MatchStrCaseMismatch {
     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
         if_chain! {
             if !in_external_macro(cx.tcx.sess, expr.span);
diff --git a/clippy_lints/src/matches.rs b/clippy_lints/src/matches.rs
index 5fa8f249e70..60dd957db01 100644
--- a/clippy_lints/src/matches.rs
+++ b/clippy_lints/src/matches.rs
@@ -2,16 +2,17 @@ use clippy_utils::consts::{constant, constant_full_int, miri_to_const, FullInt};
 use clippy_utils::diagnostics::{
     multispan_sugg, span_lint_and_help, span_lint_and_note, span_lint_and_sugg, span_lint_and_then,
 };
-use clippy_utils::higher;
+use clippy_utils::macros::{is_panic, root_macro_call};
 use clippy_utils::source::{expr_block, indent_of, snippet, snippet_block, snippet_opt, snippet_with_applicability};
 use clippy_utils::sugg::Sugg;
 use clippy_utils::ty::{implements_trait, is_type_diagnostic_item, match_type, peel_mid_ty_refs};
 use clippy_utils::visitors::is_local_used;
 use clippy_utils::{
-    get_parent_expr, is_expn_of, is_lang_ctor, is_lint_allowed, is_refutable, is_unit_expr, is_wild, meets_msrv, msrvs,
+    get_parent_expr, is_lang_ctor, is_lint_allowed, is_refutable, is_unit_expr, is_wild, meets_msrv, msrvs,
     path_to_local, path_to_local_id, peel_blocks, peel_hir_pat_refs, peel_n_hir_expr_refs, recurse_or_patterns,
     strip_pat_refs,
 };
+use clippy_utils::{higher, peel_blocks_with_stmt};
 use clippy_utils::{paths, search_same, SpanlessEq, SpanlessHash};
 use core::iter::{once, ExactSizeIterator};
 use if_chain::if_chain;
@@ -974,7 +975,8 @@ fn check_wild_err_arm<'tcx>(cx: &LateContext<'tcx>, ex: &Expr<'tcx>, arms: &[Arm
                     }
                     if_chain! {
                         if matching_wild;
-                        if is_panic_call(arm.body);
+                        if let Some(macro_call) = root_macro_call(peel_blocks_with_stmt(arm.body).span);
+                        if is_panic(cx, macro_call.def_id);
                         then {
                             // `Err(_)` or `Err(_e)` arm with `panic!` found
                             span_lint_and_note(cx,
@@ -997,7 +999,7 @@ enum CommonPrefixSearcher<'a> {
     Path(&'a [PathSegment<'a>]),
     Mixed,
 }
-impl CommonPrefixSearcher<'a> {
+impl<'a> CommonPrefixSearcher<'a> {
     fn with_path(&mut self, path: &'a [PathSegment<'a>]) {
         match path {
             [path @ .., _] => self.with_prefix(path),
@@ -1179,22 +1181,6 @@ fn check_wild_enum_match(cx: &LateContext<'_>, ex: &Expr<'_>, arms: &[Arm<'_>])
     };
 }
 
-// If the block contains only a `panic!` macro (as expression or statement)
-fn is_panic_call(expr: &Expr<'_>) -> bool {
-    // Unwrap any wrapping blocks
-    let span = if let ExprKind::Block(block, _) = expr.kind {
-        match (&block.expr, block.stmts.len(), block.stmts.first()) {
-            (&Some(exp), 0, _) => exp.span,
-            (&None, 1, Some(stmt)) => stmt.span,
-            _ => return false,
-        }
-    } else {
-        expr.span
-    };
-
-    is_expn_of(span, "panic").is_some() && is_expn_of(span, "unreachable").is_none()
-}
-
 fn check_match_ref_pats<'a, 'b, I>(cx: &LateContext<'_>, ex: &Expr<'_>, pats: I, expr: &Expr<'_>)
 where
     'b: 'a,
@@ -1818,11 +1804,15 @@ mod redundant_pattern_match {
     /// Checks if the drop order for a type matters. Some std types implement drop solely to
     /// deallocate memory. For these types, and composites containing them, changing the drop order
     /// won't result in any observable side effects.
-    fn type_needs_ordered_drop(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool {
+    fn type_needs_ordered_drop<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool {
         type_needs_ordered_drop_inner(cx, ty, &mut FxHashSet::default())
     }
 
-    fn type_needs_ordered_drop_inner(cx: &LateContext<'tcx>, ty: Ty<'tcx>, seen: &mut FxHashSet<Ty<'tcx>>) -> bool {
+    fn type_needs_ordered_drop_inner<'tcx>(
+        cx: &LateContext<'tcx>,
+        ty: Ty<'tcx>,
+        seen: &mut FxHashSet<Ty<'tcx>>,
+    ) -> bool {
         if !seen.insert(ty) {
             return false;
         }
@@ -1884,7 +1874,7 @@ mod redundant_pattern_match {
 
     // Checks if there are any temporaries created in the given expression for which drop order
     // matters.
-    fn temporaries_need_ordered_drop(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) -> bool {
+    fn temporaries_need_ordered_drop<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) -> bool {
         struct V<'a, 'tcx> {
             cx: &'a LateContext<'tcx>,
             res: bool,
diff --git a/clippy_lints/src/methods/expect_fun_call.rs b/clippy_lints/src/methods/expect_fun_call.rs
index 0ec9387f9c4..0f39470f342 100644
--- a/clippy_lints/src/methods/expect_fun_call.rs
+++ b/clippy_lints/src/methods/expect_fun_call.rs
@@ -1,5 +1,5 @@
 use clippy_utils::diagnostics::span_lint_and_sugg;
-use clippy_utils::higher::FormatExpn;
+use clippy_utils::macros::{root_macro_call_first_node, FormatArgsExpn};
 use clippy_utils::source::snippet_with_applicability;
 use clippy_utils::ty::is_type_diagnostic_item;
 use rustc_errors::Applicability;
@@ -14,7 +14,13 @@ use super::EXPECT_FUN_CALL;
 
 /// Checks for the `EXPECT_FUN_CALL` lint.
 #[allow(clippy::too_many_lines)]
-pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, method_span: Span, name: &str, args: &[hir::Expr<'_>]) {
+pub(super) fn check<'tcx>(
+    cx: &LateContext<'tcx>,
+    expr: &hir::Expr<'_>,
+    method_span: Span,
+    name: &str,
+    args: &'tcx [hir::Expr<'tcx>],
+) {
     // Strip `&`, `as_ref()` and `as_str()` off `arg` until we're left with either a `String` or
     // `&str`
     fn get_arg_root<'a>(cx: &LateContext<'_>, arg: &'a hir::Expr<'a>) -> &'a hir::Expr<'a> {
@@ -128,11 +134,12 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, method_span: Spa
     let mut applicability = Applicability::MachineApplicable;
 
     //Special handling for `format!` as arg_root
-    if let Some(format_expn) = FormatExpn::parse(arg_root) {
-        let span = match *format_expn.format_args.value_args {
-            [] => format_expn.format_args.format_string_span,
-            [.., last] => format_expn.format_args.format_string_span.to(last.span),
-        };
+    if let Some(macro_call) = root_macro_call_first_node(cx, arg_root) {
+        if !cx.tcx.is_diagnostic_item(sym::format_macro, macro_call.def_id) {
+            return;
+        }
+        let Some(format_args) = FormatArgsExpn::find_nested(cx, arg_root, macro_call.expn) else { return };
+        let span = format_args.inputs_span();
         let sugg = snippet_with_applicability(cx, span, "..", &mut applicability);
         span_lint_and_sugg(
             cx,
diff --git a/clippy_lints/src/methods/from_iter_instead_of_collect.rs b/clippy_lints/src/methods/from_iter_instead_of_collect.rs
index 8ea9312c0f7..6436e28a63c 100644
--- a/clippy_lints/src/methods/from_iter_instead_of_collect.rs
+++ b/clippy_lints/src/methods/from_iter_instead_of_collect.rs
@@ -37,7 +37,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, args: &[hir::Exp
     }
 }
 
-fn extract_turbofish(cx: &LateContext<'_>, expr: &hir::Expr<'_>, ty: Ty<'tcx>) -> String {
+fn extract_turbofish(cx: &LateContext<'_>, expr: &hir::Expr<'_>, ty: Ty<'_>) -> String {
     fn strip_angle_brackets(s: &str) -> Option<&str> {
         s.strip_prefix('<')?.strip_suffix('>')
     }
diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs
index 4e33b2ff14c..1041f644e32 100644
--- a/clippy_lints/src/methods/mod.rs
+++ b/clippy_lints/src/methods/mod.rs
@@ -80,7 +80,6 @@ use rustc_middle::lint::in_external_macro;
 use rustc_middle::ty::{self, TraitRef, Ty, TyS};
 use rustc_semver::RustcVersion;
 use rustc_session::{declare_tool_lint, impl_lint_pass};
-use rustc_span::symbol::Symbol;
 use rustc_span::{sym, Span};
 use rustc_typeck::hir_ty_to_ty;
 
@@ -1895,6 +1894,11 @@ declare_clippy_lint! {
     /// ### Why is this bad?
     /// The unnecessary calls result in useless allocations.
     ///
+    /// ### Known problems
+    /// `unnecessary_to_owned` can falsely trigger if `IntoIterator::into_iter` is applied to an
+    /// owned copy of a resource and the resource is later used mutably. See
+    /// [#8148](https://github.com/rust-lang/rust-clippy/issues/8148).
+    ///
     /// ### Example
     /// ```rust
     /// let path = std::path::Path::new("x");
@@ -1997,24 +2001,16 @@ impl_lint_pass!(Methods => [
 ]);
 
 /// Extracts a method call name, args, and `Span` of the method name.
-fn method_call<'tcx>(recv: &'tcx hir::Expr<'tcx>) -> Option<(Symbol, &'tcx [hir::Expr<'tcx>], Span)> {
+fn method_call<'tcx>(recv: &'tcx hir::Expr<'tcx>) -> Option<(&'tcx str, &'tcx [hir::Expr<'tcx>], Span)> {
     if let ExprKind::MethodCall(path, span, args, _) = recv.kind {
         if !args.iter().any(|e| e.span.from_expansion()) {
-            return Some((path.ident.name, args, span));
+            let name = path.ident.name.as_str();
+            return Some((name, args, span));
         }
     }
     None
 }
 
-/// Same as `method_call` but the `Symbol` is dereferenced into a temporary `&str`
-macro_rules! method_call {
-    ($expr:expr) => {
-        method_call($expr)
-            .as_ref()
-            .map(|&(ref name, args, span)| (name.as_str(), args, span))
-    };
-}
-
 impl<'tcx> LateLintPass<'tcx> for Methods {
     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>) {
         if expr.span.from_expansion() {
@@ -2217,7 +2213,7 @@ impl<'tcx> LateLintPass<'tcx> for Methods {
 
 #[allow(clippy::too_many_lines)]
 fn check_methods<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, msrv: Option<&RustcVersion>) {
-    if let Some((name, [recv, args @ ..], span)) = method_call!(expr) {
+    if let Some((name, [recv, args @ ..], span)) = method_call(expr) {
         match (name, args) {
             ("add" | "offset" | "sub" | "wrapping_offset" | "wrapping_add" | "wrapping_sub", [_arg]) => {
                 zst_offset::check(cx, expr, recv);
@@ -2233,7 +2229,7 @@ fn check_methods<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, msrv: Optio
             ("as_ref", []) => useless_asref::check(cx, expr, "as_ref", recv),
             ("assume_init", []) => uninit_assumed_init::check(cx, expr, recv),
             ("cloned", []) => cloned_instead_of_copied::check(cx, expr, recv, span, msrv),
-            ("collect", []) => match method_call!(recv) {
+            ("collect", []) => match method_call(recv) {
                 Some((name @ ("cloned" | "copied"), [recv2], _)) => {
                     iter_cloned_collect::check(cx, name, expr, recv2);
                 },
@@ -2247,14 +2243,14 @@ fn check_methods<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, msrv: Optio
                 },
                 _ => {},
             },
-            ("count", []) => match method_call!(recv) {
+            ("count", []) => match method_call(recv) {
                 Some((name @ ("into_iter" | "iter" | "iter_mut"), [recv2], _)) => {
                     iter_count::check(cx, expr, recv2, name);
                 },
                 Some(("map", [_, arg], _)) => suspicious_map::check(cx, expr, recv, arg),
                 _ => {},
             },
-            ("expect", [_]) => match method_call!(recv) {
+            ("expect", [_]) => match method_call(recv) {
                 Some(("ok", [recv], _)) => ok_expect::check(cx, expr, recv),
                 _ => expect_used::check(cx, expr, recv),
             },
@@ -2271,13 +2267,13 @@ fn check_methods<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, msrv: Optio
                 flat_map_option::check(cx, expr, arg, span);
             },
             ("flatten", []) => {
-                if let Some(("map", [recv, map_arg], _)) = method_call!(recv) {
+                if let Some(("map", [recv, map_arg], _)) = method_call(recv) {
                     map_flatten::check(cx, expr, recv, map_arg);
                 }
             },
             ("fold", [init, acc]) => unnecessary_fold::check(cx, expr, init, acc, span),
             ("for_each", [_]) => {
-                if let Some(("inspect", [_, _], span2)) = method_call!(recv) {
+                if let Some(("inspect", [_, _], span2)) = method_call(recv) {
                     inspect_for_each::check(cx, expr, span2);
                 }
             },
@@ -2286,7 +2282,7 @@ fn check_methods<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, msrv: Optio
             ("is_none", []) => check_is_some_is_none(cx, expr, recv, false),
             ("is_some", []) => check_is_some_is_none(cx, expr, recv, true),
             ("map", [m_arg]) => {
-                if let Some((name, [recv2, args @ ..], span2)) = method_call!(recv) {
+                if let Some((name, [recv2, args @ ..], span2)) = method_call(recv) {
                     match (name, args) {
                         ("as_mut", []) => option_as_ref_deref::check(cx, expr, recv2, m_arg, true, msrv),
                         ("as_ref", []) => option_as_ref_deref::check(cx, expr, recv2, m_arg, false, msrv),
@@ -2301,7 +2297,7 @@ fn check_methods<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, msrv: Optio
             },
             ("map_or", [def, map]) => option_map_or_none::check(cx, expr, recv, def, map),
             ("next", []) => {
-                if let Some((name, [recv, args @ ..], _)) = method_call!(recv) {
+                if let Some((name, [recv, args @ ..], _)) = method_call(recv) {
                     match (name, args) {
                         ("filter", [arg]) => filter_next::check(cx, expr, recv, arg),
                         ("filter_map", [arg]) => filter_map_next::check(cx, expr, recv, arg, msrv),
@@ -2312,7 +2308,7 @@ fn check_methods<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, msrv: Optio
                     }
                 }
             },
-            ("nth", [n_arg]) => match method_call!(recv) {
+            ("nth", [n_arg]) => match method_call(recv) {
                 Some(("bytes", [recv2], _)) => bytes_nth::check(cx, expr, recv2, n_arg),
                 Some(("iter", [recv2], _)) => iter_nth::check(cx, expr, recv2, recv, n_arg, false),
                 Some(("iter_mut", [recv2], _)) => iter_nth::check(cx, expr, recv2, recv, n_arg, true),
@@ -2344,12 +2340,12 @@ fn check_methods<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, msrv: Optio
             ("to_os_string" | "to_owned" | "to_path_buf" | "to_vec", []) => {
                 implicit_clone::check(cx, name, expr, recv, span);
             },
-            ("unwrap", []) => match method_call!(recv) {
+            ("unwrap", []) => match method_call(recv) {
                 Some(("get", [recv, get_arg], _)) => get_unwrap::check(cx, expr, recv, get_arg, false),
                 Some(("get_mut", [recv, get_arg], _)) => get_unwrap::check(cx, expr, recv, get_arg, true),
                 _ => unwrap_used::check(cx, expr, recv),
             },
-            ("unwrap_or", [u_arg]) => match method_call!(recv) {
+            ("unwrap_or", [u_arg]) => match method_call(recv) {
                 Some((arith @ ("checked_add" | "checked_sub" | "checked_mul"), [lhs, rhs], _)) => {
                     manual_saturating_arithmetic::check(cx, expr, lhs, rhs, u_arg, &arith["checked_".len()..]);
                 },
@@ -2358,7 +2354,7 @@ fn check_methods<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, msrv: Optio
                 },
                 _ => {},
             },
-            ("unwrap_or_else", [u_arg]) => match method_call!(recv) {
+            ("unwrap_or_else", [u_arg]) => match method_call(recv) {
                 Some(("map", [recv, map_arg], _)) if map_unwrap_or::check(cx, expr, recv, map_arg, u_arg, msrv) => {},
                 _ => {
                     unwrap_or_else_default::check(cx, expr, recv, u_arg);
@@ -2371,7 +2367,7 @@ fn check_methods<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, msrv: Optio
 }
 
 fn check_is_some_is_none(cx: &LateContext<'_>, expr: &Expr<'_>, recv: &Expr<'_>, is_some: bool) {
-    if let Some((name @ ("find" | "position" | "rposition"), [f_recv, arg], span)) = method_call!(recv) {
+    if let Some((name @ ("find" | "position" | "rposition"), [f_recv, arg], span)) = method_call(recv) {
         search_is_some::check(cx, expr, name, is_some, f_recv, arg, recv, span);
     }
 }
@@ -2535,11 +2531,17 @@ impl SelfKind {
             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 => ty != parent_ty,
+            Self::No => matches_none(cx, parent_ty, ty),
         }
     }
 
diff --git a/clippy_lints/src/methods/str_splitn.rs b/clippy_lints/src/methods/str_splitn.rs
index 70f20da1d6d..514bdadc442 100644
--- a/clippy_lints/src/methods/str_splitn.rs
+++ b/clippy_lints/src/methods/str_splitn.rs
@@ -124,7 +124,7 @@ struct IterUsage {
 }
 
 #[allow(clippy::too_many_lines)]
-fn parse_iter_usage(
+fn parse_iter_usage<'tcx>(
     cx: &LateContext<'tcx>,
     ctxt: SyntaxContext,
     mut iter: impl Iterator<Item = (HirId, Node<'tcx>)>,
@@ -281,7 +281,7 @@ pub(super) fn check_needless_splitn(
     }
 }
 
-fn check_iter(
+fn check_iter<'tcx>(
     cx: &LateContext<'tcx>,
     ctxt: SyntaxContext,
     mut iter: impl Iterator<Item = (HirId, Node<'tcx>)>,
diff --git a/clippy_lints/src/methods/unnecessary_iter_cloned.rs b/clippy_lints/src/methods/unnecessary_iter_cloned.rs
index 8300df03e99..5999245ea7d 100644
--- a/clippy_lints/src/methods/unnecessary_iter_cloned.rs
+++ b/clippy_lints/src/methods/unnecessary_iter_cloned.rs
@@ -12,13 +12,13 @@ use rustc_span::{sym, Symbol};
 
 use super::UNNECESSARY_TO_OWNED;
 
-pub fn check(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>, method_name: Symbol, receiver: &'tcx Expr<'tcx>) -> bool {
+pub fn check(cx: &LateContext<'_>, expr: &Expr<'_>, method_name: Symbol, receiver: &Expr<'_>) -> bool {
     if_chain! {
         if let Some(parent) = get_parent_expr(cx, expr);
         if let Some(callee_def_id) = fn_def_id(cx, parent);
         if is_into_iter(cx, callee_def_id);
         then {
-            check_for_loop_iter(cx, parent, method_name, receiver)
+            check_for_loop_iter(cx, parent, method_name, receiver, false)
         } else {
             false
         }
@@ -30,10 +30,11 @@ pub fn check(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>, method_name: Symbol
 /// include this code directly is so that it can be called from
 /// `unnecessary_into_owned::check_into_iter_call_arg`.
 pub fn check_for_loop_iter(
-    cx: &LateContext<'tcx>,
-    expr: &'tcx Expr<'tcx>,
+    cx: &LateContext<'_>,
+    expr: &Expr<'_>,
     method_name: Symbol,
-    receiver: &'tcx Expr<'tcx>,
+    receiver: &Expr<'_>,
+    cloned_before_iter: bool,
 ) -> bool {
     if_chain! {
         if let Some(grandparent) = get_parent_expr(cx, expr).and_then(|parent| get_parent_expr(cx, parent));
@@ -70,12 +71,22 @@ pub fn check_for_loop_iter(
                 expr.span,
                 &format!("unnecessary use of `{}`", method_name),
                 |diag| {
-                    diag.span_suggestion(expr.span, "use", snippet, Applicability::MachineApplicable);
+                    // If `check_into_iter_call_arg` called `check_for_loop_iter` because a call to
+                    // a `to_owned`-like function was removed, then the next suggestion may be
+                    // incorrect. This is because the iterator that results from the call's removal
+                    // could hold a reference to a resource that is used mutably. See
+                    // https://github.com/rust-lang/rust-clippy/issues/8148.
+                    let applicability = if cloned_before_iter {
+                        Applicability::MaybeIncorrect
+                    } else {
+                        Applicability::MachineApplicable
+                    };
+                    diag.span_suggestion(expr.span, "use", snippet, applicability);
                     for addr_of_expr in addr_of_exprs {
                         match addr_of_expr.kind {
                             ExprKind::AddrOf(_, _, referent) => {
                                 let span = addr_of_expr.span.with_hi(referent.span.lo());
-                                diag.span_suggestion(span, "remove this `&`", String::new(), Applicability::MachineApplicable);
+                                diag.span_suggestion(span, "remove this `&`", String::new(), applicability);
                             }
                             _ => unreachable!(),
                         }
@@ -90,7 +101,7 @@ pub fn check_for_loop_iter(
 
 /// The core logic of `check_for_loop_iter` above, this function wraps a use of
 /// `CloneOrCopyVisitor`.
-fn clone_or_copy_needed(
+fn clone_or_copy_needed<'tcx>(
     cx: &LateContext<'tcx>,
     pat: &Pat<'tcx>,
     body: &'tcx Expr<'tcx>,
diff --git a/clippy_lints/src/methods/unnecessary_to_owned.rs b/clippy_lints/src/methods/unnecessary_to_owned.rs
index c48bacfce0d..e5b6d296b2d 100644
--- a/clippy_lints/src/methods/unnecessary_to_owned.rs
+++ b/clippy_lints/src/methods/unnecessary_to_owned.rs
@@ -16,7 +16,7 @@ use std::cmp::max;
 
 use super::UNNECESSARY_TO_OWNED;
 
-pub fn check(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>, method_name: Symbol, args: &'tcx [Expr<'tcx>]) {
+pub fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>, method_name: Symbol, args: &'tcx [Expr<'tcx>]) {
     if_chain! {
         if let Some(method_def_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id);
         if let [receiver] = args;
@@ -44,11 +44,11 @@ pub fn check(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>, method_name: Symbol
 /// call of a `to_owned`-like function is unnecessary.
 #[allow(clippy::too_many_lines)]
 fn check_addr_of_expr(
-    cx: &LateContext<'tcx>,
-    expr: &'tcx Expr<'tcx>,
+    cx: &LateContext<'_>,
+    expr: &Expr<'_>,
     method_name: Symbol,
     method_def_id: DefId,
-    receiver: &'tcx Expr<'tcx>,
+    receiver: &Expr<'_>,
 ) -> bool {
     if_chain! {
         if let Some(parent) = get_parent_expr(cx, expr);
@@ -171,12 +171,7 @@ fn check_addr_of_expr(
 
 /// Checks whether `expr` is an argument in an `into_iter` call and, if so, determines whether its
 /// call of a `to_owned`-like function is unnecessary.
-fn check_into_iter_call_arg(
-    cx: &LateContext<'tcx>,
-    expr: &'tcx Expr<'tcx>,
-    method_name: Symbol,
-    receiver: &'tcx Expr<'tcx>,
-) -> bool {
+fn check_into_iter_call_arg(cx: &LateContext<'_>, expr: &Expr<'_>, method_name: Symbol, receiver: &Expr<'_>) -> bool {
     if_chain! {
         if let Some(parent) = get_parent_expr(cx, expr);
         if let Some(callee_def_id) = fn_def_id(cx, parent);
@@ -187,7 +182,13 @@ fn check_into_iter_call_arg(
         if let Some(item_ty) = get_iterator_item_ty(cx, parent_ty);
         if let Some(receiver_snippet) = snippet_opt(cx, receiver.span);
         then {
-            if unnecessary_iter_cloned::check_for_loop_iter(cx, parent, method_name, receiver) {
+            if unnecessary_iter_cloned::check_for_loop_iter(
+                cx,
+                parent,
+                method_name,
+                receiver,
+                true,
+            ) {
                 return true;
             }
             let cloned_or_copied = if is_copy(cx, item_ty) {
@@ -195,6 +196,9 @@ fn check_into_iter_call_arg(
             } else {
                 "cloned"
             };
+            // The next suggestion may be incorrect because the removal of the `to_owned`-like
+            // function could cause the iterator to hold a reference to a resource that is used
+            // mutably. See https://github.com/rust-lang/rust-clippy/issues/8148.
             span_lint_and_sugg(
                 cx,
                 UNNECESSARY_TO_OWNED,
@@ -202,7 +206,7 @@ fn check_into_iter_call_arg(
                 &format!("unnecessary use of `{}`", method_name),
                 "use",
                 format!("{}.iter().{}()", receiver_snippet, cloned_or_copied),
-                Applicability::MachineApplicable,
+                Applicability::MaybeIncorrect,
             );
             return true;
         }
@@ -212,7 +216,7 @@ fn check_into_iter_call_arg(
 
 /// Checks whether `expr` is an argument in a function call and, if so, determines whether its call
 /// of a `to_owned`-like function is unnecessary.
-fn check_other_call_arg(
+fn check_other_call_arg<'tcx>(
     cx: &LateContext<'tcx>,
     expr: &'tcx Expr<'tcx>,
     method_name: Symbol,
@@ -278,7 +282,7 @@ fn check_other_call_arg(
 
 /// Walks an expression's ancestors until it finds a non-`AddrOf` expression. Returns the first such
 /// expression found (if any) along with the immediately prior expression.
-fn skip_addr_of_ancestors(
+fn skip_addr_of_ancestors<'tcx>(
     cx: &LateContext<'tcx>,
     mut expr: &'tcx Expr<'tcx>,
 ) -> Option<(&'tcx Expr<'tcx>, &'tcx Expr<'tcx>)> {
@@ -294,7 +298,7 @@ fn skip_addr_of_ancestors(
 
 /// Checks whether an expression is a function or method call and, if so, returns its `DefId`,
 /// `Substs`, and arguments.
-fn get_callee_substs_and_args(
+fn get_callee_substs_and_args<'tcx>(
     cx: &LateContext<'tcx>,
     expr: &'tcx Expr<'tcx>,
 ) -> Option<(DefId, SubstsRef<'tcx>, &'tcx [Expr<'tcx>])> {
@@ -319,7 +323,7 @@ fn get_callee_substs_and_args(
 }
 
 /// Returns the `TraitPredicate`s and `ProjectionPredicate`s for a function's input type.
-fn get_input_traits_and_projections(
+fn get_input_traits_and_projections<'tcx>(
     cx: &LateContext<'tcx>,
     callee_def_id: DefId,
     input: Ty<'tcx>,
@@ -359,7 +363,11 @@ fn get_input_traits_and_projections(
 }
 
 /// Composes two substitutions by applying the latter to the types of the former.
-fn compose_substs(cx: &LateContext<'tcx>, left: &[GenericArg<'tcx>], right: SubstsRef<'tcx>) -> Vec<GenericArg<'tcx>> {
+fn compose_substs<'tcx>(
+    cx: &LateContext<'tcx>,
+    left: &[GenericArg<'tcx>],
+    right: SubstsRef<'tcx>,
+) -> Vec<GenericArg<'tcx>> {
     left.iter()
         .map(|arg| {
             if let GenericArgKind::Type(arg_ty) = arg.unpack() {
diff --git a/clippy_lints/src/misc.rs b/clippy_lints/src/misc.rs
index 401dc27811d..21b3f81d5d9 100644
--- a/clippy_lints/src/misc.rs
+++ b/clippy_lints/src/misc.rs
@@ -717,7 +717,7 @@ fn check_cast(cx: &LateContext<'_>, span: Span, e: &Expr<'_>, ty: &hir::Ty<'_>)
     }
 }
 
-fn check_binary(
+fn check_binary<'a>(
     cx: &LateContext<'a>,
     expr: &Expr<'_>,
     cmp: &rustc_span::source_map::Spanned<rustc_hir::BinOpKind>,
diff --git a/clippy_lints/src/mutable_debug_assertion.rs b/clippy_lints/src/mutable_debug_assertion.rs
index 12e219cd5c8..842959ce36b 100644
--- a/clippy_lints/src/mutable_debug_assertion.rs
+++ b/clippy_lints/src/mutable_debug_assertion.rs
@@ -1,5 +1,5 @@
 use clippy_utils::diagnostics::span_lint;
-use clippy_utils::{higher, is_direct_expn_of};
+use clippy_utils::macros::{find_assert_eq_args, root_macro_call_first_node};
 use rustc_hir::intravisit::{walk_expr, NestedVisitorMap, Visitor};
 use rustc_hir::{BorrowKind, Expr, ExprKind, MatchSource, Mutability};
 use rustc_lint::{LateContext, LateLintPass};
@@ -34,26 +34,30 @@ declare_clippy_lint! {
 
 declare_lint_pass!(DebugAssertWithMutCall => [DEBUG_ASSERT_WITH_MUT_CALL]);
 
-const DEBUG_MACRO_NAMES: [&str; 3] = ["debug_assert", "debug_assert_eq", "debug_assert_ne"];
-
 impl<'tcx> LateLintPass<'tcx> for DebugAssertWithMutCall {
     fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) {
-        for dmn in &DEBUG_MACRO_NAMES {
-            if is_direct_expn_of(e.span, dmn).is_some() {
-                if let Some(macro_args) = higher::extract_assert_macro_args(e) {
-                    for arg in macro_args {
-                        let mut visitor = MutArgVisitor::new(cx);
-                        visitor.visit_expr(arg);
-                        if let Some(span) = visitor.expr_span() {
-                            span_lint(
-                                cx,
-                                DEBUG_ASSERT_WITH_MUT_CALL,
-                                span,
-                                &format!("do not call a function with mutable arguments inside of `{}!`", dmn),
-                            );
-                        }
-                    }
-                }
+        let Some(macro_call) = root_macro_call_first_node(cx, e) else { return };
+        let macro_name = cx.tcx.item_name(macro_call.def_id);
+        if !matches!(
+            macro_name.as_str(),
+            "debug_assert" | "debug_assert_eq" | "debug_assert_ne"
+        ) {
+            return;
+        }
+        let Some((lhs, rhs, _)) = find_assert_eq_args(cx, e, macro_call.expn) else { return };
+        for arg in [lhs, rhs] {
+            let mut visitor = MutArgVisitor::new(cx);
+            visitor.visit_expr(arg);
+            if let Some(span) = visitor.expr_span() {
+                span_lint(
+                    cx,
+                    DEBUG_ASSERT_WITH_MUT_CALL,
+                    span,
+                    &format!(
+                        "do not call a function with mutable arguments inside of `{}!`",
+                        macro_name
+                    ),
+                );
             }
         }
     }
diff --git a/clippy_lints/src/mutex_atomic.rs b/clippy_lints/src/mutex_atomic.rs
index 816377fe65e..73823779e49 100644
--- a/clippy_lints/src/mutex_atomic.rs
+++ b/clippy_lints/src/mutex_atomic.rs
@@ -38,7 +38,7 @@ declare_clippy_lint! {
     /// ```
     #[clippy::version = "pre 1.29.0"]
     pub MUTEX_ATOMIC,
-    perf,
+    nursery,
     "using a mutex where an atomic value could be used instead"
 }
 
diff --git a/clippy_lints/src/needless_for_each.rs b/clippy_lints/src/needless_for_each.rs
index 0c1da035173..19d58f7474b 100644
--- a/clippy_lints/src/needless_for_each.rs
+++ b/clippy_lints/src/needless_for_each.rs
@@ -48,7 +48,7 @@ declare_clippy_lint! {
 
 declare_lint_pass!(NeedlessForEach => [NEEDLESS_FOR_EACH]);
 
-impl LateLintPass<'_> for NeedlessForEach {
+impl<'tcx> LateLintPass<'tcx> for NeedlessForEach {
     fn check_stmt(&mut self, cx: &LateContext<'tcx>, stmt: &'tcx Stmt<'_>) {
         let expr = match stmt.kind {
             StmtKind::Expr(expr) | StmtKind::Semi(expr) => expr,
diff --git a/clippy_lints/src/needless_late_init.rs b/clippy_lints/src/needless_late_init.rs
index 094a3f111ba..9957afcbf04 100644
--- a/clippy_lints/src/needless_late_init.rs
+++ b/clippy_lints/src/needless_late_init.rs
@@ -330,7 +330,7 @@ fn check<'tcx>(
     Some(())
 }
 
-impl LateLintPass<'tcx> for NeedlessLateInit {
+impl<'tcx> LateLintPass<'tcx> for NeedlessLateInit {
     fn check_local(&mut self, cx: &LateContext<'tcx>, local: &'tcx Local<'tcx>) {
         let mut parents = cx.tcx.hir().parent_iter(local.hir_id);
 
diff --git a/clippy_lints/src/no_effect.rs b/clippy_lints/src/no_effect.rs
index 9d5babc5de8..5bf8a1ba1ca 100644
--- a/clippy_lints/src/no_effect.rs
+++ b/clippy_lints/src/no_effect.rs
@@ -82,7 +82,7 @@ impl<'tcx> LateLintPass<'tcx> for NoEffect {
     }
 }
 
-fn check_no_effect(cx: &LateContext<'tcx>, stmt: &'tcx Stmt<'_>) -> bool {
+fn check_no_effect(cx: &LateContext<'_>, stmt: &Stmt<'_>) -> bool {
     if let StmtKind::Semi(expr) = stmt.kind {
         if has_no_effect(cx, expr) {
             span_lint_hir(cx, NO_EFFECT, expr.hir_id, stmt.span, "statement with no effect");
@@ -155,7 +155,7 @@ fn has_no_effect(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
     }
 }
 
-fn check_unnecessary_operation(cx: &LateContext<'tcx>, stmt: &'tcx Stmt<'_>) {
+fn check_unnecessary_operation(cx: &LateContext<'_>, stmt: &Stmt<'_>) {
     if_chain! {
         if let StmtKind::Semi(expr) = stmt.kind;
         if let Some(reduced) = reduce_expression(cx, expr);
diff --git a/clippy_lints/src/non_octal_unix_permissions.rs b/clippy_lints/src/non_octal_unix_permissions.rs
index 4b57dbc4c41..e46fee4cac5 100644
--- a/clippy_lints/src/non_octal_unix_permissions.rs
+++ b/clippy_lints/src/non_octal_unix_permissions.rs
@@ -40,7 +40,7 @@ declare_clippy_lint! {
 
 declare_lint_pass!(NonOctalUnixPermissions => [NON_OCTAL_UNIX_PERMISSIONS]);
 
-impl LateLintPass<'_> for NonOctalUnixPermissions {
+impl<'tcx> LateLintPass<'tcx> for NonOctalUnixPermissions {
     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) {
         match &expr.kind {
             ExprKind::MethodCall(path, _, [func, param], _) => {
diff --git a/clippy_lints/src/octal_escapes.rs b/clippy_lints/src/octal_escapes.rs
index 9c971437645..e0da12f77fc 100644
--- a/clippy_lints/src/octal_escapes.rs
+++ b/clippy_lints/src/octal_escapes.rs
@@ -50,7 +50,7 @@ declare_clippy_lint! {
 declare_lint_pass!(OctalEscapes => [OCTAL_ESCAPES]);
 
 impl EarlyLintPass for OctalEscapes {
-    fn check_expr(&mut self, cx: &EarlyContext<'tcx>, expr: &Expr) {
+    fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &Expr) {
         if in_external_macro(cx.sess, expr.span) {
             return;
         }
@@ -65,7 +65,7 @@ impl EarlyLintPass for OctalEscapes {
     }
 }
 
-fn check_lit(cx: &EarlyContext<'tcx>, lit: &Lit, span: Span, is_string: bool) {
+fn check_lit(cx: &EarlyContext<'_>, lit: &Lit, span: Span, is_string: bool) {
     let contents = lit.symbol.as_str();
     let mut iter = contents.char_indices().peekable();
     let mut found = vec![];
diff --git a/clippy_lints/src/panic_in_result_fn.rs b/clippy_lints/src/panic_in_result_fn.rs
index 8769c045214..b7a56970b33 100644
--- a/clippy_lints/src/panic_in_result_fn.rs
+++ b/clippy_lints/src/panic_in_result_fn.rs
@@ -1,8 +1,10 @@
 use clippy_utils::diagnostics::span_lint_and_then;
+use clippy_utils::macros::root_macro_call_first_node;
+use clippy_utils::return_ty;
 use clippy_utils::ty::is_type_diagnostic_item;
-use clippy_utils::{find_macro_calls, is_expn_of, return_ty};
+use clippy_utils::visitors::expr_visitor_no_bodies;
 use rustc_hir as hir;
-use rustc_hir::intravisit::FnKind;
+use rustc_hir::intravisit::{FnKind, Visitor};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_session::{declare_lint_pass, declare_tool_lint};
 use rustc_span::{sym, Span};
@@ -55,19 +57,19 @@ impl<'tcx> LateLintPass<'tcx> for PanicInResultFn {
 }
 
 fn lint_impl_body<'tcx>(cx: &LateContext<'tcx>, impl_span: Span, body: &'tcx hir::Body<'tcx>) {
-    let mut panics = find_macro_calls(
-        &[
-            "unimplemented",
-            "unreachable",
-            "panic",
-            "todo",
-            "assert",
-            "assert_eq",
-            "assert_ne",
-        ],
-        body,
-    );
-    panics.retain(|span| is_expn_of(*span, "debug_assert").is_none());
+    let mut panics = Vec::new();
+    expr_visitor_no_bodies(|expr| {
+        let Some(macro_call) = root_macro_call_first_node(cx, expr) else { return true };
+        if matches!(
+            &*cx.tcx.item_name(macro_call.def_id).as_str(),
+            "unimplemented" | "unreachable" | "panic" | "todo" | "assert" | "assert_eq" | "assert_ne"
+        ) {
+            panics.push(macro_call.span);
+            return false;
+        }
+        true
+    })
+    .visit_expr(&body.value);
     if !panics.is_empty() {
         span_lint_and_then(
             cx,
diff --git a/clippy_lints/src/panic_unimplemented.rs b/clippy_lints/src/panic_unimplemented.rs
index edfac824ded..6ef6b9a20aa 100644
--- a/clippy_lints/src/panic_unimplemented.rs
+++ b/clippy_lints/src/panic_unimplemented.rs
@@ -1,10 +1,8 @@
 use clippy_utils::diagnostics::span_lint;
-use clippy_utils::{is_expn_of, match_panic_call};
-use if_chain::if_chain;
+use clippy_utils::macros::{is_panic, root_macro_call_first_node};
 use rustc_hir::Expr;
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_session::{declare_lint_pass, declare_tool_lint};
-use rustc_span::Span;
 
 declare_clippy_lint! {
     /// ### What it does
@@ -78,37 +76,37 @@ declare_lint_pass!(PanicUnimplemented => [UNIMPLEMENTED, UNREACHABLE, TODO, PANI
 
 impl<'tcx> LateLintPass<'tcx> for PanicUnimplemented {
     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
-        if match_panic_call(cx, expr).is_some()
-            && (is_expn_of(expr.span, "debug_assert").is_none() && is_expn_of(expr.span, "assert").is_none())
-        {
-            let span = get_outer_span(expr);
-            if is_expn_of(expr.span, "unimplemented").is_some() {
+        let Some(macro_call) = root_macro_call_first_node(cx, expr) else { return };
+        if is_panic(cx, macro_call.def_id) {
+            span_lint(
+                cx,
+                PANIC,
+                macro_call.span,
+                "`panic` should not be present in production code",
+            );
+            return;
+        }
+        match cx.tcx.item_name(macro_call.def_id).as_str() {
+            "todo" => {
+                span_lint(
+                    cx,
+                    TODO,
+                    macro_call.span,
+                    "`todo` should not be present in production code",
+                );
+            },
+            "unimplemented" => {
                 span_lint(
                     cx,
                     UNIMPLEMENTED,
-                    span,
+                    macro_call.span,
                     "`unimplemented` should not be present in production code",
                 );
-            } else if is_expn_of(expr.span, "todo").is_some() {
-                span_lint(cx, TODO, span, "`todo` should not be present in production code");
-            } else if is_expn_of(expr.span, "unreachable").is_some() {
-                span_lint(cx, UNREACHABLE, span, "usage of the `unreachable!` macro");
-            } else if is_expn_of(expr.span, "panic").is_some() {
-                span_lint(cx, PANIC, span, "`panic` should not be present in production code");
-            }
-        }
-    }
-}
-
-fn get_outer_span(expr: &Expr<'_>) -> Span {
-    if_chain! {
-        if expr.span.from_expansion();
-        let first = expr.span.ctxt().outer_expn_data().call_site;
-        if first.from_expansion();
-        then {
-            first.ctxt().outer_expn_data().call_site
-        } else {
-            expr.span
+            },
+            "unreachable" => {
+                span_lint(cx, UNREACHABLE, macro_call.span, "usage of the `unreachable!` macro");
+            },
+            _ => {},
         }
     }
 }
diff --git a/clippy_lints/src/ptr_eq.rs b/clippy_lints/src/ptr_eq.rs
index 3c126fc1ca6..2bec93ac606 100644
--- a/clippy_lints/src/ptr_eq.rs
+++ b/clippy_lints/src/ptr_eq.rs
@@ -39,7 +39,7 @@ declare_lint_pass!(PtrEq => [PTR_EQ]);
 
 static LINT_MSG: &str = "use `std::ptr::eq` when comparing raw pointers";
 
-impl LateLintPass<'_> for PtrEq {
+impl<'tcx> LateLintPass<'tcx> for PtrEq {
     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
         if expr.span.from_expansion() {
             return;
diff --git a/clippy_lints/src/redundant_clone.rs b/clippy_lints/src/redundant_clone.rs
index 1cf349f8aa7..1991a01fb60 100644
--- a/clippy_lints/src/redundant_clone.rs
+++ b/clippy_lints/src/redundant_clone.rs
@@ -220,7 +220,7 @@ impl<'tcx> LateLintPass<'tcx> for RedundantClone {
                     continue;
                 } else if let Some(loc) = clone_usage.cloned_consume_or_mutate_loc {
                     // cloned value is mutated, and the clone is alive.
-                    if possible_borrower.is_alive_at(ret_local, loc) {
+                    if possible_borrower.local_is_alive_at(ret_local, loc) {
                         continue;
                     }
                 }
@@ -767,7 +767,7 @@ impl PossibleBorrowerMap<'_, '_> {
         self.bitset.0 == self.bitset.1
     }
 
-    fn is_alive_at(&mut self, local: mir::Local, at: mir::Location) -> bool {
+    fn local_is_alive_at(&mut self, local: mir::Local, at: mir::Location) -> bool {
         self.maybe_live.seek_after_primary_effect(at);
         self.maybe_live.contains(local)
     }
diff --git a/clippy_lints/src/redundant_slicing.rs b/clippy_lints/src/redundant_slicing.rs
index b2bd0103d11..7c88b42ea31 100644
--- a/clippy_lints/src/redundant_slicing.rs
+++ b/clippy_lints/src/redundant_slicing.rs
@@ -42,7 +42,7 @@ declare_clippy_lint! {
 
 declare_lint_pass!(RedundantSlicing => [REDUNDANT_SLICING]);
 
-impl LateLintPass<'_> for RedundantSlicing {
+impl<'tcx> LateLintPass<'tcx> for RedundantSlicing {
     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
         if expr.span.from_expansion() {
             return;
diff --git a/clippy_lints/src/reference.rs b/clippy_lints/src/reference.rs
index 22ae7a291d0..b2448372370 100644
--- a/clippy_lints/src/reference.rs
+++ b/clippy_lints/src/reference.rs
@@ -50,6 +50,7 @@ impl EarlyLintPass for DerefAddrOf {
         if_chain! {
             if let ExprKind::Unary(UnOp::Deref, ref deref_target) = e.kind;
             if let ExprKind::AddrOf(_, ref mutability, ref addrof_target) = without_parens(deref_target).kind;
+            if deref_target.span.ctxt() == e.span.ctxt();
             if !addrof_target.span.from_expansion();
             then {
                 let mut applicability = Applicability::MachineApplicable;
diff --git a/clippy_lints/src/return_self_not_must_use.rs b/clippy_lints/src/return_self_not_must_use.rs
index b57ec96bc7e..5dafd08cf3b 100644
--- a/clippy_lints/src/return_self_not_must_use.rs
+++ b/clippy_lints/src/return_self_not_must_use.rs
@@ -1,5 +1,6 @@
+use clippy_utils::diagnostics::span_lint_and_help;
 use clippy_utils::ty::is_must_use_ty;
-use clippy_utils::{diagnostics::span_lint, nth_arg, return_ty};
+use clippy_utils::{nth_arg, return_ty};
 use rustc_hir::def_id::LocalDefId;
 use rustc_hir::intravisit::FnKind;
 use rustc_hir::{Body, FnDecl, HirId, TraitItem, TraitItemKind};
@@ -13,25 +14,46 @@ declare_clippy_lint! {
     /// This lint warns when a method returning `Self` doesn't have the `#[must_use]` attribute.
     ///
     /// ### Why is this bad?
-    /// It prevents to "forget" to use the newly created value.
+    /// Methods returning `Self` often create new values, having the `#[must_use]` attribute
+    /// prevents users from "forgetting" to use the newly created value.
+    ///
+    /// The `#[must_use]` attribute can be added to the type itself to ensure that instances
+    /// are never forgotten. Functions returning a type marked with `#[must_use]` will not be
+    /// linted, as the usage is already enforced by the type attribute.
     ///
     /// ### Limitations
     /// This lint is only applied on methods taking a `self` argument. It would be mostly noise
     /// if it was added on constructors for example.
     ///
     /// ### Example
+    /// Missing attribute
     /// ```rust
     /// pub struct Bar;
-    ///
     /// impl Bar {
     ///     // Bad
     ///     pub fn bar(&self) -> Self {
     ///         Self
     ///     }
+    /// }
+    /// ```
     ///
-    ///     // Good
+    /// It's better to have the `#[must_use]` attribute on the method like this:
+    /// ```rust
+    /// pub struct Bar;
+    /// impl Bar {
     ///     #[must_use]
-    ///     pub fn foo(&self) -> Self {
+    ///     pub fn bar(&self) -> Self {
+    ///         Self
+    ///     }
+    /// }
+    /// ```
+    ///
+    /// Or on the type definition like this:
+    /// ```rust
+    /// #[must_use]
+    /// pub struct Bar;
+    /// impl Bar {
+    ///     pub fn bar(&self) -> Self {
     ///         Self
     ///     }
     /// }
@@ -44,7 +66,7 @@ declare_clippy_lint! {
 
 declare_lint_pass!(ReturnSelfNotMustUse => [RETURN_SELF_NOT_MUST_USE]);
 
-fn check_method(cx: &LateContext<'tcx>, decl: &'tcx FnDecl<'tcx>, fn_def: LocalDefId, span: Span, hir_id: HirId) {
+fn check_method(cx: &LateContext<'_>, decl: &FnDecl<'_>, fn_def: LocalDefId, span: Span, hir_id: HirId) {
     if_chain! {
         // If it comes from an external macro, better ignore it.
         if !in_external_macro(cx.sess(), span);
@@ -65,11 +87,13 @@ fn check_method(cx: &LateContext<'tcx>, decl: &'tcx FnDecl<'tcx>, fn_def: LocalD
         if !is_must_use_ty(cx, ret_ty);
 
         then {
-            span_lint(
+            span_lint_and_help(
                 cx,
                 RETURN_SELF_NOT_MUST_USE,
                 span,
                 "missing `#[must_use]` attribute on a method returning `Self`",
+                None,
+                "consider adding the `#[must_use]` attribute to the method or directly to the `Self` type"
             );
         }
     }
diff --git a/clippy_lints/src/semicolon_if_nothing_returned.rs b/clippy_lints/src/semicolon_if_nothing_returned.rs
index 0b3bbbc8155..729694da46d 100644
--- a/clippy_lints/src/semicolon_if_nothing_returned.rs
+++ b/clippy_lints/src/semicolon_if_nothing_returned.rs
@@ -37,7 +37,7 @@ declare_clippy_lint! {
 
 declare_lint_pass!(SemicolonIfNothingReturned => [SEMICOLON_IF_NOTHING_RETURNED]);
 
-impl LateLintPass<'_> for SemicolonIfNothingReturned {
+impl<'tcx> LateLintPass<'tcx> for SemicolonIfNothingReturned {
     fn check_block(&mut self, cx: &LateContext<'tcx>, block: &'tcx Block<'tcx>) {
         if_chain! {
             if !block.span.from_expansion();
diff --git a/clippy_lints/src/single_char_lifetime_names.rs b/clippy_lints/src/single_char_lifetime_names.rs
new file mode 100644
index 00000000000..ee82666b5af
--- /dev/null
+++ b/clippy_lints/src/single_char_lifetime_names.rs
@@ -0,0 +1,63 @@
+use clippy_utils::diagnostics::span_lint_and_help;
+use rustc_ast::ast::{GenericParam, GenericParamKind};
+use rustc_lint::{EarlyContext, EarlyLintPass};
+use rustc_middle::lint::in_external_macro;
+use rustc_session::{declare_lint_pass, declare_tool_lint};
+
+declare_clippy_lint! {
+    /// ### What it does
+    /// Checks for lifetimes with names which are one character
+    /// long.
+    ///
+    /// ### Why is this bad?
+    /// A single character is likely not enough to express the
+    /// purpose of a lifetime. Using a longer name can make code
+    /// easier to understand, especially for those who are new to
+    /// Rust.
+    ///
+    /// ### Known problems
+    /// Rust programmers and learning resources tend to use single
+    /// character lifetimes, so this lint is at odds with the
+    /// ecosystem at large. In addition, the lifetime's purpose may
+    /// be obvious or, rarely, expressible in one character.
+    ///
+    /// ### Example
+    /// ```rust
+    /// struct DiagnosticCtx<'a> {
+    ///     source: &'a str,
+    /// }
+    /// ```
+    /// Use instead:
+    /// ```rust
+    /// struct DiagnosticCtx<'src> {
+    ///     source: &'src str,
+    /// }
+    /// ```
+    #[clippy::version = "1.59.0"]
+    pub SINGLE_CHAR_LIFETIME_NAMES,
+    restriction,
+    "warns against single-character lifetime names"
+}
+
+declare_lint_pass!(SingleCharLifetimeNames => [SINGLE_CHAR_LIFETIME_NAMES]);
+
+impl EarlyLintPass for SingleCharLifetimeNames {
+    fn check_generic_param(&mut self, ctx: &EarlyContext<'_>, param: &GenericParam) {
+        if in_external_macro(ctx.sess, param.ident.span) {
+            return;
+        }
+
+        if let GenericParamKind::Lifetime = param.kind {
+            if !param.is_placeholder && param.ident.as_str().len() <= 2 {
+                span_lint_and_help(
+                    ctx,
+                    SINGLE_CHAR_LIFETIME_NAMES,
+                    param.ident.span,
+                    "single-character lifetime names are likely uninformative",
+                    None,
+                    "use a more informative name",
+                );
+            }
+        }
+    }
+}
diff --git a/clippy_lints/src/size_of_in_element_count.rs b/clippy_lints/src/size_of_in_element_count.rs
index df1e85afdd7..9b195f3c0a2 100644
--- a/clippy_lints/src/size_of_in_element_count.rs
+++ b/clippy_lints/src/size_of_in_element_count.rs
@@ -37,7 +37,7 @@ declare_clippy_lint! {
 
 declare_lint_pass!(SizeOfInElementCount => [SIZE_OF_IN_ELEMENT_COUNT]);
 
-fn get_size_of_ty(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, inverted: bool) -> Option<Ty<'tcx>> {
+fn get_size_of_ty<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, inverted: bool) -> Option<Ty<'tcx>> {
     match expr.kind {
         ExprKind::Call(count_func, _func_args) => {
             if_chain! {
@@ -64,7 +64,10 @@ fn get_size_of_ty(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, inverted: bool)
     }
 }
 
-fn get_pointee_ty_and_count_expr(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> Option<(Ty<'tcx>, &'tcx Expr<'tcx>)> {
+fn get_pointee_ty_and_count_expr<'tcx>(
+    cx: &LateContext<'tcx>,
+    expr: &'tcx Expr<'_>,
+) -> Option<(Ty<'tcx>, &'tcx Expr<'tcx>)> {
     const FUNCTIONS: [&[&str]; 8] = [
         &paths::PTR_COPY_NONOVERLAPPING,
         &paths::PTR_COPY,
diff --git a/clippy_lints/src/strings.rs b/clippy_lints/src/strings.rs
index ad8e72ad764..b4a71aefd43 100644
--- a/clippy_lints/src/strings.rs
+++ b/clippy_lints/src/strings.rs
@@ -381,7 +381,7 @@ declare_clippy_lint! {
 
 declare_lint_pass!(StrToString => [STR_TO_STRING]);
 
-impl LateLintPass<'_> for StrToString {
+impl<'tcx> LateLintPass<'tcx> for StrToString {
     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &Expr<'_>) {
         if_chain! {
             if let ExprKind::MethodCall(path, _, [self_arg, ..], _) = &expr.kind;
@@ -431,7 +431,7 @@ declare_clippy_lint! {
 
 declare_lint_pass!(StringToString => [STRING_TO_STRING]);
 
-impl LateLintPass<'_> for StringToString {
+impl<'tcx> LateLintPass<'tcx> for StringToString {
     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &Expr<'_>) {
         if_chain! {
             if let ExprKind::MethodCall(path, _, [self_arg, ..], _) = &expr.kind;
diff --git a/clippy_lints/src/strlen_on_c_strings.rs b/clippy_lints/src/strlen_on_c_strings.rs
index fee01fb0bd1..d6e948a7560 100644
--- a/clippy_lints/src/strlen_on_c_strings.rs
+++ b/clippy_lints/src/strlen_on_c_strings.rs
@@ -39,7 +39,7 @@ declare_clippy_lint! {
 
 declare_lint_pass!(StrlenOnCStrings => [STRLEN_ON_C_STRINGS]);
 
-impl LateLintPass<'tcx> for StrlenOnCStrings {
+impl<'tcx> LateLintPass<'tcx> for StrlenOnCStrings {
     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
         if_chain! {
             if !expr.span.from_expansion();
diff --git a/clippy_lints/src/suspicious_operation_groupings.rs b/clippy_lints/src/suspicious_operation_groupings.rs
index faf43fd9fc1..ca725918e87 100644
--- a/clippy_lints/src/suspicious_operation_groupings.rs
+++ b/clippy_lints/src/suspicious_operation_groupings.rs
@@ -355,7 +355,7 @@ struct BinaryOp<'exprs> {
     right: &'exprs Expr,
 }
 
-impl BinaryOp<'exprs> {
+impl<'exprs> BinaryOp<'exprs> {
     fn new(op: BinOpKind, span: Span, (left, right): (&'exprs Expr, &'exprs Expr)) -> Self {
         Self { op, span, left, right }
     }
@@ -419,7 +419,7 @@ fn chained_binops(kind: &ExprKind) -> Option<Vec<BinaryOp<'_>>> {
     }
 }
 
-fn chained_binops_helper(left_outer: &'expr Expr, right_outer: &'expr Expr) -> Option<Vec<BinaryOp<'expr>>> {
+fn chained_binops_helper<'expr>(left_outer: &'expr Expr, right_outer: &'expr Expr) -> Option<Vec<BinaryOp<'expr>>> {
     match (&left_outer.kind, &right_outer.kind) {
         (
             ExprKind::Paren(ref left_e) | ExprKind::Unary(_, ref left_e),
diff --git a/clippy_lints/src/trailing_empty_array.rs b/clippy_lints/src/trailing_empty_array.rs
index af36f726700..c9b2ce476e8 100644
--- a/clippy_lints/src/trailing_empty_array.rs
+++ b/clippy_lints/src/trailing_empty_array.rs
@@ -53,13 +53,12 @@ impl<'tcx> LateLintPass<'tcx> for TrailingEmptyArray {
     }
 }
 
-fn is_struct_with_trailing_zero_sized_array(cx: &LateContext<'tcx>, item: &'tcx Item<'tcx>) -> bool {
+fn is_struct_with_trailing_zero_sized_array(cx: &LateContext<'_>, item: &Item<'_>) -> bool {
     if_chain! {
         // First check if last field is an array
         if let ItemKind::Struct(data, _) = &item.kind;
         if let Some(last_field) = data.fields().last();
-        if let rustc_hir::TyKind::Array(_, length) = last_field.ty.kind;
-        if let rustc_hir::ArrayLen::Body(length) = length;
+        if let rustc_hir::TyKind::Array(_, rustc_hir::ArrayLen::Body(length)) = last_field.ty.kind;
 
         // Then check if that that array zero-sized
         let length_ldid = cx.tcx.hir().local_def_id(length.hir_id);
diff --git a/clippy_lints/src/trait_bounds.rs b/clippy_lints/src/trait_bounds.rs
index fb4abceac25..6369aafe3f9 100644
--- a/clippy_lints/src/trait_bounds.rs
+++ b/clippy_lints/src/trait_bounds.rs
@@ -1,11 +1,16 @@
 use clippy_utils::diagnostics::span_lint_and_help;
 use clippy_utils::source::{snippet, snippet_with_applicability};
-use clippy_utils::SpanlessHash;
+use clippy_utils::{SpanlessEq, SpanlessHash};
+use core::hash::{Hash, Hasher};
 use if_chain::if_chain;
-use rustc_data_structures::fx::FxHashMap;
+use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 use rustc_data_structures::unhash::UnhashMap;
 use rustc_errors::Applicability;
-use rustc_hir::{def::Res, GenericBound, Generics, ParamName, Path, QPath, TyKind, WherePredicate};
+use rustc_hir::def::Res;
+use rustc_hir::{
+    GenericBound, Generics, Item, ItemKind, Node, ParamName, Path, PathSegment, QPath, TraitItem, Ty, TyKind,
+    WherePredicate,
+};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_session::{declare_tool_lint, impl_lint_pass};
 use rustc_span::Span;
@@ -83,6 +88,53 @@ impl<'tcx> LateLintPass<'tcx> for TraitBounds {
         self.check_type_repetition(cx, gen);
         check_trait_bound_duplication(cx, gen);
     }
+
+    fn check_trait_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx TraitItem<'tcx>) {
+        let Generics { where_clause, .. } = &item.generics;
+        let mut self_bounds_set = FxHashSet::default();
+
+        for predicate in where_clause.predicates {
+            if_chain! {
+                if let WherePredicate::BoundPredicate(ref bound_predicate) = predicate;
+                if !bound_predicate.span.from_expansion();
+                if let TyKind::Path(QPath::Resolved(_, Path { segments, .. })) = bound_predicate.bounded_ty.kind;
+                if let Some(PathSegment { res: Some(Res::SelfTy(Some(def_id), _)), .. }) = segments.first();
+
+                if let Some(
+                    Node::Item(
+                        Item {
+                            kind: ItemKind::Trait(_, _, _, self_bounds, _),
+                            .. }
+                        )
+                    ) = cx.tcx.hir().get_if_local(*def_id);
+                then {
+                    if self_bounds_set.is_empty() {
+                        for bound in self_bounds.iter() {
+                            let Some((self_res, _)) = get_trait_res_span_from_bound(bound) else { continue };
+                            self_bounds_set.insert(self_res);
+                        }
+                    }
+
+                    bound_predicate
+                        .bounds
+                        .iter()
+                        .filter_map(get_trait_res_span_from_bound)
+                        .for_each(|(trait_item_res, span)| {
+                            if self_bounds_set.get(&trait_item_res).is_some() {
+                                span_lint_and_help(
+                                    cx,
+                                    TRAIT_DUPLICATION_IN_BOUNDS,
+                                    span,
+                                    "this trait bound is already specified in trait declaration",
+                                    None,
+                                    "consider removing this trait bound",
+                                );
+                            }
+                        });
+                }
+            }
+        }
+    }
 }
 
 fn get_trait_res_span_from_bound(bound: &GenericBound<'_>) -> Option<(Res, Span)> {
@@ -94,24 +146,40 @@ fn get_trait_res_span_from_bound(bound: &GenericBound<'_>) -> Option<(Res, Span)
 }
 
 impl TraitBounds {
-    fn check_type_repetition(self, cx: &LateContext<'_>, gen: &'_ Generics<'_>) {
+    fn check_type_repetition<'tcx>(self, cx: &LateContext<'tcx>, gen: &'tcx Generics<'_>) {
+        struct SpanlessTy<'cx, 'tcx> {
+            ty: &'tcx Ty<'tcx>,
+            cx: &'cx LateContext<'tcx>,
+        }
+        impl PartialEq for SpanlessTy<'_, '_> {
+            fn eq(&self, other: &Self) -> bool {
+                let mut eq = SpanlessEq::new(self.cx);
+                eq.inter_expr().eq_ty(self.ty, other.ty)
+            }
+        }
+        impl Hash for SpanlessTy<'_, '_> {
+            fn hash<H: Hasher>(&self, h: &mut H) {
+                let mut t = SpanlessHash::new(self.cx);
+                t.hash_ty(self.ty);
+                h.write_u64(t.finish());
+            }
+        }
+        impl Eq for SpanlessTy<'_, '_> {}
+
         if gen.span.from_expansion() {
             return;
         }
-        let hash = |ty| -> u64 {
-            let mut hasher = SpanlessHash::new(cx);
-            hasher.hash_ty(ty);
-            hasher.finish()
-        };
-        let mut map: UnhashMap<u64, Vec<&GenericBound<'_>>> = UnhashMap::default();
+        let mut map: UnhashMap<SpanlessTy<'_, '_>, Vec<&GenericBound<'_>>> = UnhashMap::default();
         let mut applicability = Applicability::MaybeIncorrect;
         for bound in gen.where_clause.predicates {
             if_chain! {
                 if let WherePredicate::BoundPredicate(ref p) = bound;
                 if p.bounds.len() as u64 <= self.max_trait_bounds;
                 if !p.span.from_expansion();
-                let h = hash(p.bounded_ty);
-                if let Some(ref v) = map.insert(h, p.bounds.iter().collect::<Vec<_>>());
+                if let Some(ref v) = map.insert(
+                    SpanlessTy { ty: p.bounded_ty, cx },
+                    p.bounds.iter().collect::<Vec<_>>()
+                );
 
                 then {
                     let mut hint_string = format!(
diff --git a/clippy_lints/src/types/mod.rs b/clippy_lints/src/types/mod.rs
index 481e5957435..9d57505e55e 100644
--- a/clippy_lints/src/types/mod.rs
+++ b/clippy_lints/src/types/mod.rs
@@ -167,8 +167,9 @@ declare_clippy_lint! {
     /// Check the [Box documentation](https://doc.rust-lang.org/std/boxed/index.html) for more information.
     ///
     /// ### Why is this bad?
-    /// Any `&Box<T>` can also be a `&T`, which is more
-    /// general.
+    /// A `&Box<T>` parameter requires the function caller to box `T` first before passing it to a function.
+    /// Using `&T` defines a concrete type for the parameter and generalizes the function, this would also
+    /// auto-deref to `&T` at the function call site if passed a `&Box<T>`.
     ///
     /// ### Example
     /// ```rust,ignore
diff --git a/clippy_lints/src/undocumented_unsafe_blocks.rs b/clippy_lints/src/undocumented_unsafe_blocks.rs
index 3d3b4a6679d..697ed267e2f 100644
--- a/clippy_lints/src/undocumented_unsafe_blocks.rs
+++ b/clippy_lints/src/undocumented_unsafe_blocks.rs
@@ -113,8 +113,8 @@ impl LateLintPass<'_> for UndocumentedUnsafeBlocks {
     }
 }
 
-impl<'hir> Visitor<'hir> for UndocumentedUnsafeBlocks {
-    type Map = Map<'hir>;
+impl<'v> Visitor<'v> for UndocumentedUnsafeBlocks {
+    type Map = Map<'v>;
 
     fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
         NestedVisitorMap::None
diff --git a/clippy_lints/src/undropped_manually_drops.rs b/clippy_lints/src/undropped_manually_drops.rs
index c58fa67a023..7557e14d11f 100644
--- a/clippy_lints/src/undropped_manually_drops.rs
+++ b/clippy_lints/src/undropped_manually_drops.rs
@@ -36,7 +36,7 @@ declare_clippy_lint! {
 
 declare_lint_pass!(UndroppedManuallyDrops => [UNDROPPED_MANUALLY_DROPS]);
 
-impl LateLintPass<'tcx> for UndroppedManuallyDrops {
+impl<'tcx> LateLintPass<'tcx> for UndroppedManuallyDrops {
     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
         if let Some([arg_0, ..]) = match_function_call(cx, expr, &paths::DROP) {
             let ty = cx.typeck_results().expr_ty(arg_0);
diff --git a/clippy_lints/src/uninit_vec.rs b/clippy_lints/src/uninit_vec.rs
index 46cc76b150e..2ffaf24f942 100644
--- a/clippy_lints/src/uninit_vec.rs
+++ b/clippy_lints/src/uninit_vec.rs
@@ -78,7 +78,7 @@ impl<'tcx> LateLintPass<'tcx> for UninitVec {
     }
 }
 
-fn handle_uninit_vec_pair(
+fn handle_uninit_vec_pair<'tcx>(
     cx: &LateContext<'tcx>,
     maybe_init_or_reserve: &'tcx Stmt<'tcx>,
     maybe_set_len: &'tcx Expr<'tcx>,
@@ -196,7 +196,7 @@ fn is_reserve(cx: &LateContext<'_>, path: &PathSegment<'_>, self_expr: &Expr<'_>
 }
 
 /// Returns self if the expression is `Vec::set_len()`
-fn extract_set_len_self(cx: &LateContext<'_>, expr: &'tcx Expr<'_>) -> Option<(&'tcx Expr<'tcx>, Span)> {
+fn extract_set_len_self<'tcx>(cx: &LateContext<'_>, expr: &'tcx Expr<'_>) -> Option<(&'tcx Expr<'tcx>, Span)> {
     // peel unsafe blocks in `unsafe { vec.set_len() }`
     let expr = peel_hir_expr_while(expr, |e| {
         if let ExprKind::Block(block, _) = e.kind {
diff --git a/clippy_lints/src/unit_hash.rs b/clippy_lints/src/unit_hash.rs
index 26b4e0f58a8..dcf8a9d7c84 100644
--- a/clippy_lints/src/unit_hash.rs
+++ b/clippy_lints/src/unit_hash.rs
@@ -46,7 +46,7 @@ declare_clippy_lint! {
 }
 declare_lint_pass!(UnitHash => [UNIT_HASH]);
 
-impl LateLintPass<'tcx> for UnitHash {
+impl<'tcx> LateLintPass<'tcx> for UnitHash {
     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) {
         if_chain! {
             if let ExprKind::MethodCall(name_ident, _, args, _) = &expr.kind;
diff --git a/clippy_lints/src/unit_types/unit_cmp.rs b/clippy_lints/src/unit_types/unit_cmp.rs
index 6d9aff47421..1dd8895ebd0 100644
--- a/clippy_lints/src/unit_types/unit_cmp.rs
+++ b/clippy_lints/src/unit_types/unit_cmp.rs
@@ -1,35 +1,29 @@
 use clippy_utils::diagnostics::span_lint;
+use clippy_utils::macros::{find_assert_eq_args, root_macro_call_first_node};
 use rustc_hir::{BinOpKind, Expr, ExprKind};
 use rustc_lint::LateContext;
-use rustc_span::hygiene::{ExpnKind, MacroKind};
 
 use super::UNIT_CMP;
 
 pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>) {
     if expr.span.from_expansion() {
-        if let Some(callee) = expr.span.source_callee() {
-            if let ExpnKind::Macro(MacroKind::Bang, symbol) = callee.kind {
-                if let ExprKind::Binary(ref cmp, left, _) = expr.kind {
-                    let op = cmp.node;
-                    if op.is_comparison() && cx.typeck_results().expr_ty(left).is_unit() {
-                        let result = match symbol.as_str() {
-                            "assert_eq" | "debug_assert_eq" => "succeed",
-                            "assert_ne" | "debug_assert_ne" => "fail",
-                            _ => return,
-                        };
-                        span_lint(
-                            cx,
-                            UNIT_CMP,
-                            expr.span,
-                            &format!(
-                                "`{}` of unit values detected. This will always {}",
-                                symbol.as_str(),
-                                result
-                            ),
-                        );
-                    }
-                }
+        if let Some(macro_call) = root_macro_call_first_node(cx, expr) {
+            let macro_name = cx.tcx.item_name(macro_call.def_id);
+            let result = match macro_name.as_str() {
+                "assert_eq" | "debug_assert_eq" => "succeed",
+                "assert_ne" | "debug_assert_ne" => "fail",
+                _ => return,
+            };
+            let Some ((left, _, _)) = find_assert_eq_args(cx, expr, macro_call.expn) else { return };
+            if !cx.typeck_results().expr_ty(left).is_unit() {
+                return;
             }
+            span_lint(
+                cx,
+                UNIT_CMP,
+                macro_call.span,
+                &format!("`{}` of unit values detected. This will always {}", macro_name, result),
+            );
         }
         return;
     }
diff --git a/clippy_lints/src/unused_io_amount.rs b/clippy_lints/src/unused_io_amount.rs
index 004530db086..287ac5b4a90 100644
--- a/clippy_lints/src/unused_io_amount.rs
+++ b/clippy_lints/src/unused_io_amount.rs
@@ -1,4 +1,4 @@
-use clippy_utils::diagnostics::span_lint;
+use clippy_utils::diagnostics::{span_lint, span_lint_and_help};
 use clippy_utils::{is_try, match_trait_method, paths};
 use rustc_hir as hir;
 use rustc_lint::{LateContext, LateLintPass};
@@ -17,10 +17,17 @@ declare_clippy_lint! {
     /// partial-write/read, use
     /// `write_all`/`read_exact` instead.
     ///
+    /// When working with asynchronous code (either with the `futures`
+    /// crate or with `tokio`), a similar issue exists for
+    /// `AsyncWriteExt::write()` and `AsyncReadExt::read()` : these
+    /// functions are also not guaranteed to process the entire
+    /// buffer.  Your code should either handle partial-writes/reads, or
+    /// call the `write_all`/`read_exact` methods on those traits instead.
+    ///
     /// ### Known problems
     /// Detects only common patterns.
     ///
-    /// ### Example
+    /// ### Examples
     /// ```rust,ignore
     /// use std::io;
     /// fn foo<W: io::Write>(w: &mut W) -> io::Result<()> {
@@ -68,6 +75,23 @@ impl<'tcx> LateLintPass<'tcx> for UnusedIoAmount {
     }
 }
 
+/// If `expr` is an (e).await, return the inner expression "e" that's being
+/// waited on.  Otherwise return None.
+fn try_remove_await<'a>(expr: &'a hir::Expr<'a>) -> Option<&hir::Expr<'a>> {
+    if let hir::ExprKind::Match(expr, _, hir::MatchSource::AwaitDesugar) = expr.kind {
+        if let hir::ExprKind::Call(func, [ref arg_0, ..]) = expr.kind {
+            if matches!(
+                func.kind,
+                hir::ExprKind::Path(hir::QPath::LangItem(hir::LangItem::IntoFutureIntoFuture, ..))
+            ) {
+                return Some(arg_0);
+            }
+        }
+    }
+
+    None
+}
+
 fn check_map_error(cx: &LateContext<'_>, call: &hir::Expr<'_>, expr: &hir::Expr<'_>) {
     let mut call = call;
     while let hir::ExprKind::MethodCall(path, _, args, _) = call.kind {
@@ -77,30 +101,69 @@ fn check_map_error(cx: &LateContext<'_>, call: &hir::Expr<'_>, expr: &hir::Expr<
             break;
         }
     }
-    check_method_call(cx, call, expr);
+
+    if let Some(call) = try_remove_await(call) {
+        check_method_call(cx, call, expr, true);
+    } else {
+        check_method_call(cx, call, expr, false);
+    }
 }
 
-fn check_method_call(cx: &LateContext<'_>, call: &hir::Expr<'_>, expr: &hir::Expr<'_>) {
+fn check_method_call(cx: &LateContext<'_>, call: &hir::Expr<'_>, expr: &hir::Expr<'_>, is_await: bool) {
     if let hir::ExprKind::MethodCall(path, _, _, _) = call.kind {
         let symbol = path.ident.as_str();
-        let read_trait = match_trait_method(cx, call, &paths::IO_READ);
-        let write_trait = match_trait_method(cx, call, &paths::IO_WRITE);
+        let read_trait = if is_await {
+            match_trait_method(cx, call, &paths::FUTURES_IO_ASYNCREADEXT)
+                || match_trait_method(cx, call, &paths::TOKIO_IO_ASYNCREADEXT)
+        } else {
+            match_trait_method(cx, call, &paths::IO_READ)
+        };
+        let write_trait = if is_await {
+            match_trait_method(cx, call, &paths::FUTURES_IO_ASYNCWRITEEXT)
+                || match_trait_method(cx, call, &paths::TOKIO_IO_ASYNCWRITEEXT)
+        } else {
+            match_trait_method(cx, call, &paths::IO_WRITE)
+        };
 
-        match (read_trait, write_trait, symbol) {
-            (true, _, "read") => span_lint(
+        match (read_trait, write_trait, symbol, is_await) {
+            (true, _, "read", false) => span_lint_and_help(
+                cx,
+                UNUSED_IO_AMOUNT,
+                expr.span,
+                "read amount is not handled",
+                None,
+                "use `Read::read_exact` instead, or handle partial reads",
+            ),
+            (true, _, "read", true) => span_lint_and_help(
                 cx,
                 UNUSED_IO_AMOUNT,
                 expr.span,
-                "read amount is not handled. Use `Read::read_exact` instead",
+                "read amount is not handled",
+                None,
+                "use `AsyncReadExt::read_exact` instead, or handle partial reads",
             ),
-            (true, _, "read_vectored") => span_lint(cx, UNUSED_IO_AMOUNT, expr.span, "read amount is not handled"),
-            (_, true, "write") => span_lint(
+            (true, _, "read_vectored", _) => {
+                span_lint(cx, UNUSED_IO_AMOUNT, expr.span, "read amount is not handled");
+            },
+            (_, true, "write", false) => span_lint_and_help(
                 cx,
                 UNUSED_IO_AMOUNT,
                 expr.span,
-                "written amount is not handled. Use `Write::write_all` instead",
+                "written amount is not handled",
+                None,
+                "use `Write::write_all` instead, or handle partial writes",
             ),
-            (_, true, "write_vectored") => span_lint(cx, UNUSED_IO_AMOUNT, expr.span, "written amount is not handled"),
+            (_, true, "write", true) => span_lint_and_help(
+                cx,
+                UNUSED_IO_AMOUNT,
+                expr.span,
+                "written amount is not handled",
+                None,
+                "use `AsyncWriteExt::write_all` instead, or handle partial writes",
+            ),
+            (_, true, "write_vectored", _) => {
+                span_lint(cx, UNUSED_IO_AMOUNT, expr.span, "written amount is not handled");
+            },
             _ => (),
         }
     }
diff --git a/clippy_lints/src/utils/author.rs b/clippy_lints/src/utils/author.rs
index 9b06ca4e824..7751c593e43 100644
--- a/clippy_lints/src/utils/author.rs
+++ b/clippy_lints/src/utils/author.rs
@@ -573,7 +573,7 @@ impl<'a, 'tcx> PrintVisitor<'a, 'tcx> {
                         bind!(self, anon_const);
                         out!("if let ArrayLen::Body({anon_const}) = {length};");
                         self.body(field!(anon_const.body));
-                    }
+                    },
                 }
             },
             ExprKind::Err => kind!("Err"),
diff --git a/clippy_lints/src/utils/conf.rs b/clippy_lints/src/utils/conf.rs
index 9c83d30eb9c..d6deb50cc90 100644
--- a/clippy_lints/src/utils/conf.rs
+++ b/clippy_lints/src/utils/conf.rs
@@ -23,6 +23,14 @@ pub enum DisallowedMethod {
     WithReason { path: String, reason: Option<String> },
 }
 
+impl DisallowedMethod {
+    pub fn path(&self) -> &str {
+        let (Self::Simple(path) | Self::WithReason { path, .. }) = self;
+
+        path
+    }
+}
+
 /// A single disallowed type, used by the `DISALLOWED_TYPES` lint.
 #[derive(Clone, Debug, Deserialize)]
 #[serde(untagged)]
@@ -113,7 +121,7 @@ macro_rules! define_Conf {
             }
         }
 
-        #[cfg(feature = "metadata-collector-lint")]
+        #[cfg(feature = "internal")]
         pub mod metadata {
             use crate::utils::internal_lints::metadata_collector::ClippyConfiguration;
 
diff --git a/clippy_lints/src/utils/inspector.rs b/clippy_lints/src/utils/inspector.rs
index c96766e5678..e90b6b73b34 100644
--- a/clippy_lints/src/utils/inspector.rs
+++ b/clippy_lints/src/utils/inspector.rs
@@ -342,8 +342,8 @@ fn print_expr(cx: &LateContext<'_>, expr: &hir::Expr<'_>, indent: usize) {
             match length {
                 hir::ArrayLen::Infer(_, _) => println!("{}repeat count: _", ind),
                 hir::ArrayLen::Body(anon_const) => {
-                    print_expr(cx, &cx.tcx.hir().body(anon_const.body).value, indent + 1)
-                }
+                    print_expr(cx, &cx.tcx.hir().body(anon_const.body).value, indent + 1);
+                },
             }
         },
         hir::ExprKind::Err => {
diff --git a/clippy_lints/src/utils/internal_lints.rs b/clippy_lints/src/utils/internal_lints.rs
index 7d196af7a53..9c3dcc8e96a 100644
--- a/clippy_lints/src/utils/internal_lints.rs
+++ b/clippy_lints/src/utils/internal_lints.rs
@@ -1,5 +1,6 @@
 use clippy_utils::consts::{constant_simple, Constant};
 use clippy_utils::diagnostics::{span_lint, span_lint_and_help, span_lint_and_sugg, span_lint_and_then};
+use clippy_utils::macros::root_macro_call_first_node;
 use clippy_utils::source::snippet;
 use clippy_utils::ty::match_type;
 use clippy_utils::{
@@ -34,7 +35,7 @@ use rustc_typeck::hir_ty_to_ty;
 
 use std::borrow::{Borrow, Cow};
 
-#[cfg(feature = "metadata-collector-lint")]
+#[cfg(feature = "internal")]
 pub mod metadata_collector;
 
 declare_clippy_lint! {
@@ -410,9 +411,13 @@ impl<'tcx> LateLintPass<'tcx> for LintWithoutLintPass {
                 }
                 self.declared_lints.insert(item.ident.name, item.span);
             }
-        } else if is_expn_of(item.span, "impl_lint_pass").is_some()
-            || is_expn_of(item.span, "declare_lint_pass").is_some()
-        {
+        } else if let Some(macro_call) = root_macro_call_first_node(cx, item) {
+            if !matches!(
+                &*cx.tcx.item_name(macro_call.def_id).as_str(),
+                "impl_lint_pass" | "declare_lint_pass"
+            ) {
+                return;
+            }
             if let hir::ItemKind::Impl(hir::Impl {
                 of_trait: None,
                 items: impl_item_refs,
@@ -924,9 +929,20 @@ pub fn check_path(cx: &LateContext<'_>, path: &[&str]) -> bool {
         let lang_item_path = cx.get_def_path(*item_def_id);
         if path_syms.starts_with(&lang_item_path) {
             if let [item] = &path_syms[lang_item_path.len()..] {
-                for child in cx.tcx.module_children(*item_def_id) {
-                    if child.ident.name == *item {
-                        return true;
+                if matches!(
+                    cx.tcx.def_kind(*item_def_id),
+                    DefKind::Mod | DefKind::Enum | DefKind::Trait
+                ) {
+                    for child in cx.tcx.module_children(*item_def_id) {
+                        if child.ident.name == *item {
+                            return true;
+                        }
+                    }
+                } else {
+                    for child in cx.tcx.associated_item_def_ids(*item_def_id) {
+                        if cx.tcx.item_name(*child) == *item {
+                            return true;
+                        }
                     }
                 }
             }
diff --git a/clippy_lints/src/utils/internal_lints/metadata_collector.rs b/clippy_lints/src/utils/internal_lints/metadata_collector.rs
index 7707eebd622..4e46d79dc08 100644
--- a/clippy_lints/src/utils/internal_lints/metadata_collector.rs
+++ b/clippy_lints/src/utils/internal_lints/metadata_collector.rs
@@ -1,8 +1,7 @@
 //! This lint is used to collect metadata about clippy lints. This metadata is exported as a json
 //! file and then used to generate the [clippy lint list](https://rust-lang.github.io/rust-clippy/master/index.html)
 //!
-//! This module and therefor the entire lint is guarded by a feature flag called
-//! `metadata-collector-lint`
+//! This module and therefore the entire lint is guarded by a feature flag called `internal`
 //!
 //! The module transforms all lint names to ascii lowercase to ensure that we don't have mismatches
 //! during any comparison or mapping. (Please take care of this, it's not fun to spend time on such
@@ -578,7 +577,7 @@ fn get_lint_version(cx: &LateContext<'_>, item: &Item<'_>) -> String {
 fn get_lint_group_and_level_or_lint(
     cx: &LateContext<'_>,
     lint_name: &str,
-    item: &'hir Item<'_>,
+    item: &Item<'_>,
 ) -> Option<(String, &'static str)> {
     let result = cx
         .lint_store
@@ -697,20 +696,20 @@ fn extract_emission_info<'hir>(
 }
 
 /// Resolves the possible lints that this expression could reference
-fn resolve_lints(cx: &LateContext<'hir>, expr: &'hir hir::Expr<'hir>) -> Vec<String> {
+fn resolve_lints<'hir>(cx: &LateContext<'hir>, expr: &'hir hir::Expr<'hir>) -> Vec<String> {
     let mut resolver = LintResolver::new(cx);
     resolver.visit_expr(expr);
     resolver.lints
 }
 
 /// This function tries to resolve the linked applicability to the given expression.
-fn resolve_applicability(cx: &LateContext<'hir>, expr: &'hir hir::Expr<'hir>) -> Option<usize> {
+fn resolve_applicability<'hir>(cx: &LateContext<'hir>, expr: &'hir hir::Expr<'hir>) -> Option<usize> {
     let mut resolver = ApplicabilityResolver::new(cx);
     resolver.visit_expr(expr);
     resolver.complete()
 }
 
-fn check_is_multi_part(cx: &LateContext<'hir>, closure_expr: &'hir hir::Expr<'hir>) -> bool {
+fn check_is_multi_part<'hir>(cx: &LateContext<'hir>, closure_expr: &'hir hir::Expr<'hir>) -> bool {
     if let ExprKind::Closure(_, _, body_id, _, _) = closure_expr.kind {
         let mut scanner = IsMultiSpanScanner::new(cx);
         intravisit::walk_body(&mut scanner, cx.tcx.hir().body(body_id));
@@ -825,7 +824,7 @@ impl<'a, 'hir> intravisit::Visitor<'hir> for ApplicabilityResolver<'a, 'hir> {
 }
 
 /// This returns the parent local node if the expression is a reference one
-fn get_parent_local(cx: &LateContext<'hir>, expr: &'hir hir::Expr<'hir>) -> Option<&'hir hir::Local<'hir>> {
+fn get_parent_local<'hir>(cx: &LateContext<'hir>, expr: &'hir hir::Expr<'hir>) -> Option<&'hir hir::Local<'hir>> {
     if let ExprKind::Path(QPath::Resolved(_, path)) = expr.kind {
         if let hir::def::Res::Local(local_hir) = path.res {
             return get_parent_local_hir_id(cx, local_hir);
@@ -835,7 +834,7 @@ fn get_parent_local(cx: &LateContext<'hir>, expr: &'hir hir::Expr<'hir>) -> Opti
     None
 }
 
-fn get_parent_local_hir_id(cx: &LateContext<'hir>, hir_id: hir::HirId) -> Option<&'hir hir::Local<'hir>> {
+fn get_parent_local_hir_id<'hir>(cx: &LateContext<'hir>, hir_id: hir::HirId) -> Option<&'hir hir::Local<'hir>> {
     let map = cx.tcx.hir();
 
     match map.find(map.get_parent_node(hir_id)) {
diff --git a/clippy_lints/src/utils/mod.rs b/clippy_lints/src/utils/mod.rs
index b67448e3a57..dc385ebacba 100644
--- a/clippy_lints/src/utils/mod.rs
+++ b/clippy_lints/src/utils/mod.rs
@@ -1,5 +1,5 @@
 pub mod author;
 pub mod conf;
 pub mod inspector;
-#[cfg(any(feature = "internal-lints", feature = "metadata-collector-lint"))]
+#[cfg(feature = "internal")]
 pub mod internal_lints;
diff --git a/clippy_lints/src/vec_init_then_push.rs b/clippy_lints/src/vec_init_then_push.rs
index 1bc0eb6303c..43474da3450 100644
--- a/clippy_lints/src/vec_init_then_push.rs
+++ b/clippy_lints/src/vec_init_then_push.rs
@@ -77,7 +77,7 @@ impl VecPushSearcher {
     }
 }
 
-impl LateLintPass<'_> for VecInitThenPush {
+impl<'tcx> LateLintPass<'tcx> for VecInitThenPush {
     fn check_block(&mut self, _: &LateContext<'tcx>, _: &'tcx Block<'tcx>) {
         self.searcher = None;
     }