about summary refs log tree commit diff
path: root/clippy_lints/src
diff options
context:
space:
mode:
authorflip1995 <philipp.krones@embecosm.com>2022-05-05 15:12:52 +0100
committerflip1995 <philipp.krones@embecosm.com>2022-05-05 15:12:52 +0100
commit7cd86aa1be18d608d828239c11e887a762efc92a (patch)
treef2f098e889406b343beba0dbbf58e492c4e5dff6 /clippy_lints/src
parent82f469f81b6daafb448e36c0e811cf2d40836edb (diff)
Merge commit '7c21f91b15b7604f818565646b686d90f99d1baf' into clippyup
Diffstat (limited to 'clippy_lints/src')
-rw-r--r--clippy_lints/src/attrs.rs19
-rw-r--r--clippy_lints/src/await_holding_invalid.rs167
-rw-r--r--clippy_lints/src/bytes_count_to_len.rs70
-rw-r--r--clippy_lints/src/case_sensitive_file_extension_comparisons.rs4
-rw-r--r--clippy_lints/src/casts/cast_possible_truncation.rs20
-rw-r--r--clippy_lints/src/casts/cast_slice_different_sizes.rs110
-rw-r--r--clippy_lints/src/casts/mod.rs3
-rw-r--r--clippy_lints/src/collapsible_if.rs18
-rw-r--r--clippy_lints/src/doc.rs10
-rw-r--r--clippy_lints/src/drop_forget_ref.rs2
-rw-r--r--clippy_lints/src/empty_drop.rs65
-rw-r--r--clippy_lints/src/empty_structs_with_brackets.rs2
-rw-r--r--clippy_lints/src/eta_reduction.rs7
-rw-r--r--clippy_lints/src/format_push_string.rs77
-rw-r--r--clippy_lints/src/functions/must_use.rs9
-rw-r--r--clippy_lints/src/functions/result_unit_err.rs2
-rw-r--r--clippy_lints/src/identity_op.rs82
-rw-r--r--clippy_lints/src/implicit_hasher.rs4
-rw-r--r--clippy_lints/src/inconsistent_struct_constructor.rs3
-rw-r--r--clippy_lints/src/index_refutable_slice.rs2
-rw-r--r--clippy_lints/src/inherent_impl.rs2
-rw-r--r--clippy_lints/src/init_numbered_fields.rs2
-rw-r--r--clippy_lints/src/large_include_file.rs86
-rw-r--r--clippy_lints/src/lib.register_all.rs10
-rw-r--r--clippy_lints/src/lib.register_complexity.rs3
-rw-r--r--clippy_lints/src/lib.register_lints.rs10
-rw-r--r--clippy_lints/src/lib.register_nursery.rs3
-rw-r--r--clippy_lints/src/lib.register_pedantic.rs4
-rw-r--r--clippy_lints/src/lib.register_perf.rs2
-rw-r--r--clippy_lints/src/lib.register_restriction.rs3
-rw-r--r--clippy_lints/src/lib.register_style.rs4
-rw-r--r--clippy_lints/src/lib.register_suspicious.rs1
-rw-r--r--clippy_lints/src/lib.rs68
-rw-r--r--clippy_lints/src/lifetimes.rs72
-rw-r--r--clippy_lints/src/literal_representation.rs50
-rw-r--r--clippy_lints/src/loops/never_loop.rs5
-rw-r--r--clippy_lints/src/manual_bits.rs48
-rw-r--r--clippy_lints/src/manual_non_exhaustive.rs197
-rw-r--r--clippy_lints/src/map_clone.rs12
-rw-r--r--clippy_lints/src/match_result_ok.rs4
-rw-r--r--clippy_lints/src/matches/infallible_destructuring_match.rs (renamed from clippy_lints/src/matches/infalliable_detructuring_match.rs)0
-rw-r--r--clippy_lints/src/matches/match_same_arms.rs4
-rw-r--r--clippy_lints/src/matches/mod.rs9
-rw-r--r--clippy_lints/src/matches/needless_match.rs6
-rw-r--r--clippy_lints/src/matches/redundant_pattern_match.rs66
-rw-r--r--clippy_lints/src/matches/rest_pat_in_fully_bound_struct.rs1
-rw-r--r--clippy_lints/src/methods/is_digit_ascii_radix.rs50
-rw-r--r--clippy_lints/src/methods/iter_with_drain.rs91
-rw-r--r--clippy_lints/src/methods/mod.rs109
-rw-r--r--clippy_lints/src/methods/needless_option_take.rs41
-rw-r--r--clippy_lints/src/methods/str_splitn.rs413
-rw-r--r--clippy_lints/src/methods/unnecessary_to_owned.rs23
-rw-r--r--clippy_lints/src/methods/wrong_self_convention.rs2
-rw-r--r--clippy_lints/src/misc_early/mod.rs2
-rw-r--r--clippy_lints/src/missing_inline.rs4
-rw-r--r--clippy_lints/src/needless_bitwise_bool.rs4
-rw-r--r--clippy_lints/src/needless_late_init.rs54
-rw-r--r--clippy_lints/src/new_without_default.rs2
-rw-r--r--clippy_lints/src/non_expressive_names.rs2
-rw-r--r--clippy_lints/src/octal_escapes.rs2
-rw-r--r--clippy_lints/src/only_used_in_recursion.rs56
-rw-r--r--clippy_lints/src/option_if_let_else.rs8
-rw-r--r--clippy_lints/src/ptr.rs81
-rw-r--r--clippy_lints/src/pub_use.rs56
-rw-r--r--clippy_lints/src/redundant_pub_crate.rs21
-rw-r--r--clippy_lints/src/renamed_lints.rs39
-rw-r--r--clippy_lints/src/same_name_method.rs200
-rw-r--r--clippy_lints/src/stable_sort_primitive.rs20
-rw-r--r--clippy_lints/src/strings.rs56
-rw-r--r--clippy_lints/src/suspicious_operation_groupings.rs2
-rw-r--r--clippy_lints/src/trait_bounds.rs15
-rw-r--r--clippy_lints/src/transmute/utils.rs20
-rw-r--r--clippy_lints/src/types/mod.rs4
-rw-r--r--clippy_lints/src/undocumented_unsafe_blocks.rs7
-rw-r--r--clippy_lints/src/unit_types/let_unit_value.rs80
-rw-r--r--clippy_lints/src/unit_types/mod.rs2
-rw-r--r--clippy_lints/src/unnecessary_owned_empty_strings.rs81
-rw-r--r--clippy_lints/src/unnested_or_patterns.rs14
-rw-r--r--clippy_lints/src/use_self.rs2
-rw-r--r--clippy_lints/src/utils/author.rs2
-rw-r--r--clippy_lints/src/utils/conf.rs6
-rw-r--r--clippy_lints/src/utils/dump_hir.rs55
-rw-r--r--clippy_lints/src/utils/inspector.rs577
-rw-r--r--clippy_lints/src/utils/internal_lints.rs4
-rw-r--r--clippy_lints/src/utils/internal_lints/metadata_collector.rs8
-rw-r--r--clippy_lints/src/utils/mod.rs2
86 files changed, 2096 insertions, 1469 deletions
diff --git a/clippy_lints/src/attrs.rs b/clippy_lints/src/attrs.rs
index d0b03c0a9c2..8b0e11cb802 100644
--- a/clippy_lints/src/attrs.rs
+++ b/clippy_lints/src/attrs.rs
@@ -6,7 +6,7 @@ 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, meets_msrv};
 use if_chain::if_chain;
-use rustc_ast::{AttrKind, AttrStyle, Attribute, Lit, LitKind, MetaItemKind, NestedMetaItem};
+use rustc_ast::{AttrKind, AttrStyle, Attribute, Lit, LitKind, MacArgs, MacArgsEq, MetaItemKind, NestedMetaItem};
 use rustc_errors::Applicability;
 use rustc_hir::{
     Block, Expr, ExprKind, ImplItem, ImplItemKind, Item, ItemKind, StmtKind, TraitFn, TraitItem, TraitItemKind,
@@ -335,9 +335,6 @@ impl<'tcx> LateLintPass<'tcx> for Attributes {
                     }
                     if let Some(lint_list) = &attr.meta_item_list() {
                         if attr.ident().map_or(false, |ident| is_lint_level(ident.name)) {
-                            // permit `unused_imports`, `deprecated`, `unreachable_pub`,
-                            // `clippy::wildcard_imports`, and `clippy::enum_glob_use` for `use` items
-                            // and `unused_imports` for `extern crate` items with `macro_use`
                             for lint in lint_list {
                                 match item.kind {
                                     ItemKind::Use(..) => {
@@ -345,10 +342,12 @@ impl<'tcx> LateLintPass<'tcx> for Attributes {
                                             || is_word(lint, sym::deprecated)
                                             || is_word(lint, sym!(unreachable_pub))
                                             || is_word(lint, sym!(unused))
-                                            || extract_clippy_lint(lint)
-                                                .map_or(false, |s| s.as_str() == "wildcard_imports")
-                                            || extract_clippy_lint(lint)
-                                                .map_or(false, |s| s.as_str() == "enum_glob_use")
+                                            || extract_clippy_lint(lint).map_or(false, |s| {
+                                                matches!(
+                                                    s.as_str(),
+                                                    "wildcard_imports" | "enum_glob_use" | "redundant_pub_crate",
+                                                )
+                                            })
                                         {
                                             return;
                                         }
@@ -594,6 +593,10 @@ fn check_empty_line_after_outer_attr(cx: &EarlyContext<'_>, item: &rustc_ast::It
         };
 
         if attr.style == AttrStyle::Outer {
+            if let MacArgs::Eq(_, MacArgsEq::Ast(expr)) = &attr_item.args
+                && !matches!(expr.kind, rustc_ast::ExprKind::Lit(..)) {
+                return;
+            }
             if attr_item.args.inner_tokens().is_empty() || !is_present_in_source(cx, attr.span) {
                 return;
             }
diff --git a/clippy_lints/src/await_holding_invalid.rs b/clippy_lints/src/await_holding_invalid.rs
index 4592ca72748..5b7c4591504 100644
--- a/clippy_lints/src/await_holding_invalid.rs
+++ b/clippy_lints/src/await_holding_invalid.rs
@@ -1,12 +1,15 @@
 use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::{match_def_path, paths};
+use rustc_data_structures::fx::FxHashMap;
 use rustc_hir::def_id::DefId;
-use rustc_hir::{AsyncGeneratorKind, Body, BodyId, GeneratorKind};
+use rustc_hir::{def::Res, AsyncGeneratorKind, Body, BodyId, GeneratorKind};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::ty::GeneratorInteriorTypeCause;
-use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_session::{declare_tool_lint, impl_lint_pass};
 use rustc_span::Span;
 
+use crate::utils::conf::DisallowedType;
+
 declare_clippy_lint! {
     /// ### What it does
     /// Checks for calls to await while holding a non-async-aware MutexGuard.
@@ -127,9 +130,75 @@ declare_clippy_lint! {
     "inside an async function, holding a `RefCell` ref while calling `await`"
 }
 
-declare_lint_pass!(AwaitHolding => [AWAIT_HOLDING_LOCK, AWAIT_HOLDING_REFCELL_REF]);
+declare_clippy_lint! {
+    /// ### What it does
+    /// Allows users to configure types which should not be held across `await`
+    /// suspension points.
+    ///
+    /// ### Why is this bad?
+    /// There are some types which are perfectly "safe" to be used concurrently
+    /// from a memory access perspective but will cause bugs at runtime if they
+    /// are held in such a way.
+    ///
+    /// ### Known problems
+    ///
+    /// ### Example
+    ///
+    /// ```toml
+    /// await-holding-invalid-types = [
+    ///   # You can specify a type name
+    ///   "CustomLockType",
+    ///   # You can (optionally) specify a reason
+    ///   { path = "OtherCustomLockType", reason = "Relies on a thread local" }
+    /// ]
+    /// ```
+    ///
+    /// ```rust
+    /// # async fn baz() {}
+    /// struct CustomLockType;
+    /// struct OtherCustomLockType;
+    /// async fn foo() {
+    ///   let _x = CustomLockType;
+    ///   let _y = OtherCustomLockType;
+    ///   baz().await; // Lint violation
+    /// }
+    /// ```
+    #[clippy::version = "1.49.0"]
+    pub AWAIT_HOLDING_INVALID_TYPE,
+    suspicious,
+    "holding a type across an await point which is not allowed to be held as per the configuration"
+}
+
+impl_lint_pass!(AwaitHolding => [AWAIT_HOLDING_LOCK, AWAIT_HOLDING_REFCELL_REF, AWAIT_HOLDING_INVALID_TYPE]);
+
+#[derive(Debug)]
+pub struct AwaitHolding {
+    conf_invalid_types: Vec<DisallowedType>,
+    def_ids: FxHashMap<DefId, DisallowedType>,
+}
+
+impl AwaitHolding {
+    pub(crate) fn new(conf_invalid_types: Vec<DisallowedType>) -> Self {
+        Self {
+            conf_invalid_types,
+            def_ids: FxHashMap::default(),
+        }
+    }
+}
 
 impl LateLintPass<'_> for AwaitHolding {
+    fn check_crate(&mut self, cx: &LateContext<'_>) {
+        for conf in &self.conf_invalid_types {
+            let path = match conf {
+                DisallowedType::Simple(path) | DisallowedType::WithReason { path, .. } => path,
+            };
+            let segs: Vec<_> = path.split("::").collect();
+            if let Res::Def(_, id) = clippy_utils::def_path_res(cx, &segs) {
+                self.def_ids.insert(id, conf.clone());
+            }
+        }
+    }
+
     fn check_body(&mut self, cx: &LateContext<'_>, body: &'_ Body<'_>) {
         use AsyncGeneratorKind::{Block, Closure, Fn};
         if let Some(GeneratorKind::Async(Block | Closure | Fn)) = body.generator_kind {
@@ -137,7 +206,7 @@ impl LateLintPass<'_> for AwaitHolding {
                 hir_id: body.value.hir_id,
             };
             let typeck_results = cx.tcx.typeck_body(body_id);
-            check_interior_types(
+            self.check_interior_types(
                 cx,
                 typeck_results.generator_interior_types.as_ref().skip_binder(),
                 body.value.span,
@@ -146,46 +215,68 @@ impl LateLintPass<'_> for AwaitHolding {
     }
 }
 
-fn check_interior_types(cx: &LateContext<'_>, ty_causes: &[GeneratorInteriorTypeCause<'_>], span: Span) {
-    for ty_cause in ty_causes {
-        if let rustc_middle::ty::Adt(adt, _) = ty_cause.ty.kind() {
-            if is_mutex_guard(cx, adt.did()) {
-                span_lint_and_then(
-                    cx,
-                    AWAIT_HOLDING_LOCK,
-                    ty_cause.span,
-                    "this `MutexGuard` is held across an `await` point",
-                    |diag| {
-                        diag.help(
-                            "consider using an async-aware `Mutex` type or ensuring the \
+impl AwaitHolding {
+    fn check_interior_types(&self, cx: &LateContext<'_>, ty_causes: &[GeneratorInteriorTypeCause<'_>], span: Span) {
+        for ty_cause in ty_causes {
+            if let rustc_middle::ty::Adt(adt, _) = ty_cause.ty.kind() {
+                if is_mutex_guard(cx, adt.did()) {
+                    span_lint_and_then(
+                        cx,
+                        AWAIT_HOLDING_LOCK,
+                        ty_cause.span,
+                        "this `MutexGuard` is held across an `await` point",
+                        |diag| {
+                            diag.help(
+                                "consider using an async-aware `Mutex` type or ensuring the \
                                 `MutexGuard` is dropped before calling await",
-                        );
-                        diag.span_note(
-                            ty_cause.scope_span.unwrap_or(span),
-                            "these are all the `await` points this lock is held through",
-                        );
-                    },
-                );
-            }
-            if is_refcell_ref(cx, adt.did()) {
-                span_lint_and_then(
-                    cx,
-                    AWAIT_HOLDING_REFCELL_REF,
-                    ty_cause.span,
-                    "this `RefCell` reference is held across an `await` point",
-                    |diag| {
-                        diag.help("ensure the reference is dropped before calling `await`");
-                        diag.span_note(
-                            ty_cause.scope_span.unwrap_or(span),
-                            "these are all the `await` points this reference is held through",
-                        );
-                    },
-                );
+                            );
+                            diag.span_note(
+                                ty_cause.scope_span.unwrap_or(span),
+                                "these are all the `await` points this lock is held through",
+                            );
+                        },
+                    );
+                } else if is_refcell_ref(cx, adt.did()) {
+                    span_lint_and_then(
+                        cx,
+                        AWAIT_HOLDING_REFCELL_REF,
+                        ty_cause.span,
+                        "this `RefCell` reference is held across an `await` point",
+                        |diag| {
+                            diag.help("ensure the reference is dropped before calling `await`");
+                            diag.span_note(
+                                ty_cause.scope_span.unwrap_or(span),
+                                "these are all the `await` points this reference is held through",
+                            );
+                        },
+                    );
+                } else if let Some(disallowed) = self.def_ids.get(&adt.did()) {
+                    emit_invalid_type(cx, ty_cause.span, disallowed);
+                }
             }
         }
     }
 }
 
+fn emit_invalid_type(cx: &LateContext<'_>, span: Span, disallowed: &DisallowedType) {
+    let (type_name, reason) = match disallowed {
+        DisallowedType::Simple(path) => (path, &None),
+        DisallowedType::WithReason { path, reason } => (path, reason),
+    };
+
+    span_lint_and_then(
+        cx,
+        AWAIT_HOLDING_INVALID_TYPE,
+        span,
+        &format!("`{type_name}` may not be held across an `await` point per `clippy.toml`",),
+        |diag| {
+            if let Some(reason) = reason {
+                diag.note(reason.clone());
+            }
+        },
+    );
+}
+
 fn is_mutex_guard(cx: &LateContext<'_>, def_id: DefId) -> bool {
     match_def_path(cx, def_id, &paths::MUTEX_GUARD)
         || match_def_path(cx, def_id, &paths::RWLOCK_READ_GUARD)
diff --git a/clippy_lints/src/bytes_count_to_len.rs b/clippy_lints/src/bytes_count_to_len.rs
new file mode 100644
index 00000000000..d70dbf5b239
--- /dev/null
+++ b/clippy_lints/src/bytes_count_to_len.rs
@@ -0,0 +1,70 @@
+use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::source::snippet_with_applicability;
+use clippy_utils::ty::is_type_diagnostic_item;
+use clippy_utils::{match_def_path, paths};
+use if_chain::if_chain;
+use rustc_errors::Applicability;
+use rustc_hir as hir;
+use rustc_lint::{LateContext, LateLintPass};
+use rustc_middle::ty;
+use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_span::sym;
+
+declare_clippy_lint! {
+    /// ### What it does
+    /// It checks for `str::bytes().count()` and suggests replacing it with
+    /// `str::len()`.
+    ///
+    /// ### Why is this bad?
+    /// `str::bytes().count()` is longer and may not be as performant as using
+    /// `str::len()`.
+    ///
+    /// ### Example
+    /// ```rust
+    /// "hello".bytes().count();
+    /// String::from("hello").bytes().count();
+    /// ```
+    /// Use instead:
+    /// ```rust
+    /// "hello".len();
+    /// String::from("hello").len();
+    /// ```
+    #[clippy::version = "1.62.0"]
+    pub BYTES_COUNT_TO_LEN,
+    complexity,
+    "Using `bytes().count()` when `len()` performs the same functionality"
+}
+
+declare_lint_pass!(BytesCountToLen => [BYTES_COUNT_TO_LEN]);
+
+impl<'tcx> LateLintPass<'tcx> for BytesCountToLen {
+    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>) {
+        if_chain! {
+            if let hir::ExprKind::MethodCall(_, expr_args, _) = &expr.kind;
+            if let Some(expr_def_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id);
+            if match_def_path(cx, expr_def_id, &paths::ITER_COUNT);
+
+            if let [bytes_expr] = &**expr_args;
+            if let hir::ExprKind::MethodCall(_, bytes_args, _) = &bytes_expr.kind;
+            if let Some(bytes_def_id) = cx.typeck_results().type_dependent_def_id(bytes_expr.hir_id);
+            if match_def_path(cx, bytes_def_id, &paths::STR_BYTES);
+
+            if let [str_expr] = &**bytes_args;
+            let ty = cx.typeck_results().expr_ty(str_expr).peel_refs();
+
+            if is_type_diagnostic_item(cx, ty, sym::String) || ty.kind() == &ty::Str;
+            then {
+                let mut applicability = Applicability::MachineApplicable;
+                span_lint_and_sugg(
+                    cx,
+                    BYTES_COUNT_TO_LEN,
+                    expr.span,
+                    "using long and hard to read `.bytes().count()`",
+                    "consider calling `.len()` instead",
+                    format!("{}.len()", snippet_with_applicability(cx, str_expr.span, "..", &mut applicability)),
+                    applicability
+                );
+            }
+        };
+    }
+}
diff --git a/clippy_lints/src/case_sensitive_file_extension_comparisons.rs b/clippy_lints/src/case_sensitive_file_extension_comparisons.rs
index a8f9c189ade..7af200708ff 100644
--- a/clippy_lints/src/case_sensitive_file_extension_comparisons.rs
+++ b/clippy_lints/src/case_sensitive_file_extension_comparisons.rs
@@ -42,8 +42,8 @@ fn check_case_sensitive_file_extension_comparison(ctx: &LateContext<'_>, expr: &
         if let ExprKind::Lit(Spanned { node: LitKind::Str(ext_literal, ..), ..}) = extension.kind;
         if (2..=6).contains(&ext_literal.as_str().len());
         if ext_literal.as_str().starts_with('.');
-        if ext_literal.as_str().chars().skip(1).all(|c| c.is_uppercase() || c.is_digit(10))
-            || ext_literal.as_str().chars().skip(1).all(|c| c.is_lowercase() || c.is_digit(10));
+        if ext_literal.as_str().chars().skip(1).all(|c| c.is_uppercase() || c.is_ascii_digit())
+            || ext_literal.as_str().chars().skip(1).all(|c| c.is_lowercase() || c.is_ascii_digit());
         then {
             let mut ty = ctx.typeck_results().expr_ty(obj);
             ty = match ty.kind() {
diff --git a/clippy_lints/src/casts/cast_possible_truncation.rs b/clippy_lints/src/casts/cast_possible_truncation.rs
index 421bd6f53f7..64f87c80f8d 100644
--- a/clippy_lints/src/casts/cast_possible_truncation.rs
+++ b/clippy_lints/src/casts/cast_possible_truncation.rs
@@ -29,21 +29,19 @@ fn apply_reductions(cx: &LateContext<'_>, nbits: u64, expr: &Expr<'_>, signed: b
         ExprKind::Block(block, _) => block.expr.map_or(nbits, |e| apply_reductions(cx, nbits, e, signed)),
         ExprKind::Binary(op, left, right) => match op.node {
             BinOpKind::Div => {
-                apply_reductions(cx, nbits, left, signed)
-                    - (if signed {
-                        0 // let's be conservative here
-                    } else {
-                        // by dividing by 1, we remove 0 bits, etc.
-                        get_constant_bits(cx, right).map_or(0, |b| b.saturating_sub(1))
-                    })
+                apply_reductions(cx, nbits, left, signed).saturating_sub(if signed {
+                    // let's be conservative here
+                    0
+                } else {
+                    // by dividing by 1, we remove 0 bits, etc.
+                    get_constant_bits(cx, right).map_or(0, |b| b.saturating_sub(1))
+                })
             },
             BinOpKind::Rem | BinOpKind::BitAnd => get_constant_bits(cx, right)
                 .unwrap_or(u64::max_value())
                 .min(apply_reductions(cx, nbits, left, signed)),
-            BinOpKind::Shr => {
-                apply_reductions(cx, nbits, left, signed)
-                    - constant_int(cx, right).map_or(0, |s| u64::try_from(s).expect("shift too high"))
-            },
+            BinOpKind::Shr => apply_reductions(cx, nbits, left, signed)
+                .saturating_sub(constant_int(cx, right).map_or(0, |s| u64::try_from(s).expect("shift too high"))),
             _ => nbits,
         },
         ExprKind::MethodCall(method, [left, right], _) => {
diff --git a/clippy_lints/src/casts/cast_slice_different_sizes.rs b/clippy_lints/src/casts/cast_slice_different_sizes.rs
index 3608c1654d5..2238668abca 100644
--- a/clippy_lints/src/casts/cast_slice_different_sizes.rs
+++ b/clippy_lints/src/casts/cast_slice_different_sizes.rs
@@ -1,4 +1,4 @@
-use clippy_utils::{diagnostics::span_lint_and_then, meets_msrv, msrvs, source::snippet_opt};
+use clippy_utils::{diagnostics::span_lint_and_then, meets_msrv, msrvs, source};
 use if_chain::if_chain;
 use rustc_ast::Mutability;
 use rustc_hir::{Expr, ExprKind, Node};
@@ -8,32 +8,7 @@ use rustc_semver::RustcVersion;
 
 use super::CAST_SLICE_DIFFERENT_SIZES;
 
-fn is_child_of_cast(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
-    let map = cx.tcx.hir();
-    if_chain! {
-        if let Some(parent_id) = map.find_parent_node(expr.hir_id);
-        if let Some(parent) = map.find(parent_id);
-        then {
-            let expr = match parent {
-                Node::Block(block) => {
-                    if let Some(parent_expr) = block.expr {
-                        parent_expr
-                    } else {
-                        return false;
-                    }
-                },
-                Node::Expr(expr) => expr,
-                _ => return false,
-            };
-
-            matches!(expr.kind, ExprKind::Cast(..))
-        } else {
-            false
-        }
-    }
-}
-
-pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, msrv: &Option<RustcVersion>) {
+pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'tcx>, msrv: &Option<RustcVersion>) {
     // suggestion is invalid if `ptr::slice_from_raw_parts` does not exist
     if !meets_msrv(msrv.as_ref(), &msrvs::PTR_SLICE_RAW_PARTS) {
         return;
@@ -45,8 +20,13 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, msrv: &Option<RustcVe
         return;
     }
 
-    if let Some((from_slice_ty, to_slice_ty)) = expr_cast_chain_tys(cx, expr) {
-        if let (Ok(from_layout), Ok(to_layout)) = (cx.layout_of(from_slice_ty.ty), cx.layout_of(to_slice_ty.ty)) {
+    if let Some(CastChainInfo {
+        left_cast,
+        start_ty,
+        end_ty,
+    }) = expr_cast_chain_tys(cx, expr)
+    {
+        if let (Ok(from_layout), Ok(to_layout)) = (cx.layout_of(start_ty.ty), cx.layout_of(end_ty.ty)) {
             let from_size = from_layout.size.bytes();
             let to_size = to_layout.size.bytes();
             if from_size != to_size && from_size != 0 && to_size != 0 {
@@ -56,21 +36,20 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, msrv: &Option<RustcVe
                     expr.span,
                     &format!(
                         "casting between raw pointers to `[{}]` (element size {}) and `[{}]` (element size {}) does not adjust the count",
-                        from_slice_ty, from_size, to_slice_ty, to_size,
+                        start_ty.ty, from_size, end_ty.ty, to_size,
                     ),
                     |diag| {
-                        let cast_expr = match expr.kind {
-                            ExprKind::Cast(cast_expr, ..) => cast_expr,
-                            _ => unreachable!("expr should be a cast as checked by expr_cast_chain_tys"),
-                        };
-                        let ptr_snippet = snippet_opt(cx, cast_expr.span).unwrap();
+                        let ptr_snippet = source::snippet(cx, left_cast.span, "..");
 
-                        let (mutbl_fn_str, mutbl_ptr_str) = match to_slice_ty.mutbl {
+                        let (mutbl_fn_str, mutbl_ptr_str) = match end_ty.mutbl {
                             Mutability::Mut => ("_mut", "mut"),
                             Mutability::Not => ("", "const"),
                         };
                         let sugg = format!(
-                            "core::ptr::slice_from_raw_parts{mutbl_fn_str}({ptr_snippet} as *{mutbl_ptr_str} {to_slice_ty}, ..)"
+                            "core::ptr::slice_from_raw_parts{mutbl_fn_str}({ptr_snippet} as *{mutbl_ptr_str} {}, ..)",
+                            // get just the ty from the TypeAndMut so that the printed type isn't something like `mut
+                            // T`, extract just the `T`
+                            end_ty.ty
                         );
 
                         diag.span_suggestion(
@@ -86,6 +65,31 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, msrv: &Option<RustcVe
     }
 }
 
+fn is_child_of_cast(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
+    let map = cx.tcx.hir();
+    if_chain! {
+        if let Some(parent_id) = map.find_parent_node(expr.hir_id);
+        if let Some(parent) = map.find(parent_id);
+        then {
+            let expr = match parent {
+                Node::Block(block) => {
+                    if let Some(parent_expr) = block.expr {
+                        parent_expr
+                    } else {
+                        return false;
+                    }
+                },
+                Node::Expr(expr) => expr,
+                _ => return false,
+            };
+
+            matches!(expr.kind, ExprKind::Cast(..))
+        } else {
+            false
+        }
+    }
+}
+
 /// Returns the type T of the pointed to *const [T] or *mut [T] and the mutability of the slice if
 /// the type is one of those slices
 fn get_raw_slice_ty_mut(ty: Ty<'_>) -> Option<TypeAndMut<'_>> {
@@ -98,18 +102,40 @@ fn get_raw_slice_ty_mut(ty: Ty<'_>) -> Option<TypeAndMut<'_>> {
     }
 }
 
-/// Returns the pair (original ptr T, final ptr U) if the expression is composed of casts
+struct CastChainInfo<'tcx> {
+    /// The left most part of the cast chain, or in other words, the first cast in the chain
+    /// Used for diagnostics
+    left_cast: &'tcx Expr<'tcx>,
+    /// The starting type of the cast chain
+    start_ty: TypeAndMut<'tcx>,
+    /// The final type of the cast chain
+    end_ty: TypeAndMut<'tcx>,
+}
+
+/// Returns a `CastChainInfo` with the left-most cast in the chain and the original ptr T and final
+/// ptr U if the expression is composed of casts.
 /// Returns None if the expr is not a Cast
-fn expr_cast_chain_tys<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'_>) -> Option<(TypeAndMut<'tcx>, TypeAndMut<'tcx>)> {
+fn expr_cast_chain_tys<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'tcx>) -> Option<CastChainInfo<'tcx>> {
     if let ExprKind::Cast(cast_expr, _cast_to_hir_ty) = expr.peel_blocks().kind {
         let cast_to = cx.typeck_results().expr_ty(expr);
         let to_slice_ty = get_raw_slice_ty_mut(cast_to)?;
-        if let Some((inner_from_ty, _inner_to_ty)) = expr_cast_chain_tys(cx, cast_expr) {
-            Some((inner_from_ty, to_slice_ty))
+
+        // If the expression that makes up the source of this cast is itself a cast, recursively
+        // call `expr_cast_chain_tys` and update the end type with the final tartet type.
+        // Otherwise, this cast is not immediately nested, just construct the info for this cast
+        if let Some(prev_info) = expr_cast_chain_tys(cx, cast_expr) {
+            Some(CastChainInfo {
+                end_ty: to_slice_ty,
+                ..prev_info
+            })
         } else {
             let cast_from = cx.typeck_results().expr_ty(cast_expr);
             let from_slice_ty = get_raw_slice_ty_mut(cast_from)?;
-            Some((from_slice_ty, to_slice_ty))
+            Some(CastChainInfo {
+                left_cast: cast_expr,
+                start_ty: from_slice_ty,
+                end_ty: to_slice_ty,
+            })
         }
     } else {
         None
diff --git a/clippy_lints/src/casts/mod.rs b/clippy_lints/src/casts/mod.rs
index 55c1f085657..b58252dcb94 100644
--- a/clippy_lints/src/casts/mod.rs
+++ b/clippy_lints/src/casts/mod.rs
@@ -270,7 +270,7 @@ declare_clippy_lint! {
     ///
     /// ### Why is this bad?
     /// Casting a function pointer to an integer can have surprising results and can occur
-    /// accidentally if parantheses are omitted from a function call. If you aren't doing anything
+    /// accidentally if parentheses are omitted from a function call. If you aren't doing anything
     /// low-level with function pointers then you can opt-out of casting functions to integers in
     /// order to avoid mistakes. Alternatively, you can use this lint to audit all uses of function
     /// pointer casts in your code.
@@ -487,6 +487,7 @@ declare_clippy_lint! {
     /// let y: u32 = x.abs() as u32;
     /// ```
     /// Use instead:
+    /// ```rust
     /// let x: i32 = -42;
     /// let y: u32 = x.unsigned_abs();
     /// ```
diff --git a/clippy_lints/src/collapsible_if.rs b/clippy_lints/src/collapsible_if.rs
index eae2723a7da..3227e6e86af 100644
--- a/clippy_lints/src/collapsible_if.rs
+++ b/clippy_lints/src/collapsible_if.rs
@@ -13,13 +13,14 @@
 //! This lint is **warn** by default
 
 use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then};
-use clippy_utils::source::{snippet_block, snippet_block_with_applicability};
+use clippy_utils::source::{snippet, snippet_block, snippet_block_with_applicability};
 use clippy_utils::sugg::Sugg;
 use if_chain::if_chain;
 use rustc_ast::ast;
 use rustc_errors::Applicability;
 use rustc_lint::{EarlyContext, EarlyLintPass};
 use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_span::Span;
 
 declare_clippy_lint! {
     /// ### What it does
@@ -102,7 +103,7 @@ impl EarlyLintPass for CollapsibleIf {
 fn check_if(cx: &EarlyContext<'_>, expr: &ast::Expr) {
     if let ast::ExprKind::If(check, then, else_) = &expr.kind {
         if let Some(else_) = else_ {
-            check_collapsible_maybe_if_let(cx, else_);
+            check_collapsible_maybe_if_let(cx, then.span, else_);
         } else if let ast::ExprKind::Let(..) = check.kind {
             // Prevent triggering on `if let a = b { if c { .. } }`.
         } else {
@@ -119,7 +120,7 @@ fn block_starts_with_comment(cx: &EarlyContext<'_>, expr: &ast::Block) -> bool {
     trimmed_block_text.starts_with("//") || trimmed_block_text.starts_with("/*")
 }
 
-fn check_collapsible_maybe_if_let(cx: &EarlyContext<'_>, else_: &ast::Expr) {
+fn check_collapsible_maybe_if_let(cx: &EarlyContext<'_>, then_span: Span, else_: &ast::Expr) {
     if_chain! {
         if let ast::ExprKind::Block(ref block, _) = else_.kind;
         if !block_starts_with_comment(cx, block);
@@ -128,6 +129,11 @@ fn check_collapsible_maybe_if_let(cx: &EarlyContext<'_>, else_: &ast::Expr) {
         if !else_.span.from_expansion();
         if let ast::ExprKind::If(..) = else_.kind;
         then {
+            // Prevent "elseif"
+            // Check that the "else" is followed by whitespace
+            let up_to_else = then_span.between(block.span);
+            let requires_space = if let Some(c) = snippet(cx, up_to_else, "..").chars().last() { !c.is_whitespace() } else { false };
+
             let mut applicability = Applicability::MachineApplicable;
             span_lint_and_sugg(
                 cx,
@@ -135,7 +141,11 @@ fn check_collapsible_maybe_if_let(cx: &EarlyContext<'_>, else_: &ast::Expr) {
                 block.span,
                 "this `else { if .. }` block can be collapsed",
                 "collapse nested if block",
-                snippet_block_with_applicability(cx, else_.span, "..", Some(block.span), &mut applicability).into_owned(),
+                format!(
+                    "{}{}",
+                    if requires_space { " " } else { "" },
+                    snippet_block_with_applicability(cx, else_.span, "..", Some(block.span), &mut applicability)
+                ),
                 applicability,
             );
         }
diff --git a/clippy_lints/src/doc.rs b/clippy_lints/src/doc.rs
index 503cef76775..b3fd8af4730 100644
--- a/clippy_lints/src/doc.rs
+++ b/clippy_lints/src/doc.rs
@@ -240,7 +240,7 @@ impl<'tcx> LateLintPass<'tcx> for DocMarkdown {
                     lint_for_missing_headers(cx, item.def_id, item.span, sig, headers, Some(body_id), fpu.panic_span);
                 }
             },
-            hir::ItemKind::Impl(ref impl_) => {
+            hir::ItemKind::Impl(impl_) => {
                 self.in_trait_impl = impl_.of_trait.is_some();
             },
             hir::ItemKind::Trait(_, unsafety, ..) => {
@@ -621,10 +621,8 @@ fn check_code(cx: &LateContext<'_>, text: &str, edition: Edition, span: Span) {
                 let filename = FileName::anon_source_code(&code);
 
                 let sm = Lrc::new(SourceMap::new(FilePathMapping::empty()));
-                let fallback_bundle = rustc_errors::fallback_fluent_bundle(
-                    rustc_errors::DEFAULT_LOCALE_RESOURCES,
-                    false
-                );
+                let fallback_bundle =
+                    rustc_errors::fallback_fluent_bundle(rustc_errors::DEFAULT_LOCALE_RESOURCES, false);
                 let emitter = EmitterWriter::new(
                     Box::new(io::sink()),
                     None,
@@ -741,7 +739,7 @@ fn check_word(cx: &LateContext<'_>, word: &str, span: Span) {
     /// letters (`Clippy` is ok) and one lower-case letter (`NASA` is ok).
     /// Plurals are also excluded (`IDs` is ok).
     fn is_camel_case(s: &str) -> bool {
-        if s.starts_with(|c: char| c.is_digit(10)) {
+        if s.starts_with(|c: char| c.is_ascii_digit()) {
             return false;
         }
 
diff --git a/clippy_lints/src/drop_forget_ref.rs b/clippy_lints/src/drop_forget_ref.rs
index 88c54828da8..25014bfa1a5 100644
--- a/clippy_lints/src/drop_forget_ref.rs
+++ b/clippy_lints/src/drop_forget_ref.rs
@@ -180,7 +180,7 @@ const DROP_COPY_SUMMARY: &str = "calls to `std::mem::drop` with a value that imp
 const FORGET_COPY_SUMMARY: &str = "calls to `std::mem::forget` with a value that implements `Copy`. \
                                    Forgetting a copy leaves the original intact";
 const DROP_NON_DROP_SUMMARY: &str = "call to `std::mem::drop` with a value that does not implement `Drop`. \
-                                 Dropping such a type only extends it's contained lifetimes";
+                                 Dropping such a type only extends its contained lifetimes";
 const FORGET_NON_DROP_SUMMARY: &str = "call to `std::mem::forget` with a value that does not implement `Drop`. \
                                    Forgetting such a type is the same as dropping it";
 
diff --git a/clippy_lints/src/empty_drop.rs b/clippy_lints/src/empty_drop.rs
new file mode 100644
index 00000000000..325ae2356c1
--- /dev/null
+++ b/clippy_lints/src/empty_drop.rs
@@ -0,0 +1,65 @@
+use clippy_utils::{diagnostics::span_lint_and_sugg, peel_blocks};
+use if_chain::if_chain;
+use rustc_errors::Applicability;
+use rustc_hir::{Body, ExprKind, Impl, ImplItemKind, Item, ItemKind, Node};
+use rustc_lint::{LateContext, LateLintPass};
+use rustc_session::{declare_lint_pass, declare_tool_lint};
+
+declare_clippy_lint! {
+    /// ### What it does
+    /// Checks for empty `Drop` implementations.
+    ///
+    /// ### Why is this bad?
+    /// Empty `Drop` implementations have no effect when dropping an instance of the type. They are
+    /// most likely useless. However, an empty `Drop` implementation prevents a type from being
+    /// destructured, which might be the intention behind adding the implementation as a marker.
+    ///
+    /// ### Example
+    /// ```rust
+    /// struct S;
+    ///
+    /// impl Drop for S {
+    ///     fn drop(&mut self) {}
+    /// }
+    /// ```
+    /// Use instead:
+    /// ```rust
+    /// struct S;
+    /// ```
+    #[clippy::version = "1.61.0"]
+    pub EMPTY_DROP,
+    restriction,
+    "empty `Drop` implementations"
+}
+declare_lint_pass!(EmptyDrop => [EMPTY_DROP]);
+
+impl LateLintPass<'_> for EmptyDrop {
+    fn check_item(&mut self, cx: &LateContext<'_>, item: &Item<'_>) {
+        if_chain! {
+            if let ItemKind::Impl(Impl {
+                of_trait: Some(ref trait_ref),
+                items: [child],
+                ..
+            }) = item.kind;
+            if trait_ref.trait_def_id() == cx.tcx.lang_items().drop_trait();
+            if let impl_item_hir = child.id.hir_id();
+            if let Some(Node::ImplItem(impl_item)) = cx.tcx.hir().find(impl_item_hir);
+            if let ImplItemKind::Fn(_, b) = &impl_item.kind;
+            if let Body { value: func_expr, .. } = cx.tcx.hir().body(*b);
+            let func_expr = peel_blocks(func_expr);
+            if let ExprKind::Block(block, _) = func_expr.kind;
+            if block.stmts.is_empty() && block.expr.is_none();
+            then {
+                span_lint_and_sugg(
+                    cx,
+                    EMPTY_DROP,
+                    item.span,
+                    "empty drop implementation",
+                    "try removing this impl",
+                    String::new(),
+                    Applicability::MaybeIncorrect
+                );
+            }
+        }
+    }
+}
diff --git a/clippy_lints/src/empty_structs_with_brackets.rs b/clippy_lints/src/empty_structs_with_brackets.rs
index fdeac8d8255..8430e7b4c82 100644
--- a/clippy_lints/src/empty_structs_with_brackets.rs
+++ b/clippy_lints/src/empty_structs_with_brackets.rs
@@ -66,7 +66,7 @@ fn has_no_fields(cx: &EarlyContext<'_>, var_data: &VariantData, braces_span: Spa
     }
 
     // there might still be field declarations hidden from the AST
-    // (conditionaly compiled code using #[cfg(..)])
+    // (conditionally compiled code using #[cfg(..)])
 
     let Some(braces_span_str) = snippet_opt(cx, braces_span) else {
         return false;
diff --git a/clippy_lints/src/eta_reduction.rs b/clippy_lints/src/eta_reduction.rs
index 845863bd209..1b19868e4c7 100644
--- a/clippy_lints/src/eta_reduction.rs
+++ b/clippy_lints/src/eta_reduction.rs
@@ -3,7 +3,7 @@ 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 clippy_utils::{higher, is_adjusted, path_to_local, path_to_local_id};
 use if_chain::if_chain;
 use rustc_errors::Applicability;
 use rustc_hir::def_id::DefId;
@@ -103,6 +103,7 @@ impl<'tcx> LateLintPass<'tcx> for EtaReduction {
         let closure_ty = cx.typeck_results().expr_ty(expr);
 
         if_chain!(
+            if !is_adjusted(cx, &body.value);
             if let ExprKind::Call(callee, args) = body.value.kind;
             if let ExprKind::Path(_) = callee.kind;
             if check_inputs(cx, body.params, args);
@@ -125,8 +126,7 @@ impl<'tcx> LateLintPass<'tcx> for EtaReduction {
                         if_chain! {
                             if let ty::Closure(_, substs) = callee_ty.peel_refs().kind();
                             if substs.as_closure().kind() == ClosureKind::FnMut;
-                            if get_enclosing_loop_or_closure(cx.tcx, expr).is_some()
-                                || path_to_local(callee).map_or(false, |l| local_used_after_expr(cx, l, callee));
+                            if path_to_local(callee).map_or(false, |l| local_used_after_expr(cx, l, expr));
 
                             then {
                                 // Mutable closure is used after current expr; we cannot consume it.
@@ -145,6 +145,7 @@ impl<'tcx> LateLintPass<'tcx> for EtaReduction {
         );
 
         if_chain!(
+            if !is_adjusted(cx, &body.value);
             if let ExprKind::MethodCall(path, args, _) = body.value.kind;
             if check_inputs(cx, body.params, args);
             let method_def_id = cx.typeck_results().type_dependent_def_id(body.value.hir_id).unwrap();
diff --git a/clippy_lints/src/format_push_string.rs b/clippy_lints/src/format_push_string.rs
new file mode 100644
index 00000000000..ee15ae9f59a
--- /dev/null
+++ b/clippy_lints/src/format_push_string.rs
@@ -0,0 +1,77 @@
+use clippy_utils::diagnostics::span_lint_and_help;
+use clippy_utils::ty::is_type_diagnostic_item;
+use clippy_utils::{match_def_path, paths, peel_hir_expr_refs};
+use rustc_hir::{BinOpKind, Expr, ExprKind};
+use rustc_lint::{LateContext, LateLintPass};
+use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_span::sym;
+
+declare_clippy_lint! {
+    /// ### What it does
+    /// Detects cases where the result of a `format!` call is
+    /// appended to an existing `String`.
+    ///
+    /// ### Why is this bad?
+    /// Introduces an extra, avoidable heap allocation.
+    ///
+    /// ### Example
+    /// ```rust
+    /// let mut s = String::new();
+    /// s += &format!("0x{:X}", 1024);
+    /// s.push_str(&format!("0x{:X}", 1024));
+    /// ```
+    /// Use instead:
+    /// ```rust
+    /// use std::fmt::Write as _; // import without risk of name clashing
+    ///
+    /// let mut s = String::new();
+    /// let _ = write!(s, "0x{:X}", 1024);
+    /// ```
+    #[clippy::version = "1.61.0"]
+    pub FORMAT_PUSH_STRING,
+    perf,
+    "`format!(..)` appended to existing `String`"
+}
+declare_lint_pass!(FormatPushString => [FORMAT_PUSH_STRING]);
+
+fn is_string(cx: &LateContext<'_>, e: &Expr<'_>) -> bool {
+    is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(e).peel_refs(), sym::String)
+}
+fn is_format(cx: &LateContext<'_>, e: &Expr<'_>) -> bool {
+    if let Some(macro_def_id) = e.span.ctxt().outer_expn_data().macro_def_id {
+        cx.tcx.get_diagnostic_name(macro_def_id) == Some(sym::format_macro)
+    } else {
+        false
+    }
+}
+
+impl<'tcx> LateLintPass<'tcx> for FormatPushString {
+    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
+        let arg = match expr.kind {
+            ExprKind::MethodCall(_, [_, arg], _) => {
+                if let Some(fn_def_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id) &&
+                match_def_path(cx, fn_def_id, &paths::PUSH_STR) {
+                    arg
+                } else {
+                    return;
+                }
+            }
+            ExprKind::AssignOp(op, left, arg)
+            if op.node == BinOpKind::Add && is_string(cx, left) => {
+                arg
+            },
+            _ => return,
+        };
+        let (arg, _) = peel_hir_expr_refs(arg);
+        if is_format(cx, arg) {
+            span_lint_and_help(
+                cx,
+                FORMAT_PUSH_STRING,
+                expr.span,
+                "`format!(..)` appended to existing `String`",
+                None,
+                "consider using `write!` to avoid the extra allocation",
+            );
+        }
+    }
+}
diff --git a/clippy_lints/src/functions/must_use.rs b/clippy_lints/src/functions/must_use.rs
index 5462d913fb4..38e943d2eb8 100644
--- a/clippy_lints/src/functions/must_use.rs
+++ b/clippy_lints/src/functions/must_use.rs
@@ -20,7 +20,7 @@ use super::{DOUBLE_MUST_USE, MUST_USE_CANDIDATE, MUST_USE_UNIT};
 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 {
+    if let hir::ItemKind::Fn(ref sig, _generics, 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());
         if let Some(attr) = attr {
@@ -105,12 +105,7 @@ fn check_needless_must_use(
             fn_header_span,
             "this unit-returning function has a `#[must_use]` attribute",
             |diag| {
-                diag.span_suggestion(
-                    attr.span,
-                    "remove the attribute",
-                    "",
-                    Applicability::MachineApplicable,
-                );
+                diag.span_suggestion(attr.span, "remove the attribute", "", Applicability::MachineApplicable);
             },
         );
     } else if attr.value_str().is_none() && is_must_use_ty(cx, return_ty(cx, item_id)) {
diff --git a/clippy_lints/src/functions/result_unit_err.rs b/clippy_lints/src/functions/result_unit_err.rs
index 120fcb2619c..2e63a1f920d 100644
--- a/clippy_lints/src/functions/result_unit_err.rs
+++ b/clippy_lints/src/functions/result_unit_err.rs
@@ -14,7 +14,7 @@ use clippy_utils::ty::is_type_diagnostic_item;
 use super::RESULT_UNIT_ERR;
 
 pub(super) fn check_item(cx: &LateContext<'_>, item: &hir::Item<'_>) {
-    if let hir::ItemKind::Fn(ref sig, ref _generics, _) = item.kind {
+    if let hir::ItemKind::Fn(ref sig, _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());
         if is_public {
diff --git a/clippy_lints/src/identity_op.rs b/clippy_lints/src/identity_op.rs
index 4d6bef89bea..40cc5cd4bcf 100644
--- a/clippy_lints/src/identity_op.rs
+++ b/clippy_lints/src/identity_op.rs
@@ -1,3 +1,4 @@
+use clippy_utils::get_parent_expr;
 use clippy_utils::source::snippet;
 use rustc_hir::{BinOp, BinOpKind, Expr, ExprKind};
 use rustc_lint::{LateContext, LateLintPass};
@@ -22,6 +23,11 @@ declare_clippy_lint! {
     /// # let x = 1;
     /// x / 1 + 0 * 1 - 0 | 0;
     /// ```
+    ///
+    /// ### Known problems
+    /// False negatives: `f(0 + if b { 1 } else { 2 } + 3);` is reducible to
+    /// `f(if b { 1 } else { 2 } + 3);`. But the lint doesn't trigger for the code.
+    /// See [#8724](https://github.com/rust-lang/rust-clippy/issues/8724)
     #[clippy::version = "pre 1.29.0"]
     pub IDENTITY_OP,
     complexity,
@@ -31,36 +37,66 @@ declare_clippy_lint! {
 declare_lint_pass!(IdentityOp => [IDENTITY_OP]);
 
 impl<'tcx> LateLintPass<'tcx> for IdentityOp {
-    fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) {
-        if e.span.from_expansion() {
+    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
+        if expr.span.from_expansion() {
             return;
         }
-        if let ExprKind::Binary(cmp, left, right) = e.kind {
-            if is_allowed(cx, cmp, left, right) {
-                return;
-            }
-            match cmp.node {
-                BinOpKind::Add | BinOpKind::BitOr | BinOpKind::BitXor => {
-                    check(cx, left, 0, e.span, right.span);
-                    check(cx, right, 0, e.span, left.span);
-                },
-                BinOpKind::Shl | BinOpKind::Shr | BinOpKind::Sub => check(cx, right, 0, e.span, left.span),
-                BinOpKind::Mul => {
-                    check(cx, left, 1, e.span, right.span);
-                    check(cx, right, 1, e.span, left.span);
-                },
-                BinOpKind::Div => check(cx, right, 1, e.span, left.span),
-                BinOpKind::BitAnd => {
-                    check(cx, left, -1, e.span, right.span);
-                    check(cx, right, -1, e.span, left.span);
-                },
-                BinOpKind::Rem => check_remainder(cx, left, right, e.span, left.span),
-                _ => (),
+        if let ExprKind::Binary(cmp, left, right) = &expr.kind {
+            if !is_allowed(cx, *cmp, left, right) {
+                match cmp.node {
+                    BinOpKind::Add | BinOpKind::BitOr | BinOpKind::BitXor => {
+                        if reducible_to_right(cx, expr, right) {
+                            check(cx, left, 0, expr.span, right.span);
+                        }
+                        check(cx, right, 0, expr.span, left.span);
+                    },
+                    BinOpKind::Shl | BinOpKind::Shr | BinOpKind::Sub => {
+                        check(cx, right, 0, expr.span, left.span);
+                    },
+                    BinOpKind::Mul => {
+                        if reducible_to_right(cx, expr, right) {
+                            check(cx, left, 1, expr.span, right.span);
+                        }
+                        check(cx, right, 1, expr.span, left.span);
+                    },
+                    BinOpKind::Div => check(cx, right, 1, expr.span, left.span),
+                    BinOpKind::BitAnd => {
+                        if reducible_to_right(cx, expr, right) {
+                            check(cx, left, -1, expr.span, right.span);
+                        }
+                        check(cx, right, -1, expr.span, left.span);
+                    },
+                    BinOpKind::Rem => {
+                        // Don't call reducible_to_right because N % N is always reducible to 1
+                        check_remainder(cx, left, right, expr.span, left.span);
+                    },
+                    _ => (),
+                }
             }
         }
     }
 }
 
+/// Checks if `left op ..right` can be actually reduced to `right`
+/// e.g. `0 + if b { 1 } else { 2 } + if b { 3 } else { 4 }`
+/// cannot be reduced to `if b { 1 } else { 2 } +  if b { 3 } else { 4 }`
+/// See #8724
+fn reducible_to_right(cx: &LateContext<'_>, binary: &Expr<'_>, right: &Expr<'_>) -> bool {
+    if let ExprKind::If(..) | ExprKind::Match(..) | ExprKind::Block(..) | ExprKind::Loop(..) = right.kind {
+        is_toplevel_binary(cx, binary)
+    } else {
+        true
+    }
+}
+
+fn is_toplevel_binary(cx: &LateContext<'_>, must_be_binary: &Expr<'_>) -> bool {
+    if let Some(parent) = get_parent_expr(cx, must_be_binary) && let ExprKind::Binary(..) = &parent.kind {
+        false
+    } else {
+        true
+    }
+}
+
 fn is_allowed(cx: &LateContext<'_>, cmp: BinOp, left: &Expr<'_>, right: &Expr<'_>) -> bool {
     // This lint applies to integers
     !cx.typeck_results().expr_ty(left).peel_refs().is_integral()
diff --git a/clippy_lints/src/implicit_hasher.rs b/clippy_lints/src/implicit_hasher.rs
index d5430a8c917..feb1b1014b1 100644
--- a/clippy_lints/src/implicit_hasher.rs
+++ b/clippy_lints/src/implicit_hasher.rs
@@ -117,7 +117,7 @@ impl<'tcx> LateLintPass<'tcx> for ImplicitHasher {
         }
 
         match item.kind {
-            ItemKind::Impl(ref impl_) => {
+            ItemKind::Impl(impl_) => {
                 let mut vis = ImplicitHasherTypeVisitor::new(cx);
                 vis.visit_ty(impl_.self_ty);
 
@@ -155,7 +155,7 @@ impl<'tcx> LateLintPass<'tcx> for ImplicitHasher {
                     );
                 }
             },
-            ItemKind::Fn(ref sig, ref generics, body_id) => {
+            ItemKind::Fn(ref sig, generics, body_id) => {
                 let body = cx.tcx.hir().body(body_id);
 
                 for ty in sig.decl.inputs {
diff --git a/clippy_lints/src/inconsistent_struct_constructor.rs b/clippy_lints/src/inconsistent_struct_constructor.rs
index c8ec2f45137..14b22d2b50d 100644
--- a/clippy_lints/src/inconsistent_struct_constructor.rs
+++ b/clippy_lints/src/inconsistent_struct_constructor.rs
@@ -7,6 +7,7 @@ use rustc_hir::{self as hir, ExprKind};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_session::{declare_lint_pass, declare_tool_lint};
 use rustc_span::symbol::Symbol;
+use std::fmt::Write as _;
 
 declare_clippy_lint! {
     /// ### What it does
@@ -89,7 +90,7 @@ impl<'tcx> LateLintPass<'tcx> for InconsistentStructConstructor {
                 let mut fields_snippet = String::new();
                 let (last_ident, idents) = ordered_fields.split_last().unwrap();
                 for ident in idents {
-                    fields_snippet.push_str(&format!("{}, ", ident));
+                    let _ = write!(fields_snippet, "{}, ", ident);
                 }
                 fields_snippet.push_str(&last_ident.to_string());
 
diff --git a/clippy_lints/src/index_refutable_slice.rs b/clippy_lints/src/index_refutable_slice.rs
index 6b62748ffef..8a84513b779 100644
--- a/clippy_lints/src/index_refutable_slice.rs
+++ b/clippy_lints/src/index_refutable_slice.rs
@@ -116,7 +116,7 @@ fn find_slice_values(cx: &LateContext<'_>, pat: &hir::Pat<'_>) -> FxIndexMap<hir
             let bound_ty = cx.typeck_results().node_type(pat.hir_id);
             if let ty::Slice(inner_ty) | ty::Array(inner_ty, _) = bound_ty.peel_refs().kind() {
                 // The values need to use the `ref` keyword if they can't be copied.
-                // This will need to be adjusted if the lint want to support multable access in the future
+                // This will need to be adjusted if the lint want to support mutable access in the future
                 let src_is_ref = bound_ty.is_ref() && binding != hir::BindingAnnotation::Ref;
                 let needs_ref = !(src_is_ref || is_copy(cx, *inner_ty));
 
diff --git a/clippy_lints/src/inherent_impl.rs b/clippy_lints/src/inherent_impl.rs
index 254d3f8a4d0..6a031a627df 100644
--- a/clippy_lints/src/inherent_impl.rs
+++ b/clippy_lints/src/inherent_impl.rs
@@ -119,7 +119,7 @@ impl<'tcx> LateLintPass<'tcx> for MultipleInherentImpl {
 fn get_impl_span(cx: &LateContext<'_>, id: LocalDefId) -> Option<Span> {
     let id = cx.tcx.hir().local_def_id_to_hir_id(id);
     if let Node::Item(&Item {
-        kind: ItemKind::Impl(ref impl_item),
+        kind: ItemKind::Impl(impl_item),
         span,
         ..
     }) = cx.tcx.hir().get(id)
diff --git a/clippy_lints/src/init_numbered_fields.rs b/clippy_lints/src/init_numbered_fields.rs
index 9284e002409..7e1548531f1 100644
--- a/clippy_lints/src/init_numbered_fields.rs
+++ b/clippy_lints/src/init_numbered_fields.rs
@@ -1,6 +1,7 @@
 use clippy_utils::diagnostics::span_lint_and_sugg;
 use clippy_utils::source::snippet_with_applicability;
 use rustc_errors::Applicability;
+use rustc_hir::def::{DefKind, Res};
 use rustc_hir::{Expr, ExprKind};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_session::{declare_lint_pass, declare_tool_lint};
@@ -49,6 +50,7 @@ impl<'tcx> LateLintPass<'tcx> for NumberedFields {
                 && fields
                     .iter()
                     .all(|f| f.ident.as_str().as_bytes().iter().all(u8::is_ascii_digit))
+                && !matches!(cx.qpath_res(path, e.hir_id), Res::Def(DefKind::TyAlias, ..))
             {
                 let expr_spans = fields
                     .iter()
diff --git a/clippy_lints/src/large_include_file.rs b/clippy_lints/src/large_include_file.rs
new file mode 100644
index 00000000000..8bef13c682d
--- /dev/null
+++ b/clippy_lints/src/large_include_file.rs
@@ -0,0 +1,86 @@
+use clippy_utils::diagnostics::span_lint_and_note;
+use clippy_utils::is_lint_allowed;
+use clippy_utils::macros::root_macro_call_first_node;
+use rustc_ast::LitKind;
+use rustc_hir::Expr;
+use rustc_hir::ExprKind;
+use rustc_lint::{LateContext, LateLintPass};
+use rustc_session::{declare_tool_lint, impl_lint_pass};
+use rustc_span::sym;
+
+declare_clippy_lint! {
+    /// ### What it does
+    /// Checks for the inclusion of large files via `include_bytes!()`
+    /// and `include_str!()`
+    ///
+    /// ### Why is this bad?
+    /// Including large files can increase the size of the binary
+    ///
+    /// ### Example
+    /// ```rust,ignore
+    /// let included_str = include_str!("very_large_file.txt");
+    /// let included_bytes = include_bytes!("very_large_file.txt");
+    /// ```
+    ///
+    /// Instead, you can load the file at runtime:
+    /// ```rust,ignore
+    /// use std::fs;
+    ///
+    /// let string = fs::read_to_string("very_large_file.txt")?;
+    /// let bytes = fs::read("very_large_file.txt")?;
+    /// ```
+    #[clippy::version = "1.62.0"]
+    pub LARGE_INCLUDE_FILE,
+    restriction,
+    "including a large file"
+}
+
+pub struct LargeIncludeFile {
+    max_file_size: u64,
+}
+
+impl LargeIncludeFile {
+    #[must_use]
+    pub fn new(max_file_size: u64) -> Self {
+        Self { max_file_size }
+    }
+}
+
+impl_lint_pass!(LargeIncludeFile => [LARGE_INCLUDE_FILE]);
+
+impl LateLintPass<'_> for LargeIncludeFile {
+    fn check_expr(&mut self, cx: &LateContext<'_>, expr: &'_ Expr<'_>) {
+        if_chain! {
+            if let Some(macro_call) = root_macro_call_first_node(cx, expr);
+            if !is_lint_allowed(cx, LARGE_INCLUDE_FILE, expr.hir_id);
+            if cx.tcx.is_diagnostic_item(sym::include_bytes_macro, macro_call.def_id)
+            || cx.tcx.is_diagnostic_item(sym::include_str_macro, macro_call.def_id);
+            if let ExprKind::Lit(lit) = &expr.kind;
+            then {
+                let len = match &lit.node {
+                    // include_bytes
+                    LitKind::ByteStr(bstr) => bstr.len(),
+                    // include_str
+                    LitKind::Str(sym, _) => sym.as_str().len(),
+                    _ => return,
+                };
+
+                if len as u64 <= self.max_file_size {
+                    return;
+                }
+
+                span_lint_and_note(
+                    cx,
+                    LARGE_INCLUDE_FILE,
+                    expr.span,
+                    "attempted to include a large file",
+                    None,
+                    &format!(
+                        "the configuration allows a maximum size of {} bytes",
+                        self.max_file_size
+                    ),
+                );
+            }
+        }
+    }
+}
diff --git a/clippy_lints/src/lib.register_all.rs b/clippy_lints/src/lib.register_all.rs
index 14ca93b5f3c..e68718f9fdf 100644
--- a/clippy_lints/src/lib.register_all.rs
+++ b/clippy_lints/src/lib.register_all.rs
@@ -14,6 +14,7 @@ store.register_group(true, "clippy::all", Some("clippy_all"), vec![
     LintId::of(attrs::DEPRECATED_SEMVER),
     LintId::of(attrs::MISMATCHED_TARGET_OS),
     LintId::of(attrs::USELESS_ATTRIBUTE),
+    LintId::of(await_holding_invalid::AWAIT_HOLDING_INVALID_TYPE),
     LintId::of(await_holding_invalid::AWAIT_HOLDING_LOCK),
     LintId::of(await_holding_invalid::AWAIT_HOLDING_REFCELL_REF),
     LintId::of(bit_mask::BAD_BIT_MASK),
@@ -23,6 +24,7 @@ store.register_group(true, "clippy::all", Some("clippy_all"), vec![
     LintId::of(bool_assert_comparison::BOOL_ASSERT_COMPARISON),
     LintId::of(booleans::LOGIC_BUG),
     LintId::of(booleans::NONMINIMAL_BOOL),
+    LintId::of(bytes_count_to_len::BYTES_COUNT_TO_LEN),
     LintId::of(casts::CAST_ABS_TO_UNSIGNED),
     LintId::of(casts::CAST_ENUM_CONSTRUCTOR),
     LintId::of(casts::CAST_ENUM_TRUNCATION),
@@ -77,6 +79,7 @@ store.register_group(true, "clippy::all", Some("clippy_all"), vec![
     LintId::of(format_args::TO_STRING_IN_FORMAT_ARGS),
     LintId::of(format_impl::PRINT_IN_FORMAT_IMPL),
     LintId::of(format_impl::RECURSIVE_FORMAT_IMPL),
+    LintId::of(format_push_string::FORMAT_PUSH_STRING),
     LintId::of(formatting::POSSIBLE_MISSING_COMMA),
     LintId::of(formatting::SUSPICIOUS_ASSIGNMENT_FORMATTING),
     LintId::of(formatting::SUSPICIOUS_ELSE_FORMATTING),
@@ -165,6 +168,7 @@ store.register_group(true, "clippy::all", Some("clippy_all"), vec![
     LintId::of(methods::FLAT_MAP_IDENTITY),
     LintId::of(methods::INSPECT_FOR_EACH),
     LintId::of(methods::INTO_ITER_ON_REF),
+    LintId::of(methods::IS_DIGIT_ASCII_RADIX),
     LintId::of(methods::ITERATOR_STEP_BY_ZERO),
     LintId::of(methods::ITER_CLONED_COLLECT),
     LintId::of(methods::ITER_COUNT),
@@ -182,6 +186,7 @@ store.register_group(true, "clippy::all", Some("clippy_all"), vec![
     LintId::of(methods::MAP_FLATTEN),
     LintId::of(methods::MAP_IDENTITY),
     LintId::of(methods::NEEDLESS_OPTION_AS_DEREF),
+    LintId::of(methods::NEEDLESS_OPTION_TAKE),
     LintId::of(methods::NEEDLESS_SPLITN),
     LintId::of(methods::NEW_RET_NO_SELF),
     LintId::of(methods::OK_EXPECT),
@@ -243,7 +248,6 @@ store.register_group(true, "clippy::all", Some("clippy_all"), vec![
     LintId::of(non_expressive_names::JUST_UNDERSCORES_AND_DIGITS),
     LintId::of(non_octal_unix_permissions::NON_OCTAL_UNIX_PERMISSIONS),
     LintId::of(octal_escapes::OCTAL_ESCAPES),
-    LintId::of(only_used_in_recursion::ONLY_USED_IN_RECURSION),
     LintId::of(open_options::NONSENSICAL_OPEN_OPTIONS),
     LintId::of(option_env_unwrap::OPTION_ENV_UNWRAP),
     LintId::of(overflow_check_conditional::OVERFLOW_CHECK_CONDITIONAL),
@@ -275,8 +279,8 @@ store.register_group(true, "clippy::all", Some("clippy_all"), vec![
     LintId::of(single_component_path_imports::SINGLE_COMPONENT_PATH_IMPORTS),
     LintId::of(size_of_in_element_count::SIZE_OF_IN_ELEMENT_COUNT),
     LintId::of(slow_vector_initialization::SLOW_VECTOR_INITIALIZATION),
-    LintId::of(stable_sort_primitive::STABLE_SORT_PRIMITIVE),
     LintId::of(strings::STRING_FROM_UTF8_AS_BYTES),
+    LintId::of(strings::TRIM_SPLIT_WHITESPACE),
     LintId::of(strlen_on_c_strings::STRLEN_ON_C_STRINGS),
     LintId::of(suspicious_trait_impl::SUSPICIOUS_ARITHMETIC_IMPL),
     LintId::of(suspicious_trait_impl::SUSPICIOUS_OP_ASSIGN_IMPL),
@@ -306,10 +310,12 @@ store.register_group(true, "clippy::all", Some("clippy_all"), vec![
     LintId::of(uninit_vec::UNINIT_VEC),
     LintId::of(unit_hash::UNIT_HASH),
     LintId::of(unit_return_expecting_ord::UNIT_RETURN_EXPECTING_ORD),
+    LintId::of(unit_types::LET_UNIT_VALUE),
     LintId::of(unit_types::UNIT_ARG),
     LintId::of(unit_types::UNIT_CMP),
     LintId::of(unnamed_address::FN_ADDRESS_COMPARISONS),
     LintId::of(unnamed_address::VTABLE_ADDRESS_COMPARISONS),
+    LintId::of(unnecessary_owned_empty_strings::UNNECESSARY_OWNED_EMPTY_STRINGS),
     LintId::of(unnecessary_sort_by::UNNECESSARY_SORT_BY),
     LintId::of(unsafe_removed_from_name::UNSAFE_REMOVED_FROM_NAME),
     LintId::of(unused_io_amount::UNUSED_IO_AMOUNT),
diff --git a/clippy_lints/src/lib.register_complexity.rs b/clippy_lints/src/lib.register_complexity.rs
index 10369a855ae..6f3c433af31 100644
--- a/clippy_lints/src/lib.register_complexity.rs
+++ b/clippy_lints/src/lib.register_complexity.rs
@@ -5,6 +5,7 @@
 store.register_group(true, "clippy::complexity", Some("clippy_complexity"), vec![
     LintId::of(attrs::DEPRECATED_CFG_ATTR),
     LintId::of(booleans::NONMINIMAL_BOOL),
+    LintId::of(bytes_count_to_len::BYTES_COUNT_TO_LEN),
     LintId::of(casts::CHAR_LIT_AS_U8),
     LintId::of(casts::UNNECESSARY_CAST),
     LintId::of(derivable_impls::DERIVABLE_IMPLS),
@@ -45,6 +46,7 @@ store.register_group(true, "clippy::complexity", Some("clippy_complexity"), vec!
     LintId::of(methods::MAP_FLATTEN),
     LintId::of(methods::MAP_IDENTITY),
     LintId::of(methods::NEEDLESS_OPTION_AS_DEREF),
+    LintId::of(methods::NEEDLESS_OPTION_TAKE),
     LintId::of(methods::NEEDLESS_SPLITN),
     LintId::of(methods::OPTION_AS_REF_DEREF),
     LintId::of(methods::OPTION_FILTER_MAP),
@@ -66,7 +68,6 @@ store.register_group(true, "clippy::complexity", Some("clippy_complexity"), vec!
     LintId::of(neg_cmp_op_on_partial_ord::NEG_CMP_OP_ON_PARTIAL_ORD),
     LintId::of(no_effect::NO_EFFECT),
     LintId::of(no_effect::UNNECESSARY_OPERATION),
-    LintId::of(only_used_in_recursion::ONLY_USED_IN_RECURSION),
     LintId::of(overflow_check_conditional::OVERFLOW_CHECK_CONDITIONAL),
     LintId::of(partialeq_ne_impl::PARTIALEQ_NE_IMPL),
     LintId::of(precedence::PRECEDENCE),
diff --git a/clippy_lints/src/lib.register_lints.rs b/clippy_lints/src/lib.register_lints.rs
index 532590aaa5a..5768edc5018 100644
--- a/clippy_lints/src/lib.register_lints.rs
+++ b/clippy_lints/src/lib.register_lints.rs
@@ -52,6 +52,7 @@ store.register_lints(&[
     attrs::INLINE_ALWAYS,
     attrs::MISMATCHED_TARGET_OS,
     attrs::USELESS_ATTRIBUTE,
+    await_holding_invalid::AWAIT_HOLDING_INVALID_TYPE,
     await_holding_invalid::AWAIT_HOLDING_LOCK,
     await_holding_invalid::AWAIT_HOLDING_REFCELL_REF,
     bit_mask::BAD_BIT_MASK,
@@ -64,6 +65,7 @@ store.register_lints(&[
     booleans::NONMINIMAL_BOOL,
     borrow_as_ptr::BORROW_AS_PTR,
     bytecount::NAIVE_BYTECOUNT,
+    bytes_count_to_len::BYTES_COUNT_TO_LEN,
     cargo::CARGO_COMMON_METADATA,
     cargo::MULTIPLE_CRATE_VERSIONS,
     cargo::NEGATIVE_FEATURE_NAMES,
@@ -132,6 +134,7 @@ store.register_lints(&[
     drop_forget_ref::UNDROPPED_MANUALLY_DROPS,
     duration_subsec::DURATION_SUBSEC,
     else_if_without_else::ELSE_IF_WITHOUT_ELSE,
+    empty_drop::EMPTY_DROP,
     empty_enum::EMPTY_ENUM,
     empty_structs_with_brackets::EMPTY_STRUCTS_WITH_BRACKETS,
     entry::MAP_ENTRY,
@@ -165,6 +168,7 @@ store.register_lints(&[
     format_args::TO_STRING_IN_FORMAT_ARGS,
     format_impl::PRINT_IN_FORMAT_IMPL,
     format_impl::RECURSIVE_FORMAT_IMPL,
+    format_push_string::FORMAT_PUSH_STRING,
     formatting::POSSIBLE_MISSING_COMMA,
     formatting::SUSPICIOUS_ASSIGNMENT_FORMATTING,
     formatting::SUSPICIOUS_ELSE_FORMATTING,
@@ -205,6 +209,7 @@ store.register_lints(&[
     iter_not_returning_iterator::ITER_NOT_RETURNING_ITERATOR,
     large_const_arrays::LARGE_CONST_ARRAYS,
     large_enum_variant::LARGE_ENUM_VARIANT,
+    large_include_file::LARGE_INCLUDE_FILE,
     large_stack_arrays::LARGE_STACK_ARRAYS,
     len_zero::COMPARISON_TO_EMPTY,
     len_zero::LEN_WITHOUT_IS_EMPTY,
@@ -302,6 +307,7 @@ store.register_lints(&[
     methods::INEFFICIENT_TO_STRING,
     methods::INSPECT_FOR_EACH,
     methods::INTO_ITER_ON_REF,
+    methods::IS_DIGIT_ASCII_RADIX,
     methods::ITERATOR_STEP_BY_ZERO,
     methods::ITER_CLONED_COLLECT,
     methods::ITER_COUNT,
@@ -321,6 +327,7 @@ store.register_lints(&[
     methods::MAP_IDENTITY,
     methods::MAP_UNWRAP_OR,
     methods::NEEDLESS_OPTION_AS_DEREF,
+    methods::NEEDLESS_OPTION_TAKE,
     methods::NEEDLESS_SPLITN,
     methods::NEW_RET_NO_SELF,
     methods::OK_EXPECT,
@@ -432,6 +439,7 @@ store.register_lints(&[
     ptr::PTR_ARG,
     ptr_eq::PTR_EQ,
     ptr_offset_with_cast::PTR_OFFSET_WITH_CAST,
+    pub_use::PUB_USE,
     question_mark::QUESTION_MARK,
     ranges::MANUAL_RANGE_CONTAINS,
     ranges::RANGE_MINUS_ONE,
@@ -474,6 +482,7 @@ store.register_lints(&[
     strings::STRING_SLICE,
     strings::STRING_TO_STRING,
     strings::STR_TO_STRING,
+    strings::TRIM_SPLIT_WHITESPACE,
     strlen_on_c_strings::STRLEN_ON_C_STRINGS,
     suspicious_operation_groupings::SUSPICIOUS_OPERATION_GROUPINGS,
     suspicious_trait_impl::SUSPICIOUS_ARITHMETIC_IMPL,
@@ -523,6 +532,7 @@ store.register_lints(&[
     unit_types::UNIT_CMP,
     unnamed_address::FN_ADDRESS_COMPARISONS,
     unnamed_address::VTABLE_ADDRESS_COMPARISONS,
+    unnecessary_owned_empty_strings::UNNECESSARY_OWNED_EMPTY_STRINGS,
     unnecessary_self_imports::UNNECESSARY_SELF_IMPORTS,
     unnecessary_sort_by::UNNECESSARY_SORT_BY,
     unnecessary_wraps::UNNECESSARY_WRAPS,
diff --git a/clippy_lints/src/lib.register_nursery.rs b/clippy_lints/src/lib.register_nursery.rs
index c2fc67afba5..ec187563b3f 100644
--- a/clippy_lints/src/lib.register_nursery.rs
+++ b/clippy_lints/src/lib.register_nursery.rs
@@ -20,6 +20,7 @@ store.register_group(true, "clippy::nursery", Some("clippy_nursery"), vec![
     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),
+    LintId::of(only_used_in_recursion::ONLY_USED_IN_RECURSION),
     LintId::of(option_if_let_else::OPTION_IF_LET_ELSE),
     LintId::of(path_buf_push_overwrite::PATH_BUF_PUSH_OVERWRITE),
     LintId::of(redundant_pub_crate::REDUNDANT_PUB_CRATE),
@@ -27,6 +28,8 @@ store.register_group(true, "clippy::nursery", Some("clippy_nursery"), vec![
     LintId::of(strings::STRING_LIT_AS_BYTES),
     LintId::of(suspicious_operation_groupings::SUSPICIOUS_OPERATION_GROUPINGS),
     LintId::of(trailing_empty_array::TRAILING_EMPTY_ARRAY),
+    LintId::of(trait_bounds::TRAIT_DUPLICATION_IN_BOUNDS),
+    LintId::of(trait_bounds::TYPE_REPETITION_IN_BOUNDS),
     LintId::of(transmute::TRANSMUTE_UNDEFINED_REPR),
     LintId::of(transmute::USELESS_TRANSMUTE),
     LintId::of(use_self::USE_SELF),
diff --git a/clippy_lints/src/lib.register_pedantic.rs b/clippy_lints/src/lib.register_pedantic.rs
index eb6534cb8ca..2ee2c6e3358 100644
--- a/clippy_lints/src/lib.register_pedantic.rs
+++ b/clippy_lints/src/lib.register_pedantic.rs
@@ -82,14 +82,12 @@ store.register_group(true, "clippy::pedantic", Some("clippy_pedantic"), vec![
     LintId::of(ref_option_ref::REF_OPTION_REF),
     LintId::of(return_self_not_must_use::RETURN_SELF_NOT_MUST_USE),
     LintId::of(semicolon_if_nothing_returned::SEMICOLON_IF_NOTHING_RETURNED),
+    LintId::of(stable_sort_primitive::STABLE_SORT_PRIMITIVE),
     LintId::of(strings::STRING_ADD_ASSIGN),
-    LintId::of(trait_bounds::TRAIT_DUPLICATION_IN_BOUNDS),
-    LintId::of(trait_bounds::TYPE_REPETITION_IN_BOUNDS),
     LintId::of(transmute::TRANSMUTE_PTR_TO_PTR),
     LintId::of(types::LINKEDLIST),
     LintId::of(types::OPTION_OPTION),
     LintId::of(unicode::UNICODE_NOT_NFC),
-    LintId::of(unit_types::LET_UNIT_VALUE),
     LintId::of(unnecessary_wraps::UNNECESSARY_WRAPS),
     LintId::of(unnested_or_patterns::UNNESTED_OR_PATTERNS),
     LintId::of(unused_async::UNUSED_ASYNC),
diff --git a/clippy_lints/src/lib.register_perf.rs b/clippy_lints/src/lib.register_perf.rs
index f2f5c988d8f..82431863e6c 100644
--- a/clippy_lints/src/lib.register_perf.rs
+++ b/clippy_lints/src/lib.register_perf.rs
@@ -7,6 +7,7 @@ store.register_group(true, "clippy::perf", Some("clippy_perf"), vec![
     LintId::of(escape::BOXED_LOCAL),
     LintId::of(format_args::FORMAT_IN_FORMAT_ARGS),
     LintId::of(format_args::TO_STRING_IN_FORMAT_ARGS),
+    LintId::of(format_push_string::FORMAT_PUSH_STRING),
     LintId::of(large_const_arrays::LARGE_CONST_ARRAYS),
     LintId::of(large_enum_variant::LARGE_ENUM_VARIANT),
     LintId::of(loops::MANUAL_MEMCPY),
@@ -23,7 +24,6 @@ store.register_group(true, "clippy::perf", Some("clippy_perf"), vec![
     LintId::of(misc::CMP_OWNED),
     LintId::of(redundant_clone::REDUNDANT_CLONE),
     LintId::of(slow_vector_initialization::SLOW_VECTOR_INITIALIZATION),
-    LintId::of(stable_sort_primitive::STABLE_SORT_PRIMITIVE),
     LintId::of(types::BOX_COLLECTION),
     LintId::of(types::REDUNDANT_ALLOCATION),
     LintId::of(vec::USELESS_VEC),
diff --git a/clippy_lints/src/lib.register_restriction.rs b/clippy_lints/src/lib.register_restriction.rs
index 4802dd877e9..77ec6c83ba4 100644
--- a/clippy_lints/src/lib.register_restriction.rs
+++ b/clippy_lints/src/lib.register_restriction.rs
@@ -16,6 +16,7 @@ store.register_group(true, "clippy::restriction", Some("clippy_restriction"), ve
     LintId::of(default_union_representation::DEFAULT_UNION_REPRESENTATION),
     LintId::of(disallowed_script_idents::DISALLOWED_SCRIPT_IDENTS),
     LintId::of(else_if_without_else::ELSE_IF_WITHOUT_ELSE),
+    LintId::of(empty_drop::EMPTY_DROP),
     LintId::of(empty_structs_with_brackets::EMPTY_STRUCTS_WITH_BRACKETS),
     LintId::of(exhaustive_items::EXHAUSTIVE_ENUMS),
     LintId::of(exhaustive_items::EXHAUSTIVE_STRUCTS),
@@ -26,6 +27,7 @@ store.register_group(true, "clippy::restriction", Some("clippy_restriction"), ve
     LintId::of(indexing_slicing::INDEXING_SLICING),
     LintId::of(inherent_impl::MULTIPLE_INHERENT_IMPL),
     LintId::of(integer_division::INTEGER_DIVISION),
+    LintId::of(large_include_file::LARGE_INCLUDE_FILE),
     LintId::of(let_underscore::LET_UNDERSCORE_MUST_USE),
     LintId::of(literal_representation::DECIMAL_LITERAL_REPRESENTATION),
     LintId::of(map_err_ignore::MAP_ERR_IGNORE),
@@ -53,6 +55,7 @@ store.register_group(true, "clippy::restriction", Some("clippy_restriction"), ve
     LintId::of(panic_unimplemented::UNIMPLEMENTED),
     LintId::of(panic_unimplemented::UNREACHABLE),
     LintId::of(pattern_type_mismatch::PATTERN_TYPE_MISMATCH),
+    LintId::of(pub_use::PUB_USE),
     LintId::of(redundant_slicing::DEREF_BY_SLICING),
     LintId::of(same_name_method::SAME_NAME_METHOD),
     LintId::of(shadow::SHADOW_REUSE),
diff --git a/clippy_lints/src/lib.register_style.rs b/clippy_lints/src/lib.register_style.rs
index 3114afac886..d183c0449cd 100644
--- a/clippy_lints/src/lib.register_style.rs
+++ b/clippy_lints/src/lib.register_style.rs
@@ -61,6 +61,7 @@ store.register_group(true, "clippy::style", Some("clippy_style"), vec![
     LintId::of(methods::CHARS_NEXT_CMP),
     LintId::of(methods::ERR_EXPECT),
     LintId::of(methods::INTO_ITER_ON_REF),
+    LintId::of(methods::IS_DIGIT_ASCII_RADIX),
     LintId::of(methods::ITER_CLONED_COLLECT),
     LintId::of(methods::ITER_NEXT_SLICE),
     LintId::of(methods::ITER_NTH_ZERO),
@@ -104,8 +105,11 @@ store.register_group(true, "clippy::style", Some("clippy_style"), vec![
     LintId::of(returns::NEEDLESS_RETURN),
     LintId::of(self_named_constructors::SELF_NAMED_CONSTRUCTORS),
     LintId::of(single_component_path_imports::SINGLE_COMPONENT_PATH_IMPORTS),
+    LintId::of(strings::TRIM_SPLIT_WHITESPACE),
     LintId::of(tabs_in_doc_comments::TABS_IN_DOC_COMMENTS),
     LintId::of(to_digit_is_some::TO_DIGIT_IS_SOME),
+    LintId::of(unit_types::LET_UNIT_VALUE),
+    LintId::of(unnecessary_owned_empty_strings::UNNECESSARY_OWNED_EMPTY_STRINGS),
     LintId::of(unsafe_removed_from_name::UNSAFE_REMOVED_FROM_NAME),
     LintId::of(unused_unit::UNUSED_UNIT),
     LintId::of(upper_case_acronyms::UPPER_CASE_ACRONYMS),
diff --git a/clippy_lints/src/lib.register_suspicious.rs b/clippy_lints/src/lib.register_suspicious.rs
index 82f45b5fd58..7a881bfe399 100644
--- a/clippy_lints/src/lib.register_suspicious.rs
+++ b/clippy_lints/src/lib.register_suspicious.rs
@@ -5,6 +5,7 @@
 store.register_group(true, "clippy::suspicious", Some("clippy_suspicious"), vec![
     LintId::of(assign_ops::MISREFACTORED_ASSIGN_OP),
     LintId::of(attrs::BLANKET_CLIPPY_RESTRICTION_LINTS),
+    LintId::of(await_holding_invalid::AWAIT_HOLDING_INVALID_TYPE),
     LintId::of(await_holding_invalid::AWAIT_HOLDING_LOCK),
     LintId::of(await_holding_invalid::AWAIT_HOLDING_REFCELL_REF),
     LintId::of(casts::CAST_ABS_TO_UNSIGNED),
diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs
index c9b836f9580..3bb821a1482 100644
--- a/clippy_lints/src/lib.rs
+++ b/clippy_lints/src/lib.rs
@@ -163,6 +163,8 @@ mod deprecated_lints;
 #[cfg_attr(feature = "internal", allow(clippy::missing_clippy_version_attribute))]
 mod utils;
 
+mod renamed_lints;
+
 // begin lints modules, do not remove this comment, it’s used in `update_lints`
 mod absurd_extreme_comparisons;
 mod approx_const;
@@ -181,6 +183,7 @@ mod bool_assert_comparison;
 mod booleans;
 mod borrow_as_ptr;
 mod bytecount;
+mod bytes_count_to_len;
 mod cargo;
 mod case_sensitive_file_extension_comparisons;
 mod casts;
@@ -209,6 +212,7 @@ mod double_parens;
 mod drop_forget_ref;
 mod duration_subsec;
 mod else_if_without_else;
+mod empty_drop;
 mod empty_enum;
 mod empty_structs_with_brackets;
 mod entry;
@@ -231,6 +235,7 @@ mod floating_point_arithmetic;
 mod format;
 mod format_args;
 mod format_impl;
+mod format_push_string;
 mod formatting;
 mod from_over_into;
 mod from_str_radix_10;
@@ -259,6 +264,7 @@ mod items_after_statements;
 mod iter_not_returning_iterator;
 mod large_const_arrays;
 mod large_enum_variant;
+mod large_include_file;
 mod large_stack_arrays;
 mod len_zero;
 mod let_if_seq;
@@ -336,6 +342,7 @@ mod precedence;
 mod ptr;
 mod ptr_eq;
 mod ptr_offset_with_cast;
+mod pub_use;
 mod question_mark;
 mod ranges;
 mod redundant_clone;
@@ -383,6 +390,7 @@ mod unit_hash;
 mod unit_return_expecting_ord;
 mod unit_types;
 mod unnamed_address;
+mod unnecessary_owned_empty_strings;
 mod unnecessary_self_imports;
 mod unnecessary_sort_by;
 mod unnecessary_wraps;
@@ -499,7 +507,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
     {
         store.register_early_pass(|| Box::new(utils::internal_lints::ClippyLintsInternal));
         store.register_early_pass(|| Box::new(utils::internal_lints::ProduceIce));
-        store.register_late_pass(|| Box::new(utils::inspector::DeepCodeInspector));
         store.register_late_pass(|| Box::new(utils::internal_lints::CollapsibleCalls));
         store.register_late_pass(|| Box::new(utils::internal_lints::CompilerLintFunctions::new()));
         store.register_late_pass(|| Box::new(utils::internal_lints::IfChainStyle));
@@ -511,8 +518,14 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
         store.register_late_pass(|| Box::new(utils::internal_lints::MsrvAttrImpl));
     }
 
+    store.register_late_pass(|| Box::new(utils::dump_hir::DumpHir));
     store.register_late_pass(|| Box::new(utils::author::Author));
-    store.register_late_pass(|| Box::new(await_holding_invalid::AwaitHolding));
+    let await_holding_invalid_types = conf.await_holding_invalid_types.clone();
+    store.register_late_pass(move || {
+        Box::new(await_holding_invalid::AwaitHolding::new(
+            await_holding_invalid_types.clone(),
+        ))
+    });
     store.register_late_pass(|| Box::new(serde_api::SerdeApi));
     let vec_box_size_threshold = conf.vec_box_size_threshold;
     let type_complexity_threshold = conf.type_complexity_threshold;
@@ -572,7 +585,8 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
     store.register_late_pass(move || Box::new(approx_const::ApproxConstant::new(msrv)));
     store.register_late_pass(move || Box::new(methods::Methods::new(avoid_breaking_exported_api, msrv)));
     store.register_late_pass(move || Box::new(matches::Matches::new(msrv)));
-    store.register_early_pass(move || Box::new(manual_non_exhaustive::ManualNonExhaustive::new(msrv)));
+    store.register_early_pass(move || Box::new(manual_non_exhaustive::ManualNonExhaustiveStruct::new(msrv)));
+    store.register_late_pass(move || Box::new(manual_non_exhaustive::ManualNonExhaustiveEnum::new(msrv)));
     store.register_late_pass(move || Box::new(manual_strip::ManualStrip::new(msrv)));
     store.register_early_pass(move || Box::new(redundant_static_lifetimes::RedundantStaticLifetimes::new(msrv)));
     store.register_early_pass(move || Box::new(redundant_field_names::RedundantFieldNames::new(msrv)));
@@ -812,6 +826,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
     store.register_late_pass(move || Box::new(disallowed_methods::DisallowedMethods::new(disallowed_methods.clone())));
     store.register_early_pass(|| Box::new(asm_syntax::InlineAsmX86AttSyntax));
     store.register_early_pass(|| Box::new(asm_syntax::InlineAsmX86IntelSyntax));
+    store.register_late_pass(|| Box::new(empty_drop::EmptyDrop));
     store.register_late_pass(|| Box::new(strings::StrToString));
     store.register_late_pass(|| Box::new(strings::StringToString));
     store.register_late_pass(|| Box::new(zero_sized_map_values::ZeroSizedMapValues));
@@ -868,6 +883,13 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
     });
     store.register_early_pass(|| Box::new(crate_in_macro_def::CrateInMacroDef));
     store.register_early_pass(|| Box::new(empty_structs_with_brackets::EmptyStructsWithBrackets));
+    store.register_late_pass(|| Box::new(unnecessary_owned_empty_strings::UnnecessaryOwnedEmptyStrings));
+    store.register_early_pass(|| Box::new(pub_use::PubUse));
+    store.register_late_pass(|| Box::new(format_push_string::FormatPushString));
+    store.register_late_pass(|| Box::new(bytes_count_to_len::BytesCountToLen));
+    let max_include_file_size = conf.max_include_file_size;
+    store.register_late_pass(move || Box::new(large_include_file::LargeIncludeFile::new(max_include_file_size)));
+    store.register_late_pass(|| Box::new(strings::TrimSplitWhitespace));
     // add lints here, do not remove this comment, it's used in `new_lint`
 }
 
@@ -919,43 +941,9 @@ fn register_removed_non_tool_lints(store: &mut rustc_lint::LintStore) {
 ///
 /// Used in `./src/driver.rs`.
 pub fn register_renamed(ls: &mut rustc_lint::LintStore) {
-    // NOTE: when renaming a lint, add a corresponding test to tests/ui/rename.rs
-    ls.register_renamed("clippy::stutter", "clippy::module_name_repetitions");
-    ls.register_renamed("clippy::new_without_default_derive", "clippy::new_without_default");
-    ls.register_renamed("clippy::cyclomatic_complexity", "clippy::cognitive_complexity");
-    ls.register_renamed("clippy::const_static_lifetime", "clippy::redundant_static_lifetimes");
-    ls.register_renamed("clippy::option_and_then_some", "clippy::bind_instead_of_map");
-    ls.register_renamed("clippy::box_vec", "clippy::box_collection");
-    ls.register_renamed("clippy::block_in_if_condition_expr", "clippy::blocks_in_if_conditions");
-    ls.register_renamed("clippy::block_in_if_condition_stmt", "clippy::blocks_in_if_conditions");
-    ls.register_renamed("clippy::option_map_unwrap_or", "clippy::map_unwrap_or");
-    ls.register_renamed("clippy::option_map_unwrap_or_else", "clippy::map_unwrap_or");
-    ls.register_renamed("clippy::result_map_unwrap_or_else", "clippy::map_unwrap_or");
-    ls.register_renamed("clippy::option_unwrap_used", "clippy::unwrap_used");
-    ls.register_renamed("clippy::result_unwrap_used", "clippy::unwrap_used");
-    ls.register_renamed("clippy::option_expect_used", "clippy::expect_used");
-    ls.register_renamed("clippy::result_expect_used", "clippy::expect_used");
-    ls.register_renamed("clippy::for_loop_over_option", "clippy::for_loops_over_fallibles");
-    ls.register_renamed("clippy::for_loop_over_result", "clippy::for_loops_over_fallibles");
-    ls.register_renamed("clippy::identity_conversion", "clippy::useless_conversion");
-    ls.register_renamed("clippy::zero_width_space", "clippy::invisible_characters");
-    ls.register_renamed("clippy::single_char_push_str", "clippy::single_char_add_str");
-    ls.register_renamed("clippy::if_let_some_result", "clippy::match_result_ok");
-    ls.register_renamed("clippy::disallowed_type", "clippy::disallowed_types");
-    ls.register_renamed("clippy::disallowed_method", "clippy::disallowed_methods");
-    ls.register_renamed("clippy::ref_in_deref", "clippy::needless_borrow");
-    ls.register_renamed("clippy::to_string_in_display", "clippy::recursive_format_impl");
-
-    // uplifted lints
-    ls.register_renamed("clippy::invalid_ref", "invalid_value");
-    ls.register_renamed("clippy::into_iter_on_array", "array_into_iter");
-    ls.register_renamed("clippy::unused_label", "unused_labels");
-    ls.register_renamed("clippy::drop_bounds", "drop_bounds");
-    ls.register_renamed("clippy::temporary_cstring_as_ptr", "temporary_cstring_as_ptr");
-    ls.register_renamed("clippy::panic_params", "non_fmt_panics");
-    ls.register_renamed("clippy::unknown_clippy_lints", "unknown_lints");
-    ls.register_renamed("clippy::invalid_atomic_ordering", "invalid_atomic_ordering");
-    ls.register_renamed("clippy::mem_discriminant_non_enum", "enum_intrinsics_non_enums");
+    for (old_name, new_name) in renamed_lints::RENAMED_LINTS {
+        ls.register_renamed(old_name, new_name);
+    }
 }
 
 // only exists to let the dogfood integration test works.
diff --git a/clippy_lints/src/lifetimes.rs b/clippy_lints/src/lifetimes.rs
index 662a561f171..ab5d3fa7b6d 100644
--- a/clippy_lints/src/lifetimes.rs
+++ b/clippy_lints/src/lifetimes.rs
@@ -1,16 +1,19 @@
 use clippy_utils::diagnostics::span_lint;
 use clippy_utils::trait_ref_of_method;
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
+use rustc_hir::intravisit::nested_filter::{self as hir_nested_filter, NestedFilter};
 use rustc_hir::intravisit::{
-    walk_fn_decl, walk_generic_param, walk_generics, walk_item, walk_param_bound, walk_poly_trait_ref, walk_ty, Visitor,
+    walk_fn_decl, walk_generic_param, walk_generics, walk_impl_item_ref, walk_item, walk_param_bound,
+    walk_poly_trait_ref, walk_trait_ref, walk_ty, Visitor,
 };
 use rustc_hir::FnRetTy::Return;
 use rustc_hir::{
-    BareFnTy, BodyId, FnDecl, GenericArg, GenericBound, GenericParam, GenericParamKind, Generics, ImplItem,
+    BareFnTy, BodyId, FnDecl, GenericArg, GenericBound, GenericParam, GenericParamKind, Generics, Impl, ImplItem,
     ImplItemKind, Item, ItemKind, LangItem, Lifetime, LifetimeName, ParamName, PolyTraitRef, TraitBoundModifier,
     TraitFn, TraitItem, TraitItemKind, Ty, TyKind, WherePredicate,
 };
 use rustc_lint::{LateContext, LateLintPass};
+use rustc_middle::hir::nested_filter as middle_nested_filter;
 use rustc_session::{declare_lint_pass, declare_tool_lint};
 use rustc_span::source_map::Span;
 use rustc_span::symbol::{kw, Ident, Symbol};
@@ -82,8 +85,10 @@ declare_lint_pass!(Lifetimes => [NEEDLESS_LIFETIMES, EXTRA_UNUSED_LIFETIMES]);
 
 impl<'tcx> LateLintPass<'tcx> for Lifetimes {
     fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) {
-        if let ItemKind::Fn(ref sig, ref generics, id) = item.kind {
+        if let ItemKind::Fn(ref sig, generics, id) = item.kind {
             check_fn_inner(cx, sig.decl, Some(id), None, generics, item.span, true);
+        } else if let ItemKind::Impl(impl_) = item.kind {
+            report_extra_impl_lifetimes(cx, impl_);
         }
     }
 
@@ -95,7 +100,7 @@ impl<'tcx> LateLintPass<'tcx> for Lifetimes {
                 sig.decl,
                 Some(id),
                 None,
-                &item.generics,
+                item.generics,
                 item.span,
                 report_extra_lifetimes,
             );
@@ -108,7 +113,7 @@ impl<'tcx> LateLintPass<'tcx> for Lifetimes {
                 TraitFn::Required(sig) => (None, Some(sig)),
                 TraitFn::Provided(id) => (Some(id), None),
             };
-            check_fn_inner(cx, sig.decl, body, trait_sig, &item.generics, item.span, true);
+            check_fn_inner(cx, sig.decl, body, trait_sig, item.generics, item.span, true);
         }
     }
 }
@@ -201,8 +206,7 @@ fn explicit_self_type<'tcx>(cx: &LateContext<'tcx>, func: &FnDecl<'tcx>, ident:
             visitor.visit_ty(self_ty);
 
             !visitor.all_lts().is_empty()
-        }
-        else {
+        } else {
             false
         }
     }
@@ -486,11 +490,29 @@ fn has_where_lifetimes<'tcx>(cx: &LateContext<'tcx>, generics: &'tcx Generics<'_
     false
 }
 
-struct LifetimeChecker {
+struct LifetimeChecker<'cx, 'tcx, F> {
+    cx: &'cx LateContext<'tcx>,
     map: FxHashMap<Symbol, Span>,
+    phantom: std::marker::PhantomData<F>,
 }
 
-impl<'tcx> Visitor<'tcx> for LifetimeChecker {
+impl<'cx, 'tcx, F> LifetimeChecker<'cx, 'tcx, F> {
+    fn new(cx: &'cx LateContext<'tcx>, map: FxHashMap<Symbol, Span>) -> LifetimeChecker<'cx, 'tcx, F> {
+        Self {
+            cx,
+            map,
+            phantom: std::marker::PhantomData,
+        }
+    }
+}
+
+impl<'cx, 'tcx, F> Visitor<'tcx> for LifetimeChecker<'cx, 'tcx, F>
+where
+    F: NestedFilter<'tcx>,
+{
+    type Map = rustc_middle::hir::map::Map<'tcx>;
+    type NestedFilter = F;
+
     // for lifetimes as parameters of generics
     fn visit_lifetime(&mut self, lifetime: &'tcx Lifetime) {
         self.map.remove(&lifetime.name.ident().name);
@@ -506,6 +528,10 @@ impl<'tcx> Visitor<'tcx> for LifetimeChecker {
             walk_generic_param(self, param);
         }
     }
+
+    fn nested_visit_map(&mut self) -> Self::Map {
+        self.cx.tcx.hir()
+    }
 }
 
 fn report_extra_lifetimes<'tcx>(cx: &LateContext<'tcx>, func: &'tcx FnDecl<'_>, generics: &'tcx Generics<'_>) {
@@ -517,7 +543,7 @@ fn report_extra_lifetimes<'tcx>(cx: &LateContext<'tcx>, func: &'tcx FnDecl<'_>,
             _ => None,
         })
         .collect();
-    let mut checker = LifetimeChecker { map: hs };
+    let mut checker = LifetimeChecker::<hir_nested_filter::None>::new(cx, hs);
 
     walk_generics(&mut checker, generics);
     walk_fn_decl(&mut checker, func);
@@ -532,6 +558,32 @@ fn report_extra_lifetimes<'tcx>(cx: &LateContext<'tcx>, func: &'tcx FnDecl<'_>,
     }
 }
 
+fn report_extra_impl_lifetimes<'tcx>(cx: &LateContext<'tcx>, impl_: &'tcx Impl<'_>) {
+    let hs = impl_
+        .generics
+        .params
+        .iter()
+        .filter_map(|par| match par.kind {
+            GenericParamKind::Lifetime { .. } => Some((par.name.ident().name, par.span)),
+            _ => None,
+        })
+        .collect();
+    let mut checker = LifetimeChecker::<middle_nested_filter::All>::new(cx, hs);
+
+    walk_generics(&mut checker, impl_.generics);
+    if let Some(ref trait_ref) = impl_.of_trait {
+        walk_trait_ref(&mut checker, trait_ref);
+    }
+    walk_ty(&mut checker, impl_.self_ty);
+    for item in impl_.items {
+        walk_impl_item_ref(&mut checker, item);
+    }
+
+    for &v in checker.map.values() {
+        span_lint(cx, EXTRA_UNUSED_LIFETIMES, v, "this lifetime isn't used in the impl");
+    }
+}
+
 struct BodyLifetimeChecker {
     lifetimes_used_in_body: bool,
 }
diff --git a/clippy_lints/src/literal_representation.rs b/clippy_lints/src/literal_representation.rs
index b7430f49229..269d3c62eaf 100644
--- a/clippy_lints/src/literal_representation.rs
+++ b/clippy_lints/src/literal_representation.rs
@@ -42,17 +42,12 @@ declare_clippy_lint! {
     /// This is most probably a typo
     ///
     /// ### Known problems
-    /// - Recommends a signed suffix, even though the number might be too big and an unsigned
-    ///   suffix is required
+    /// - Does not match on integers too large to fit in the corresponding unsigned type
     /// - Does not match on `_127` since that is a valid grouping for decimal and octal numbers
     ///
     /// ### Example
-    /// ```rust
-    /// // Probably mistyped
-    /// 2_32;
-    ///
-    /// // Good
-    /// 2_i32;
+    /// `2_32` => `2_i32`
+    /// `250_8 => `250_u8`
     /// ```
     #[clippy::version = "1.30.0"]
     pub MISTYPED_LITERAL_SUFFIXES,
@@ -310,18 +305,47 @@ impl LiteralDigitGrouping {
             return true;
         }
 
-        let (part, mistyped_suffixes, missing_char) = if let Some((_, exponent)) = &mut num_lit.exponent {
-            (exponent, &["32", "64"][..], 'f')
+        let (part, mistyped_suffixes, is_float) = if let Some((_, exponent)) = &mut num_lit.exponent {
+            (exponent, &["32", "64"][..], true)
         } else if num_lit.fraction.is_some() {
-            (&mut num_lit.integer, &["32", "64"][..], 'f')
+            return true;
         } else {
-            (&mut num_lit.integer, &["8", "16", "32", "64"][..], 'i')
+            (&mut num_lit.integer, &["8", "16", "32", "64"][..], false)
         };
 
         let mut split = part.rsplit('_');
         let last_group = split.next().expect("At least one group");
         if split.next().is_some() && mistyped_suffixes.contains(&last_group) {
-            *part = &part[..part.len() - last_group.len()];
+            let main_part = &part[..part.len() - last_group.len()];
+            let missing_char;
+            if is_float {
+                missing_char = 'f';
+            } else {
+                let radix = match num_lit.radix {
+                    Radix::Binary => 2,
+                    Radix::Octal => 8,
+                    Radix::Decimal => 10,
+                    Radix::Hexadecimal => 16,
+                };
+                if let Ok(int) = u64::from_str_radix(&main_part.replace('_', ""), radix) {
+                    missing_char = match (last_group, int) {
+                        ("8", i) if i8::try_from(i).is_ok() => 'i',
+                        ("16", i) if i16::try_from(i).is_ok() => 'i',
+                        ("32", i) if i32::try_from(i).is_ok() => 'i',
+                        ("64", i) if i64::try_from(i).is_ok() => 'i',
+                        ("8", u) if u8::try_from(u).is_ok() => 'u',
+                        ("16", u) if u16::try_from(u).is_ok() => 'u',
+                        ("32", u) if u32::try_from(u).is_ok() => 'u',
+                        ("64", _) => 'u',
+                        _ => {
+                            return true;
+                        },
+                    }
+                } else {
+                    return true;
+                }
+            }
+            *part = main_part;
             let mut sugg = num_lit.format();
             sugg.push('_');
             sugg.push(missing_char);
diff --git a/clippy_lints/src/loops/never_loop.rs b/clippy_lints/src/loops/never_loop.rs
index 9ba9642fcc8..70a118d6b35 100644
--- a/clippy_lints/src/loops/never_loop.rs
+++ b/clippy_lints/src/loops/never_loop.rs
@@ -168,8 +168,9 @@ fn never_loop_expr(expr: &Expr<'_>, main_loop_id: HirId) -> NeverLoopResult {
             .operands
             .iter()
             .map(|(o, _)| match o {
-                InlineAsmOperand::In { expr, .. }
-                | InlineAsmOperand::InOut { expr, .. } => never_loop_expr(expr, main_loop_id),
+                InlineAsmOperand::In { expr, .. } | InlineAsmOperand::InOut { expr, .. } => {
+                    never_loop_expr(expr, main_loop_id)
+                },
                 InlineAsmOperand::Out { expr, .. } => never_loop_expr_all(&mut expr.iter(), main_loop_id),
                 InlineAsmOperand::SplitInOut { in_expr, out_expr, .. } => {
                     never_loop_expr_all(&mut once(in_expr).chain(out_expr.iter()), main_loop_id)
diff --git a/clippy_lints/src/manual_bits.rs b/clippy_lints/src/manual_bits.rs
index dcf44303cf4..ac3d9447b6b 100644
--- a/clippy_lints/src/manual_bits.rs
+++ b/clippy_lints/src/manual_bits.rs
@@ -1,6 +1,6 @@
 use clippy_utils::diagnostics::span_lint_and_sugg;
-use clippy_utils::source::snippet_opt;
-use clippy_utils::{meets_msrv, msrvs};
+use clippy_utils::source::snippet_with_applicability;
+use clippy_utils::{get_parent_expr, meets_msrv, msrvs};
 use rustc_ast::ast::LitKind;
 use rustc_errors::Applicability;
 use rustc_hir::{BinOpKind, Expr, ExprKind, GenericArg, QPath};
@@ -24,7 +24,7 @@ declare_clippy_lint! {
     /// ```
     /// Use instead:
     /// ```rust
-    /// usize::BITS;
+    /// usize::BITS as usize;
     /// ```
     #[clippy::version = "1.60.0"]
     pub MANUAL_BITS,
@@ -59,16 +59,19 @@ impl<'tcx> LateLintPass<'tcx> for ManualBits {
             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 {
+                let mut app = Applicability::MachineApplicable;
+                let ty_snip = snippet_with_applicability(cx, real_ty.span, "..", &mut app);
+                let sugg = create_sugg(cx, expr, format!("{ty_snip}::BITS"));
+
                 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,
+                    sugg,
+                    app,
                 );
             }
         }
@@ -108,3 +111,36 @@ fn get_size_of_ty<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> Option<
         }
     }
 }
+
+fn create_sugg(cx: &LateContext<'_>, expr: &Expr<'_>, base_sugg: String) -> String {
+    if let Some(parent_expr) = get_parent_expr(cx, expr) {
+        if is_ty_conversion(parent_expr) {
+            return base_sugg;
+        }
+
+        // These expressions have precedence over casts, the suggestion therefore
+        // needs to be wrapped into parentheses
+        match parent_expr.kind {
+            ExprKind::Unary(..) | ExprKind::AddrOf(..) | ExprKind::MethodCall(..) => {
+                return format!("({base_sugg} as usize)");
+            },
+            _ => {},
+        }
+    }
+
+    format!("{base_sugg} as usize")
+}
+
+fn is_ty_conversion(expr: &Expr<'_>) -> bool {
+    if let ExprKind::Cast(..) = expr.kind {
+        true
+    } else if let ExprKind::MethodCall(path, [_], _) = expr.kind
+        && path.ident.name == rustc_span::sym::try_into
+    {
+        // This is only called for `usize` which implements `TryInto`. Therefore,
+        // we don't have to check here if `self` implements the `TryInto` trait.
+        true
+    } else {
+        false
+    }
+}
diff --git a/clippy_lints/src/manual_non_exhaustive.rs b/clippy_lints/src/manual_non_exhaustive.rs
index 33d1bb2985f..b8d620d8171 100644
--- a/clippy_lints/src/manual_non_exhaustive.rs
+++ b/clippy_lints/src/manual_non_exhaustive.rs
@@ -1,13 +1,17 @@
 use clippy_utils::attrs::is_doc_hidden;
 use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::source::snippet_opt;
-use clippy_utils::{meets_msrv, msrvs};
-use if_chain::if_chain;
-use rustc_ast::ast::{FieldDef, Item, ItemKind, Variant, VariantData, VisibilityKind};
+use clippy_utils::{is_lint_allowed, meets_msrv, msrvs};
+use rustc_ast::ast::{self, VisibilityKind};
+use rustc_data_structures::fx::FxHashSet;
 use rustc_errors::Applicability;
-use rustc_lint::{EarlyContext, EarlyLintPass, LintContext};
+use rustc_hir::def::{CtorKind, CtorOf, DefKind, Res};
+use rustc_hir::{self as hir, Expr, ExprKind, QPath};
+use rustc_lint::{EarlyContext, EarlyLintPass, LateContext, LateLintPass, LintContext};
+use rustc_middle::ty::DefIdTree;
 use rustc_semver::RustcVersion;
 use rustc_session::{declare_tool_lint, impl_lint_pass};
+use rustc_span::def_id::{DefId, LocalDefId};
 use rustc_span::{sym, Span};
 
 declare_clippy_lint! {
@@ -58,67 +62,75 @@ declare_clippy_lint! {
     "manual implementations of the non-exhaustive pattern can be simplified using #[non_exhaustive]"
 }
 
-#[derive(Clone)]
-pub struct ManualNonExhaustive {
+#[allow(clippy::module_name_repetitions)]
+pub struct ManualNonExhaustiveStruct {
     msrv: Option<RustcVersion>,
 }
 
-impl ManualNonExhaustive {
+impl ManualNonExhaustiveStruct {
     #[must_use]
     pub fn new(msrv: Option<RustcVersion>) -> Self {
         Self { msrv }
     }
 }
 
-impl_lint_pass!(ManualNonExhaustive => [MANUAL_NON_EXHAUSTIVE]);
+impl_lint_pass!(ManualNonExhaustiveStruct => [MANUAL_NON_EXHAUSTIVE]);
 
-impl EarlyLintPass for ManualNonExhaustive {
-    fn check_item(&mut self, cx: &EarlyContext<'_>, item: &Item) {
-        if !meets_msrv(self.msrv.as_ref(), &msrvs::NON_EXHAUSTIVE) {
-            return;
-        }
+#[allow(clippy::module_name_repetitions)]
+pub struct ManualNonExhaustiveEnum {
+    msrv: Option<RustcVersion>,
+    constructed_enum_variants: FxHashSet<(DefId, DefId)>,
+    potential_enums: Vec<(LocalDefId, LocalDefId, Span, Span)>,
+}
 
-        match &item.kind {
-            ItemKind::Enum(def, _) => {
-                check_manual_non_exhaustive_enum(cx, item, &def.variants);
-            },
-            ItemKind::Struct(variant_data, _) => {
-                if let VariantData::Unit(..) = variant_data {
-                    return;
-                }
-
-                check_manual_non_exhaustive_struct(cx, item, variant_data);
-            },
-            _ => {},
+impl ManualNonExhaustiveEnum {
+    #[must_use]
+    pub fn new(msrv: Option<RustcVersion>) -> Self {
+        Self {
+            msrv,
+            constructed_enum_variants: FxHashSet::default(),
+            potential_enums: Vec::new(),
         }
     }
-
-    extract_msrv_attr!(EarlyContext);
 }
 
-fn check_manual_non_exhaustive_enum(cx: &EarlyContext<'_>, item: &Item, variants: &[Variant]) {
-    fn is_non_exhaustive_marker(variant: &Variant) -> bool {
-        matches!(variant.data, VariantData::Unit(_))
-            && variant.ident.as_str().starts_with('_')
-            && is_doc_hidden(&variant.attrs)
-    }
+impl_lint_pass!(ManualNonExhaustiveEnum => [MANUAL_NON_EXHAUSTIVE]);
 
-    let mut markers = variants.iter().filter(|v| is_non_exhaustive_marker(v));
-    if_chain! {
-        if let Some(marker) = markers.next();
-        if markers.count() == 0 && variants.len() > 1;
-        then {
-            span_lint_and_then(
-                cx,
-                MANUAL_NON_EXHAUSTIVE,
-                item.span,
-                "this seems like a manual implementation of the non-exhaustive pattern",
-                |diag| {
-                    if_chain! {
-                        if !item.attrs.iter().any(|attr| attr.has_name(sym::non_exhaustive));
-                        let header_span = cx.sess().source_map().span_until_char(item.span, '{');
-                        if let Some(snippet) = snippet_opt(cx, header_span);
-                        then {
+impl EarlyLintPass for ManualNonExhaustiveStruct {
+    fn check_item(&mut self, cx: &EarlyContext<'_>, item: &ast::Item) {
+        if !meets_msrv(self.msrv.as_ref(), &msrvs::NON_EXHAUSTIVE) {
+            return;
+        }
+
+        if let ast::ItemKind::Struct(variant_data, _) = &item.kind {
+            let (fields, delimiter) = match variant_data {
+                ast::VariantData::Struct(fields, _) => (&**fields, '{'),
+                ast::VariantData::Tuple(fields, _) => (&**fields, '('),
+                ast::VariantData::Unit(_) => return,
+            };
+            if fields.len() <= 1 {
+                return;
+            }
+            let mut iter = fields.iter().filter_map(|f| match f.vis.kind {
+                VisibilityKind::Public => None,
+                VisibilityKind::Inherited => Some(Ok(f)),
+                _ => Some(Err(())),
+            });
+            if let Some(Ok(field)) = iter.next()
+                && iter.next().is_none()
+                && field.ty.kind.is_unit()
+                && field.ident.map_or(true, |name| name.as_str().starts_with('_'))
+            {
+                span_lint_and_then(
+                    cx,
+                    MANUAL_NON_EXHAUSTIVE,
+                    item.span,
+                    "this seems like a manual implementation of the non-exhaustive pattern",
+                    |diag| {
+                        if !item.attrs.iter().any(|attr| attr.has_name(sym::non_exhaustive))
+                            && let header_span = cx.sess().source_map().span_until_char(item.span, delimiter)
+                            && let Some(snippet) = snippet_opt(cx, header_span)
+                        {
                             diag.span_suggestion(
                                 header_span,
                                 "add the attribute",
@@ -126,61 +138,84 @@ fn check_manual_non_exhaustive_enum(cx: &EarlyContext<'_>, item: &Item, variants
                                 Applicability::Unspecified,
                             );
                         }
+                        diag.span_help(field.span, "remove this field");
                     }
-                    diag.span_help(marker.span, "remove this variant");
-                });
+                );
+            }
         }
     }
+
+    extract_msrv_attr!(EarlyContext);
 }
 
-fn check_manual_non_exhaustive_struct(cx: &EarlyContext<'_>, item: &Item, data: &VariantData) {
-    fn is_private(field: &FieldDef) -> bool {
-        matches!(field.vis.kind, VisibilityKind::Inherited)
-    }
+impl<'tcx> LateLintPass<'tcx> for ManualNonExhaustiveEnum {
+    fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::Item<'_>) {
+        if !meets_msrv(self.msrv.as_ref(), &msrvs::NON_EXHAUSTIVE) {
+            return;
+        }
 
-    fn is_non_exhaustive_marker(field: &FieldDef) -> bool {
-        is_private(field) && field.ty.kind.is_unit() && field.ident.map_or(true, |n| n.as_str().starts_with('_'))
+        if let hir::ItemKind::Enum(def, _) = &item.kind
+            && def.variants.len() > 1
+        {
+            let mut iter = def.variants.iter().filter_map(|v| {
+                let id = cx.tcx.hir().local_def_id(v.id);
+                (matches!(v.data, hir::VariantData::Unit(_))
+                    && v.ident.as_str().starts_with('_')
+                    && is_doc_hidden(cx.tcx.get_attrs(id.to_def_id())))
+                .then(|| (id, v.span))
+            });
+            if let Some((id, span)) = iter.next()
+                && iter.next().is_none()
+            {
+                self.potential_enums.push((item.def_id, id, item.span, span));
+            }
+        }
     }
 
-    fn find_header_span(cx: &EarlyContext<'_>, item: &Item, data: &VariantData) -> Span {
-        let delimiter = match data {
-            VariantData::Struct(..) => '{',
-            VariantData::Tuple(..) => '(',
-            VariantData::Unit(_) => unreachable!("`VariantData::Unit` is already handled above"),
-        };
+    fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) {
+        if let ExprKind::Path(QPath::Resolved(None, p)) = &e.kind
+            && let [.., name] = p.segments
+            && let Res::Def(DefKind::Ctor(CtorOf::Variant, CtorKind::Const), id) = p.res
+            && name.ident.as_str().starts_with('_')
+        {
+            let variant_id = cx.tcx.parent(id);
+            let enum_id = cx.tcx.parent(variant_id);
 
-        cx.sess().source_map().span_until_char(item.span, delimiter)
+            self.constructed_enum_variants.insert((enum_id, variant_id));
+        }
     }
 
-    let fields = data.fields();
-    let private_fields = fields.iter().filter(|f| is_private(f)).count();
-    let public_fields = fields.iter().filter(|f| f.vis.kind.is_pub()).count();
-
-    if_chain! {
-        if private_fields == 1 && public_fields >= 1 && public_fields == fields.len() - 1;
-        if let Some(marker) = fields.iter().find(|f| is_non_exhaustive_marker(f));
-        then {
+    fn check_crate_post(&mut self, cx: &LateContext<'tcx>) {
+        for &(enum_id, _, enum_span, variant_span) in
+            self.potential_enums.iter().filter(|&&(enum_id, variant_id, _, _)| {
+                !self
+                    .constructed_enum_variants
+                    .contains(&(enum_id.to_def_id(), variant_id.to_def_id()))
+                    && !is_lint_allowed(cx, MANUAL_NON_EXHAUSTIVE, cx.tcx.hir().local_def_id_to_hir_id(enum_id))
+            })
+        {
             span_lint_and_then(
                 cx,
                 MANUAL_NON_EXHAUSTIVE,
-                item.span,
+                enum_span,
                 "this seems like a manual implementation of the non-exhaustive pattern",
                 |diag| {
-                    if_chain! {
-                        if !item.attrs.iter().any(|attr| attr.has_name(sym::non_exhaustive));
-                        let header_span = find_header_span(cx, item, data);
-                        if let Some(snippet) = snippet_opt(cx, header_span);
-                        then {
+                    if !cx.tcx.adt_def(enum_id).is_variant_list_non_exhaustive()
+                        && let header_span = cx.sess().source_map().span_until_char(enum_span, '{')
+                        && let Some(snippet) = snippet_opt(cx, header_span)
+                    {
                             diag.span_suggestion(
                                 header_span,
                                 "add the attribute",
                                 format!("#[non_exhaustive] {}", snippet),
                                 Applicability::Unspecified,
                             );
-                        }
                     }
-                    diag.span_help(marker.span, "remove this field");
-                });
+                    diag.span_help(variant_span, "remove this variant");
+                },
+            );
         }
     }
+
+    extract_msrv_attr!(LateContext);
 }
diff --git a/clippy_lints/src/map_clone.rs b/clippy_lints/src/map_clone.rs
index e233300e26a..ceb66947d02 100644
--- a/clippy_lints/src/map_clone.rs
+++ b/clippy_lints/src/map_clone.rs
@@ -143,15 +143,11 @@ fn lint_needless_cloning(cx: &LateContext<'_>, root: Span, receiver: Span) {
 impl MapClone {
     fn lint_explicit_closure(&self, cx: &LateContext<'_>, replace: Span, root: Span, is_copy: bool) {
         let mut applicability = Applicability::MachineApplicable;
-        let message = if is_copy {
-            "you are using an explicit closure for copying elements"
-        } else {
-            "you are using an explicit closure for cloning elements"
-        };
-        let sugg_method = if is_copy && meets_msrv(self.msrv.as_ref(), &msrvs::ITERATOR_COPIED) {
-            "copied"
+
+        let (message, sugg_method) = if is_copy && meets_msrv(self.msrv.as_ref(), &msrvs::ITERATOR_COPIED) {
+            ("you are using an explicit closure for copying elements", "copied")
         } else {
-            "cloned"
+            ("you are using an explicit closure for cloning elements", "cloned")
         };
 
         span_lint_and_sugg(
diff --git a/clippy_lints/src/match_result_ok.rs b/clippy_lints/src/match_result_ok.rs
index 77a4917ec58..3349b85f134 100644
--- a/clippy_lints/src/match_result_ok.rs
+++ b/clippy_lints/src/match_result_ok.rs
@@ -24,7 +24,7 @@ declare_clippy_lint! {
     ///     vec.push(value)
     /// }
     ///
-    /// if let Some(valie) = iter.next().ok() {
+    /// if let Some(value) = iter.next().ok() {
     ///     vec.push(value)
     /// }
     /// ```
@@ -60,7 +60,7 @@ impl<'tcx> LateLintPass<'tcx> for MatchResultOk {
         if_chain! {
             if let ExprKind::MethodCall(ok_path, [ref result_types_0, ..], _) = let_expr.kind; //check is expr.ok() has type Result<T,E>.ok(, _)
             if let PatKind::TupleStruct(QPath::Resolved(_, x), y, _)  = let_pat.kind; //get operation
-            if method_chain_args(let_expr, &["ok"]).is_some(); //test to see if using ok() methoduse std::marker::Sized;
+            if method_chain_args(let_expr, &["ok"]).is_some(); //test to see if using ok() method use std::marker::Sized;
             if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(result_types_0), sym::Result);
             if rustc_hir_pretty::to_string(rustc_hir_pretty::NO_ANN, |s| s.print_path(x, false)) == "Some";
 
diff --git a/clippy_lints/src/matches/infalliable_detructuring_match.rs b/clippy_lints/src/matches/infallible_destructuring_match.rs
index 2472acb6f6e..2472acb6f6e 100644
--- a/clippy_lints/src/matches/infalliable_detructuring_match.rs
+++ b/clippy_lints/src/matches/infallible_destructuring_match.rs
diff --git a/clippy_lints/src/matches/match_same_arms.rs b/clippy_lints/src/matches/match_same_arms.rs
index b8591fe0db0..9b7344fb8b0 100644
--- a/clippy_lints/src/matches/match_same_arms.rs
+++ b/clippy_lints/src/matches/match_same_arms.rs
@@ -30,7 +30,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, arms: &'tcx [Arm<'_>]) {
         .map(|a| NormalizedPat::from_pat(cx, &arena, a.pat))
         .collect();
 
-    // The furthast forwards a pattern can move without semantic changes
+    // The furthest forwards a pattern can move without semantic changes
     let forwards_blocking_idxs: Vec<_> = normalized_pats
         .iter()
         .enumerate()
@@ -43,7 +43,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, arms: &'tcx [Arm<'_>]) {
         })
         .collect();
 
-    // The furthast backwards a pattern can move without semantic changes
+    // The furthest backwards a pattern can move without semantic changes
     let backwards_blocking_idxs: Vec<_> = normalized_pats
         .iter()
         .enumerate()
diff --git a/clippy_lints/src/matches/mod.rs b/clippy_lints/src/matches/mod.rs
index e93b494653f..401ecef460c 100644
--- a/clippy_lints/src/matches/mod.rs
+++ b/clippy_lints/src/matches/mod.rs
@@ -1,4 +1,4 @@
-use clippy_utils::source::{snippet_opt, walk_span_to_context};
+use clippy_utils::source::{snippet_opt, span_starts_with, walk_span_to_context};
 use clippy_utils::{meets_msrv, msrvs};
 use rustc_hir::{Arm, Expr, ExprKind, Local, MatchSource, Pat};
 use rustc_lexer::{tokenize, TokenKind};
@@ -7,7 +7,7 @@ use rustc_semver::RustcVersion;
 use rustc_session::{declare_tool_lint, impl_lint_pass};
 use rustc_span::{Span, SpanData, SyntaxContext};
 
-mod infalliable_detructuring_match;
+mod infallible_destructuring_match;
 mod match_as_ref;
 mod match_bool;
 mod match_like_matches;
@@ -653,6 +653,9 @@ impl<'tcx> LateLintPass<'tcx> for Matches {
         }
 
         if let ExprKind::Match(ex, arms, source) = expr.kind {
+            if !span_starts_with(cx, expr.span, "match") {
+                return;
+            }
             if !contains_cfg_arm(cx, expr, ex, arms) {
                 if source == MatchSource::Normal {
                     if !(meets_msrv(self.msrv.as_ref(), &msrvs::MATCHES_MACRO)
@@ -691,7 +694,7 @@ impl<'tcx> LateLintPass<'tcx> for Matches {
     }
 
     fn check_local(&mut self, cx: &LateContext<'tcx>, local: &'tcx Local<'_>) {
-        self.infallible_destructuring_match_linted |= infalliable_detructuring_match::check(cx, local);
+        self.infallible_destructuring_match_linted |= infallible_destructuring_match::check(cx, local);
     }
 
     fn check_pat(&mut self, cx: &LateContext<'tcx>, pat: &'tcx Pat<'_>) {
diff --git a/clippy_lints/src/matches/needless_match.rs b/clippy_lints/src/matches/needless_match.rs
index 2105a03e03a..f920ad4651f 100644
--- a/clippy_lints/src/matches/needless_match.rs
+++ b/clippy_lints/src/matches/needless_match.rs
@@ -83,7 +83,7 @@ fn check_if_let(cx: &LateContext<'_>, if_let: &higher::IfLet<'_>) -> bool {
             return false;
         }
 
-        // Recurrsively check for each `else if let` phrase,
+        // Recursively check for each `else if let` phrase,
         if let Some(ref nested_if_let) = higher::IfLet::hir(cx, if_else) {
             return check_if_let(cx, nested_if_let);
         }
@@ -99,7 +99,7 @@ fn check_if_let(cx: &LateContext<'_>, if_let: &higher::IfLet<'_>) -> bool {
                 if let ExprKind::Path(ref qpath) = ret.kind {
                     return is_lang_ctor(cx, qpath, OptionNone) || eq_expr_value(cx, if_let.let_expr, ret);
                 }
-                return true;
+                return false;
             }
             return eq_expr_value(cx, if_let.let_expr, ret);
         }
@@ -118,7 +118,7 @@ fn strip_return<'hir>(expr: &'hir Expr<'hir>) -> &'hir Expr<'hir> {
 }
 
 /// Manually check for coercion casting by checking if the type of the match operand or let expr
-/// differs with the assigned local variable or the funtion return type.
+/// differs with the assigned local variable or the function return type.
 fn expr_ty_matches_p_ty(cx: &LateContext<'_>, expr: &Expr<'_>, p_expr: &Expr<'_>) -> bool {
     if let Some(p_node) = get_parent_node(cx.tcx, p_expr.hir_id) {
         match p_node {
diff --git a/clippy_lints/src/matches/redundant_pattern_match.rs b/clippy_lints/src/matches/redundant_pattern_match.rs
index aa3552001f4..37b67647efe 100644
--- a/clippy_lints/src/matches/redundant_pattern_match.rs
+++ b/clippy_lints/src/matches/redundant_pattern_match.rs
@@ -2,17 +2,16 @@ use super::REDUNDANT_PATTERN_MATCHING;
 use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::source::snippet;
 use clippy_utils::sugg::Sugg;
-use clippy_utils::ty::{implements_trait, is_type_diagnostic_item, is_type_lang_item, match_type};
+use clippy_utils::ty::needs_ordered_drop;
 use clippy_utils::{higher, match_def_path};
 use clippy_utils::{is_lang_ctor, is_trait_method, paths};
 use if_chain::if_chain;
 use rustc_ast::ast::LitKind;
-use rustc_data_structures::fx::FxHashSet;
 use rustc_errors::Applicability;
 use rustc_hir::LangItem::{OptionNone, PollPending};
 use rustc_hir::{
     intravisit::{walk_expr, Visitor},
-    Arm, Block, Expr, ExprKind, LangItem, Node, Pat, PatKind, QPath, UnOp,
+    Arm, Block, Expr, ExprKind, Node, Pat, PatKind, QPath, UnOp,
 };
 use rustc_lint::LateContext;
 use rustc_middle::ty::{self, subst::GenericArgKind, DefIdTree, Ty};
@@ -32,59 +31,6 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
     }
 }
 
-/// 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<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool {
-    type_needs_ordered_drop_inner(cx, ty, &mut FxHashSet::default())
-}
-
-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;
-    }
-    if !ty.needs_drop(cx.tcx, cx.param_env) {
-        false
-    } else if !cx
-        .tcx
-        .lang_items()
-        .drop_trait()
-        .map_or(false, |id| implements_trait(cx, ty, id, &[]))
-    {
-        // This type doesn't implement drop, so no side effects here.
-        // Check if any component type has any.
-        match ty.kind() {
-            ty::Tuple(fields) => fields.iter().any(|ty| type_needs_ordered_drop_inner(cx, ty, seen)),
-            ty::Array(ty, _) => type_needs_ordered_drop_inner(cx, *ty, seen),
-            ty::Adt(adt, subs) => adt
-                .all_fields()
-                .map(|f| f.ty(cx.tcx, subs))
-                .any(|ty| type_needs_ordered_drop_inner(cx, ty, seen)),
-            _ => true,
-        }
-    }
-    // Check for std types which implement drop, but only for memory allocation.
-    else if is_type_diagnostic_item(cx, ty, sym::Vec)
-        || is_type_lang_item(cx, ty, LangItem::OwnedBox)
-        || is_type_diagnostic_item(cx, ty, sym::Rc)
-        || is_type_diagnostic_item(cx, ty, sym::Arc)
-        || is_type_diagnostic_item(cx, ty, sym::cstring_type)
-        || is_type_diagnostic_item(cx, ty, sym::BTreeMap)
-        || is_type_diagnostic_item(cx, ty, sym::LinkedList)
-        || match_type(cx, ty, &paths::WEAK_RC)
-        || match_type(cx, ty, &paths::WEAK_ARC)
-    {
-        // Check all of the generic arguments.
-        if let ty::Adt(_, subs) = ty.kind() {
-            subs.types().any(|ty| type_needs_ordered_drop_inner(cx, ty, seen))
-        } else {
-            true
-        }
-    } else {
-        true
-    }
-}
-
 // Extract the generic arguments out of a type
 fn try_get_generic_ty(ty: Ty<'_>, index: usize) -> Option<Ty<'_>> {
     if_chain! {
@@ -115,7 +61,7 @@ fn temporaries_need_ordered_drop<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<
                 // e.g. In `(String::new(), 0).1` the string is a temporary value.
                 ExprKind::AddrOf(_, _, expr) | ExprKind::Field(expr, _) => {
                     if !matches!(expr.kind, ExprKind::Path(_)) {
-                        if type_needs_ordered_drop(self.cx, self.cx.typeck_results().expr_ty(expr)) {
+                        if needs_ordered_drop(self.cx, self.cx.typeck_results().expr_ty(expr)) {
                             self.res = true;
                         } else {
                             self.visit_expr(expr);
@@ -126,7 +72,7 @@ fn temporaries_need_ordered_drop<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<
                 // e.g. In `(vec![0])[0]` the vector is a temporary value.
                 ExprKind::Index(base, index) => {
                     if !matches!(base.kind, ExprKind::Path(_)) {
-                        if type_needs_ordered_drop(self.cx, self.cx.typeck_results().expr_ty(base)) {
+                        if needs_ordered_drop(self.cx, self.cx.typeck_results().expr_ty(base)) {
                             self.res = true;
                         } else {
                             self.visit_expr(base);
@@ -143,7 +89,7 @@ fn temporaries_need_ordered_drop<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<
                             .typeck_results()
                             .type_dependent_def_id(expr.hir_id)
                             .map_or(false, |id| self.cx.tcx.fn_sig(id).skip_binder().inputs()[0].is_ref());
-                        if self_by_ref && type_needs_ordered_drop(self.cx, self.cx.typeck_results().expr_ty(self_arg)) {
+                        if self_by_ref && needs_ordered_drop(self.cx, self.cx.typeck_results().expr_ty(self_arg)) {
                             self.res = true;
                         } else {
                             self.visit_expr(self_arg);
@@ -243,7 +189,7 @@ fn find_sugg_for_if_let<'tcx>(
     // scrutinee would be, so they have to be considered as well.
     // e.g. in `if let Some(x) = foo.lock().unwrap().baz.as_ref() { .. }` the lock will be held
     // for the duration if body.
-    let needs_drop = type_needs_ordered_drop(cx, check_ty) || temporaries_need_ordered_drop(cx, let_expr);
+    let needs_drop = needs_ordered_drop(cx, check_ty) || temporaries_need_ordered_drop(cx, let_expr);
 
     // check that `while_let_on_iterator` lint does not trigger
     if_chain! {
diff --git a/clippy_lints/src/matches/rest_pat_in_fully_bound_struct.rs b/clippy_lints/src/matches/rest_pat_in_fully_bound_struct.rs
index 5076239a57c..0aadb482acd 100644
--- a/clippy_lints/src/matches/rest_pat_in_fully_bound_struct.rs
+++ b/clippy_lints/src/matches/rest_pat_in_fully_bound_struct.rs
@@ -14,6 +14,7 @@ pub(crate) fn check(cx: &LateContext<'_>, pat: &Pat<'_>) {
         if let ty::Adt(def, _) = ty.kind();
         if def.is_struct() || def.is_union();
         if fields.len() == def.non_enum_variant().fields.len();
+        if !def.non_enum_variant().is_field_list_non_exhaustive();
 
         then {
             span_lint_and_help(
diff --git a/clippy_lints/src/methods/is_digit_ascii_radix.rs b/clippy_lints/src/methods/is_digit_ascii_radix.rs
new file mode 100644
index 00000000000..ad333df2f2d
--- /dev/null
+++ b/clippy_lints/src/methods/is_digit_ascii_radix.rs
@@ -0,0 +1,50 @@
+//! Lint for `c.is_digit(10)`
+
+use super::IS_DIGIT_ASCII_RADIX;
+use clippy_utils::{
+    consts::constant_full_int, consts::FullInt, diagnostics::span_lint_and_sugg, meets_msrv, msrvs,
+    source::snippet_with_applicability,
+};
+use rustc_errors::Applicability;
+use rustc_hir::Expr;
+use rustc_lint::LateContext;
+use rustc_semver::RustcVersion;
+
+pub(super) fn check<'tcx>(
+    cx: &LateContext<'tcx>,
+    expr: &'tcx Expr<'_>,
+    self_arg: &'tcx Expr<'_>,
+    radix: &'tcx Expr<'_>,
+    msrv: Option<&RustcVersion>,
+) {
+    if !meets_msrv(msrv, &msrvs::IS_ASCII_DIGIT) {
+        return;
+    }
+
+    if !cx.typeck_results().expr_ty_adjusted(self_arg).peel_refs().is_char() {
+        return;
+    }
+
+    if let Some(radix_val) = constant_full_int(cx, cx.typeck_results(), radix) {
+        let (num, replacement) = match radix_val {
+            FullInt::S(10) | FullInt::U(10) => (10, "is_ascii_digit"),
+            FullInt::S(16) | FullInt::U(16) => (16, "is_ascii_hexdigit"),
+            _ => return,
+        };
+        let mut applicability = Applicability::MachineApplicable;
+
+        span_lint_and_sugg(
+            cx,
+            IS_DIGIT_ASCII_RADIX,
+            expr.span,
+            &format!("use of `char::is_digit` with literal radix of {}", num),
+            "try",
+            format!(
+                "{}.{}()",
+                snippet_with_applicability(cx, self_arg.span, "..", &mut applicability),
+                replacement
+            ),
+            applicability,
+        );
+    }
+}
diff --git a/clippy_lints/src/methods/iter_with_drain.rs b/clippy_lints/src/methods/iter_with_drain.rs
index 958c3773087..152072e09c7 100644
--- a/clippy_lints/src/methods/iter_with_drain.rs
+++ b/clippy_lints/src/methods/iter_with_drain.rs
@@ -1,72 +1,47 @@
 use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::higher::Range;
 use clippy_utils::is_integer_const;
-use clippy_utils::ty::is_type_diagnostic_item;
-use clippy_utils::{
-    higher::{self, Range},
-    SpanlessEq,
-};
 use rustc_ast::ast::RangeLimits;
 use rustc_errors::Applicability;
 use rustc_hir::{Expr, ExprKind, QPath};
 use rustc_lint::LateContext;
-use rustc_span::symbol::{sym, Symbol};
+use rustc_span::symbol::sym;
 use rustc_span::Span;
 
 use super::ITER_WITH_DRAIN;
 
-const DRAIN_TYPES: &[Symbol] = &[sym::Vec, sym::VecDeque];
-
 pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, recv: &Expr<'_>, span: Span, arg: &Expr<'_>) {
-    let ty = cx.typeck_results().expr_ty(recv).peel_refs();
-    if let Some(drained_type) = DRAIN_TYPES.iter().find(|&&sym| is_type_diagnostic_item(cx, ty, sym)) {
-        // Refuse to emit `into_iter` suggestion on draining struct fields due
-        // to the strong possibility of processing unmovable field.
-        if let ExprKind::Field(..) = recv.kind {
-            return;
-        }
+    if !matches!(recv.kind, ExprKind::Field(..))
+        && let Some(adt) = cx.typeck_results().expr_ty(recv).ty_adt_def()
+        && let Some(ty_name) = cx.tcx.get_diagnostic_name(adt.did())
+        && matches!(ty_name, sym::Vec | sym::VecDeque)
+        && let Some(range) = Range::hir(arg)
+        && is_full_range(cx, recv, range)
+    {
+        span_lint_and_sugg(
+            cx,
+            ITER_WITH_DRAIN,
+            span.with_hi(expr.span.hi()),
+            &format!("`drain(..)` used on a `{}`", ty_name),
+            "try this",
+            "into_iter()".to_string(),
+            Applicability::MaybeIncorrect,
+        );
+    };
+}
 
-        if let Some(range) = higher::Range::hir(arg) {
-            let left_full = match range {
-                Range { start: Some(start), .. } if is_integer_const(cx, start, 0) => true,
-                Range { start: None, .. } => true,
-                _ => false,
-            };
-            let full = left_full
-                && match range {
-                    Range {
-                        end: Some(end),
-                        limits: RangeLimits::HalfOpen,
-                        ..
-                    } => {
-                        // `x.drain(..x.len())` call
-                        if_chain! {
-                            if let ExprKind::MethodCall(len_path, len_args, _) = end.kind;
-                            if len_path.ident.name == sym::len && len_args.len() == 1;
-                            if let ExprKind::Path(QPath::Resolved(_, drain_path)) = recv.kind;
-                            if let ExprKind::Path(QPath::Resolved(_, len_path)) = len_args[0].kind;
-                            if SpanlessEq::new(cx).eq_path(drain_path, len_path);
-                            then { true }
-                            else { false }
-                        }
-                    },
-                    Range {
-                        end: None,
-                        limits: RangeLimits::HalfOpen,
-                        ..
-                    } => true,
-                    _ => false,
-                };
-            if full {
-                span_lint_and_sugg(
-                    cx,
-                    ITER_WITH_DRAIN,
-                    span.with_hi(expr.span.hi()),
-                    &format!("`drain(..)` used on a `{}`", drained_type),
-                    "try this",
-                    "into_iter()".to_string(),
-                    Applicability::MaybeIncorrect,
-                );
+fn is_full_range(cx: &LateContext<'_>, container: &Expr<'_>, range: Range<'_>) -> bool {
+    range.start.map_or(true, |e| is_integer_const(cx, e, 0))
+        && range.end.map_or(true, |e| {
+            if range.limits == RangeLimits::HalfOpen
+                && let ExprKind::Path(QPath::Resolved(None, container_path)) = container.kind
+                && let ExprKind::MethodCall(name, [self_arg], _) = e.kind
+                && name.ident.name == sym::len
+                && let ExprKind::Path(QPath::Resolved(None, path)) = self_arg.kind
+            {
+                container_path.res == path.res
+            } else {
+                false
             }
-        }
-    }
+        })
 }
diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs
index 70d021a1668..f3be71f6b8b 100644
--- a/clippy_lints/src/methods/mod.rs
+++ b/clippy_lints/src/methods/mod.rs
@@ -26,6 +26,7 @@ mod implicit_clone;
 mod inefficient_to_string;
 mod inspect_for_each;
 mod into_iter_on_ref;
+mod is_digit_ascii_radix;
 mod iter_cloned_collect;
 mod iter_count;
 mod iter_next_slice;
@@ -42,6 +43,7 @@ mod map_flatten;
 mod map_identity;
 mod map_unwrap_or;
 mod needless_option_as_deref;
+mod needless_option_take;
 mod ok_expect;
 mod option_as_ref_deref;
 mod option_map_or_none;
@@ -294,15 +296,15 @@ declare_clippy_lint! {
     /// Checks for methods with certain name prefixes and which
     /// doesn't match how self is taken. The actual rules are:
     ///
-    /// |Prefix |Postfix     |`self` taken           | `self` type  |
-    /// |-------|------------|-----------------------|--------------|
-    /// |`as_`  | none       |`&self` or `&mut self` | any          |
-    /// |`from_`| none       | none                  | any          |
-    /// |`into_`| none       |`self`                 | any          |
-    /// |`is_`  | none       |`&self` or none        | any          |
-    /// |`to_`  | `_mut`     |`&mut self`            | any          |
-    /// |`to_`  | not `_mut` |`self`                 | `Copy`       |
-    /// |`to_`  | not `_mut` |`&self`                | not `Copy`   |
+    /// |Prefix |Postfix     |`self` taken                   | `self` type  |
+    /// |-------|------------|-------------------------------|--------------|
+    /// |`as_`  | none       |`&self` or `&mut self`         | any          |
+    /// |`from_`| none       | none                          | any          |
+    /// |`into_`| none       |`self`                         | any          |
+    /// |`is_`  | none       |`&mut self` or `&self` or none | any          |
+    /// |`to_`  | `_mut`     |`&mut self`                    | any          |
+    /// |`to_`  | not `_mut` |`self`                         | `Copy`       |
+    /// |`to_`  | not `_mut` |`&self`                        | not `Copy`   |
     ///
     /// Note: Clippy doesn't trigger methods with `to_` prefix in:
     /// - Traits definition.
@@ -1265,7 +1267,7 @@ declare_clippy_lint! {
     #[clippy::version = "1.55.0"]
     pub EXTEND_WITH_DRAIN,
     perf,
-    "using vec.append(&mut vec) to move the full range of a vecor to another"
+    "using vec.append(&mut vec) to move the full range of a vector to another"
 }
 
 declare_clippy_lint! {
@@ -2007,13 +2009,27 @@ declare_clippy_lint! {
     /// ### Example
     /// ```rust,ignore
     /// // Bad
-    ///  let (key, value) = _.splitn(2, '=').next_tuple()?;
-    ///  let value = _.splitn(2, '=').nth(1)?;
+    /// let s = "key=value=add";
+    /// let (key, value) = s.splitn(2, '=').next_tuple()?;
+    /// let value = s.splitn(2, '=').nth(1)?;
     ///
+    /// let mut parts = s.splitn(2, '=');
+    /// let key = parts.next()?;
+    /// let value = parts.next()?;
+    /// ```
+    /// Use instead:
+    /// ```rust,ignore
     /// // Good
-    /// let (key, value) = _.split_once('=')?;
-    /// let value = _.split_once('=')?.1;
+    /// let s = "key=value=add";
+    /// let (key, value) = s.split_once('=')?;
+    /// let value = s.split_once('=')?.1;
+    ///
+    /// let (key, value) = s.split_once('=')?;
     /// ```
+    ///
+    /// ### Limitations
+    /// The multiple statement variant currently only detects `iter.next()?`/`iter.next().unwrap()`
+    /// in two separate `let` statements that immediately follow the `splitn()`
     #[clippy::version = "1.57.0"]
     pub MANUAL_SPLIT_ONCE,
     complexity,
@@ -2099,7 +2115,7 @@ declare_clippy_lint! {
     /// using `.collect::<String>()` over `.collect::<Vec<String>>().join("")`
     /// will prevent loop unrolling and will result in a negative performance impact.
     ///
-    /// Additionlly, differences have been observed between aarch64 and x86_64 assembly output,
+    /// Additionally, differences have been observed between aarch64 and x86_64 assembly output,
     /// with aarch64 tending to producing faster assembly in more cases when using `.collect::<String>()`
     #[clippy::version = "1.61.0"]
     pub UNNECESSARY_JOIN,
@@ -2131,6 +2147,56 @@ declare_clippy_lint! {
     "no-op use of `deref` or `deref_mut` method to `Option`."
 }
 
+declare_clippy_lint! {
+    /// ### What it does
+    /// Finds usages of [`char::is_digit`]
+    /// (https://doc.rust-lang.org/stable/std/primitive.char.html#method.is_digit) that
+    /// can be replaced with [`is_ascii_digit`]
+    /// (https://doc.rust-lang.org/stable/std/primitive.char.html#method.is_ascii_digit) or
+    /// [`is_ascii_hexdigit`]
+    /// (https://doc.rust-lang.org/stable/std/primitive.char.html#method.is_ascii_hexdigit).
+    ///
+    /// ### Why is this bad?
+    /// `is_digit(..)` is slower and requires specifying the radix.
+    ///
+    /// ### Example
+    /// ```rust
+    /// let c: char = '6';
+    /// c.is_digit(10);
+    /// c.is_digit(16);
+    /// ```
+    /// Use instead:
+    /// ```rust
+    /// let c: char = '6';
+    /// c.is_ascii_digit();
+    /// c.is_ascii_hexdigit();
+    /// ```
+    #[clippy::version = "1.61.0"]
+    pub IS_DIGIT_ASCII_RADIX,
+    style,
+    "use of `char::is_digit(..)` with literal radix of 10 or 16"
+}
+
+declare_clippy_lint! {
+    ///
+    /// ### Why is this bad?
+    ///
+    /// ### Example
+    /// ```rust
+    /// let x = Some(3);
+    /// x.as_ref().take();
+    /// ```
+    /// Use instead:
+    /// ```rust
+    /// let x = Some(3);
+    /// x.as_ref();
+    /// ```
+    #[clippy::version = "1.61.0"]
+    pub NEEDLESS_OPTION_TAKE,
+    complexity,
+    "using `.as_ref().take()` on a temporary value"
+}
+
 pub struct Methods {
     avoid_breaking_exported_api: bool,
     msrv: Option<RustcVersion>,
@@ -2219,6 +2285,8 @@ impl_lint_pass!(Methods => [
     UNNECESSARY_JOIN,
     ERR_EXPECT,
     NEEDLESS_OPTION_AS_DEREF,
+    IS_DIGIT_ASCII_RADIX,
+    NEEDLESS_OPTION_TAKE,
 ]);
 
 /// Extracts a method call name, args, and `Span` of the method name.
@@ -2254,7 +2322,7 @@ impl<'tcx> LateLintPass<'tcx> for Methods {
                 single_char_add_str::check(cx, expr, args);
                 into_iter_on_ref::check(cx, expr, method_span, method_call.ident.name, args);
                 single_char_pattern::check(cx, expr, method_call.ident.name, args);
-                unnecessary_to_owned::check(cx, expr, method_call.ident.name, args);
+                unnecessary_to_owned::check(cx, expr, method_call.ident.name, args, self.msrv.as_ref());
             },
             hir::ExprKind::Binary(op, lhs, rhs) if op.node == hir::BinOpKind::Eq || op.node == hir::BinOpKind::Ne => {
                 let mut info = BinaryExprInfo {
@@ -2516,6 +2584,7 @@ fn check_methods<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, msrv: Optio
             },
             ("get_or_insert_with", [arg]) => unnecessary_lazy_eval::check(cx, expr, recv, arg, "get_or_insert"),
             ("is_file", []) => filetype_is_file::check(cx, expr, recv),
+            ("is_digit", [radix]) => is_digit_ascii_radix::check(cx, expr, recv, radix, msrv),
             ("is_none", []) => check_is_some_is_none(cx, expr, recv, false),
             ("is_some", []) => check_is_some_is_none(cx, expr, recv, true),
             ("join", [join_arg]) => {
@@ -2574,12 +2643,7 @@ fn check_methods<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, msrv: Optio
             ("splitn" | "rsplitn", [count_arg, pat_arg]) => {
                 if let Some((Constant::Int(count), _)) = constant(cx, cx.typeck_results(), count_arg) {
                     suspicious_splitn::check(cx, name, expr, recv, count);
-                    if count == 2 && meets_msrv(msrv, &msrvs::STR_SPLIT_ONCE) {
-                        str_splitn::check_manual_split_once(cx, name, expr, recv, pat_arg);
-                    }
-                    if count >= 2 {
-                        str_splitn::check_needless_splitn(cx, name, expr, recv, pat_arg, count);
-                    }
+                    str_splitn::check(cx, name, expr, recv, pat_arg, count, msrv);
                 }
             },
             ("splitn_mut" | "rsplitn_mut", [count_arg, _]) => {
@@ -2595,6 +2659,7 @@ fn check_methods<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, msrv: Optio
                     }
                 }
             },
+            ("take", []) => needless_option_take::check(cx, expr, recv),
             ("to_os_string" | "to_owned" | "to_path_buf" | "to_vec", []) => {
                 implicit_clone::check(cx, name, expr, recv);
             },
diff --git a/clippy_lints/src/methods/needless_option_take.rs b/clippy_lints/src/methods/needless_option_take.rs
new file mode 100644
index 00000000000..829c118d291
--- /dev/null
+++ b/clippy_lints/src/methods/needless_option_take.rs
@@ -0,0 +1,41 @@
+use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::match_def_path;
+use clippy_utils::source::snippet_with_applicability;
+use clippy_utils::ty::is_type_diagnostic_item;
+use rustc_errors::Applicability;
+use rustc_hir::Expr;
+use rustc_lint::LateContext;
+use rustc_span::sym;
+
+use super::NEEDLESS_OPTION_TAKE;
+
+pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, recv: &'tcx Expr<'_>) {
+    // Checks if expression type is equal to sym::Option and if the expr is not a syntactic place
+    if !recv.is_syntactic_place_expr() && is_expr_option(cx, recv) && has_expr_as_ref_path(cx, recv) {
+        let mut applicability = Applicability::MachineApplicable;
+        span_lint_and_sugg(
+            cx,
+            NEEDLESS_OPTION_TAKE,
+            expr.span,
+            "called `Option::take()` on a temporary value",
+            "try",
+            format!(
+                "{}",
+                snippet_with_applicability(cx, recv.span, "..", &mut applicability)
+            ),
+            applicability,
+        );
+    }
+}
+
+fn is_expr_option(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
+    let expr_type = cx.typeck_results().expr_ty(expr);
+    is_type_diagnostic_item(cx, expr_type, sym::Option)
+}
+
+fn has_expr_as_ref_path(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
+    if let Some(ref_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id) {
+        return match_def_path(cx, ref_id, &["core", "option", "Option", "as_ref"]);
+    }
+    false
+}
diff --git a/clippy_lints/src/methods/str_splitn.rs b/clippy_lints/src/methods/str_splitn.rs
index 8125930b304..52891eeed06 100644
--- a/clippy_lints/src/methods/str_splitn.rs
+++ b/clippy_lints/src/methods/str_splitn.rs
@@ -1,36 +1,83 @@
 use clippy_utils::consts::{constant, Constant};
-use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then};
 use clippy_utils::source::snippet_with_context;
-use clippy_utils::{is_diag_item_method, match_def_path, paths};
+use clippy_utils::usage::local_used_after_expr;
+use clippy_utils::visitors::expr_visitor;
+use clippy_utils::{is_diag_item_method, match_def_path, meets_msrv, msrvs, path_to_local_id, paths};
 use if_chain::if_chain;
 use rustc_errors::Applicability;
-use rustc_hir::{Expr, ExprKind, HirId, LangItem, Node, QPath};
+use rustc_hir::intravisit::Visitor;
+use rustc_hir::{
+    BindingAnnotation, Expr, ExprKind, HirId, LangItem, Local, MatchSource, Node, Pat, PatKind, QPath, Stmt, StmtKind,
+};
 use rustc_lint::LateContext;
-use rustc_middle::ty::{self, adjustment::Adjust};
-use rustc_span::{symbol::sym, Span, SyntaxContext};
+use rustc_middle::ty;
+use rustc_semver::RustcVersion;
+use rustc_span::{sym, Span, Symbol, SyntaxContext};
 
-use super::MANUAL_SPLIT_ONCE;
+use super::{MANUAL_SPLIT_ONCE, NEEDLESS_SPLITN};
 
-pub(super) fn check_manual_split_once(
+pub(super) fn check(
     cx: &LateContext<'_>,
     method_name: &str,
     expr: &Expr<'_>,
     self_arg: &Expr<'_>,
     pat_arg: &Expr<'_>,
+    count: u128,
+    msrv: Option<&RustcVersion>,
 ) {
-    if !cx.typeck_results().expr_ty_adjusted(self_arg).peel_refs().is_str() {
+    if count < 2 || !cx.typeck_results().expr_ty_adjusted(self_arg).peel_refs().is_str() {
         return;
     }
 
+    let needless = |usage_kind| match usage_kind {
+        IterUsageKind::Nth(n) => count > n + 1,
+        IterUsageKind::NextTuple => count > 2,
+    };
+    let manual = count == 2 && meets_msrv(msrv, &msrvs::STR_SPLIT_ONCE);
+
+    match parse_iter_usage(cx, expr.span.ctxt(), cx.tcx.hir().parent_iter(expr.hir_id)) {
+        Some(usage) if needless(usage.kind) => lint_needless(cx, method_name, expr, self_arg, pat_arg),
+        Some(usage) if manual => check_manual_split_once(cx, method_name, expr, self_arg, pat_arg, &usage),
+        None if manual => {
+            check_manual_split_once_indirect(cx, method_name, expr, self_arg, pat_arg);
+        },
+        _ => {},
+    }
+}
+
+fn lint_needless(cx: &LateContext<'_>, method_name: &str, expr: &Expr<'_>, self_arg: &Expr<'_>, pat_arg: &Expr<'_>) {
+    let mut app = Applicability::MachineApplicable;
+    let r = if method_name == "splitn" { "" } else { "r" };
+
+    span_lint_and_sugg(
+        cx,
+        NEEDLESS_SPLITN,
+        expr.span,
+        &format!("unnecessary use of `{r}splitn`"),
+        "try this",
+        format!(
+            "{}.{r}split({})",
+            snippet_with_context(cx, self_arg.span, expr.span.ctxt(), "..", &mut app).0,
+            snippet_with_context(cx, pat_arg.span, expr.span.ctxt(), "..", &mut app).0,
+        ),
+        app,
+    );
+}
+
+fn check_manual_split_once(
+    cx: &LateContext<'_>,
+    method_name: &str,
+    expr: &Expr<'_>,
+    self_arg: &Expr<'_>,
+    pat_arg: &Expr<'_>,
+    usage: &IterUsage,
+) {
     let ctxt = expr.span.ctxt();
-    let (method_name, msg, reverse) = if method_name == "splitn" {
-        ("split_once", "manual implementation of `split_once`", false)
+    let (msg, reverse) = if method_name == "splitn" {
+        ("manual implementation of `split_once`", false)
     } else {
-        ("rsplit_once", "manual implementation of `rsplit_once`", true)
-    };
-    let usage = match parse_iter_usage(cx, ctxt, cx.tcx.hir().parent_iter(expr.hir_id), reverse) {
-        Some(x) => x,
-        None => return,
+        ("manual implementation of `rsplit_once`", true)
     };
 
     let mut app = Applicability::MachineApplicable;
@@ -39,84 +86,198 @@ pub(super) fn check_manual_split_once(
 
     let sugg = match usage.kind {
         IterUsageKind::NextTuple => {
-            format!("{}.{}({})", self_snip, method_name, pat_snip)
-        },
-        IterUsageKind::RNextTuple => format!("{}.{}({}).map(|(x, y)| (y, x))", self_snip, method_name, pat_snip),
-        IterUsageKind::Next | IterUsageKind::Second => {
-            let self_deref = {
-                let adjust = cx.typeck_results().expr_adjustments(self_arg);
-                if adjust.len() < 2 {
-                    String::new()
-                } else if cx.typeck_results().expr_ty(self_arg).is_box()
-                    || adjust
-                        .iter()
-                        .any(|a| matches!(a.kind, Adjust::Deref(Some(_))) || a.target.is_box())
-                {
-                    format!("&{}", "*".repeat(adjust.len().saturating_sub(1)))
-                } else {
-                    "*".repeat(adjust.len().saturating_sub(2))
-                }
-            };
-            if matches!(usage.kind, IterUsageKind::Next) {
-                match usage.unwrap_kind {
-                    Some(UnwrapKind::Unwrap) => {
-                        if reverse {
-                            format!("{}.{}({}).unwrap().0", self_snip, method_name, pat_snip)
-                        } else {
-                            format!(
-                                "{}.{}({}).map_or({}{}, |x| x.0)",
-                                self_snip, method_name, pat_snip, self_deref, &self_snip
-                            )
-                        }
-                    },
-                    Some(UnwrapKind::QuestionMark) => {
-                        format!(
-                            "{}.{}({}).map_or({}{}, |x| x.0)",
-                            self_snip, method_name, pat_snip, self_deref, &self_snip
-                        )
-                    },
-                    None => {
-                        format!(
-                            "Some({}.{}({}).map_or({}{}, |x| x.0))",
-                            &self_snip, method_name, pat_snip, self_deref, &self_snip
-                        )
-                    },
-                }
+            if reverse {
+                format!("{self_snip}.rsplit_once({pat_snip}).map(|(x, y)| (y, x))")
             } else {
-                match usage.unwrap_kind {
-                    Some(UnwrapKind::Unwrap) => {
-                        if reverse {
-                            // In this case, no better suggestion is offered.
-                            return;
-                        }
-                        format!("{}.{}({}).unwrap().1", self_snip, method_name, pat_snip)
-                    },
-                    Some(UnwrapKind::QuestionMark) => {
-                        format!("{}.{}({})?.1", self_snip, method_name, pat_snip)
-                    },
-                    None => {
-                        format!("{}.{}({}).map(|x| x.1)", self_snip, method_name, pat_snip)
-                    },
-                }
+                format!("{self_snip}.split_once({pat_snip})")
+            }
+        },
+        IterUsageKind::Nth(1) => {
+            let (r, field) = if reverse { ("r", 0) } else { ("", 1) };
+
+            match usage.unwrap_kind {
+                Some(UnwrapKind::Unwrap) => {
+                    format!("{self_snip}.{r}split_once({pat_snip}).unwrap().{field}")
+                },
+                Some(UnwrapKind::QuestionMark) => {
+                    format!("{self_snip}.{r}split_once({pat_snip})?.{field}")
+                },
+                None => {
+                    format!("{self_snip}.{r}split_once({pat_snip}).map(|x| x.{field})")
+                },
             }
         },
+        IterUsageKind::Nth(_) => return,
     };
 
     span_lint_and_sugg(cx, MANUAL_SPLIT_ONCE, usage.span, msg, "try this", sugg, app);
 }
 
+/// checks for
+///
+/// ```
+/// let mut iter = "a.b.c".splitn(2, '.');
+/// let a = iter.next();
+/// let b = iter.next();
+/// ```
+fn check_manual_split_once_indirect(
+    cx: &LateContext<'_>,
+    method_name: &str,
+    expr: &Expr<'_>,
+    self_arg: &Expr<'_>,
+    pat_arg: &Expr<'_>,
+) -> Option<()> {
+    let ctxt = expr.span.ctxt();
+    let mut parents = cx.tcx.hir().parent_iter(expr.hir_id);
+    if let (_, Node::Local(local)) = parents.next()?
+        && let PatKind::Binding(BindingAnnotation::Mutable, iter_binding_id, iter_ident, None) = local.pat.kind
+        && let (iter_stmt_id, Node::Stmt(_)) = parents.next()?
+        && let (_, Node::Block(enclosing_block)) = parents.next()?
+
+        && let mut stmts = enclosing_block
+            .stmts
+            .iter()
+            .skip_while(|stmt| stmt.hir_id != iter_stmt_id)
+            .skip(1)
+
+        && let first = indirect_usage(cx, stmts.next()?, iter_binding_id, ctxt)?
+        && let second = indirect_usage(cx, stmts.next()?, iter_binding_id, ctxt)?
+        && first.unwrap_kind == second.unwrap_kind
+        && first.name != second.name
+        && !local_used_after_expr(cx, iter_binding_id, second.init_expr)
+    {
+        let (r, lhs, rhs) = if method_name == "splitn" {
+            ("", first.name, second.name)
+        } else {
+            ("r", second.name, first.name)
+        };
+        let msg = format!("manual implementation of `{r}split_once`");
+
+        let mut app = Applicability::MachineApplicable;
+        let self_snip = snippet_with_context(cx, self_arg.span, ctxt, "..", &mut app).0;
+        let pat_snip = snippet_with_context(cx, pat_arg.span, ctxt, "..", &mut app).0;
+
+        span_lint_and_then(cx, MANUAL_SPLIT_ONCE, local.span, &msg, |diag| {
+            diag.span_label(first.span, "first usage here");
+            diag.span_label(second.span, "second usage here");
+
+            let unwrap = match first.unwrap_kind {
+                UnwrapKind::Unwrap => ".unwrap()",
+                UnwrapKind::QuestionMark => "?",
+            };
+            diag.span_suggestion_verbose(
+                local.span,
+                &format!("try `{r}split_once`"),
+                format!("let ({lhs}, {rhs}) = {self_snip}.{r}split_once({pat_snip}){unwrap};"),
+                app,
+            );
+
+            let remove_msg = format!("remove the `{iter_ident}` usages");
+            diag.span_suggestion(
+                first.span,
+                &remove_msg,
+                String::new(),
+                app,
+            );
+            diag.span_suggestion(
+                second.span,
+                &remove_msg,
+                String::new(),
+                app,
+            );
+        });
+    }
+
+    Some(())
+}
+
+#[derive(Debug)]
+struct IndirectUsage<'a> {
+    name: Symbol,
+    span: Span,
+    init_expr: &'a Expr<'a>,
+    unwrap_kind: UnwrapKind,
+}
+
+/// returns `Some(IndirectUsage)` for e.g.
+///
+/// ```ignore
+/// let name = binding.next()?;
+/// let name = binding.next().unwrap();
+/// ```
+fn indirect_usage<'tcx>(
+    cx: &LateContext<'tcx>,
+    stmt: &Stmt<'tcx>,
+    binding: HirId,
+    ctxt: SyntaxContext,
+) -> Option<IndirectUsage<'tcx>> {
+    if let StmtKind::Local(Local {
+        pat:
+            Pat {
+                kind: PatKind::Binding(BindingAnnotation::Unannotated, _, ident, None),
+                ..
+            },
+        init: Some(init_expr),
+        hir_id: local_hir_id,
+        ..
+    }) = stmt.kind
+    {
+        let mut path_to_binding = None;
+        expr_visitor(cx, |expr| {
+            if path_to_local_id(expr, binding) {
+                path_to_binding = Some(expr);
+            }
+
+            path_to_binding.is_none()
+        })
+        .visit_expr(init_expr);
+
+        let mut parents = cx.tcx.hir().parent_iter(path_to_binding?.hir_id);
+        let iter_usage = parse_iter_usage(cx, ctxt, &mut parents)?;
+
+        let (parent_id, _) = parents.find(|(_, node)| {
+            !matches!(
+                node,
+                Node::Expr(Expr {
+                    kind: ExprKind::Match(.., MatchSource::TryDesugar),
+                    ..
+                })
+            )
+        })?;
+
+        if let IterUsage {
+            kind: IterUsageKind::Nth(0),
+            unwrap_kind: Some(unwrap_kind),
+            ..
+        } = iter_usage
+        {
+            if parent_id == *local_hir_id {
+                return Some(IndirectUsage {
+                    name: ident.name,
+                    span: stmt.span,
+                    init_expr,
+                    unwrap_kind,
+                });
+            }
+        }
+    }
+
+    None
+}
+
+#[derive(Debug, Clone, Copy)]
 enum IterUsageKind {
-    Next,
-    Second,
+    Nth(u128),
     NextTuple,
-    RNextTuple,
 }
 
+#[derive(Debug, PartialEq)]
 enum UnwrapKind {
     Unwrap,
     QuestionMark,
 }
 
+#[derive(Debug)]
 struct IterUsage {
     kind: IterUsageKind,
     unwrap_kind: Option<UnwrapKind>,
@@ -128,7 +289,6 @@ fn parse_iter_usage<'tcx>(
     cx: &LateContext<'tcx>,
     ctxt: SyntaxContext,
     mut iter: impl Iterator<Item = (HirId, Node<'tcx>)>,
-    reverse: bool,
 ) -> Option<IterUsage> {
     let (kind, span) = match iter.next() {
         Some((_, Node::Expr(e))) if e.span.ctxt() == ctxt => {
@@ -141,13 +301,7 @@ fn parse_iter_usage<'tcx>(
             let iter_id = cx.tcx.get_diagnostic_item(sym::Iterator)?;
 
             match (name.ident.as_str(), args) {
-                ("next", []) if cx.tcx.trait_of_item(did) == Some(iter_id) => {
-                    if reverse {
-                        (IterUsageKind::Second, e.span)
-                    } else {
-                        (IterUsageKind::Next, e.span)
-                    }
-                },
+                ("next", []) if cx.tcx.trait_of_item(did) == Some(iter_id) => (IterUsageKind::Nth(0), e.span),
                 ("next_tuple", []) => {
                     return if_chain! {
                         if match_def_path(cx, did, &paths::ITERTOOLS_NEXT_TUPLE);
@@ -157,7 +311,7 @@ fn parse_iter_usage<'tcx>(
                         if subs.len() == 2;
                         then {
                             Some(IterUsage {
-                                kind: if reverse { IterUsageKind::RNextTuple } else { IterUsageKind::NextTuple },
+                                kind: IterUsageKind::NextTuple,
                                 span: e.span,
                                 unwrap_kind: None
                             })
@@ -185,11 +339,7 @@ fn parse_iter_usage<'tcx>(
                                 }
                             }
                         };
-                        match if reverse { idx ^ 1 } else { idx } {
-                            0 => (IterUsageKind::Next, span),
-                            1 => (IterUsageKind::Second, span),
-                            _ => return None,
-                        }
+                        (IterUsageKind::Nth(idx), span)
                     } else {
                         return None;
                     }
@@ -238,86 +388,3 @@ fn parse_iter_usage<'tcx>(
         span,
     })
 }
-
-use super::NEEDLESS_SPLITN;
-
-pub(super) fn check_needless_splitn(
-    cx: &LateContext<'_>,
-    method_name: &str,
-    expr: &Expr<'_>,
-    self_arg: &Expr<'_>,
-    pat_arg: &Expr<'_>,
-    count: u128,
-) {
-    if !cx.typeck_results().expr_ty_adjusted(self_arg).peel_refs().is_str() {
-        return;
-    }
-    let ctxt = expr.span.ctxt();
-    let mut app = Applicability::MachineApplicable;
-    let (reverse, message) = if method_name == "splitn" {
-        (false, "unnecessary use of `splitn`")
-    } else {
-        (true, "unnecessary use of `rsplitn`")
-    };
-    if_chain! {
-        if count >= 2;
-        if check_iter(cx, ctxt, cx.tcx.hir().parent_iter(expr.hir_id), count);
-        then {
-            span_lint_and_sugg(
-                cx,
-                NEEDLESS_SPLITN,
-                expr.span,
-                message,
-                "try this",
-                format!(
-                    "{}.{}({})",
-                    snippet_with_context(cx, self_arg.span, ctxt, "..", &mut app).0,
-                    if reverse {"rsplit"} else {"split"},
-                    snippet_with_context(cx, pat_arg.span, ctxt, "..", &mut app).0
-                ),
-                app,
-            );
-        }
-    }
-}
-
-fn check_iter<'tcx>(
-    cx: &LateContext<'tcx>,
-    ctxt: SyntaxContext,
-    mut iter: impl Iterator<Item = (HirId, Node<'tcx>)>,
-    count: u128,
-) -> bool {
-    match iter.next() {
-        Some((_, Node::Expr(e))) if e.span.ctxt() == ctxt => {
-            let (name, args) = if let ExprKind::MethodCall(name, [_, args @ ..], _) = e.kind {
-                (name, args)
-            } else {
-                return false;
-            };
-            if_chain! {
-                if let Some(did) = cx.typeck_results().type_dependent_def_id(e.hir_id);
-                if let Some(iter_id) = cx.tcx.get_diagnostic_item(sym::Iterator);
-                then {
-                    match (name.ident.as_str(), args) {
-                        ("next", []) if cx.tcx.trait_of_item(did) == Some(iter_id) => {
-                            return true;
-                        },
-                        ("next_tuple", []) if count > 2 => {
-                            return true;
-                        },
-                        ("nth", [idx_expr]) if cx.tcx.trait_of_item(did) == Some(iter_id) => {
-                            if let Some((Constant::Int(idx), _)) = constant(cx, cx.typeck_results(), idx_expr) {
-                                if count > idx + 1 {
-                                    return true;
-                                }
-                            }
-                        },
-                        _ =>  return false,
-                    }
-                }
-            }
-        },
-        _ => return false,
-    };
-    false
-}
diff --git a/clippy_lints/src/methods/unnecessary_to_owned.rs b/clippy_lints/src/methods/unnecessary_to_owned.rs
index 1555758fc4a..02b882e8b55 100644
--- a/clippy_lints/src/methods/unnecessary_to_owned.rs
+++ b/clippy_lints/src/methods/unnecessary_to_owned.rs
@@ -5,6 +5,8 @@ use clippy_utils::source::snippet_opt;
 use clippy_utils::ty::{
     contains_ty, get_associated_type, get_iterator_item_ty, implements_trait, is_copy, peel_mid_ty_refs,
 };
+use clippy_utils::{meets_msrv, msrvs};
+
 use clippy_utils::{fn_def_id, get_parent_expr, is_diag_item_method, is_diag_trait_item};
 use rustc_errors::Applicability;
 use rustc_hir::{def_id::DefId, BorrowKind, Expr, ExprKind};
@@ -13,12 +15,19 @@ use rustc_middle::mir::Mutability;
 use rustc_middle::ty::adjustment::{Adjust, Adjustment, OverloadedDeref};
 use rustc_middle::ty::subst::{GenericArg, GenericArgKind, SubstsRef};
 use rustc_middle::ty::{self, PredicateKind, ProjectionPredicate, TraitPredicate, Ty};
+use rustc_semver::RustcVersion;
 use rustc_span::{sym, Symbol};
 use std::cmp::max;
 
 use super::UNNECESSARY_TO_OWNED;
 
-pub fn check<'tcx>(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>],
+    msrv: Option<&RustcVersion>,
+) {
     if_chain! {
         if let Some(method_def_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id);
         if let [receiver] = args;
@@ -33,7 +42,7 @@ pub fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>, method_name:
                 if check_addr_of_expr(cx, expr, method_name, method_def_id, receiver) {
                     return;
                 }
-                if check_into_iter_call_arg(cx, expr, method_name, receiver) {
+                if check_into_iter_call_arg(cx, expr, method_name, receiver, msrv) {
                     return;
                 }
                 check_other_call_arg(cx, expr, method_name, receiver);
@@ -178,7 +187,13 @@ 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<'_>, expr: &Expr<'_>, method_name: Symbol, receiver: &Expr<'_>) -> bool {
+fn check_into_iter_call_arg(
+    cx: &LateContext<'_>,
+    expr: &Expr<'_>,
+    method_name: Symbol,
+    receiver: &Expr<'_>,
+    msrv: Option<&RustcVersion>,
+) -> bool {
     if_chain! {
         if let Some(parent) = get_parent_expr(cx, expr);
         if let Some(callee_def_id) = fn_def_id(cx, parent);
@@ -192,7 +207,7 @@ fn check_into_iter_call_arg(cx: &LateContext<'_>, expr: &Expr<'_>, method_name:
             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) { "copied" } else { "cloned" };
+            let cloned_or_copied = if is_copy(cx, item_ty) && meets_msrv(msrv, &msrvs::ITERATOR_COPIED) { "copied" } 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.
diff --git a/clippy_lints/src/methods/wrong_self_convention.rs b/clippy_lints/src/methods/wrong_self_convention.rs
index aecfea9c141..4b368d3ffae 100644
--- a/clippy_lints/src/methods/wrong_self_convention.rs
+++ b/clippy_lints/src/methods/wrong_self_convention.rs
@@ -14,7 +14,7 @@ const CONVENTIONS: [(&[Convention], &[SelfKind]); 9] = [
     (&[Convention::StartsWith("as_")], &[SelfKind::Ref, SelfKind::RefMut]),
     (&[Convention::StartsWith("from_")], &[SelfKind::No]),
     (&[Convention::StartsWith("into_")], &[SelfKind::Value]),
-    (&[Convention::StartsWith("is_")], &[SelfKind::Ref, SelfKind::No]),
+    (&[Convention::StartsWith("is_")], &[SelfKind::RefMut, SelfKind::Ref, SelfKind::No]),
     (&[Convention::Eq("to_mut")], &[SelfKind::RefMut]),
     (&[Convention::StartsWith("to_"), Convention::EndsWith("_mut")], &[SelfKind::RefMut]),
 
diff --git a/clippy_lints/src/misc_early/mod.rs b/clippy_lints/src/misc_early/mod.rs
index d955fad7d41..6860b60acbd 100644
--- a/clippy_lints/src/misc_early/mod.rs
+++ b/clippy_lints/src/misc_early/mod.rs
@@ -361,7 +361,7 @@ impl MiscEarlyLints {
         // See <https://github.com/rust-lang/rust-clippy/issues/4507> for a regression.
         // FIXME: Find a better way to detect those cases.
         let lit_snip = match snippet_opt(cx, lit.span) {
-            Some(snip) if snip.chars().next().map_or(false, |c| c.is_digit(10)) => snip,
+            Some(snip) if snip.chars().next().map_or(false, |c| c.is_ascii_digit()) => snip,
             _ => return,
         };
 
diff --git a/clippy_lints/src/missing_inline.rs b/clippy_lints/src/missing_inline.rs
index ac2f16b49e3..0d953299189 100644
--- a/clippy_lints/src/missing_inline.rs
+++ b/clippy_lints/src/missing_inline.rs
@@ -44,7 +44,7 @@ declare_clippy_lint! {
     /// pub struct PubBaz;
     /// impl PubBaz {
     ///    fn private() {} // ok
-    ///    pub fn not_ptrivate() {} // missing #[inline]
+    ///    pub fn not_private() {} // missing #[inline]
     /// }
     ///
     /// impl Bar for PubBaz {
@@ -97,7 +97,7 @@ impl<'tcx> LateLintPass<'tcx> for MissingInline {
                 let attrs = cx.tcx.hir().attrs(it.hir_id());
                 check_missing_inline_attrs(cx, attrs, it.span, desc);
             },
-            hir::ItemKind::Trait(ref _is_auto, ref _unsafe, ref _generics, _bounds, trait_items) => {
+            hir::ItemKind::Trait(ref _is_auto, ref _unsafe, _generics, _bounds, trait_items) => {
                 // note: we need to check if the trait is exported so we can't use
                 // `LateLintPass::check_trait_item` here.
                 for tit in trait_items {
diff --git a/clippy_lints/src/needless_bitwise_bool.rs b/clippy_lints/src/needless_bitwise_bool.rs
index a8a8d174a82..95395e2e136 100644
--- a/clippy_lints/src/needless_bitwise_bool.rs
+++ b/clippy_lints/src/needless_bitwise_bool.rs
@@ -53,7 +53,7 @@ fn is_bitwise_operation(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
     false
 }
 
-fn suggession_snippet(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option<String> {
+fn suggesstion_snippet(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option<String> {
     if let ExprKind::Binary(ref op, left, right) = expr.kind {
         if let (Some(l_snippet), Some(r_snippet)) = (snippet_opt(cx, left.span), snippet_opt(cx, right.span)) {
             let op_snippet = match op.node {
@@ -75,7 +75,7 @@ impl LateLintPass<'_> for NeedlessBitwiseBool {
                 expr.span,
                 "use of bitwise operator instead of lazy operator between booleans",
                 |diag| {
-                    if let Some(sugg) = suggession_snippet(cx, expr) {
+                    if let Some(sugg) = suggesstion_snippet(cx, expr) {
                         diag.span_suggestion(expr.span, "try", sugg, Applicability::MachineApplicable);
                     }
                 },
diff --git a/clippy_lints/src/needless_late_init.rs b/clippy_lints/src/needless_late_init.rs
index 9957afcbf04..b70871b38be 100644
--- a/clippy_lints/src/needless_late_init.rs
+++ b/clippy_lints/src/needless_late_init.rs
@@ -1,10 +1,14 @@
 use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::path_to_local;
 use clippy_utils::source::snippet_opt;
-use clippy_utils::visitors::{expr_visitor, is_local_used};
-use rustc_errors::Applicability;
+use clippy_utils::ty::needs_ordered_drop;
+use clippy_utils::visitors::{expr_visitor, expr_visitor_no_bodies, is_local_used};
+use rustc_errors::{Applicability, MultiSpan};
 use rustc_hir::intravisit::Visitor;
-use rustc_hir::{Block, Expr, ExprKind, HirId, Local, LocalSource, MatchSource, Node, Pat, PatKind, Stmt, StmtKind};
+use rustc_hir::{
+    BindingAnnotation, Block, Expr, ExprKind, HirId, Local, LocalSource, MatchSource, Node, Pat, PatKind, Stmt,
+    StmtKind,
+};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_session::{declare_lint_pass, declare_tool_lint};
 use rustc_span::Span;
@@ -73,6 +77,31 @@ fn contains_assign_expr<'tcx>(cx: &LateContext<'tcx>, stmt: &'tcx Stmt<'tcx>) ->
     seen
 }
 
+fn contains_let(cond: &Expr<'_>) -> bool {
+    let mut seen = false;
+    expr_visitor_no_bodies(|expr| {
+        if let ExprKind::Let(_) = expr.kind {
+            seen = true;
+        }
+
+        !seen
+    })
+    .visit_expr(cond);
+
+    seen
+}
+
+fn stmt_needs_ordered_drop(cx: &LateContext<'_>, stmt: &Stmt<'_>) -> bool {
+    let StmtKind::Local(local) = stmt.kind else { return false };
+    !local.pat.walk_short(|pat| {
+        if let PatKind::Binding(.., None) = pat.kind {
+            !needs_ordered_drop(cx, cx.typeck_results().pat_ty(pat))
+        } else {
+            true
+        }
+    })
+}
+
 #[derive(Debug)]
 struct LocalAssign {
     lhs_id: HirId,
@@ -187,11 +216,14 @@ fn first_usage<'tcx>(
     local_stmt_id: HirId,
     block: &'tcx Block<'tcx>,
 ) -> Option<Usage<'tcx>> {
+    let significant_drop = needs_ordered_drop(cx, cx.typeck_results().node_type(binding_id));
+
     block
         .stmts
         .iter()
         .skip_while(|stmt| stmt.hir_id != local_stmt_id)
         .skip(1)
+        .take_while(|stmt| !significant_drop || !stmt_needs_ordered_drop(cx, stmt))
         .find(|&stmt| is_local_used(cx, stmt, binding_id))
         .and_then(|stmt| match stmt.kind {
             StmtKind::Expr(expr) => Some(Usage {
@@ -235,12 +267,15 @@ fn check<'tcx>(
     match usage.expr.kind {
         ExprKind::Assign(..) => {
             let assign = LocalAssign::new(cx, usage.expr, binding_id)?;
+            let mut msg_span = MultiSpan::from_spans(vec![local_stmt.span, assign.span]);
+            msg_span.push_span_label(local_stmt.span, "created here");
+            msg_span.push_span_label(assign.span, "initialised here");
 
             span_lint_and_then(
                 cx,
                 NEEDLESS_LATE_INIT,
-                local_stmt.span,
-                "unneeded late initalization",
+                msg_span,
+                "unneeded late initialization",
                 |diag| {
                     diag.tool_only_span_suggestion(
                         local_stmt.span,
@@ -258,14 +293,14 @@ fn check<'tcx>(
                 },
             );
         },
-        ExprKind::If(_, then_expr, Some(else_expr)) => {
+        ExprKind::If(cond, then_expr, Some(else_expr)) if !contains_let(cond) => {
             let (applicability, suggestions) = assignment_suggestions(cx, binding_id, [then_expr, else_expr])?;
 
             span_lint_and_then(
                 cx,
                 NEEDLESS_LATE_INIT,
                 local_stmt.span,
-                "unneeded late initalization",
+                "unneeded late initialization",
                 |diag| {
                     diag.tool_only_span_suggestion(local_stmt.span, "remove the local", String::new(), applicability);
 
@@ -296,7 +331,7 @@ fn check<'tcx>(
                 cx,
                 NEEDLESS_LATE_INIT,
                 local_stmt.span,
-                "unneeded late initalization",
+                "unneeded late initialization",
                 |diag| {
                     diag.tool_only_span_suggestion(local_stmt.span, "remove the local", String::new(), applicability);
 
@@ -333,12 +368,11 @@ fn check<'tcx>(
 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);
-
         if_chain! {
             if let Local {
                 init: None,
                 pat: &Pat {
-                    kind: PatKind::Binding(_, binding_id, _, None),
+                    kind: PatKind::Binding(BindingAnnotation::Unannotated, binding_id, _, None),
                     ..
                 },
                 source: LocalSource::Normal,
diff --git a/clippy_lints/src/new_without_default.rs b/clippy_lints/src/new_without_default.rs
index 96c00c205ff..2f733f221d5 100644
--- a/clippy_lints/src/new_without_default.rs
+++ b/clippy_lints/src/new_without_default.rs
@@ -62,7 +62,7 @@ impl<'tcx> LateLintPass<'tcx> for NewWithoutDefault {
     fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::Item<'_>) {
         if let hir::ItemKind::Impl(hir::Impl {
             of_trait: None,
-            ref generics,
+            generics,
             self_ty: impl_self_ty,
             items,
             ..
diff --git a/clippy_lints/src/non_expressive_names.rs b/clippy_lints/src/non_expressive_names.rs
index 0d0c88b02c7..e3bc40c4b49 100644
--- a/clippy_lints/src/non_expressive_names.rs
+++ b/clippy_lints/src/non_expressive_names.rs
@@ -197,7 +197,7 @@ impl<'a, 'tcx, 'b> SimilarNamesNameVisitor<'a, 'tcx, 'b> {
         if interned_name.chars().any(char::is_uppercase) {
             return;
         }
-        if interned_name.chars().all(|c| c.is_digit(10) || c == '_') {
+        if interned_name.chars().all(|c| c.is_ascii_digit() || c == '_') {
             span_lint(
                 self.0.cx,
                 JUST_UNDERSCORES_AND_DIGITS,
diff --git a/clippy_lints/src/octal_escapes.rs b/clippy_lints/src/octal_escapes.rs
index c19cea66104..e8532db4f71 100644
--- a/clippy_lints/src/octal_escapes.rs
+++ b/clippy_lints/src/octal_escapes.rs
@@ -25,7 +25,7 @@ declare_clippy_lint! {
     ///
     /// ### Known problems
     /// The actual meaning can be the intended one. `\x00` can be used in these
-    /// cases to be unambigious.
+    /// cases to be unambiguous.
     ///
     /// The lint does not trigger for format strings in `print!()`, `write!()`
     /// and friends since the string is already preprocessed when Clippy lints
diff --git a/clippy_lints/src/only_used_in_recursion.rs b/clippy_lints/src/only_used_in_recursion.rs
index 8e61f234776..beb812793f8 100644
--- a/clippy_lints/src/only_used_in_recursion.rs
+++ b/clippy_lints/src/only_used_in_recursion.rs
@@ -1,6 +1,7 @@
 use std::collections::VecDeque;
 
 use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::is_lint_allowed;
 use itertools::{izip, Itertools};
 use rustc_ast::{walk_list, Label, Mutability};
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
@@ -8,7 +9,7 @@ use rustc_errors::Applicability;
 use rustc_hir::def::{DefKind, Res};
 use rustc_hir::def_id::DefId;
 use rustc_hir::definitions::{DefPathData, DisambiguatedDefPathData};
-use rustc_hir::intravisit::{walk_expr, FnKind, Visitor};
+use rustc_hir::intravisit::{walk_expr, walk_stmt, FnKind, Visitor};
 use rustc_hir::{
     Arm, Block, Body, Expr, ExprKind, Guard, HirId, ImplicitSelfKind, Let, Local, Pat, PatKind, Path, PathSegment,
     QPath, Stmt, StmtKind, TyKind, UnOp,
@@ -33,6 +34,9 @@ declare_clippy_lint! {
     /// and the assigned variables are also only in recursion, it is useless.
     ///
     /// ### Known problems
+    /// Too many code paths in the linting code are currently untested and prone to produce false
+    /// positives or are prone to have performance implications.
+    ///
     /// In some cases, this would not catch all useless arguments.
     ///
     /// ```rust
@@ -85,7 +89,7 @@ declare_clippy_lint! {
     /// ```
     #[clippy::version = "1.60.0"]
     pub ONLY_USED_IN_RECURSION,
-    complexity,
+    nursery,
     "arguments that is only used in recursion can be removed"
 }
 declare_lint_pass!(OnlyUsedInRecursion => [ONLY_USED_IN_RECURSION]);
@@ -100,6 +104,9 @@ impl<'tcx> LateLintPass<'tcx> for OnlyUsedInRecursion {
         _: Span,
         id: HirId,
     ) {
+        if is_lint_allowed(cx, ONLY_USED_IN_RECURSION, id) {
+            return;
+        }
         if let FnKind::ItemFn(ident, ..) | FnKind::Method(ident, ..) = kind {
             let def_id = id.owner.to_def_id();
             let data = cx.tcx.def_path(def_id).data;
@@ -145,7 +152,8 @@ impl<'tcx> LateLintPass<'tcx> for OnlyUsedInRecursion {
                 is_method: matches!(kind, FnKind::Method(..)),
                 has_self,
                 ty_res,
-                ty_ctx: cx.tcx,
+                tcx: cx.tcx,
+                visited_exprs: FxHashSet::default(),
             };
 
             visitor.visit_expr(&body.value);
@@ -206,19 +214,13 @@ impl<'tcx> LateLintPass<'tcx> for OnlyUsedInRecursion {
 }
 
 pub fn is_primitive(ty: Ty<'_>) -> bool {
-    match ty.kind() {
-        ty::Bool | ty::Char | ty::Int(_) | ty::Uint(_) | ty::Float(_) | ty::Str => true,
-        ty::Ref(_, t, _) => is_primitive(*t),
-        _ => false,
-    }
+    let ty = ty.peel_refs();
+    ty.is_primitive() || ty.is_str()
 }
 
 pub fn is_array(ty: Ty<'_>) -> bool {
-    match ty.kind() {
-        ty::Array(..) | ty::Slice(..) => true,
-        ty::Ref(_, t, _) => is_array(*t),
-        _ => false,
-    }
+    let ty = ty.peel_refs();
+    ty.is_array() || ty.is_array_slice()
 }
 
 /// This builds the graph of side effect.
@@ -250,40 +252,30 @@ pub struct SideEffectVisit<'tcx> {
     is_method: bool,
     has_self: bool,
     ty_res: &'tcx TypeckResults<'tcx>,
-    ty_ctx: TyCtxt<'tcx>,
+    tcx: TyCtxt<'tcx>,
+    visited_exprs: FxHashSet<HirId>,
 }
 
 impl<'tcx> Visitor<'tcx> for SideEffectVisit<'tcx> {
-    fn visit_block(&mut self, b: &'tcx Block<'tcx>) {
-        b.stmts.iter().for_each(|stmt| {
-            self.visit_stmt(stmt);
-            self.ret_vars.clear();
-        });
-        walk_list!(self, visit_expr, b.expr);
-    }
-
     fn visit_stmt(&mut self, s: &'tcx Stmt<'tcx>) {
         match s.kind {
             StmtKind::Local(Local {
                 pat, init: Some(init), ..
             }) => {
                 self.visit_pat_expr(pat, init, false);
-                self.ret_vars.clear();
             },
-            StmtKind::Item(i) => {
-                let item = self.ty_ctx.hir().item(i);
-                self.visit_item(item);
-                self.ret_vars.clear();
-            },
-            StmtKind::Expr(e) | StmtKind::Semi(e) => {
-                self.visit_expr(e);
-                self.ret_vars.clear();
+            StmtKind::Item(_) | StmtKind::Expr(_) | StmtKind::Semi(_) => {
+                walk_stmt(self, s);
             },
             StmtKind::Local(_) => {},
         }
+        self.ret_vars.clear();
     }
 
     fn visit_expr(&mut self, ex: &'tcx Expr<'tcx>) {
+        if !self.visited_exprs.insert(ex.hir_id) {
+            return;
+        }
         match ex.kind {
             ExprKind::Array(exprs) | ExprKind::Tup(exprs) => {
                 self.ret_vars = exprs
@@ -307,7 +299,7 @@ impl<'tcx> Visitor<'tcx> for SideEffectVisit<'tcx> {
             ExprKind::Match(expr, arms, _) => self.visit_match(expr, arms),
             // since analysing the closure is not easy, just set all variables in it to side-effect
             ExprKind::Closure(_, _, body_id, _, _) => {
-                let body = self.ty_ctx.hir().body(body_id);
+                let body = self.tcx.hir().body(body_id);
                 self.visit_body(body);
                 let vars = std::mem::take(&mut self.ret_vars);
                 self.add_side_effect(vars);
diff --git a/clippy_lints/src/option_if_let_else.rs b/clippy_lints/src/option_if_let_else.rs
index c9f807f2aa3..ea5a8f0858b 100644
--- a/clippy_lints/src/option_if_let_else.rs
+++ b/clippy_lints/src/option_if_let_else.rs
@@ -78,7 +78,7 @@ fn is_result_ok(cx: &LateContext<'_>, expr: &'_ Expr<'_>) -> bool {
 
 /// A struct containing information about occurrences of the
 /// `if let Some(..) = .. else` construct that this lint detects.
-struct OptionIfLetElseOccurence {
+struct OptionIfLetElseOccurrence {
     option: String,
     method_sugg: String,
     some_expr: String,
@@ -100,9 +100,9 @@ fn format_option_in_sugg(cx: &LateContext<'_>, cond_expr: &Expr<'_>, as_ref: boo
 }
 
 /// If this expression is the option if let/else construct we're detecting, then
-/// this function returns an `OptionIfLetElseOccurence` struct with details if
+/// this function returns an `OptionIfLetElseOccurrence` struct with details if
 /// this construct is found, or None if this construct is not found.
-fn detect_option_if_let_else<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'tcx>) -> Option<OptionIfLetElseOccurence> {
+fn detect_option_if_let_else<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'tcx>) -> Option<OptionIfLetElseOccurrence> {
     if_chain! {
         if !expr.span.from_expansion(); // Don't lint macros, because it behaves weirdly
         if !in_constant(cx, expr.hir_id);
@@ -154,7 +154,7 @@ fn detect_option_if_let_else<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'tcx>) ->
                     }
                 }
             }
-            Some(OptionIfLetElseOccurence {
+            Some(OptionIfLetElseOccurrence {
                 option: format_option_in_sugg(cx, cond_expr, as_ref, as_mut),
                 method_sugg: method_sugg.to_string(),
                 some_expr: format!("|{}{}| {}", capture_mut, capture_name, Sugg::hir_with_macro_callsite(cx, some_body, "..")),
diff --git a/clippy_lints/src/ptr.rs b/clippy_lints/src/ptr.rs
index 48a2666a2e0..c35eeeac67a 100644
--- a/clippy_lints/src/ptr.rs
+++ b/clippy_lints/src/ptr.rs
@@ -3,6 +3,7 @@
 use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg, span_lint_and_then};
 use clippy_utils::source::snippet_opt;
 use clippy_utils::ty::expr_sig;
+use clippy_utils::visitors::contains_unsafe_block;
 use clippy_utils::{get_expr_use_or_unification_node, is_lint_allowed, path_def_id, path_to_local, paths};
 use if_chain::if_chain;
 use rustc_errors::{Applicability, MultiSpan};
@@ -10,9 +11,9 @@ use rustc_hir::def_id::DefId;
 use rustc_hir::hir_id::HirIdMap;
 use rustc_hir::intravisit::{walk_expr, Visitor};
 use rustc_hir::{
-    self as hir, AnonConst, BinOpKind, BindingAnnotation, Body, Expr, ExprKind, FnDecl, FnRetTy, GenericArg,
+    self as hir, AnonConst, BinOpKind, BindingAnnotation, Body, Expr, ExprKind, FnRetTy, FnSig, GenericArg,
     ImplItemKind, ItemKind, Lifetime, LifetimeName, Mutability, Node, Param, ParamName, PatKind, QPath, TraitFn,
-    TraitItem, TraitItemKind, TyKind,
+    TraitItem, TraitItemKind, TyKind, Unsafety,
 };
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::hir::nested_filter;
@@ -88,19 +89,26 @@ declare_clippy_lint! {
 
 declare_clippy_lint! {
     /// ### What it does
-    /// This lint checks for functions that take immutable
-    /// references and return mutable ones.
+    /// This lint checks for functions that take immutable references and return
+    /// mutable ones. This will not trigger if no unsafe code exists as there
+    /// are multiple safe functions which will do this transformation
+    ///
+    /// To be on the conservative side, if there's at least one mutable
+    /// reference with the output lifetime, this lint will not trigger.
     ///
     /// ### Why is this bad?
-    /// This is trivially unsound, as one can create two
-    /// mutable references from the same (immutable!) source.
-    /// This [error](https://github.com/rust-lang/rust/issues/39465)
-    /// actually lead to an interim Rust release 1.15.1.
+    /// Creating a mutable reference which can be repeatably derived from an
+    /// immutable reference is unsound as it allows creating multiple live
+    /// mutable references to the same object.
+    ///
+    /// This [error](https://github.com/rust-lang/rust/issues/39465) actually
+    /// lead to an interim Rust release 1.15.1.
     ///
     /// ### Known problems
-    /// To be on the conservative side, if there's at least one
-    /// mutable reference with the output lifetime, this lint will not trigger.
-    /// In practice, this case is unlikely anyway.
+    /// This pattern is used by memory allocators to allow allocating multiple
+    /// objects while returning mutable references to each one. So long as
+    /// different mutable references are returned each time such a function may
+    /// be safe.
     ///
     /// ### Example
     /// ```ignore
@@ -145,7 +153,7 @@ impl<'tcx> LateLintPass<'tcx> for Ptr {
                 return;
             }
 
-            check_mut_from_ref(cx, sig.decl);
+            check_mut_from_ref(cx, sig, None);
             for arg in check_fn_args(
                 cx,
                 cx.tcx.fn_sig(item.def_id).skip_binder().inputs(),
@@ -170,10 +178,10 @@ impl<'tcx> LateLintPass<'tcx> for Ptr {
     fn check_body(&mut self, cx: &LateContext<'tcx>, body: &'tcx Body<'_>) {
         let hir = cx.tcx.hir();
         let mut parents = hir.parent_iter(body.value.hir_id);
-        let (item_id, decl, is_trait_item) = match parents.next() {
+        let (item_id, sig, is_trait_item) = match parents.next() {
             Some((_, Node::Item(i))) => {
                 if let ItemKind::Fn(sig, ..) = &i.kind {
-                    (i.def_id, sig.decl, false)
+                    (i.def_id, sig, false)
                 } else {
                     return;
                 }
@@ -185,14 +193,14 @@ impl<'tcx> LateLintPass<'tcx> for Ptr {
                     return;
                 }
                 if let ImplItemKind::Fn(sig, _) = &i.kind {
-                    (i.def_id, sig.decl, false)
+                    (i.def_id, sig, false)
                 } else {
                     return;
                 }
             },
             Some((_, Node::TraitItem(i))) => {
                 if let TraitItemKind::Fn(sig, _) = &i.kind {
-                    (i.def_id, sig.decl, true)
+                    (i.def_id, sig, true)
                 } else {
                     return;
                 }
@@ -200,7 +208,8 @@ impl<'tcx> LateLintPass<'tcx> for Ptr {
             _ => return,
         };
 
-        check_mut_from_ref(cx, decl);
+        check_mut_from_ref(cx, sig, Some(body));
+        let decl = sig.decl;
         let sig = cx.tcx.fn_sig(item_id).skip_binder();
         let lint_args: Vec<_> = check_fn_args(cx, sig.inputs(), decl.inputs, body.params)
             .filter(|arg| !is_trait_item || arg.mutability() == Mutability::Not)
@@ -473,31 +482,31 @@ fn check_fn_args<'cx, 'tcx: 'cx>(
         })
 }
 
-fn check_mut_from_ref(cx: &LateContext<'_>, decl: &FnDecl<'_>) {
-    if let FnRetTy::Return(ty) = decl.output {
-        if let Some((out, Mutability::Mut, _)) = get_rptr_lm(ty) {
-            let mut immutables = vec![];
-            for (_, mutbl, argspan) in decl
-                .inputs
-                .iter()
-                .filter_map(get_rptr_lm)
-                .filter(|&(lt, _, _)| lt.name == out.name)
-            {
-                if mutbl == Mutability::Mut {
-                    return;
-                }
-                immutables.push(argspan);
-            }
-            if immutables.is_empty() {
-                return;
-            }
+fn check_mut_from_ref<'tcx>(cx: &LateContext<'tcx>, sig: &FnSig<'_>, body: Option<&'tcx Body<'_>>) {
+    if let FnRetTy::Return(ty) = sig.decl.output
+        && let Some((out, Mutability::Mut, _)) = get_rptr_lm(ty)
+    {
+        let args: Option<Vec<_>> = sig
+            .decl
+            .inputs
+            .iter()
+            .filter_map(get_rptr_lm)
+            .filter(|&(lt, _, _)| lt.name == out.name)
+            .map(|(_, mutability, span)| (mutability == Mutability::Not).then(|| span))
+            .collect();
+        if let Some(args) = args
+            && !args.is_empty()
+            && body.map_or(true, |body| {
+                sig.header.unsafety == Unsafety::Unsafe || contains_unsafe_block(cx, &body.value)
+            })
+        {
             span_lint_and_then(
                 cx,
                 MUT_FROM_REF,
                 ty.span,
                 "mutable borrow from immutable input(s)",
                 |diag| {
-                    let ms = MultiSpan::from_spans(immutables);
+                    let ms = MultiSpan::from_spans(args);
                     diag.span_note(ms, "immutable borrow here");
                 },
             );
diff --git a/clippy_lints/src/pub_use.rs b/clippy_lints/src/pub_use.rs
new file mode 100644
index 00000000000..9d2b0cedb60
--- /dev/null
+++ b/clippy_lints/src/pub_use.rs
@@ -0,0 +1,56 @@
+use clippy_utils::diagnostics::span_lint_and_help;
+use rustc_ast::ast::{Item, ItemKind, VisibilityKind};
+use rustc_lint::{EarlyContext, EarlyLintPass};
+use rustc_session::{declare_lint_pass, declare_tool_lint};
+
+declare_clippy_lint! {
+    /// ### What it does
+    ///
+    /// Restricts the usage of `pub use ...`
+    ///
+    /// ### Why is this bad?
+    ///
+    /// `pub use` is usually fine, but a project may wish to limit `pub use` instances to prevent
+    /// unintentional exports or to encourage placing exported items directly in public modules
+    ///
+    /// ### Example
+    /// ```rust
+    /// pub mod outer {
+    ///     mod inner {
+    ///         pub struct Test {}
+    ///     }
+    ///     pub use inner::Test;
+    /// }
+    ///
+    /// use outer::Test;
+    /// ```
+    /// Use instead:
+    /// ```rust
+    /// pub mod outer {
+    ///     pub struct Test {}
+    /// }
+    ///
+    /// use outer::Test;
+    /// ```
+    #[clippy::version = "1.62.0"]
+    pub PUB_USE,
+    restriction,
+    "restricts the usage of `pub use`"
+}
+declare_lint_pass!(PubUse => [PUB_USE]);
+
+impl EarlyLintPass for PubUse {
+    fn check_item(&mut self, cx: &EarlyContext<'_>, item: &Item) {
+        if let ItemKind::Use(_) = item.kind &&
+            let VisibilityKind::Public = item.vis.kind {
+                span_lint_and_help(
+                    cx,
+                    PUB_USE,
+                    item.span,
+                    "using `pub use`",
+                    None,
+                    "move the exported item to a public module instead",
+                );
+            }
+    }
+}
diff --git a/clippy_lints/src/redundant_pub_crate.rs b/clippy_lints/src/redundant_pub_crate.rs
index e2e2400f8e2..323326381d4 100644
--- a/clippy_lints/src/redundant_pub_crate.rs
+++ b/clippy_lints/src/redundant_pub_crate.rs
@@ -1,10 +1,12 @@
 use clippy_utils::diagnostics::span_lint_and_then;
 use rustc_errors::Applicability;
+use rustc_hir::def::{DefKind, Res};
 use rustc_hir::{Item, ItemKind};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::ty;
 use rustc_session::{declare_tool_lint, impl_lint_pass};
 use rustc_span::def_id::CRATE_DEF_ID;
+use rustc_span::hygiene::MacroKind;
 
 declare_clippy_lint! {
     /// ### What it does
@@ -43,8 +45,11 @@ impl_lint_pass!(RedundantPubCrate => [REDUNDANT_PUB_CRATE]);
 
 impl<'tcx> LateLintPass<'tcx> for RedundantPubCrate {
     fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'tcx>) {
-        if cx.tcx.visibility(item.def_id) == ty::Visibility::Restricted(CRATE_DEF_ID.to_def_id()) {
-            if !cx.access_levels.is_exported(item.def_id) && self.is_exported.last() == Some(&false) {
+        if_chain! {
+            if cx.tcx.visibility(item.def_id) == ty::Visibility::Restricted(CRATE_DEF_ID.to_def_id());
+            if !cx.access_levels.is_exported(item.def_id) && self.is_exported.last() == Some(&false);
+            if is_not_macro_export(item);
+            then {
                 let span = item.span.with_hi(item.ident.span.hi());
                 let descr = cx.tcx.def_kind(item.def_id).descr(item.def_id.to_def_id());
                 span_lint_and_then(
@@ -75,3 +80,15 @@ impl<'tcx> LateLintPass<'tcx> for RedundantPubCrate {
         }
     }
 }
+
+fn is_not_macro_export<'tcx>(item: &'tcx Item<'tcx>) -> bool {
+    if let ItemKind::Use(path, _) = item.kind {
+        if let Res::Def(DefKind::Macro(MacroKind::Bang), _) = path.res {
+            return false;
+        }
+    } else if let ItemKind::Macro(..) = item.kind {
+        return false;
+    }
+
+    true
+}
diff --git a/clippy_lints/src/renamed_lints.rs b/clippy_lints/src/renamed_lints.rs
new file mode 100644
index 00000000000..bfc03116fe2
--- /dev/null
+++ b/clippy_lints/src/renamed_lints.rs
@@ -0,0 +1,39 @@
+// This file is managed by `cargo dev rename_lint`. Prefer using that when possible.
+
+#[rustfmt::skip]
+pub static RENAMED_LINTS: &[(&str, &str)] = &[
+    ("clippy::block_in_if_condition_expr", "clippy::blocks_in_if_conditions"),
+    ("clippy::block_in_if_condition_stmt", "clippy::blocks_in_if_conditions"),
+    ("clippy::box_vec", "clippy::box_collection"),
+    ("clippy::const_static_lifetime", "clippy::redundant_static_lifetimes"),
+    ("clippy::cyclomatic_complexity", "clippy::cognitive_complexity"),
+    ("clippy::disallowed_method", "clippy::disallowed_methods"),
+    ("clippy::disallowed_type", "clippy::disallowed_types"),
+    ("clippy::for_loop_over_option", "clippy::for_loops_over_fallibles"),
+    ("clippy::for_loop_over_result", "clippy::for_loops_over_fallibles"),
+    ("clippy::identity_conversion", "clippy::useless_conversion"),
+    ("clippy::if_let_some_result", "clippy::match_result_ok"),
+    ("clippy::new_without_default_derive", "clippy::new_without_default"),
+    ("clippy::option_and_then_some", "clippy::bind_instead_of_map"),
+    ("clippy::option_expect_used", "clippy::expect_used"),
+    ("clippy::option_map_unwrap_or", "clippy::map_unwrap_or"),
+    ("clippy::option_map_unwrap_or_else", "clippy::map_unwrap_or"),
+    ("clippy::option_unwrap_used", "clippy::unwrap_used"),
+    ("clippy::ref_in_deref", "clippy::needless_borrow"),
+    ("clippy::result_expect_used", "clippy::expect_used"),
+    ("clippy::result_map_unwrap_or_else", "clippy::map_unwrap_or"),
+    ("clippy::result_unwrap_used", "clippy::unwrap_used"),
+    ("clippy::single_char_push_str", "clippy::single_char_add_str"),
+    ("clippy::stutter", "clippy::module_name_repetitions"),
+    ("clippy::to_string_in_display", "clippy::recursive_format_impl"),
+    ("clippy::zero_width_space", "clippy::invisible_characters"),
+    ("clippy::drop_bounds", "drop_bounds"),
+    ("clippy::into_iter_on_array", "array_into_iter"),
+    ("clippy::invalid_atomic_ordering", "invalid_atomic_ordering"),
+    ("clippy::invalid_ref", "invalid_value"),
+    ("clippy::mem_discriminant_non_enum", "enum_intrinsics_non_enums"),
+    ("clippy::panic_params", "non_fmt_panics"),
+    ("clippy::temporary_cstring_as_ptr", "temporary_cstring_as_ptr"),
+    ("clippy::unknown_clippy_lints", "unknown_lints"),
+    ("clippy::unused_label", "unused_labels"),
+];
diff --git a/clippy_lints/src/same_name_method.rs b/clippy_lints/src/same_name_method.rs
index a01e2f2db3a..f63925a2f14 100644
--- a/clippy_lints/src/same_name_method.rs
+++ b/clippy_lints/src/same_name_method.rs
@@ -51,114 +51,110 @@ impl<'tcx> LateLintPass<'tcx> for SameNameMethod {
         let mut map = FxHashMap::<Res, ExistingName>::default();
 
         for id in cx.tcx.hir().items() {
-            if !matches!(cx.tcx.hir().def_kind(id.def_id), DefKind::Impl) {
-                continue;
-            }
-
-            let item = cx.tcx.hir().item(id);
-            if let ItemKind::Impl(Impl {
-                items,
-                of_trait,
-                self_ty,
-                ..
-            }) = &item.kind
+            if matches!(cx.tcx.hir().def_kind(id.def_id), DefKind::Impl)
+                && let item = cx.tcx.hir().item(id)
+                && let ItemKind::Impl(Impl {
+                    items,
+                    of_trait,
+                    self_ty,
+                    ..
+                }) = &item.kind
+                && let TyKind::Path(QPath::Resolved(_, Path { res, .. })) = self_ty.kind
             {
-                if let TyKind::Path(QPath::Resolved(_, Path { res, .. })) = self_ty.kind {
-                    if !map.contains_key(res) {
-                        map.insert(
-                            *res,
-                            ExistingName {
-                                impl_methods: BTreeMap::new(),
-                                trait_methods: BTreeMap::new(),
-                            },
-                        );
-                    }
-                    let existing_name = map.get_mut(res).unwrap();
-
-                    match of_trait {
-                        Some(trait_ref) => {
-                            let mut methods_in_trait: BTreeSet<Symbol> = if_chain! {
-                                if let Some(Node::TraitRef(TraitRef { path, .. })) =
-                                    cx.tcx.hir().find(trait_ref.hir_ref_id);
-                                if let Res::Def(DefKind::Trait, did) = path.res;
-                                then{
-                                    // FIXME: if
-                                    // `rustc_middle::ty::assoc::AssocItems::items` is public,
-                                    // we can iterate its keys instead of `in_definition_order`,
-                                    // which's more efficient
-                                    cx.tcx
-                                        .associated_items(did)
-                                        .in_definition_order()
-                                        .filter(|assoc_item| {
-                                            matches!(assoc_item.kind, AssocKind::Fn)
-                                        })
-                                        .map(|assoc_item| assoc_item.name)
-                                        .collect()
-                                }else{
-                                    BTreeSet::new()
-                                }
-                            };
-
-                            let mut check_trait_method = |method_name: Symbol, trait_method_span: Span| {
-                                if let Some(impl_span) = existing_name.impl_methods.get(&method_name) {
-                                    span_lint_and_then(
-                                        cx,
-                                        SAME_NAME_METHOD,
-                                        *impl_span,
-                                        "method's name is the same as an existing method in a trait",
-                                        |diag| {
-                                            diag.span_note(
-                                                trait_method_span,
-                                                &format!("existing `{}` defined here", method_name),
-                                            );
-                                        },
-                                    );
-                                }
-                                if let Some(v) = existing_name.trait_methods.get_mut(&method_name) {
-                                    v.push(trait_method_span);
-                                } else {
-                                    existing_name.trait_methods.insert(method_name, vec![trait_method_span]);
-                                }
-                            };
+                if !map.contains_key(res) {
+                    map.insert(
+                        *res,
+                        ExistingName {
+                            impl_methods: BTreeMap::new(),
+                            trait_methods: BTreeMap::new(),
+                        },
+                    );
+                }
+                let existing_name = map.get_mut(res).unwrap();
 
-                            for impl_item_ref in (*items).iter().filter(|impl_item_ref| {
-                                matches!(impl_item_ref.kind, rustc_hir::AssocItemKind::Fn { .. })
-                            }) {
-                                let method_name = impl_item_ref.ident.name;
-                                methods_in_trait.remove(&method_name);
-                                check_trait_method(method_name, impl_item_ref.span);
+                match of_trait {
+                    Some(trait_ref) => {
+                        let mut methods_in_trait: BTreeSet<Symbol> = if_chain! {
+                            if let Some(Node::TraitRef(TraitRef { path, .. })) =
+                                cx.tcx.hir().find(trait_ref.hir_ref_id);
+                            if let Res::Def(DefKind::Trait, did) = path.res;
+                            then{
+                                // FIXME: if
+                                // `rustc_middle::ty::assoc::AssocItems::items` is public,
+                                // we can iterate its keys instead of `in_definition_order`,
+                                // which's more efficient
+                                cx.tcx
+                                    .associated_items(did)
+                                    .in_definition_order()
+                                    .filter(|assoc_item| {
+                                        matches!(assoc_item.kind, AssocKind::Fn)
+                                    })
+                                    .map(|assoc_item| assoc_item.name)
+                                    .collect()
+                            }else{
+                                BTreeSet::new()
                             }
+                        };
 
-                            for method_name in methods_in_trait {
-                                check_trait_method(method_name, item.span);
+                        let mut check_trait_method = |method_name: Symbol, trait_method_span: Span| {
+                            if let Some(impl_span) = existing_name.impl_methods.get(&method_name) {
+                                span_lint_and_then(
+                                    cx,
+                                    SAME_NAME_METHOD,
+                                    *impl_span,
+                                    "method's name is the same as an existing method in a trait",
+                                    |diag| {
+                                        diag.span_note(
+                                            trait_method_span,
+                                            &format!("existing `{}` defined here", method_name),
+                                        );
+                                    },
+                                );
                             }
-                        },
-                        None => {
-                            for impl_item_ref in (*items).iter().filter(|impl_item_ref| {
-                                matches!(impl_item_ref.kind, rustc_hir::AssocItemKind::Fn { .. })
-                            }) {
-                                let method_name = impl_item_ref.ident.name;
-                                let impl_span = impl_item_ref.span;
-                                if let Some(trait_spans) = existing_name.trait_methods.get(&method_name) {
-                                    span_lint_and_then(
-                                        cx,
-                                        SAME_NAME_METHOD,
-                                        impl_span,
-                                        "method's name is the same as an existing method in a trait",
-                                        |diag| {
-                                            // TODO should we `span_note` on every trait?
-                                            // iterate on trait_spans?
-                                            diag.span_note(
-                                                trait_spans[0],
-                                                &format!("existing `{}` defined here", method_name),
-                                            );
-                                        },
-                                    );
-                                }
-                                existing_name.impl_methods.insert(method_name, impl_span);
+                            if let Some(v) = existing_name.trait_methods.get_mut(&method_name) {
+                                v.push(trait_method_span);
+                            } else {
+                                existing_name.trait_methods.insert(method_name, vec![trait_method_span]);
                             }
-                        },
-                    }
+                        };
+
+                        for impl_item_ref in (*items).iter().filter(|impl_item_ref| {
+                            matches!(impl_item_ref.kind, rustc_hir::AssocItemKind::Fn { .. })
+                        }) {
+                            let method_name = impl_item_ref.ident.name;
+                            methods_in_trait.remove(&method_name);
+                            check_trait_method(method_name, impl_item_ref.span);
+                        }
+
+                        for method_name in methods_in_trait {
+                            check_trait_method(method_name, item.span);
+                        }
+                    },
+                    None => {
+                        for impl_item_ref in (*items).iter().filter(|impl_item_ref| {
+                            matches!(impl_item_ref.kind, rustc_hir::AssocItemKind::Fn { .. })
+                        }) {
+                            let method_name = impl_item_ref.ident.name;
+                            let impl_span = impl_item_ref.span;
+                            if let Some(trait_spans) = existing_name.trait_methods.get(&method_name) {
+                                span_lint_and_then(
+                                    cx,
+                                    SAME_NAME_METHOD,
+                                    impl_span,
+                                    "method's name is the same as an existing method in a trait",
+                                    |diag| {
+                                        // TODO should we `span_note` on every trait?
+                                        // iterate on trait_spans?
+                                        diag.span_note(
+                                            trait_spans[0],
+                                            &format!("existing `{}` defined here", method_name),
+                                        );
+                                    },
+                                );
+                            }
+                            existing_name.impl_methods.insert(method_name, impl_span);
+                        }
+                    },
                 }
             }
         }
diff --git a/clippy_lints/src/stable_sort_primitive.rs b/clippy_lints/src/stable_sort_primitive.rs
index bcd28b42978..a6c685df721 100644
--- a/clippy_lints/src/stable_sort_primitive.rs
+++ b/clippy_lints/src/stable_sort_primitive.rs
@@ -9,15 +9,25 @@ use rustc_session::{declare_lint_pass, declare_tool_lint};
 declare_clippy_lint! {
     /// ### What it does
     /// When sorting primitive values (integers, bools, chars, as well
-    /// as arrays, slices, and tuples of such items), it is better to
+    /// as arrays, slices, and tuples of such items), it is typically better to
     /// use an unstable sort than a stable sort.
     ///
     /// ### Why is this bad?
-    /// Using a stable sort consumes more memory and cpu cycles. Because
-    /// values which compare equal are identical, preserving their
+    /// Typically, using a stable sort consumes more memory and cpu cycles.
+    /// Because values which compare equal are identical, preserving their
     /// relative order (the guarantee that a stable sort provides) means
     /// nothing, while the extra costs still apply.
     ///
+    /// ### Known problems
+    ///
+    /// As pointed out in
+    /// [issue #8241](https://github.com/rust-lang/rust-clippy/issues/8241),
+    /// a stable sort can instead be significantly faster for certain scenarios
+    /// (eg. when a sorted vector is extended with new data and resorted).
+    ///
+    /// For more information and benchmarking results, please refer to the
+    /// issue linked above.
+    ///
     /// ### Example
     /// ```rust
     /// let mut vec = vec![2, 1, 3];
@@ -30,7 +40,7 @@ declare_clippy_lint! {
     /// ```
     #[clippy::version = "1.47.0"]
     pub STABLE_SORT_PRIMITIVE,
-    perf,
+    pedantic,
     "use of sort() when sort_unstable() is equivalent"
 }
 
@@ -126,7 +136,7 @@ impl LateLintPass<'_> for StableSortPrimitive {
                         Applicability::MachineApplicable,
                     );
                     diag.note(
-                        "an unstable sort would perform faster without any observable difference for this data type",
+                        "an unstable sort typically performs faster without any observable difference for this data type",
                     );
                 },
             );
diff --git a/clippy_lints/src/strings.rs b/clippy_lints/src/strings.rs
index 3573f632a36..7c196ccaa8c 100644
--- a/clippy_lints/src/strings.rs
+++ b/clippy_lints/src/strings.rs
@@ -5,6 +5,7 @@ use clippy_utils::{get_parent_expr, is_lint_allowed, match_function_call, method
 use clippy_utils::{peel_blocks, SpanlessEq};
 use if_chain::if_chain;
 use rustc_errors::Applicability;
+use rustc_hir::def_id::DefId;
 use rustc_hir::{BinOpKind, BorrowKind, Expr, ExprKind, LangItem, QPath};
 use rustc_lint::{LateContext, LateLintPass, LintContext};
 use rustc_middle::lint::in_external_macro;
@@ -451,3 +452,58 @@ impl<'tcx> LateLintPass<'tcx> for StringToString {
         }
     }
 }
+
+declare_clippy_lint! {
+    /// ### What it does
+    /// Warns about calling `str::trim` (or variants) before `str::split_whitespace`.
+    ///
+    /// ### Why is this bad?
+    /// `split_whitespace` already ignores leading and trailing whitespace.
+    ///
+    /// ### Example
+    /// ```rust
+    /// " A B C ".trim().split_whitespace();
+    /// ```
+    /// Use instead:
+    /// ```rust
+    /// " A B C ".split_whitespace();
+    /// ```
+    #[clippy::version = "1.62.0"]
+    pub TRIM_SPLIT_WHITESPACE,
+    style,
+    "using `str::trim()` or alike before `str::split_whitespace`"
+}
+declare_lint_pass!(TrimSplitWhitespace => [TRIM_SPLIT_WHITESPACE]);
+
+impl<'tcx> LateLintPass<'tcx> for TrimSplitWhitespace {
+    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &Expr<'_>) {
+        let tyckres = cx.typeck_results();
+        if_chain! {
+            if let ExprKind::MethodCall(path, [split_recv], split_ws_span) = expr.kind;
+            if path.ident.name == sym!(split_whitespace);
+            if let Some(split_ws_def_id) = tyckres.type_dependent_def_id(expr.hir_id);
+            if cx.tcx.is_diagnostic_item(sym::str_split_whitespace, split_ws_def_id);
+            if let ExprKind::MethodCall(path, [_trim_recv], trim_span) = split_recv.kind;
+            if let trim_fn_name @ ("trim" | "trim_start" | "trim_end") = path.ident.name.as_str();
+            if let Some(trim_def_id) = tyckres.type_dependent_def_id(split_recv.hir_id);
+            if is_one_of_trim_diagnostic_items(cx, trim_def_id);
+            then {
+                span_lint_and_sugg(
+                    cx,
+                    TRIM_SPLIT_WHITESPACE,
+                    trim_span.with_hi(split_ws_span.lo()),
+                    &format!("found call to `str::{}` before `str::split_whitespace`", trim_fn_name),
+                    &format!("remove `{}()`", trim_fn_name),
+                    String::new(),
+                    Applicability::MachineApplicable,
+                );
+            }
+        }
+    }
+}
+
+fn is_one_of_trim_diagnostic_items(cx: &LateContext<'_>, trim_def_id: DefId) -> bool {
+    cx.tcx.is_diagnostic_item(sym::str_trim, trim_def_id)
+        || cx.tcx.is_diagnostic_item(sym::str_trim_start, trim_def_id)
+        || cx.tcx.is_diagnostic_item(sym::str_trim_end, trim_def_id)
+}
diff --git a/clippy_lints/src/suspicious_operation_groupings.rs b/clippy_lints/src/suspicious_operation_groupings.rs
index b5dd27ff80d..c4c1aa11004 100644
--- a/clippy_lints/src/suspicious_operation_groupings.rs
+++ b/clippy_lints/src/suspicious_operation_groupings.rs
@@ -550,7 +550,7 @@ fn ident_difference_expr_with_base_location(
     // IdentIter, then the output of this function will be almost always be correct
     // in practice.
     //
-    // If it turns out that problematic cases are more prelavent than we assume,
+    // If it turns out that problematic cases are more prevalent than we assume,
     // then we should be able to change this function to do the correct traversal,
     // without needing to change the rest of the code.
 
diff --git a/clippy_lints/src/trait_bounds.rs b/clippy_lints/src/trait_bounds.rs
index 3d1b2ee925b..78e388a49af 100644
--- a/clippy_lints/src/trait_bounds.rs
+++ b/clippy_lints/src/trait_bounds.rs
@@ -13,6 +13,7 @@ use rustc_hir::{
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_session::{declare_tool_lint, impl_lint_pass};
 use rustc_span::Span;
+use std::fmt::Write as _;
 
 declare_clippy_lint! {
     /// ### What it does
@@ -34,7 +35,7 @@ declare_clippy_lint! {
     /// ```
     #[clippy::version = "1.38.0"]
     pub TYPE_REPETITION_IN_BOUNDS,
-    pedantic,
+    nursery,
     "Types are repeated unnecessary in trait bounds use `+` instead of using `T: _, T: _`"
 }
 
@@ -64,7 +65,7 @@ declare_clippy_lint! {
     /// ```
     #[clippy::version = "1.47.0"]
     pub TRAIT_DUPLICATION_IN_BOUNDS,
-    pedantic,
+    nursery,
     "Check if the same trait bounds are specified twice during a function declaration"
 }
 
@@ -182,19 +183,19 @@ impl TraitBounds {
                     for b in v.iter() {
                         if let GenericBound::Trait(ref poly_trait_ref, _) = b {
                             let path = &poly_trait_ref.trait_ref.path;
-                            hint_string.push_str(&format!(
+                            let _ = write!(hint_string,
                                 " {} +",
                                 snippet_with_applicability(cx, path.span, "..", &mut applicability)
-                            ));
+                            );
                         }
                     }
                     for b in p.bounds.iter() {
                         if let GenericBound::Trait(ref poly_trait_ref, _) = b {
                             let path = &poly_trait_ref.trait_ref.path;
-                            hint_string.push_str(&format!(
+                            let _ = write!(hint_string,
                                 " {} +",
                                 snippet_with_applicability(cx, path.span, "..", &mut applicability)
-                            ));
+                            );
                         }
                     }
                     hint_string.truncate(hint_string.len() - 2);
@@ -241,7 +242,7 @@ fn check_trait_bound_duplication(cx: &LateContext<'_>, gen: &'_ Generics<'_>) {
                         );
                     }
                     else {
-                        trait_resolutions_direct.push((res_where, span_where))
+                        trait_resolutions_direct.push((res_where, span_where));
                     }
                 }
             }
diff --git a/clippy_lints/src/transmute/utils.rs b/clippy_lints/src/transmute/utils.rs
index f359b606e45..0cbf5ccefa6 100644
--- a/clippy_lints/src/transmute/utils.rs
+++ b/clippy_lints/src/transmute/utils.rs
@@ -1,10 +1,9 @@
 use clippy_utils::last_path_segment;
 use clippy_utils::source::snippet;
-use clippy_utils::ty::is_normalizable;
 use if_chain::if_chain;
 use rustc_hir::{Expr, GenericArg, QPath, TyKind};
 use rustc_lint::LateContext;
-use rustc_middle::ty::{self, cast::CastKind, Ty};
+use rustc_middle::ty::{cast::CastKind, Ty};
 use rustc_span::DUMMY_SP;
 use rustc_typeck::check::{cast::CastCheck, FnCtxt, Inherited};
 
@@ -34,15 +33,12 @@ pub(super) fn get_type_snippet(cx: &LateContext<'_>, path: &QPath<'_>, to_ref_ty
 // check if the component types of the transmuted collection and the result have different ABI,
 // size or alignment
 pub(super) fn is_layout_incompatible<'tcx>(cx: &LateContext<'tcx>, from: Ty<'tcx>, to: Ty<'tcx>) -> bool {
-    let empty_param_env = ty::ParamEnv::empty();
-    // check if `from` and `to` are normalizable to avoid ICE (#4968)
-    if !(is_normalizable(cx, empty_param_env, from) && is_normalizable(cx, empty_param_env, to)) {
-        return false;
-    }
-    let from_ty_layout = cx.tcx.layout_of(empty_param_env.and(from));
-    let to_ty_layout = cx.tcx.layout_of(empty_param_env.and(to));
-    if let (Ok(from_layout), Ok(to_layout)) = (from_ty_layout, to_ty_layout) {
-        from_layout.size != to_layout.size || from_layout.align != to_layout.align || from_layout.abi != to_layout.abi
+    if let Ok(from) = cx.tcx.try_normalize_erasing_regions(cx.param_env, from)
+        && let Ok(to) = cx.tcx.try_normalize_erasing_regions(cx.param_env, to)
+        && let Ok(from_layout) = cx.tcx.layout_of(cx.param_env.and(from))
+        && let Ok(to_layout) = cx.tcx.layout_of(cx.param_env.and(to))
+    {
+        from_layout.size != to_layout.size || from_layout.align.abi != to_layout.align.abi
     } else {
         // no idea about layout, so don't lint
         false
@@ -91,7 +87,7 @@ fn check_cast<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>, from_ty: Ty<'tcx>
             let res = check.do_check(&fn_ctxt);
 
             // do_check's documentation says that it might return Ok and create
-            // errors in the fcx instead of returing Err in some cases. Those cases
+            // errors in the fcx instead of returning Err in some cases. Those cases
             // should be filtered out before getting here.
             assert!(
                 !fn_ctxt.errors_reported_since_creation(),
diff --git a/clippy_lints/src/types/mod.rs b/clippy_lints/src/types/mod.rs
index 67cc8913318..353a6f6b899 100644
--- a/clippy_lints/src/types/mod.rs
+++ b/clippy_lints/src/types/mod.rs
@@ -432,8 +432,8 @@ impl Types {
     fn check_fn_decl(&mut self, cx: &LateContext<'_>, decl: &FnDecl<'_>, context: CheckTyContext) {
         // Ignore functions in trait implementations as they are usually forced by the trait definition.
         //
-        // FIXME: idially we would like to warn *if the compicated type can be simplified*, but it's hard to
-        // check.
+        // FIXME: ideally we would like to warn *if the complicated type can be simplified*, but it's hard
+        // to check.
         if context.is_in_trait_impl {
             return;
         }
diff --git a/clippy_lints/src/undocumented_unsafe_blocks.rs b/clippy_lints/src/undocumented_unsafe_blocks.rs
index c8912a18f18..465d8a914fb 100644
--- a/clippy_lints/src/undocumented_unsafe_blocks.rs
+++ b/clippy_lints/src/undocumented_unsafe_blocks.rs
@@ -156,8 +156,9 @@ fn text_has_safety_comment(src: &str, line_starts: &[BytePos], offset: usize) ->
         .array_windows::<2>()
         .rev()
         .map_while(|[start, end]| {
-            src.get(start.to_usize() - offset..end.to_usize() - offset)
-                .map(|text| (start.to_usize(), text.trim_start()))
+            let start = start.to_usize() - offset;
+            let end = end.to_usize() - offset;
+            src.get(start..end).map(|text| (start, text.trim_start()))
         })
         .filter(|(_, text)| !text.is_empty());
 
@@ -182,7 +183,7 @@ fn text_has_safety_comment(src: &str, line_starts: &[BytePos], offset: usize) ->
     let (mut line_start, mut line) = (line_start, line);
     loop {
         if line.starts_with("/*") {
-            let src = src[line_start..line_starts.last().unwrap().to_usize()].trim_start();
+            let src = src[line_start..line_starts.last().unwrap().to_usize() - offset].trim_start();
             let mut tokens = tokenize(src);
             return src[..tokens.next().unwrap().len]
                 .to_ascii_uppercase()
diff --git a/clippy_lints/src/unit_types/let_unit_value.rs b/clippy_lints/src/unit_types/let_unit_value.rs
index b25a6e3375b..f3f1f53aac5 100644
--- a/clippy_lints/src/unit_types/let_unit_value.rs
+++ b/clippy_lints/src/unit_types/let_unit_value.rs
@@ -1,18 +1,46 @@
 use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::source::snippet_with_macro_callsite;
+use clippy_utils::visitors::for_each_value_source;
+use core::ops::ControlFlow;
 use rustc_errors::Applicability;
-use rustc_hir::{Stmt, StmtKind};
+use rustc_hir::{Expr, ExprKind, PatKind, Stmt, StmtKind};
 use rustc_lint::{LateContext, LintContext};
 use rustc_middle::lint::in_external_macro;
+use rustc_middle::ty::{self, Ty, TypeFoldable, TypeVisitor};
 
 use super::LET_UNIT_VALUE;
 
 pub(super) fn check(cx: &LateContext<'_>, stmt: &Stmt<'_>) {
-    if let StmtKind::Local(local) = stmt.kind {
-        if cx.typeck_results().pat_ty(local.pat).is_unit() {
-            if in_external_macro(cx.sess(), stmt.span) || local.pat.span.from_expansion() {
-                return;
+    if let StmtKind::Local(local) = stmt.kind
+        && let Some(init) = local.init
+        && !local.pat.span.from_expansion()
+        && !in_external_macro(cx.sess(), stmt.span)
+        && cx.typeck_results().pat_ty(local.pat).is_unit()
+    {
+        let needs_inferred = for_each_value_source(init, &mut |e| if needs_inferred_result_ty(cx, e) {
+            ControlFlow::Continue(())
+        } else {
+            ControlFlow::Break(())
+        }).is_continue();
+
+        if needs_inferred {
+            if !matches!(local.pat.kind, PatKind::Wild) {
+                span_lint_and_then(
+                    cx,
+                    LET_UNIT_VALUE,
+                    stmt.span,
+                    "this let-binding has unit value",
+                    |diag| {
+                            diag.span_suggestion(
+                                local.pat.span,
+                                "use a wild (`_`) binding",
+                                "_",
+                                Applicability::MaybeIncorrect, // snippet
+                            );
+                    },
+                );
             }
+        } else {
             span_lint_and_then(
                 cx,
                 LET_UNIT_VALUE,
@@ -33,3 +61,45 @@ pub(super) fn check(cx: &LateContext<'_>, stmt: &Stmt<'_>) {
         }
     }
 }
+
+fn needs_inferred_result_ty(cx: &LateContext<'_>, e: &Expr<'_>) -> bool {
+    let id = match e.kind {
+        ExprKind::Call(
+            Expr {
+                kind: ExprKind::Path(ref path),
+                hir_id,
+                ..
+            },
+            _,
+        ) => cx.qpath_res(path, *hir_id).opt_def_id(),
+        ExprKind::MethodCall(..) => cx.typeck_results().type_dependent_def_id(e.hir_id),
+        _ => return false,
+    };
+    if let Some(id) = id
+        && let sig = cx.tcx.fn_sig(id).skip_binder()
+        && let ty::Param(output_ty) = *sig.output().kind()
+    {
+        sig.inputs().iter().all(|&ty| !ty_contains_param(ty, output_ty.index))
+    } else {
+        false
+    }
+}
+
+fn ty_contains_param(ty: Ty<'_>, index: u32) -> bool {
+    struct Visitor(u32);
+    impl<'tcx> TypeVisitor<'tcx> for Visitor {
+        type BreakTy = ();
+        fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
+            if let ty::Param(ty) = *ty.kind() {
+                if ty.index == self.0 {
+                    ControlFlow::BREAK
+                } else {
+                    ControlFlow::CONTINUE
+                }
+            } else {
+                ty.super_visit_with(self)
+            }
+        }
+    }
+    ty.visit_with(&mut Visitor(index)).is_break()
+}
diff --git a/clippy_lints/src/unit_types/mod.rs b/clippy_lints/src/unit_types/mod.rs
index d9f5b53b413..a9e2073dec2 100644
--- a/clippy_lints/src/unit_types/mod.rs
+++ b/clippy_lints/src/unit_types/mod.rs
@@ -23,7 +23,7 @@ declare_clippy_lint! {
     /// ```
     #[clippy::version = "pre 1.29.0"]
     pub LET_UNIT_VALUE,
-    pedantic,
+    style,
     "creating a `let` binding to a value of unit type, which usually can't be used afterwards"
 }
 
diff --git a/clippy_lints/src/unnecessary_owned_empty_strings.rs b/clippy_lints/src/unnecessary_owned_empty_strings.rs
new file mode 100644
index 00000000000..8a4f4c0ad97
--- /dev/null
+++ b/clippy_lints/src/unnecessary_owned_empty_strings.rs
@@ -0,0 +1,81 @@
+use clippy_utils::{diagnostics::span_lint_and_sugg, ty::is_type_diagnostic_item};
+use clippy_utils::{match_def_path, paths};
+use if_chain::if_chain;
+use rustc_ast::ast::LitKind;
+use rustc_errors::Applicability;
+use rustc_hir::{BorrowKind, Expr, ExprKind, Mutability};
+use rustc_lint::{LateContext, LateLintPass};
+use rustc_middle::ty;
+use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_span::sym;
+
+declare_clippy_lint! {
+    /// ### What it does
+    ///
+    /// Detects cases of owned empty strings being passed as an argument to a function expecting `&str`
+    ///
+    /// ### Why is this bad?
+    ///
+    /// This results in longer and less readable code
+    ///
+    /// ### Example
+    /// ```rust
+    /// vec!["1", "2", "3"].join(&String::new());
+    /// ```
+    /// Use instead:
+    /// ```rust
+    /// vec!["1", "2", "3"].join("");
+    /// ```
+    #[clippy::version = "1.62.0"]
+    pub UNNECESSARY_OWNED_EMPTY_STRINGS,
+    style,
+    "detects cases of references to owned empty strings being passed as an argument to a function expecting `&str`"
+}
+declare_lint_pass!(UnnecessaryOwnedEmptyStrings => [UNNECESSARY_OWNED_EMPTY_STRINGS]);
+
+impl<'tcx> LateLintPass<'tcx> for UnnecessaryOwnedEmptyStrings {
+    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) {
+        if_chain! {
+            if let ExprKind::AddrOf(BorrowKind::Ref, Mutability::Not, inner_expr) = expr.kind;
+            if let ExprKind::Call(fun, args) = inner_expr.kind;
+            if let ExprKind::Path(ref qpath) = fun.kind;
+            if let Some(fun_def_id) = cx.qpath_res(qpath, fun.hir_id).opt_def_id();
+            if let ty::Ref(_, inner_str, _) = cx.typeck_results().expr_ty_adjusted(expr).kind();
+            if inner_str.is_str();
+            then {
+                if match_def_path(cx, fun_def_id, &paths::STRING_NEW) {
+                     span_lint_and_sugg(
+                            cx,
+                            UNNECESSARY_OWNED_EMPTY_STRINGS,
+                            expr.span,
+                            "usage of `&String::new()` for a function expecting a `&str` argument",
+                            "try",
+                            "\"\"".to_owned(),
+                            Applicability::MachineApplicable,
+                        );
+                } else {
+                    if_chain! {
+                        if match_def_path(cx, fun_def_id, &paths::FROM_FROM);
+                        if let [.., last_arg] = args;
+                        if let ExprKind::Lit(spanned) = &last_arg.kind;
+                        if let LitKind::Str(symbol, _) = spanned.node;
+                        if symbol.is_empty();
+                        let inner_expr_type = cx.typeck_results().expr_ty(inner_expr);
+                        if is_type_diagnostic_item(cx, inner_expr_type, sym::String);
+                        then {
+                            span_lint_and_sugg(
+                                cx,
+                                UNNECESSARY_OWNED_EMPTY_STRINGS,
+                                expr.span,
+                                "usage of `&String::from(\"\")` for a function expecting a `&str` argument",
+                                "try",
+                                "\"\"".to_owned(),
+                                Applicability::MachineApplicable,
+                            );
+                        }
+                    }
+                }
+            }
+        }
+    }
+}
diff --git a/clippy_lints/src/unnested_or_patterns.rs b/clippy_lints/src/unnested_or_patterns.rs
index 1d4fe9cfd3c..ae431aac83b 100644
--- a/clippy_lints/src/unnested_or_patterns.rs
+++ b/clippy_lints/src/unnested_or_patterns.rs
@@ -5,7 +5,7 @@ use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::{meets_msrv, msrvs, over};
 use rustc_ast::mut_visit::*;
 use rustc_ast::ptr::P;
-use rustc_ast::{self as ast, Pat, PatKind, PatKind::*, DUMMY_NODE_ID};
+use rustc_ast::{self as ast, Mutability, Pat, PatKind, PatKind::*, DUMMY_NODE_ID};
 use rustc_ast_pretty::pprust;
 use rustc_errors::Applicability;
 use rustc_lint::{EarlyContext, EarlyLintPass};
@@ -25,7 +25,7 @@ declare_clippy_lint! {
     /// *disjunctive normal form (DNF)* into *conjunctive normal form (CNF)*.
     ///
     /// ### Why is this bad?
-    /// In the example above, `Some` is repeated, which unncessarily complicates the pattern.
+    /// In the example above, `Some` is repeated, which unnecessarily complicates the pattern.
     ///
     /// ### Example
     /// ```rust
@@ -230,6 +230,10 @@ fn transform_with_focus_on_idx(alternatives: &mut Vec<P<Pat>>, focus_idx: usize)
         // with which a pattern `C(p_0)` may be formed,
         // which we would want to join with other `C(p_j)`s.
         Ident(.., None) | Lit(_) | Wild | Path(..) | Range(..) | Rest | MacCall(_)
+        // Skip immutable refs, as grouping them saves few characters,
+        // and almost always requires adding parens (increasing noisiness).
+        // In the case of only two patterns, replacement adds net characters.
+        | Ref(_, Mutability::Not)
         // Dealt with elsewhere.
         | Or(_) | Paren(_) => false,
         // Transform `box x | ... | box y` into `box (x | y)`.
@@ -241,10 +245,10 @@ fn transform_with_focus_on_idx(alternatives: &mut Vec<P<Pat>>, focus_idx: usize)
             |k| matches!(k, Box(_)),
             |k| always_pat!(k, Box(p) => p),
         ),
-        // Transform `&m x | ... | &m y` into `&m (x | y)`.
-        Ref(target, m1) => extend_with_matching(
+        // Transform `&mut x | ... | &mut y` into `&mut (x | y)`.
+        Ref(target, Mutability::Mut) => extend_with_matching(
             target, start, alternatives,
-            |k| matches!(k, Ref(_, m2) if m1 == m2), // Mutabilities must match.
+            |k| matches!(k, Ref(_, Mutability::Mut)),
             |k| always_pat!(k, Ref(p, _) => p),
         ),
         // Transform `b @ p0 | ... b @ p1` into `b @ (p0 | p1)`.
diff --git a/clippy_lints/src/use_self.rs b/clippy_lints/src/use_self.rs
index f8e1021af0e..138f8bccb3f 100644
--- a/clippy_lints/src/use_self.rs
+++ b/clippy_lints/src/use_self.rs
@@ -30,7 +30,7 @@ declare_clippy_lint! {
     ///
     /// ### Known problems
     /// - Unaddressed false negative in fn bodies of trait implementations
-    /// - False positive with assotiated types in traits (#4140)
+    /// - False positive with associated types in traits (#4140)
     ///
     /// ### Example
     /// ```rust
diff --git a/clippy_lints/src/utils/author.rs b/clippy_lints/src/utils/author.rs
index d23c85c033b..ff5be825b78 100644
--- a/clippy_lints/src/utils/author.rs
+++ b/clippy_lints/src/utils/author.rs
@@ -70,7 +70,7 @@ macro_rules! bind {
     };
 }
 
-/// Transforms the given `Option<T>` varibles into `OptionPat<Binding<T>>`.
+/// Transforms the given `Option<T>` variables into `OptionPat<Binding<T>>`.
 /// This displays as `Some($name)` or `None` when printed. The name of the inner binding
 /// is set to the name of the variable passed to the macro.
 macro_rules! opt_bind {
diff --git a/clippy_lints/src/utils/conf.rs b/clippy_lints/src/utils/conf.rs
index 271c3a3dd18..74b0168a179 100644
--- a/clippy_lints/src/utils/conf.rs
+++ b/clippy_lints/src/utils/conf.rs
@@ -310,6 +310,12 @@ define_Conf! {
     /// the slice pattern that is suggested. If more elements would be necessary, the lint is suppressed.
     /// For example, `[_, _, _, e, ..]` is a slice pattern with 4 elements.
     (max_suggested_slice_pattern_length: u64 = 3),
+    /// Lint: AWAIT_HOLDING_INVALID_TYPE
+    (await_holding_invalid_types: Vec<crate::utils::conf::DisallowedType> = Vec::new()),
+    /// Lint: LARGE_INCLUDE_FILE.
+    ///
+    /// The maximum size of a file included via `include_bytes!()` or `include_str!()`, in bytes
+    (max_include_file_size: u64 = 1_000_000),
 }
 
 /// Search for the configuration file.
diff --git a/clippy_lints/src/utils/dump_hir.rs b/clippy_lints/src/utils/dump_hir.rs
new file mode 100644
index 00000000000..01efc527a8c
--- /dev/null
+++ b/clippy_lints/src/utils/dump_hir.rs
@@ -0,0 +1,55 @@
+use clippy_utils::get_attr;
+use rustc_hir as hir;
+use rustc_lint::{LateContext, LateLintPass, LintContext};
+use rustc_session::{declare_lint_pass, declare_tool_lint};
+
+declare_clippy_lint! {
+    /// ### What it does
+    /// It formats the attached node with `{:#?}` and writes the result to the
+    /// standard output. This is intended for debugging.
+    ///
+    /// ### Examples
+    /// ```rs
+    /// #[clippy::dump]
+    /// use std::mem;
+    ///
+    /// #[clippy::dump]
+    /// fn foo(input: u32) -> u64 {
+    ///     input as u64
+    /// }
+    /// ```
+    pub DUMP_HIR,
+    internal_warn,
+    "helper to dump info about code"
+}
+
+declare_lint_pass!(DumpHir => [DUMP_HIR]);
+
+impl<'tcx> LateLintPass<'tcx> for DumpHir {
+    fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::Item<'_>) {
+        if has_attr(cx, item.hir_id()) {
+            println!("{item:#?}");
+        }
+    }
+
+    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>) {
+        if has_attr(cx, expr.hir_id) {
+            println!("{expr:#?}");
+        }
+    }
+
+    fn check_stmt(&mut self, cx: &LateContext<'tcx>, stmt: &'tcx hir::Stmt<'_>) {
+        match stmt.kind {
+            hir::StmtKind::Expr(e) | hir::StmtKind::Semi(e) if has_attr(cx, e.hir_id) => return,
+            _ => {},
+        }
+        if has_attr(cx, stmt.hir_id) {
+            println!("{stmt:#?}");
+        }
+    }
+}
+
+fn has_attr(cx: &LateContext<'_>, hir_id: hir::HirId) -> bool {
+    let attrs = cx.tcx.hir().attrs(hir_id);
+    get_attr(cx.sess(), attrs, "dump").count() > 0
+}
diff --git a/clippy_lints/src/utils/inspector.rs b/clippy_lints/src/utils/inspector.rs
deleted file mode 100644
index 37b114a0cfb..00000000000
--- a/clippy_lints/src/utils/inspector.rs
+++ /dev/null
@@ -1,577 +0,0 @@
-//! checks for attributes
-
-use clippy_utils::get_attr;
-use rustc_ast::ast::{Attribute, InlineAsmTemplatePiece};
-use rustc_hir as hir;
-use rustc_lint::{LateContext, LateLintPass, LintContext};
-use rustc_middle::ty;
-use rustc_session::Session;
-use rustc_session::{declare_lint_pass, declare_tool_lint};
-
-declare_clippy_lint! {
-    /// ### What it does
-    /// Dumps every ast/hir node which has the `#[clippy::dump]`
-    /// attribute
-    ///
-    /// ### Example
-    /// ```rust,ignore
-    /// #[clippy::dump]
-    /// extern crate foo;
-    /// ```
-    ///
-    /// prints
-    ///
-    /// ```text
-    /// item `foo`
-    /// visibility inherited from outer item
-    /// extern crate dylib source: "/path/to/foo.so"
-    /// ```
-    pub DEEP_CODE_INSPECTION,
-    internal_warn,
-    "helper to dump info about code"
-}
-
-declare_lint_pass!(DeepCodeInspector => [DEEP_CODE_INSPECTION]);
-
-impl<'tcx> LateLintPass<'tcx> for DeepCodeInspector {
-    fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::Item<'_>) {
-        if !has_attr(cx.sess(), cx.tcx.hir().attrs(item.hir_id())) {
-            return;
-        }
-        print_item(cx, item);
-    }
-
-    fn check_impl_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::ImplItem<'_>) {
-        if !has_attr(cx.sess(), cx.tcx.hir().attrs(item.hir_id())) {
-            return;
-        }
-        println!("impl item `{}`", item.ident.name);
-        match cx.tcx.visibility(item.def_id) {
-            ty::Visibility::Public => println!("public"),
-            ty::Visibility::Restricted(def_id) => {
-                if def_id.is_top_level_module() {
-                    println!("visible crate wide")
-                } else {
-                    println!("visible in module `{}`", cx.tcx.def_path_str(def_id))
-                }
-            },
-            ty::Visibility::Invisible => println!("invisible"),
-        }
-        match item.kind {
-            hir::ImplItemKind::Const(_, body_id) => {
-                println!("associated constant");
-                print_expr(cx, &cx.tcx.hir().body(body_id).value, 1);
-            },
-            hir::ImplItemKind::Fn(..) => println!("method"),
-            hir::ImplItemKind::TyAlias(_) => println!("associated type"),
-        }
-    }
-
-    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>) {
-        if !has_attr(cx.sess(), cx.tcx.hir().attrs(expr.hir_id)) {
-            return;
-        }
-        print_expr(cx, expr, 0);
-    }
-
-    fn check_arm(&mut self, cx: &LateContext<'tcx>, arm: &'tcx hir::Arm<'_>) {
-        if !has_attr(cx.sess(), cx.tcx.hir().attrs(arm.hir_id)) {
-            return;
-        }
-        print_pat(cx, arm.pat, 1);
-        if let Some(ref guard) = arm.guard {
-            println!("guard:");
-            print_guard(cx, guard, 1);
-        }
-        println!("body:");
-        print_expr(cx, arm.body, 1);
-    }
-
-    fn check_stmt(&mut self, cx: &LateContext<'tcx>, stmt: &'tcx hir::Stmt<'_>) {
-        if !has_attr(cx.sess(), cx.tcx.hir().attrs(stmt.hir_id)) {
-            return;
-        }
-        match stmt.kind {
-            hir::StmtKind::Local(local) => {
-                println!("local variable of type {}", cx.typeck_results().node_type(local.hir_id));
-                println!("pattern:");
-                print_pat(cx, local.pat, 0);
-                if let Some(e) = local.init {
-                    println!("init expression:");
-                    print_expr(cx, e, 0);
-                }
-            },
-            hir::StmtKind::Item(_) => println!("item decl"),
-            hir::StmtKind::Expr(e) | hir::StmtKind::Semi(e) => print_expr(cx, e, 0),
-        }
-    }
-}
-
-fn has_attr(sess: &Session, attrs: &[Attribute]) -> bool {
-    get_attr(sess, attrs, "dump").count() > 0
-}
-
-#[allow(clippy::similar_names)]
-#[allow(clippy::too_many_lines)]
-fn print_expr(cx: &LateContext<'_>, expr: &hir::Expr<'_>, indent: usize) {
-    let ind = "  ".repeat(indent);
-    println!("{}+", ind);
-    println!("{}ty: {}", ind, cx.typeck_results().expr_ty(expr));
-    println!(
-        "{}adjustments: {:?}",
-        ind,
-        cx.typeck_results().adjustments().get(expr.hir_id)
-    );
-    match expr.kind {
-        hir::ExprKind::Box(e) => {
-            println!("{}Box", ind);
-            print_expr(cx, e, indent + 1);
-        },
-        hir::ExprKind::Array(v) => {
-            println!("{}Array", ind);
-            for e in v {
-                print_expr(cx, e, indent + 1);
-            }
-        },
-        hir::ExprKind::Call(func, args) => {
-            println!("{}Call", ind);
-            println!("{}function:", ind);
-            print_expr(cx, func, indent + 1);
-            println!("{}arguments:", ind);
-            for arg in args {
-                print_expr(cx, arg, indent + 1);
-            }
-        },
-        hir::ExprKind::Let(hir::Let { pat, init, ty, .. }) => {
-            print_pat(cx, pat, indent + 1);
-            if let Some(ty) = ty {
-                println!("{}  type annotation: {:?}", ind, ty);
-            }
-            print_expr(cx, init, indent + 1);
-        },
-        hir::ExprKind::MethodCall(path, args, _) => {
-            println!("{}MethodCall", ind);
-            println!("{}method name: {}", ind, path.ident.name);
-            for arg in args {
-                print_expr(cx, arg, indent + 1);
-            }
-        },
-        hir::ExprKind::Tup(v) => {
-            println!("{}Tup", ind);
-            for e in v {
-                print_expr(cx, e, indent + 1);
-            }
-        },
-        hir::ExprKind::Binary(op, lhs, rhs) => {
-            println!("{}Binary", ind);
-            println!("{}op: {:?}", ind, op.node);
-            println!("{}lhs:", ind);
-            print_expr(cx, lhs, indent + 1);
-            println!("{}rhs:", ind);
-            print_expr(cx, rhs, indent + 1);
-        },
-        hir::ExprKind::Unary(op, inner) => {
-            println!("{}Unary", ind);
-            println!("{}op: {:?}", ind, op);
-            print_expr(cx, inner, indent + 1);
-        },
-        hir::ExprKind::Lit(ref lit) => {
-            println!("{}Lit", ind);
-            println!("{}{:?}", ind, lit);
-        },
-        hir::ExprKind::Cast(e, target) => {
-            println!("{}Cast", ind);
-            print_expr(cx, e, indent + 1);
-            println!("{}target type: {:?}", ind, target);
-        },
-        hir::ExprKind::Type(e, target) => {
-            println!("{}Type", ind);
-            print_expr(cx, e, indent + 1);
-            println!("{}target type: {:?}", ind, target);
-        },
-        hir::ExprKind::Loop(..) => {
-            println!("{}Loop", ind);
-        },
-        hir::ExprKind::If(cond, _, ref else_opt) => {
-            println!("{}If", ind);
-            println!("{}condition:", ind);
-            print_expr(cx, cond, indent + 1);
-            if let Some(els) = *else_opt {
-                println!("{}else:", ind);
-                print_expr(cx, els, indent + 1);
-            }
-        },
-        hir::ExprKind::Match(cond, _, ref source) => {
-            println!("{}Match", ind);
-            println!("{}condition:", ind);
-            print_expr(cx, cond, indent + 1);
-            println!("{}source: {:?}", ind, source);
-        },
-        hir::ExprKind::Closure(ref clause, _, _, _, _) => {
-            println!("{}Closure", ind);
-            println!("{}clause: {:?}", ind, clause);
-        },
-        hir::ExprKind::Yield(sub, _) => {
-            println!("{}Yield", ind);
-            print_expr(cx, sub, indent + 1);
-        },
-        hir::ExprKind::Block(_, _) => {
-            println!("{}Block", ind);
-        },
-        hir::ExprKind::Assign(lhs, rhs, _) => {
-            println!("{}Assign", ind);
-            println!("{}lhs:", ind);
-            print_expr(cx, lhs, indent + 1);
-            println!("{}rhs:", ind);
-            print_expr(cx, rhs, indent + 1);
-        },
-        hir::ExprKind::AssignOp(ref binop, lhs, rhs) => {
-            println!("{}AssignOp", ind);
-            println!("{}op: {:?}", ind, binop.node);
-            println!("{}lhs:", ind);
-            print_expr(cx, lhs, indent + 1);
-            println!("{}rhs:", ind);
-            print_expr(cx, rhs, indent + 1);
-        },
-        hir::ExprKind::Field(e, ident) => {
-            println!("{}Field", ind);
-            println!("{}field name: {}", ind, ident.name);
-            println!("{}struct expr:", ind);
-            print_expr(cx, e, indent + 1);
-        },
-        hir::ExprKind::Index(arr, idx) => {
-            println!("{}Index", ind);
-            println!("{}array expr:", ind);
-            print_expr(cx, arr, indent + 1);
-            println!("{}index expr:", ind);
-            print_expr(cx, idx, indent + 1);
-        },
-        hir::ExprKind::Path(hir::QPath::Resolved(ref ty, path)) => {
-            println!("{}Resolved Path, {:?}", ind, ty);
-            println!("{}path: {:?}", ind, path);
-        },
-        hir::ExprKind::Path(hir::QPath::TypeRelative(ty, seg)) => {
-            println!("{}Relative Path, {:?}", ind, ty);
-            println!("{}seg: {:?}", ind, seg);
-        },
-        hir::ExprKind::Path(hir::QPath::LangItem(lang_item, ..)) => {
-            println!("{}Lang Item Path, {:?}", ind, lang_item.name());
-        },
-        hir::ExprKind::AddrOf(kind, ref muta, e) => {
-            println!("{}AddrOf", ind);
-            println!("kind: {:?}", kind);
-            println!("mutability: {:?}", muta);
-            print_expr(cx, e, indent + 1);
-        },
-        hir::ExprKind::Break(_, ref e) => {
-            println!("{}Break", ind);
-            if let Some(e) = *e {
-                print_expr(cx, e, indent + 1);
-            }
-        },
-        hir::ExprKind::Continue(_) => println!("{}Again", ind),
-        hir::ExprKind::Ret(ref e) => {
-            println!("{}Ret", ind);
-            if let Some(e) = *e {
-                print_expr(cx, e, indent + 1);
-            }
-        },
-        hir::ExprKind::InlineAsm(asm) => {
-            println!("{}InlineAsm", ind);
-            println!("{}template: {}", ind, InlineAsmTemplatePiece::to_string(asm.template));
-            println!("{}options: {:?}", ind, asm.options);
-            println!("{}operands:", ind);
-            for (op, _op_sp) in asm.operands {
-                match op {
-                    hir::InlineAsmOperand::In { expr, .. }
-                    | hir::InlineAsmOperand::InOut { expr, .. } => {
-                        print_expr(cx, expr, indent + 1);
-                    }
-                    hir::InlineAsmOperand::Out { expr, .. } => {
-                        if let Some(expr) = expr {
-                            print_expr(cx, expr, indent + 1);
-                        }
-                    },
-                    hir::InlineAsmOperand::SplitInOut { in_expr, out_expr, .. } => {
-                        print_expr(cx, in_expr, indent + 1);
-                        if let Some(out_expr) = out_expr {
-                            print_expr(cx, out_expr, indent + 1);
-                        }
-                    },
-                    hir::InlineAsmOperand::Const { anon_const }
-                    | hir::InlineAsmOperand::SymFn { anon_const } => {
-                        println!("{}anon_const:", ind);
-                        print_expr(cx, &cx.tcx.hir().body(anon_const.body).value, indent + 1);
-                    },
-                    hir::InlineAsmOperand::SymStatic { path, .. } => {
-                        match path {
-                            hir::QPath::Resolved(ref ty, path) => {
-                                println!("{}Resolved Path, {:?}", ind, ty);
-                                println!("{}path: {:?}", ind, path);
-                            },
-                            hir::QPath::TypeRelative(ty, seg) => {
-                                println!("{}Relative Path, {:?}", ind, ty);
-                                println!("{}seg: {:?}", ind, seg);
-                            },
-                            hir::QPath::LangItem(lang_item, ..) => {
-                                println!("{}Lang Item Path, {:?}", ind, lang_item.name());
-                            },
-                        }
-                    }
-                }
-            }
-        },
-        hir::ExprKind::Struct(path, fields, ref base) => {
-            println!("{}Struct", ind);
-            println!("{}path: {:?}", ind, path);
-            for field in fields {
-                println!("{}field \"{}\":", ind, field.ident.name);
-                print_expr(cx, field.expr, indent + 1);
-            }
-            if let Some(base) = *base {
-                println!("{}base:", ind);
-                print_expr(cx, base, indent + 1);
-            }
-        },
-        hir::ExprKind::ConstBlock(ref anon_const) => {
-            println!("{}ConstBlock", ind);
-            println!("{}anon_const:", ind);
-            print_expr(cx, &cx.tcx.hir().body(anon_const.body).value, indent + 1);
-        },
-        hir::ExprKind::Repeat(val, length) => {
-            println!("{}Repeat", ind);
-            println!("{}value:", ind);
-            print_expr(cx, val, indent + 1);
-            println!("{}repeat count:", ind);
-            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);
-                },
-            }
-        },
-        hir::ExprKind::Err => {
-            println!("{}Err", ind);
-        },
-        hir::ExprKind::DropTemps(e) => {
-            println!("{}DropTemps", ind);
-            print_expr(cx, e, indent + 1);
-        },
-    }
-}
-
-fn print_item(cx: &LateContext<'_>, item: &hir::Item<'_>) {
-    let did = item.def_id;
-    println!("item `{}`", item.ident.name);
-    match cx.tcx.visibility(item.def_id) {
-        ty::Visibility::Public => println!("public"),
-        ty::Visibility::Restricted(def_id) => {
-            if def_id.is_top_level_module() {
-                println!("visible crate wide")
-            } else {
-                println!("visible in module `{}`", cx.tcx.def_path_str(def_id))
-            }
-        },
-        ty::Visibility::Invisible => println!("invisible"),
-    }
-    match item.kind {
-        hir::ItemKind::ExternCrate(ref _renamed_from) => {
-            if let Some(crate_id) = cx.tcx.extern_mod_stmt_cnum(did) {
-                let source = cx.tcx.used_crate_source(crate_id);
-                if let Some(ref src) = source.dylib {
-                    println!("extern crate dylib source: {:?}", src.0);
-                }
-                if let Some(ref src) = source.rlib {
-                    println!("extern crate rlib source: {:?}", src.0);
-                }
-            } else {
-                println!("weird extern crate without a crate id");
-            }
-        },
-        hir::ItemKind::Use(path, ref kind) => println!("{:?}, {:?}", path, kind),
-        hir::ItemKind::Static(..) => println!("static item of type {:#?}", cx.tcx.type_of(did)),
-        hir::ItemKind::Const(..) => println!("const item of type {:#?}", cx.tcx.type_of(did)),
-        hir::ItemKind::Fn(..) => {
-            let item_ty = cx.tcx.type_of(did);
-            println!("function of type {:#?}", item_ty);
-        },
-        hir::ItemKind::Macro(ref macro_def, _) => {
-            if macro_def.macro_rules {
-                println!("macro introduced by `macro_rules!`");
-            } else {
-                println!("macro introduced by `macro`");
-            }
-        },
-        hir::ItemKind::Mod(..) => println!("module"),
-        hir::ItemKind::ForeignMod { abi, .. } => println!("foreign module with abi: {}", abi),
-        hir::ItemKind::GlobalAsm(asm) => println!("global asm: {:?}", asm),
-        hir::ItemKind::TyAlias(..) => {
-            println!("type alias for {:?}", cx.tcx.type_of(did));
-        },
-        hir::ItemKind::OpaqueTy(..) => {
-            println!("existential type with real type {:?}", cx.tcx.type_of(did));
-        },
-        hir::ItemKind::Enum(..) => {
-            println!("enum definition of type {:?}", cx.tcx.type_of(did));
-        },
-        hir::ItemKind::Struct(..) => {
-            println!("struct definition of type {:?}", cx.tcx.type_of(did));
-        },
-        hir::ItemKind::Union(..) => {
-            println!("union definition of type {:?}", cx.tcx.type_of(did));
-        },
-        hir::ItemKind::Trait(..) => {
-            println!("trait decl");
-            if cx.tcx.trait_is_auto(did.to_def_id()) {
-                println!("trait is auto");
-            } else {
-                println!("trait is not auto");
-            }
-        },
-        hir::ItemKind::TraitAlias(..) => {
-            println!("trait alias");
-        },
-        hir::ItemKind::Impl(hir::Impl {
-            of_trait: Some(ref _trait_ref),
-            ..
-        }) => {
-            println!("trait impl");
-        },
-        hir::ItemKind::Impl(hir::Impl { of_trait: None, .. }) => {
-            println!("impl");
-        },
-    }
-}
-
-#[allow(clippy::similar_names)]
-#[allow(clippy::too_many_lines)]
-fn print_pat(cx: &LateContext<'_>, pat: &hir::Pat<'_>, indent: usize) {
-    let ind = "  ".repeat(indent);
-    println!("{}+", ind);
-    match pat.kind {
-        hir::PatKind::Wild => println!("{}Wild", ind),
-        hir::PatKind::Binding(ref mode, .., ident, ref inner) => {
-            println!("{}Binding", ind);
-            println!("{}mode: {:?}", ind, mode);
-            println!("{}name: {}", ind, ident.name);
-            if let Some(inner) = *inner {
-                println!("{}inner:", ind);
-                print_pat(cx, inner, indent + 1);
-            }
-        },
-        hir::PatKind::Or(fields) => {
-            println!("{}Or", ind);
-            for field in fields {
-                print_pat(cx, field, indent + 1);
-            }
-        },
-        hir::PatKind::Struct(ref path, fields, ignore) => {
-            println!("{}Struct", ind);
-            println!(
-                "{}name: {}",
-                ind,
-                rustc_hir_pretty::to_string(rustc_hir_pretty::NO_ANN, |s| s.print_qpath(path, false))
-            );
-            println!("{}ignore leftover fields: {}", ind, ignore);
-            println!("{}fields:", ind);
-            for field in fields {
-                println!("{}  field name: {}", ind, field.ident.name);
-                if field.is_shorthand {
-                    println!("{}  in shorthand notation", ind);
-                }
-                print_pat(cx, field.pat, indent + 1);
-            }
-        },
-        hir::PatKind::TupleStruct(ref path, fields, opt_dots_position) => {
-            println!("{}TupleStruct", ind);
-            println!(
-                "{}path: {}",
-                ind,
-                rustc_hir_pretty::to_string(rustc_hir_pretty::NO_ANN, |s| s.print_qpath(path, false))
-            );
-            if let Some(dot_position) = opt_dots_position {
-                println!("{}dot position: {}", ind, dot_position);
-            }
-            for field in fields {
-                print_pat(cx, field, indent + 1);
-            }
-        },
-        hir::PatKind::Path(hir::QPath::Resolved(ref ty, path)) => {
-            println!("{}Resolved Path, {:?}", ind, ty);
-            println!("{}path: {:?}", ind, path);
-        },
-        hir::PatKind::Path(hir::QPath::TypeRelative(ty, seg)) => {
-            println!("{}Relative Path, {:?}", ind, ty);
-            println!("{}seg: {:?}", ind, seg);
-        },
-        hir::PatKind::Path(hir::QPath::LangItem(lang_item, ..)) => {
-            println!("{}Lang Item Path, {:?}", ind, lang_item.name());
-        },
-        hir::PatKind::Tuple(pats, opt_dots_position) => {
-            println!("{}Tuple", ind);
-            if let Some(dot_position) = opt_dots_position {
-                println!("{}dot position: {}", ind, dot_position);
-            }
-            for field in pats {
-                print_pat(cx, field, indent + 1);
-            }
-        },
-        hir::PatKind::Box(inner) => {
-            println!("{}Box", ind);
-            print_pat(cx, inner, indent + 1);
-        },
-        hir::PatKind::Ref(inner, ref muta) => {
-            println!("{}Ref", ind);
-            println!("{}mutability: {:?}", ind, muta);
-            print_pat(cx, inner, indent + 1);
-        },
-        hir::PatKind::Lit(e) => {
-            println!("{}Lit", ind);
-            print_expr(cx, e, indent + 1);
-        },
-        hir::PatKind::Range(ref l, ref r, ref range_end) => {
-            println!("{}Range", ind);
-            if let Some(expr) = l {
-                print_expr(cx, expr, indent + 1);
-            }
-            if let Some(expr) = r {
-                print_expr(cx, expr, indent + 1);
-            }
-            match *range_end {
-                hir::RangeEnd::Included => println!("{} end included", ind),
-                hir::RangeEnd::Excluded => println!("{} end excluded", ind),
-            }
-        },
-        hir::PatKind::Slice(first_pats, ref range, last_pats) => {
-            println!("{}Slice [a, b, ..i, y, z]", ind);
-            println!("[a, b]:");
-            for pat in first_pats {
-                print_pat(cx, pat, indent + 1);
-            }
-            println!("i:");
-            if let Some(pat) = *range {
-                print_pat(cx, pat, indent + 1);
-            }
-            println!("[y, z]:");
-            for pat in last_pats {
-                print_pat(cx, pat, indent + 1);
-            }
-        },
-    }
-}
-
-fn print_guard(cx: &LateContext<'_>, guard: &hir::Guard<'_>, indent: usize) {
-    let ind = "  ".repeat(indent);
-    println!("{}+", ind);
-    match guard {
-        hir::Guard::If(expr) => {
-            println!("{}If", ind);
-            print_expr(cx, expr, indent + 1);
-        },
-        hir::Guard::IfLet(pat, expr) => {
-            println!("{}IfLet", ind);
-            print_pat(cx, pat, indent + 1);
-            print_expr(cx, expr, indent + 1);
-        },
-    }
-}
diff --git a/clippy_lints/src/utils/internal_lints.rs b/clippy_lints/src/utils/internal_lints.rs
index 25d74b8c499..0e8f40e9210 100644
--- a/clippy_lints/src/utils/internal_lints.rs
+++ b/clippy_lints/src/utils/internal_lints.rs
@@ -292,7 +292,7 @@ declare_clippy_lint! {
     /// Checks for unnecessary conversion from Symbol to a string.
     ///
     /// ### Why is this bad?
-    /// It's faster use symbols directly intead of strings.
+    /// It's faster use symbols directly instead of strings.
     ///
     /// ### Example
     /// Bad:
@@ -823,7 +823,7 @@ fn suggest_note(
         cx,
         COLLAPSIBLE_SPAN_LINT_CALLS,
         expr.span,
-        "this call is collspible",
+        "this call is collapsible",
         "collapse into",
         format!(
             "span_lint_and_note({}, {}, {}, {}, {}, {})",
diff --git a/clippy_lints/src/utils/internal_lints/metadata_collector.rs b/clippy_lints/src/utils/internal_lints/metadata_collector.rs
index ca03b8010dd..8c1910b3b2a 100644
--- a/clippy_lints/src/utils/internal_lints/metadata_collector.rs
+++ b/clippy_lints/src/utils/internal_lints/metadata_collector.rs
@@ -33,7 +33,7 @@ use std::path::Path;
 /// This is the output file of the lint collector.
 const OUTPUT_FILE: &str = "../util/gh-pages/lints.json";
 /// These lints are excluded from the export.
-const BLACK_LISTED_LINTS: [&str; 3] = ["lint_author", "deep_code_inspection", "internal_metadata_collector"];
+const BLACK_LISTED_LINTS: &[&str] = &["lint_author", "dump_hir", "internal_metadata_collector"];
 /// These groups will be ignored by the lint group matcher. This is useful for collections like
 /// `clippy::all`
 const IGNORED_LINT_GROUPS: [&str; 1] = ["clippy::all"];
@@ -117,7 +117,7 @@ const APPLICABILITY_NAME_INDEX: usize = 2;
 /// This applicability will be set for unresolved applicability values.
 const APPLICABILITY_UNRESOLVED_STR: &str = "Unresolved";
 /// The version that will be displayed if none has been defined
-const VERION_DEFAULT_STR: &str = "Unknown";
+const VERSION_DEFAULT_STR: &str = "Unknown";
 
 declare_clippy_lint! {
     /// ### What it does
@@ -571,7 +571,7 @@ fn extract_attr_docs(cx: &LateContext<'_>, item: &Item<'_>) -> Option<String> {
 
 fn get_lint_version(cx: &LateContext<'_>, item: &Item<'_>) -> String {
     extract_clippy_version_value(cx, item).map_or_else(
-        || VERION_DEFAULT_STR.to_string(),
+        || VERSION_DEFAULT_STR.to_string(),
         |version| version.as_str().to_string(),
     )
 }
@@ -872,7 +872,7 @@ impl<'a, 'hir> IsMultiSpanScanner<'a, 'hir> {
         self.suggestion_count += 2;
     }
 
-    /// Checks if the suggestions include multiple spanns
+    /// Checks if the suggestions include multiple spans
     fn is_multi_part(&self) -> bool {
         self.suggestion_count > 1
     }
diff --git a/clippy_lints/src/utils/mod.rs b/clippy_lints/src/utils/mod.rs
index dc385ebacba..787e9fd982c 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;
+pub mod dump_hir;
 #[cfg(feature = "internal")]
 pub mod internal_lints;