about summary refs log tree commit diff
path: root/src/tools/clippy/clippy_lints
diff options
context:
space:
mode:
authorPhilipp Krones <hello@philkrones.com>2023-10-21 14:16:11 +0200
committerPhilipp Krones <hello@philkrones.com>2023-10-21 14:16:11 +0200
commit24b3554e738b48920a2cdc60dc7f25b33ce90c96 (patch)
treeea21db5f4f4bc75009992057c373aeba94204c24 /src/tools/clippy/clippy_lints
parent6f97d838c644174b38413d920ed8d43b70cdc7db (diff)
parent2b030eb03d9e5837440b1ee0b98c50b97c0c5889 (diff)
downloadrust-24b3554e738b48920a2cdc60dc7f25b33ce90c96.tar.gz
rust-24b3554e738b48920a2cdc60dc7f25b33ce90c96.zip
Merge commit '2b030eb03d9e5837440b1ee0b98c50b97c0c5889' into clippyup
Diffstat (limited to 'src/tools/clippy/clippy_lints')
-rw-r--r--src/tools/clippy/clippy_lints/src/async_yields_async.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/await_holding_invalid.rs5
-rw-r--r--src/tools/clippy/clippy_lints/src/box_default.rs3
-rw-r--r--src/tools/clippy/clippy_lints/src/declared_lints.rs7
-rw-r--r--src/tools/clippy/clippy_lints/src/default_instead_of_iter_empty.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/exit.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/from_raw_with_void_ptr.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/functions/impl_trait_in_params.rs126
-rw-r--r--src/tools/clippy/clippy_lints/src/functions/mod.rs12
-rw-r--r--src/tools/clippy/clippy_lints/src/item_name_repetitions.rs (renamed from src/tools/clippy/clippy_lints/src/enum_variants.rs)211
-rw-r--r--src/tools/clippy/clippy_lints/src/iter_without_into_iter.rs29
-rw-r--r--src/tools/clippy/clippy_lints/src/lib.rs75
-rw-r--r--src/tools/clippy/clippy_lints/src/loops/same_item_push.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/manual_async_fn.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/manual_bits.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/manual_is_ascii_check.rs24
-rw-r--r--src/tools/clippy/clippy_lints/src/matches/mod.rs3
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/filter_map_identity.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/flat_map_identity.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/get_first.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/map_identity.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/search_is_some.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/unnecessary_lazy_eval.rs12
-rw-r--r--src/tools/clippy/clippy_lints/src/missing_doc.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/missing_enforced_import_rename.rs5
-rw-r--r--src/tools/clippy/clippy_lints/src/missing_fields_in_debug.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/multiple_unsafe_ops_per_block.rs7
-rw-r--r--src/tools/clippy/clippy_lints/src/needless_continue.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/needless_pass_by_ref_mut.rs104
-rw-r--r--src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/needless_question_mark.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/non_copy_const.rs315
-rw-r--r--src/tools/clippy/clippy_lints/src/non_send_fields_in_send_ty.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/only_used_in_recursion.rs1
-rw-r--r--src/tools/clippy/clippy_lints/src/operators/cmp_owned.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/rc_clone_in_vec_init.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/redundant_async_block.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/redundant_locals.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/slow_vector_initialization.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/swap_ptr_to_ref.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/types/mod.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/uninit_vec.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/unnecessary_map_on_constructor.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/use_self.rs3
-rw-r--r--src/tools/clippy/clippy_lints/src/utils/author.rs18
-rw-r--r--src/tools/clippy/clippy_lints/src/utils/conf.rs115
-rw-r--r--src/tools/clippy/clippy_lints/src/utils/internal_lints/if_chain_style.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/utils/internal_lints/interning_defined_symbol.rs23
48 files changed, 756 insertions, 410 deletions
diff --git a/src/tools/clippy/clippy_lints/src/async_yields_async.rs b/src/tools/clippy/clippy_lints/src/async_yields_async.rs
index 96a90d599ab..56f56fff1e7 100644
--- a/src/tools/clippy/clippy_lints/src/async_yields_async.rs
+++ b/src/tools/clippy/clippy_lints/src/async_yields_async.rs
@@ -2,7 +2,7 @@ use clippy_utils::diagnostics::span_lint_hir_and_then;
 use clippy_utils::source::snippet;
 use clippy_utils::ty::implements_trait;
 use rustc_errors::Applicability;
-use rustc_hir::{AsyncCoroutineKind, Body, BodyId, ExprKind, CoroutineKind, QPath};
+use rustc_hir::{AsyncCoroutineKind, Body, BodyId, CoroutineKind, ExprKind, QPath};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_session::{declare_lint_pass, declare_tool_lint};
 
diff --git a/src/tools/clippy/clippy_lints/src/await_holding_invalid.rs b/src/tools/clippy/clippy_lints/src/await_holding_invalid.rs
index 60f9bbd7458..ae8618dcaa0 100644
--- a/src/tools/clippy/clippy_lints/src/await_holding_invalid.rs
+++ b/src/tools/clippy/clippy_lints/src/await_holding_invalid.rs
@@ -287,5 +287,8 @@ fn is_mutex_guard(cx: &LateContext<'_>, def_id: DefId) -> bool {
 }
 
 fn is_refcell_ref(cx: &LateContext<'_>, def_id: DefId) -> bool {
-    matches!(cx.tcx.get_diagnostic_name(def_id), Some(sym::RefCellRef | sym::RefCellRefMut))
+    matches!(
+        cx.tcx.get_diagnostic_name(def_id),
+        Some(sym::RefCellRef | sym::RefCellRefMut)
+    )
 }
diff --git a/src/tools/clippy/clippy_lints/src/box_default.rs b/src/tools/clippy/clippy_lints/src/box_default.rs
index 3f1ff66b8cf..cc9bd727937 100644
--- a/src/tools/clippy/clippy_lints/src/box_default.rs
+++ b/src/tools/clippy/clippy_lints/src/box_default.rs
@@ -3,8 +3,9 @@ use clippy_utils::macros::macro_backtrace;
 use clippy_utils::ty::expr_sig;
 use clippy_utils::{get_parent_node, is_default_equivalent, path_def_id};
 use rustc_errors::Applicability;
+use rustc_hir::def::Res;
 use rustc_hir::intravisit::{walk_ty, Visitor};
-use rustc_hir::{def::Res, Block, Expr, ExprKind, Local, Node, QPath, TyKind};
+use rustc_hir::{Block, Expr, ExprKind, Local, Node, QPath, TyKind};
 use rustc_lint::{LateContext, LateLintPass, LintContext};
 use rustc_middle::lint::in_external_macro;
 use rustc_middle::ty::print::with_forced_trimmed_paths;
diff --git a/src/tools/clippy/clippy_lints/src/declared_lints.rs b/src/tools/clippy/clippy_lints/src/declared_lints.rs
index 481c44031cf..77438b27f90 100644
--- a/src/tools/clippy/clippy_lints/src/declared_lints.rs
+++ b/src/tools/clippy/clippy_lints/src/declared_lints.rs
@@ -154,9 +154,6 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[
     crate::endian_bytes::LITTLE_ENDIAN_BYTES_INFO,
     crate::entry::MAP_ENTRY_INFO,
     crate::enum_clike::ENUM_CLIKE_UNPORTABLE_VARIANT_INFO,
-    crate::enum_variants::ENUM_VARIANT_NAMES_INFO,
-    crate::enum_variants::MODULE_INCEPTION_INFO,
-    crate::enum_variants::MODULE_NAME_REPETITIONS_INFO,
     crate::equatable_if_let::EQUATABLE_IF_LET_INFO,
     crate::error_impl_error::ERROR_IMPL_ERROR_INFO,
     crate::escape::BOXED_LOCAL_INFO,
@@ -226,6 +223,10 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[
     crate::instant_subtraction::UNCHECKED_DURATION_SUBTRACTION_INFO,
     crate::int_plus_one::INT_PLUS_ONE_INFO,
     crate::invalid_upcast_comparisons::INVALID_UPCAST_COMPARISONS_INFO,
+    crate::item_name_repetitions::ENUM_VARIANT_NAMES_INFO,
+    crate::item_name_repetitions::MODULE_INCEPTION_INFO,
+    crate::item_name_repetitions::MODULE_NAME_REPETITIONS_INFO,
+    crate::item_name_repetitions::STRUCT_FIELD_NAMES_INFO,
     crate::items_after_statements::ITEMS_AFTER_STATEMENTS_INFO,
     crate::items_after_test_module::ITEMS_AFTER_TEST_MODULE_INFO,
     crate::iter_not_returning_iterator::ITER_NOT_RETURNING_ITERATOR_INFO,
diff --git a/src/tools/clippy/clippy_lints/src/default_instead_of_iter_empty.rs b/src/tools/clippy/clippy_lints/src/default_instead_of_iter_empty.rs
index 3d6d257e386..2d11fa6b647 100644
--- a/src/tools/clippy/clippy_lints/src/default_instead_of_iter_empty.rs
+++ b/src/tools/clippy/clippy_lints/src/default_instead_of_iter_empty.rs
@@ -1,6 +1,6 @@
 use clippy_utils::diagnostics::span_lint_and_sugg;
-use clippy_utils::source::snippet_with_context;
 use clippy_utils::last_path_segment;
+use clippy_utils::source::snippet_with_context;
 use rustc_errors::Applicability;
 use rustc_hir::{def, Expr, ExprKind, GenericArg, QPath, TyKind};
 use rustc_lint::{LateContext, LateLintPass};
diff --git a/src/tools/clippy/clippy_lints/src/exit.rs b/src/tools/clippy/clippy_lints/src/exit.rs
index 5de79133c7d..5ecd0ffadf3 100644
--- a/src/tools/clippy/clippy_lints/src/exit.rs
+++ b/src/tools/clippy/clippy_lints/src/exit.rs
@@ -1,5 +1,5 @@
 use clippy_utils::diagnostics::span_lint;
-use clippy_utils::{is_entrypoint_fn};
+use clippy_utils::is_entrypoint_fn;
 use if_chain::if_chain;
 use rustc_hir::{Expr, ExprKind, Item, ItemKind, Node};
 use rustc_lint::{LateContext, LateLintPass};
diff --git a/src/tools/clippy/clippy_lints/src/from_raw_with_void_ptr.rs b/src/tools/clippy/clippy_lints/src/from_raw_with_void_ptr.rs
index d82ea6d2fc8..617c96b4fcb 100644
--- a/src/tools/clippy/clippy_lints/src/from_raw_with_void_ptr.rs
+++ b/src/tools/clippy/clippy_lints/src/from_raw_with_void_ptr.rs
@@ -1,6 +1,6 @@
 use clippy_utils::diagnostics::span_lint_and_help;
-use clippy_utils::ty::is_c_void;
 use clippy_utils::path_def_id;
+use clippy_utils::ty::is_c_void;
 use rustc_hir::def_id::DefId;
 use rustc_hir::{Expr, ExprKind, QPath};
 use rustc_lint::{LateContext, LateLintPass};
diff --git a/src/tools/clippy/clippy_lints/src/functions/impl_trait_in_params.rs b/src/tools/clippy/clippy_lints/src/functions/impl_trait_in_params.rs
index 597fca88885..ee66c841ed2 100644
--- a/src/tools/clippy/clippy_lints/src/functions/impl_trait_in_params.rs
+++ b/src/tools/clippy/clippy_lints/src/functions/impl_trait_in_params.rs
@@ -1,50 +1,104 @@
 use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::is_in_test_function;
 
+use rustc_hir as hir;
 use rustc_hir::intravisit::FnKind;
-use rustc_hir::{Body, HirId};
+use rustc_hir::{Body, GenericParam, Generics, HirId, ImplItem, ImplItemKind, TraitItem, TraitItemKind};
 use rustc_lint::LateContext;
-use rustc_span::Span;
+use rustc_span::symbol::Ident;
+use rustc_span::{BytePos, Span};
 
 use super::IMPL_TRAIT_IN_PARAMS;
 
+fn report(
+    cx: &LateContext<'_>,
+    param: &GenericParam<'_>,
+    ident: &Ident,
+    generics: &Generics<'_>,
+    first_param_span: Span,
+) {
+    // No generics with nested generics, and no generics like FnMut(x)
+    span_lint_and_then(
+        cx,
+        IMPL_TRAIT_IN_PARAMS,
+        param.span,
+        "`impl Trait` used as a function parameter",
+        |diag| {
+            if let Some(gen_span) = generics.span_for_param_suggestion() {
+                // If there's already a generic param with the same bound, do not lint **this** suggestion.
+                diag.span_suggestion_with_style(
+                    gen_span,
+                    "add a type parameter",
+                    format!(", {{ /* Generic name */ }}: {}", &param.name.ident().as_str()[5..]),
+                    rustc_errors::Applicability::HasPlaceholders,
+                    rustc_errors::SuggestionStyle::ShowAlways,
+                );
+            } else {
+                diag.span_suggestion_with_style(
+                    Span::new(
+                        first_param_span.lo() - rustc_span::BytePos(1),
+                        ident.span.hi(),
+                        ident.span.ctxt(),
+                        ident.span.parent(),
+                    ),
+                    "add a type parameter",
+                    format!("<{{ /* Generic name */ }}: {}>", &param.name.ident().as_str()[5..]),
+                    rustc_errors::Applicability::HasPlaceholders,
+                    rustc_errors::SuggestionStyle::ShowAlways,
+                );
+            }
+        },
+    );
+}
+
 pub(super) fn check_fn<'tcx>(cx: &LateContext<'_>, kind: &'tcx FnKind<'_>, body: &'tcx Body<'_>, hir_id: HirId) {
-    if cx.tcx.visibility(cx.tcx.hir().body_owner_def_id(body.id())).is_public() && !is_in_test_function(cx.tcx, hir_id)
-    {
-        if let FnKind::ItemFn(ident, generics, _) = kind {
+    if_chain! {
+        if let FnKind::ItemFn(ident, generics, _) = kind;
+        if cx.tcx.visibility(cx.tcx.hir().body_owner_def_id(body.id())).is_public();
+        if !is_in_test_function(cx.tcx, hir_id);
+        then {
             for param in generics.params {
                 if param.is_impl_trait() {
-                    // No generics with nested generics, and no generics like FnMut(x)
-                    span_lint_and_then(
-                        cx,
-                        IMPL_TRAIT_IN_PARAMS,
-                        param.span,
-                        "'`impl Trait` used as a function parameter'",
-                        |diag| {
-                            if let Some(gen_span) = generics.span_for_param_suggestion() {
-                                diag.span_suggestion_with_style(
-                                    gen_span,
-                                    "add a type parameter",
-                                    format!(", {{ /* Generic name */ }}: {}", &param.name.ident().as_str()[5..]),
-                                    rustc_errors::Applicability::HasPlaceholders,
-                                    rustc_errors::SuggestionStyle::ShowAlways,
-                                );
-                            } else {
-                                diag.span_suggestion_with_style(
-                                    Span::new(
-                                        body.params[0].span.lo() - rustc_span::BytePos(1),
-                                        ident.span.hi(),
-                                        ident.span.ctxt(),
-                                        ident.span.parent(),
-                                    ),
-                                    "add a type parameter",
-                                    format!("<{{ /* Generic name */ }}: {}>", &param.name.ident().as_str()[5..]),
-                                    rustc_errors::Applicability::HasPlaceholders,
-                                    rustc_errors::SuggestionStyle::ShowAlways,
-                                );
-                            }
-                        },
-                    );
+                    report(cx, param, ident, generics, body.params[0].span);
+                };
+            }
+        }
+    }
+}
+
+pub(super) fn check_impl_item(cx: &LateContext<'_>, impl_item: &ImplItem<'_>) {
+    if_chain! {
+        if let ImplItemKind::Fn(_, body_id) = impl_item.kind;
+        if let hir::Node::Item(item) = cx.tcx.hir().get_parent(impl_item.hir_id());
+        if let hir::ItemKind::Impl(impl_) = item.kind;
+        if let hir::Impl { of_trait, .. } = *impl_;
+        if of_trait.is_none();
+        let body = cx.tcx.hir().body(body_id);
+        if cx.tcx.visibility(cx.tcx.hir().body_owner_def_id(body.id())).is_public();
+        if !is_in_test_function(cx.tcx, impl_item.hir_id());
+        then {
+            for param in impl_item.generics.params {
+                if param.is_impl_trait() {
+                    report(cx, param, &impl_item.ident, impl_item.generics, body.params[0].span);
+                }
+            }
+        }
+    }
+}
+
+pub(super) fn check_trait_item(cx: &LateContext<'_>, trait_item: &TraitItem<'_>, avoid_breaking_exported_api: bool) {
+    if_chain! {
+        if !avoid_breaking_exported_api;
+        if let TraitItemKind::Fn(_, _) = trait_item.kind;
+        if let hir::Node::Item(item) = cx.tcx.hir().get_parent(trait_item.hir_id());
+        // ^^ (Will always be a trait)
+        if !item.vis_span.is_empty(); // Is public
+        if !is_in_test_function(cx.tcx, trait_item.hir_id());
+        then {
+            for param in trait_item.generics.params {
+                if param.is_impl_trait() {
+                    let sp = trait_item.ident.span.with_hi(trait_item.ident.span.hi() + BytePos(1));
+                    report(cx, param, &trait_item.ident, trait_item.generics, sp.shrink_to_hi());
                 }
             }
         }
diff --git a/src/tools/clippy/clippy_lints/src/functions/mod.rs b/src/tools/clippy/clippy_lints/src/functions/mod.rs
index ee10334c67f..716908483e9 100644
--- a/src/tools/clippy/clippy_lints/src/functions/mod.rs
+++ b/src/tools/clippy/clippy_lints/src/functions/mod.rs
@@ -360,18 +360,26 @@ declare_clippy_lint! {
 }
 
 #[derive(Copy, Clone)]
+#[allow(clippy::struct_field_names)]
 pub struct Functions {
     too_many_arguments_threshold: u64,
     too_many_lines_threshold: u64,
     large_error_threshold: u64,
+    avoid_breaking_exported_api: bool,
 }
 
 impl Functions {
-    pub fn new(too_many_arguments_threshold: u64, too_many_lines_threshold: u64, large_error_threshold: u64) -> Self {
+    pub fn new(
+        too_many_arguments_threshold: u64,
+        too_many_lines_threshold: u64,
+        large_error_threshold: u64,
+        avoid_breaking_exported_api: bool,
+    ) -> Self {
         Self {
             too_many_arguments_threshold,
             too_many_lines_threshold,
             large_error_threshold,
+            avoid_breaking_exported_api,
         }
     }
 }
@@ -415,6 +423,7 @@ impl<'tcx> LateLintPass<'tcx> for Functions {
     fn check_impl_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::ImplItem<'_>) {
         must_use::check_impl_item(cx, item);
         result::check_impl_item(cx, item, self.large_error_threshold);
+        impl_trait_in_params::check_impl_item(cx, item);
     }
 
     fn check_trait_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::TraitItem<'_>) {
@@ -422,5 +431,6 @@ impl<'tcx> LateLintPass<'tcx> for Functions {
         not_unsafe_ptr_arg_deref::check_trait_item(cx, item);
         must_use::check_trait_item(cx, item);
         result::check_trait_item(cx, item, self.large_error_threshold);
+        impl_trait_in_params::check_trait_item(cx, item, self.avoid_breaking_exported_api);
     }
 }
diff --git a/src/tools/clippy/clippy_lints/src/enum_variants.rs b/src/tools/clippy/clippy_lints/src/item_name_repetitions.rs
index e332f681b6d..8b4984da3dd 100644
--- a/src/tools/clippy/clippy_lints/src/enum_variants.rs
+++ b/src/tools/clippy/clippy_lints/src/item_name_repetitions.rs
@@ -1,9 +1,10 @@
 //! lint on enum variants that are prefixed or suffixed by the same characters
 
 use clippy_utils::diagnostics::{span_lint, span_lint_and_help, span_lint_hir};
+use clippy_utils::macros::span_is_local;
 use clippy_utils::source::is_present_in_source;
-use clippy_utils::str_utils::{camel_case_split, count_match_end, count_match_start};
-use rustc_hir::{EnumDef, Item, ItemKind, OwnerId, Variant};
+use clippy_utils::str_utils::{camel_case_split, count_match_end, count_match_start, to_camel_case, to_snake_case};
+use rustc_hir::{EnumDef, FieldDef, Item, ItemKind, OwnerId, Variant, VariantData};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_session::{declare_tool_lint, impl_lint_pass};
 use rustc_span::source_map::Span;
@@ -103,32 +104,184 @@ declare_clippy_lint! {
     style,
     "modules that have the same name as their parent module"
 }
+declare_clippy_lint! {
+    /// ### What it does
+    /// Detects struct fields that are prefixed or suffixed
+    /// by the same characters or the name of the struct itself.
+    ///
+    /// ### Why is this bad?
+    /// Information common to all struct fields is better represented in the struct name.
+    ///
+    /// ### Limitations
+    /// Characters with no casing will be considered when comparing prefixes/suffixes
+    /// This applies to numbers and non-ascii characters without casing
+    /// e.g. `foo1` and `foo2` is considered to have different prefixes
+    /// (the prefixes are `foo1` and `foo2` respectively), as also `bar螃`, `bar蟹`
+    ///
+    /// ### Example
+    /// ```rust
+    /// struct Cake {
+    ///     cake_sugar: u8,
+    ///     cake_flour: u8,
+    ///     cake_eggs: u8
+    /// }
+    /// ```
+    /// Use instead:
+    /// ```rust
+    /// struct Cake {
+    ///     sugar: u8,
+    ///     flour: u8,
+    ///     eggs: u8
+    /// }
+    /// ```
+    #[clippy::version = "1.75.0"]
+    pub STRUCT_FIELD_NAMES,
+    pedantic,
+    "structs where all fields share a prefix/postfix or contain the name of the struct"
+}
 
-pub struct EnumVariantNames {
+pub struct ItemNameRepetitions {
     modules: Vec<(Symbol, String, OwnerId)>,
-    threshold: u64,
+    enum_threshold: u64,
+    struct_threshold: u64,
     avoid_breaking_exported_api: bool,
     allow_private_module_inception: bool,
 }
 
-impl EnumVariantNames {
+impl ItemNameRepetitions {
     #[must_use]
-    pub fn new(threshold: u64, avoid_breaking_exported_api: bool, allow_private_module_inception: bool) -> Self {
+    pub fn new(
+        enum_threshold: u64,
+        struct_threshold: u64,
+        avoid_breaking_exported_api: bool,
+        allow_private_module_inception: bool,
+    ) -> Self {
         Self {
             modules: Vec::new(),
-            threshold,
+            enum_threshold,
+            struct_threshold,
             avoid_breaking_exported_api,
             allow_private_module_inception,
         }
     }
 }
 
-impl_lint_pass!(EnumVariantNames => [
+impl_lint_pass!(ItemNameRepetitions => [
     ENUM_VARIANT_NAMES,
+    STRUCT_FIELD_NAMES,
     MODULE_NAME_REPETITIONS,
     MODULE_INCEPTION
 ]);
 
+#[must_use]
+fn have_no_extra_prefix(prefixes: &[&str]) -> bool {
+    prefixes.iter().all(|p| p == &"" || p == &"_")
+}
+
+fn check_fields(cx: &LateContext<'_>, threshold: u64, item: &Item<'_>, fields: &[FieldDef<'_>]) {
+    if (fields.len() as u64) < threshold {
+        return;
+    }
+
+    check_struct_name_repetition(cx, item, fields);
+
+    // if the SyntaxContext of the identifiers of the fields and struct differ dont lint them.
+    // this prevents linting in macros in which the location of the field identifier names differ
+    if !fields.iter().all(|field| item.ident.span.eq_ctxt(field.ident.span)) {
+        return;
+    }
+
+    let mut pre: Vec<&str> = match fields.first() {
+        Some(first_field) => first_field.ident.name.as_str().split('_').collect(),
+        None => return,
+    };
+    let mut post = pre.clone();
+    post.reverse();
+    for field in fields {
+        let field_split: Vec<&str> = field.ident.name.as_str().split('_').collect();
+        if field_split.len() == 1 {
+            return;
+        }
+
+        pre = pre
+            .into_iter()
+            .zip(field_split.iter())
+            .take_while(|(a, b)| &a == b)
+            .map(|e| e.0)
+            .collect();
+        post = post
+            .into_iter()
+            .zip(field_split.iter().rev())
+            .take_while(|(a, b)| &a == b)
+            .map(|e| e.0)
+            .collect();
+    }
+    let prefix = pre.join("_");
+    post.reverse();
+    let postfix = match post.last() {
+        Some(&"") => post.join("_") + "_",
+        Some(_) | None => post.join("_"),
+    };
+    if fields.len() > 1 {
+        let (what, value) = match (
+            prefix.is_empty() || prefix.chars().all(|c| c == '_'),
+            postfix.is_empty(),
+        ) {
+            (true, true) => return,
+            (false, _) => ("pre", prefix),
+            (true, false) => ("post", postfix),
+        };
+        span_lint_and_help(
+            cx,
+            STRUCT_FIELD_NAMES,
+            item.span,
+            &format!("all fields have the same {what}fix: `{value}`"),
+            None,
+            &format!("remove the {what}fixes"),
+        );
+    }
+}
+
+fn check_struct_name_repetition(cx: &LateContext<'_>, item: &Item<'_>, fields: &[FieldDef<'_>]) {
+    let snake_name = to_snake_case(item.ident.name.as_str());
+    let item_name_words: Vec<&str> = snake_name.split('_').collect();
+    for field in fields {
+        if field.ident.span.eq_ctxt(item.ident.span) {
+            //consider linting only if the field identifier has the same SyntaxContext as the item(struct)
+            let field_words: Vec<&str> = field.ident.name.as_str().split('_').collect();
+            if field_words.len() >= item_name_words.len() {
+                // if the field name is shorter than the struct name it cannot contain it
+                if field_words.iter().zip(item_name_words.iter()).all(|(a, b)| a == b) {
+                    span_lint_hir(
+                        cx,
+                        STRUCT_FIELD_NAMES,
+                        field.hir_id,
+                        field.span,
+                        "field name starts with the struct's name",
+                    );
+                }
+                if field_words.len() > item_name_words.len() {
+                    // lint only if the end is not covered by the start
+                    if field_words
+                        .iter()
+                        .rev()
+                        .zip(item_name_words.iter().rev())
+                        .all(|(a, b)| a == b)
+                    {
+                        span_lint_hir(
+                            cx,
+                            STRUCT_FIELD_NAMES,
+                            field.hir_id,
+                            field.span,
+                            "field name ends with the struct's name",
+                        );
+                    }
+                }
+            }
+        }
+    }
+}
+
 fn check_enum_start(cx: &LateContext<'_>, item_name: &str, variant: &Variant<'_>) {
     let name = variant.ident.name.as_str();
     let item_name_chars = item_name.chars().count();
@@ -218,35 +371,7 @@ fn check_variant(cx: &LateContext<'_>, threshold: u64, def: &EnumDef<'_>, item_n
     );
 }
 
-#[must_use]
-fn have_no_extra_prefix(prefixes: &[&str]) -> bool {
-    prefixes.iter().all(|p| p == &"" || p == &"_")
-}
-
-#[must_use]
-fn to_camel_case(item_name: &str) -> String {
-    let mut s = String::new();
-    let mut up = true;
-    for c in item_name.chars() {
-        if c.is_uppercase() {
-            // we only turn snake case text into CamelCase
-            return item_name.to_string();
-        }
-        if c == '_' {
-            up = true;
-            continue;
-        }
-        if up {
-            up = false;
-            s.extend(c.to_uppercase());
-        } else {
-            s.push(c);
-        }
-    }
-    s
-}
-
-impl LateLintPass<'_> for EnumVariantNames {
+impl LateLintPass<'_> for ItemNameRepetitions {
     fn check_item_post(&mut self, _cx: &LateContext<'_>, _item: &Item<'_>) {
         let last = self.modules.pop();
         assert!(last.is_some());
@@ -303,9 +428,15 @@ impl LateLintPass<'_> for EnumVariantNames {
                 }
             }
         }
-        if let ItemKind::Enum(ref def, _) = item.kind {
-            if !(self.avoid_breaking_exported_api && cx.effective_visibilities.is_exported(item.owner_id.def_id)) {
-                check_variant(cx, self.threshold, def, item_name, item.span);
+        if !(self.avoid_breaking_exported_api && cx.effective_visibilities.is_exported(item.owner_id.def_id))
+            && span_is_local(item.span)
+        {
+            match item.kind {
+                ItemKind::Enum(def, _) => check_variant(cx, self.enum_threshold, &def, item_name, item.span),
+                ItemKind::Struct(VariantData::Struct(fields, _), _) => {
+                    check_fields(cx, self.struct_threshold, item, fields);
+                },
+                _ => (),
             }
         }
         self.modules.push((item.ident.name, item_camel, item.owner_id));
diff --git a/src/tools/clippy/clippy_lints/src/iter_without_into_iter.rs b/src/tools/clippy/clippy_lints/src/iter_without_into_iter.rs
index 43e1b92c9b9..0ee291a4e9d 100644
--- a/src/tools/clippy/clippy_lints/src/iter_without_into_iter.rs
+++ b/src/tools/clippy/clippy_lints/src/iter_without_into_iter.rs
@@ -9,6 +9,7 @@ use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::ty::{self, Ty};
 use rustc_session::{declare_lint_pass, declare_tool_lint};
 use rustc_span::{sym, Symbol};
+use std::iter;
 
 declare_clippy_lint! {
     /// ### What it does
@@ -52,12 +53,13 @@ declare_clippy_lint! {
 declare_clippy_lint! {
     /// ### What it does
     /// This is the opposite of the `iter_without_into_iter` lint.
-    /// It looks for `IntoIterator for (&|&mut) Type` implementations without an inherent `iter` or `iter_mut` method.
+    /// It looks for `IntoIterator for (&|&mut) Type` implementations without an inherent `iter` or `iter_mut` method
+    /// on the type or on any of the types in its `Deref` chain.
     ///
     /// ### Why is this bad?
     /// It's not bad, but having them is idiomatic and allows the type to be used in iterator chains
-    /// by just calling `.iter()`, instead of the more awkward `<&Type>::into_iter` or `(&val).iter()` syntax
-    /// in case of ambiguity with another `Intoiterator` impl.
+    /// by just calling `.iter()`, instead of the more awkward `<&Type>::into_iter` or `(&val).into_iter()` syntax
+    /// in case of ambiguity with another `IntoIterator` impl.
     ///
     /// ### Example
     /// ```rust
@@ -102,7 +104,20 @@ fn is_nameable_in_impl_trait(ty: &rustc_hir::Ty<'_>) -> bool {
     !matches!(ty.kind, TyKind::OpaqueDef(..))
 }
 
-fn type_has_inherent_method(cx: &LateContext<'_>, ty: Ty<'_>, method_name: Symbol) -> bool {
+/// Returns the deref chain of a type, starting with the type itself.
+fn deref_chain<'cx, 'tcx>(cx: &'cx LateContext<'tcx>, ty: Ty<'tcx>) -> impl Iterator<Item = Ty<'tcx>> + 'cx {
+    iter::successors(Some(ty), |&ty| {
+        if let Some(deref_did) = cx.tcx.lang_items().deref_trait()
+            && implements_trait(cx, ty, deref_did, &[])
+        {
+            make_normalized_projection(cx.tcx, cx.param_env, deref_did, sym::Target, [ty])
+        } else {
+            None
+        }
+    })
+}
+
+fn adt_has_inherent_method(cx: &LateContext<'_>, ty: Ty<'_>, method_name: Symbol) -> bool {
     if let Some(ty_did) = ty.ty_adt_def().map(ty::AdtDef::did) {
         cx.tcx.inherent_impls(ty_did).iter().any(|&did| {
             cx.tcx
@@ -127,7 +142,11 @@ impl LateLintPass<'_> for IterWithoutIntoIter {
                 Mutability::Mut => sym::iter_mut,
                 Mutability::Not => sym::iter,
             }
-            && !type_has_inherent_method(cx, ty, expected_method_name)
+            && !deref_chain(cx, ty)
+                .any(|ty| {
+                    // We can't check inherent impls for slices, but we know that they have an `iter(_mut)` method
+                    ty.peel_refs().is_slice() || adt_has_inherent_method(cx, ty, expected_method_name)
+                })
             && let Some(iter_assoc_span) = imp.items.iter().find_map(|item| {
                 if item.ident.name == sym!(IntoIter) {
                     Some(cx.tcx.hir().impl_item(item.id).expect_type().span)
diff --git a/src/tools/clippy/clippy_lints/src/lib.rs b/src/tools/clippy/clippy_lints/src/lib.rs
index 0f35ec27665..a70a38ee08b 100644
--- a/src/tools/clippy/clippy_lints/src/lib.rs
+++ b/src/tools/clippy/clippy_lints/src/lib.rs
@@ -50,9 +50,6 @@ extern crate clippy_utils;
 #[macro_use]
 extern crate declare_clippy_lint;
 
-use std::io;
-use std::path::PathBuf;
-
 use clippy_utils::msrvs::Msrv;
 use rustc_data_structures::fx::FxHashSet;
 use rustc_lint::{Lint, LintId};
@@ -121,7 +118,6 @@ mod empty_structs_with_brackets;
 mod endian_bytes;
 mod entry;
 mod enum_clike;
-mod enum_variants;
 mod equatable_if_let;
 mod error_impl_error;
 mod escape;
@@ -166,6 +162,7 @@ mod inline_fn_without_body;
 mod instant_subtraction;
 mod int_plus_one;
 mod invalid_upcast_comparisons;
+mod item_name_repetitions;
 mod items_after_statements;
 mod items_after_test_module;
 mod iter_not_returning_iterator;
@@ -362,7 +359,6 @@ mod zero_sized_map_values;
 // end lints modules, do not remove this comment, it’s used in `update_lints`
 
 use crate::utils::conf::metadata::get_configuration_metadata;
-use crate::utils::conf::TryConf;
 pub use crate::utils::conf::{lookup_conf_file, Conf};
 use crate::utils::FindAll;
 
@@ -374,65 +370,13 @@ use crate::utils::FindAll;
 /// level (i.e `#![cfg_attr(...)]`) will still be expanded even when using a pre-expansion pass.
 ///
 /// Used in `./src/driver.rs`.
-pub fn register_pre_expansion_lints(store: &mut rustc_lint::LintStore, sess: &Session, conf: &Conf) {
+pub fn register_pre_expansion_lints(store: &mut rustc_lint::LintStore, conf: &'static Conf) {
     // NOTE: Do not add any more pre-expansion passes. These should be removed eventually.
-    let msrv = Msrv::read(&conf.msrv, sess);
-    let msrv = move || msrv.clone();
+    let msrv = || conf.msrv.clone();
 
     store.register_pre_expansion_pass(move || Box::new(attrs::EarlyAttributes { msrv: msrv() }));
 }
 
-#[doc(hidden)]
-pub fn read_conf(sess: &Session, path: &io::Result<(Option<PathBuf>, Vec<String>)>) -> Conf {
-    if let Ok((_, warnings)) = path {
-        for warning in warnings {
-            sess.warn(warning.clone());
-        }
-    }
-    let file_name = match path {
-        Ok((Some(path), _)) => path,
-        Ok((None, _)) => return Conf::default(),
-        Err(error) => {
-            sess.err(format!("error finding Clippy's configuration file: {error}"));
-            return Conf::default();
-        },
-    };
-
-    let TryConf { conf, errors, warnings } = utils::conf::read(sess, file_name);
-    // all conf errors are non-fatal, we just use the default conf in case of error
-    for error in errors {
-        if let Some(span) = error.span {
-            sess.span_err(
-                span,
-                format!("error reading Clippy's configuration file: {}", error.message),
-            );
-        } else {
-            sess.err(format!(
-                "error reading Clippy's configuration file `{}`: {}",
-                file_name.display(),
-                error.message
-            ));
-        }
-    }
-
-    for warning in warnings {
-        if let Some(span) = warning.span {
-            sess.span_warn(
-                span,
-                format!("error reading Clippy's configuration file: {}", warning.message),
-            );
-        } else {
-            sess.warn(format!(
-                "error reading Clippy's configuration file `{}`: {}",
-                file_name.display(),
-                warning.message
-            ));
-        }
-    }
-
-    conf
-}
-
 #[derive(Default)]
 struct RegistrationGroups {
     all: Vec<LintId>,
@@ -558,7 +502,7 @@ fn register_categories(store: &mut rustc_lint::LintStore) {
 ///
 /// Used in `./src/driver.rs`.
 #[expect(clippy::too_many_lines)]
-pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: &Conf) {
+pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: &'static Conf) {
     register_removed_non_tool_lints(store);
     register_categories(store);
 
@@ -660,8 +604,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
     store.register_late_pass(|_| Box::new(non_octal_unix_permissions::NonOctalUnixPermissions));
     store.register_early_pass(|| Box::new(unnecessary_self_imports::UnnecessarySelfImports));
 
-    let msrv = Msrv::read(&conf.msrv, sess);
-    let msrv = move || msrv.clone();
+    let msrv = || conf.msrv.clone();
     let avoid_breaking_exported_api = conf.avoid_breaking_exported_api;
     let allow_expect_in_tests = conf.allow_expect_in_tests;
     let allow_unwrap_in_tests = conf.allow_unwrap_in_tests;
@@ -762,6 +705,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
             too_many_arguments_threshold,
             too_many_lines_threshold,
             large_error_threshold,
+            avoid_breaking_exported_api,
         ))
     });
     let doc_valid_idents = conf.doc_valid_idents.iter().cloned().collect::<FxHashSet<_>>();
@@ -806,7 +750,8 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
             suppress_restriction_lint_in_const,
         ))
     });
-    store.register_late_pass(|_| Box::new(non_copy_const::NonCopyConst));
+    let ignore_interior_mutability = conf.ignore_interior_mutability.clone();
+    store.register_late_pass(move |_| Box::new(non_copy_const::NonCopyConst::new(ignore_interior_mutability.clone())));
     store.register_late_pass(|_| Box::new(ptr_offset_with_cast::PtrOffsetWithCast));
     store.register_late_pass(|_| Box::new(redundant_clone::RedundantClone));
     store.register_late_pass(|_| Box::new(slow_vector_initialization::SlowVectorInit));
@@ -851,10 +796,12 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
         ))
     });
     let enum_variant_name_threshold = conf.enum_variant_name_threshold;
+    let struct_field_name_threshold = conf.struct_field_name_threshold;
     let allow_private_module_inception = conf.allow_private_module_inception;
     store.register_late_pass(move |_| {
-        Box::new(enum_variants::EnumVariantNames::new(
+        Box::new(item_name_repetitions::ItemNameRepetitions::new(
             enum_variant_name_threshold,
+            struct_field_name_threshold,
             avoid_breaking_exported_api,
             allow_private_module_inception,
         ))
diff --git a/src/tools/clippy/clippy_lints/src/loops/same_item_push.rs b/src/tools/clippy/clippy_lints/src/loops/same_item_push.rs
index f7b3b2358a0..5fffb27cda2 100644
--- a/src/tools/clippy/clippy_lints/src/loops/same_item_push.rs
+++ b/src/tools/clippy/clippy_lints/src/loops/same_item_push.rs
@@ -185,7 +185,7 @@ fn get_vec_push<'tcx>(
             if let StmtKind::Semi(semi_stmt) = &stmt.kind;
             if let ExprKind::MethodCall(path, self_expr, args, _) = &semi_stmt.kind;
             // Figure out the parameters for the method call
-            if let Some(pushed_item) = args.get(0);
+            if let Some(pushed_item) = args.first();
             // Check that the method being called is push() on a Vec
             if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(self_expr), sym::Vec);
             if path.ident.name.as_str() == "push";
diff --git a/src/tools/clippy/clippy_lints/src/manual_async_fn.rs b/src/tools/clippy/clippy_lints/src/manual_async_fn.rs
index 914ceca2995..5a87e75722d 100644
--- a/src/tools/clippy/clippy_lints/src/manual_async_fn.rs
+++ b/src/tools/clippy/clippy_lints/src/manual_async_fn.rs
@@ -4,7 +4,7 @@ use if_chain::if_chain;
 use rustc_errors::Applicability;
 use rustc_hir::intravisit::FnKind;
 use rustc_hir::{
-    AsyncCoroutineKind, Block, Body, Closure, Expr, ExprKind, FnDecl, FnRetTy, CoroutineKind, GenericArg, GenericBound,
+    AsyncCoroutineKind, Block, Body, Closure, CoroutineKind, Expr, ExprKind, FnDecl, FnRetTy, GenericArg, GenericBound,
     ImplItem, Item, ItemKind, LifetimeName, Node, Term, TraitRef, Ty, TyKind, TypeBindingKind,
 };
 use rustc_lint::{LateContext, LateLintPass};
diff --git a/src/tools/clippy/clippy_lints/src/manual_bits.rs b/src/tools/clippy/clippy_lints/src/manual_bits.rs
index 6c7c57ba1d6..552c57d5e02 100644
--- a/src/tools/clippy/clippy_lints/src/manual_bits.rs
+++ b/src/tools/clippy/clippy_lints/src/manual_bits.rs
@@ -103,9 +103,9 @@ fn get_size_of_ty<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> Option<
         if let ExprKind::Path(ref count_func_qpath) = count_func.kind;
 
         if let QPath::Resolved(_, count_func_path) = count_func_qpath;
-        if let Some(segment_zero) = count_func_path.segments.get(0);
+        if let Some(segment_zero) = count_func_path.segments.first();
         if let Some(args) = segment_zero.args;
-        if let Some(GenericArg::Type(real_ty)) = args.args.get(0);
+        if let Some(GenericArg::Type(real_ty)) = args.args.first();
 
         if let Some(def_id) = cx.qpath_res(count_func_qpath, count_func.hir_id).opt_def_id();
         if cx.tcx.is_diagnostic_item(sym::mem_size_of, def_id);
diff --git a/src/tools/clippy/clippy_lints/src/manual_is_ascii_check.rs b/src/tools/clippy/clippy_lints/src/manual_is_ascii_check.rs
index f264424470d..9da20a28fba 100644
--- a/src/tools/clippy/clippy_lints/src/manual_is_ascii_check.rs
+++ b/src/tools/clippy/clippy_lints/src/manual_is_ascii_check.rs
@@ -15,12 +15,13 @@ use rustc_span::{sym, Span};
 declare_clippy_lint! {
     /// ### What it does
     /// Suggests to use dedicated built-in methods,
-    /// `is_ascii_(lowercase|uppercase|digit)` for checking on corresponding ascii range
+    /// `is_ascii_(lowercase|uppercase|digit|hexdigit)` for checking on corresponding
+    /// ascii range
     ///
     /// ### Why is this bad?
     /// Using the built-in functions is more readable and makes it
     /// clear that it's not a specific subset of characters, but all
-    /// ASCII (lowercase|uppercase|digit) characters.
+    /// ASCII (lowercase|uppercase|digit|hexdigit) characters.
     /// ### Example
     /// ```rust
     /// fn main() {
@@ -28,6 +29,7 @@ declare_clippy_lint! {
     ///     assert!(matches!(b'X', b'A'..=b'Z'));
     ///     assert!(matches!('2', '0'..='9'));
     ///     assert!(matches!('x', 'A'..='Z' | 'a'..='z'));
+    ///     assert!(matches!('C', '0'..='9' | 'a'..='f' | 'A'..='F'));
     ///
     ///     ('0'..='9').contains(&'0');
     ///     ('a'..='z').contains(&'a');
@@ -41,6 +43,7 @@ declare_clippy_lint! {
     ///     assert!(b'X'.is_ascii_uppercase());
     ///     assert!('2'.is_ascii_digit());
     ///     assert!('x'.is_ascii_alphabetic());
+    ///     assert!('C'.is_ascii_hexdigit());
     ///
     ///     '0'.is_ascii_digit();
     ///     'a'.is_ascii_lowercase();
@@ -75,6 +78,12 @@ enum CharRange {
     FullChar,
     /// '0..=9'
     Digit,
+    /// 'a..=f'
+    LowerHexLetter,
+    /// 'A..=F'
+    UpperHexLetter,
+    /// '0..=9' | 'a..=f' | 'A..=F'
+    HexDigit,
     Otherwise,
 }
 
@@ -116,7 +125,8 @@ fn check_is_ascii(cx: &LateContext<'_>, span: Span, recv: &Expr<'_>, range: &Cha
         CharRange::LowerChar => Some("is_ascii_lowercase"),
         CharRange::FullChar => Some("is_ascii_alphabetic"),
         CharRange::Digit => Some("is_ascii_digit"),
-        CharRange::Otherwise => None,
+        CharRange::HexDigit => Some("is_ascii_hexdigit"),
+        CharRange::Otherwise | CharRange::LowerHexLetter | CharRange::UpperHexLetter => None,
     } {
         let default_snip = "..";
         let mut app = Applicability::MachineApplicable;
@@ -141,6 +151,12 @@ fn check_pat(pat_kind: &PatKind<'_>) -> CharRange {
 
             if ranges.len() == 2 && ranges.contains(&CharRange::UpperChar) && ranges.contains(&CharRange::LowerChar) {
                 CharRange::FullChar
+            } else if ranges.len() == 3
+                && ranges.contains(&CharRange::Digit)
+                && ranges.contains(&CharRange::LowerHexLetter)
+                && ranges.contains(&CharRange::UpperHexLetter)
+            {
+                CharRange::HexDigit
             } else {
                 CharRange::Otherwise
             }
@@ -156,6 +172,8 @@ fn check_range(start: &Expr<'_>, end: &Expr<'_>) -> CharRange {
         match (&start_lit.node, &end_lit.node) {
             (Char('a'), Char('z')) | (Byte(b'a'), Byte(b'z')) => CharRange::LowerChar,
             (Char('A'), Char('Z')) | (Byte(b'A'), Byte(b'Z')) => CharRange::UpperChar,
+            (Char('a'), Char('f')) | (Byte(b'a'), Byte(b'f')) => CharRange::LowerHexLetter,
+            (Char('A'), Char('F')) | (Byte(b'A'), Byte(b'F')) => CharRange::UpperHexLetter,
             (Char('0'), Char('9')) | (Byte(b'0'), Byte(b'9')) => CharRange::Digit,
             _ => CharRange::Otherwise,
         }
diff --git a/src/tools/clippy/clippy_lints/src/matches/mod.rs b/src/tools/clippy/clippy_lints/src/matches/mod.rs
index a23000e5fe1..b5ab94b3a2f 100644
--- a/src/tools/clippy/clippy_lints/src/matches/mod.rs
+++ b/src/tools/clippy/clippy_lints/src/matches/mod.rs
@@ -967,7 +967,6 @@ declare_clippy_lint! {
     "checks for unnecessary guards in match expressions"
 }
 
-#[derive(Default)]
 pub struct Matches {
     msrv: Msrv,
     infallible_destructuring_match_linted: bool,
@@ -978,7 +977,7 @@ impl Matches {
     pub fn new(msrv: Msrv) -> Self {
         Self {
             msrv,
-            ..Matches::default()
+            infallible_destructuring_match_linted: false,
         }
     }
 }
diff --git a/src/tools/clippy/clippy_lints/src/methods/filter_map_identity.rs b/src/tools/clippy/clippy_lints/src/methods/filter_map_identity.rs
index 3337b250c0e..20878f1e4df 100644
--- a/src/tools/clippy/clippy_lints/src/methods/filter_map_identity.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/filter_map_identity.rs
@@ -1,5 +1,5 @@
 use clippy_utils::diagnostics::span_lint_and_sugg;
-use clippy_utils::{is_expr_identity_function, is_trait_method};
+use clippy_utils::{is_expr_untyped_identity_function, is_trait_method};
 use rustc_errors::Applicability;
 use rustc_hir as hir;
 use rustc_lint::LateContext;
@@ -9,7 +9,7 @@ use rustc_span::sym;
 use super::FILTER_MAP_IDENTITY;
 
 pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, filter_map_arg: &hir::Expr<'_>, filter_map_span: Span) {
-    if is_trait_method(cx, expr, sym::Iterator) && is_expr_identity_function(cx, filter_map_arg) {
+    if is_trait_method(cx, expr, sym::Iterator) && is_expr_untyped_identity_function(cx, filter_map_arg) {
         span_lint_and_sugg(
             cx,
             FILTER_MAP_IDENTITY,
diff --git a/src/tools/clippy/clippy_lints/src/methods/flat_map_identity.rs b/src/tools/clippy/clippy_lints/src/methods/flat_map_identity.rs
index 84a21de0ac8..8849a4f4942 100644
--- a/src/tools/clippy/clippy_lints/src/methods/flat_map_identity.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/flat_map_identity.rs
@@ -1,5 +1,5 @@
 use clippy_utils::diagnostics::span_lint_and_sugg;
-use clippy_utils::{is_expr_identity_function, is_trait_method};
+use clippy_utils::{is_expr_untyped_identity_function, is_trait_method};
 use rustc_errors::Applicability;
 use rustc_hir as hir;
 use rustc_lint::LateContext;
@@ -15,7 +15,7 @@ pub(super) fn check<'tcx>(
     flat_map_arg: &'tcx hir::Expr<'_>,
     flat_map_span: Span,
 ) {
-    if is_trait_method(cx, expr, sym::Iterator) && is_expr_identity_function(cx, flat_map_arg) {
+    if is_trait_method(cx, expr, sym::Iterator) && is_expr_untyped_identity_function(cx, flat_map_arg) {
         span_lint_and_sugg(
             cx,
             FLAT_MAP_IDENTITY,
diff --git a/src/tools/clippy/clippy_lints/src/methods/get_first.rs b/src/tools/clippy/clippy_lints/src/methods/get_first.rs
index ee063adac64..e7b4564c651 100644
--- a/src/tools/clippy/clippy_lints/src/methods/get_first.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/get_first.rs
@@ -1,5 +1,4 @@
 use clippy_utils::diagnostics::span_lint_and_sugg;
-use clippy_utils::is_slice_of_primitives;
 use clippy_utils::source::snippet_with_applicability;
 use if_chain::if_chain;
 use rustc_ast::LitKind;
@@ -20,7 +19,6 @@ pub(super) fn check<'tcx>(
         if let Some(method_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id);
         if let Some(impl_id) = cx.tcx.impl_of_method(method_id);
         if cx.tcx.type_of(impl_id).instantiate_identity().is_slice();
-        if let Some(_) = is_slice_of_primitives(cx, recv);
         if let hir::ExprKind::Lit(Spanned { node: LitKind::Int(0, _), .. }) = arg.kind;
         then {
             let mut app = Applicability::MachineApplicable;
diff --git a/src/tools/clippy/clippy_lints/src/methods/map_identity.rs b/src/tools/clippy/clippy_lints/src/methods/map_identity.rs
index 7be1ce483f6..57581363cfa 100644
--- a/src/tools/clippy/clippy_lints/src/methods/map_identity.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/map_identity.rs
@@ -1,6 +1,6 @@
 use clippy_utils::diagnostics::span_lint_and_sugg;
 use clippy_utils::ty::is_type_diagnostic_item;
-use clippy_utils::{is_expr_identity_function, is_trait_method};
+use clippy_utils::{is_expr_untyped_identity_function, is_trait_method};
 use rustc_errors::Applicability;
 use rustc_hir as hir;
 use rustc_lint::LateContext;
@@ -23,7 +23,7 @@ pub(super) fn check(
         if is_trait_method(cx, expr, sym::Iterator)
             || is_type_diagnostic_item(cx, caller_ty, sym::Result)
             || is_type_diagnostic_item(cx, caller_ty, sym::Option);
-        if is_expr_identity_function(cx, map_arg);
+        if is_expr_untyped_identity_function(cx, map_arg);
         if let Some(sugg_span) = expr.span.trim_start(caller.span);
         then {
             span_lint_and_sugg(
diff --git a/src/tools/clippy/clippy_lints/src/methods/search_is_some.rs b/src/tools/clippy/clippy_lints/src/methods/search_is_some.rs
index afdb8ce94ac..04ddaaa2f46 100644
--- a/src/tools/clippy/clippy_lints/src/methods/search_is_some.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/search_is_some.rs
@@ -39,7 +39,7 @@ pub(super) fn check<'tcx>(
                 if search_method == "find";
                 if let hir::ExprKind::Closure(&hir::Closure { body, .. }) = search_arg.kind;
                 let closure_body = cx.tcx.hir().body(body);
-                if let Some(closure_arg) = closure_body.params.get(0);
+                if let Some(closure_arg) = closure_body.params.first();
                 then {
                     if let hir::PatKind::Ref(..) = closure_arg.pat.kind {
                         Some(search_snippet.replacen('&', "", 1))
diff --git a/src/tools/clippy/clippy_lints/src/methods/unnecessary_lazy_eval.rs b/src/tools/clippy/clippy_lints/src/methods/unnecessary_lazy_eval.rs
index 47e2e744112..4a651396f14 100644
--- a/src/tools/clippy/clippy_lints/src/methods/unnecessary_lazy_eval.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/unnecessary_lazy_eval.rs
@@ -2,6 +2,7 @@ use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::source::snippet;
 use clippy_utils::ty::is_type_diagnostic_item;
 use clippy_utils::{eager_or_lazy, is_from_proc_macro, usage};
+use hir::FnRetTy;
 use rustc_errors::Applicability;
 use rustc_hir as hir;
 use rustc_lint::LateContext;
@@ -27,7 +28,7 @@ pub(super) fn check<'tcx>(
     let is_bool = cx.typeck_results().expr_ty(recv).is_bool();
 
     if is_option || is_result || is_bool {
-        if let hir::ExprKind::Closure(&hir::Closure { body, .. }) = arg.kind {
+        if let hir::ExprKind::Closure(&hir::Closure { body, fn_decl, .. }) = arg.kind {
             let body = cx.tcx.hir().body(body);
             let body_expr = &body.value;
 
@@ -48,7 +49,14 @@ pub(super) fn check<'tcx>(
                     .iter()
                     // bindings are checked to be unused above
                     .all(|param| matches!(param.pat.kind, hir::PatKind::Binding(..) | hir::PatKind::Wild))
-                {
+                    && matches!(
+                        fn_decl.output,
+                        FnRetTy::DefaultReturn(_)
+                            | FnRetTy::Return(hir::Ty {
+                                kind: hir::TyKind::Infer,
+                                ..
+                            })
+                    ) {
                     Applicability::MachineApplicable
                 } else {
                     // replacing the lambda may break type inference
diff --git a/src/tools/clippy/clippy_lints/src/missing_doc.rs b/src/tools/clippy/clippy_lints/src/missing_doc.rs
index f2773cad400..0629dee4f72 100644
--- a/src/tools/clippy/clippy_lints/src/missing_doc.rs
+++ b/src/tools/clippy/clippy_lints/src/missing_doc.rs
@@ -67,7 +67,7 @@ impl MissingDoc {
         if_chain! {
             if let Some(meta) = meta;
             if let MetaItemKind::List(list) = meta.kind;
-            if let Some(meta) = list.get(0);
+            if let Some(meta) = list.first();
             if let Some(name) = meta.ident();
             then {
                 name.name == sym::include
diff --git a/src/tools/clippy/clippy_lints/src/missing_enforced_import_rename.rs b/src/tools/clippy/clippy_lints/src/missing_enforced_import_rename.rs
index 96d83e114a4..fc088710e42 100644
--- a/src/tools/clippy/clippy_lints/src/missing_enforced_import_rename.rs
+++ b/src/tools/clippy/clippy_lints/src/missing_enforced_import_rename.rs
@@ -17,6 +17,9 @@ declare_clippy_lint! {
     /// Checks for imports that do not rename the item as specified
     /// in the `enforce-import-renames` config option.
     ///
+    /// Note: Even though this lint is warn-by-default, it will only trigger if
+    /// import renames are defined in the clippy.toml file.
+    ///
     /// ### Why is this bad?
     /// Consistency is important, if a project has defined import
     /// renames they should be followed. More practically, some item names are too
@@ -38,7 +41,7 @@ declare_clippy_lint! {
     /// ```
     #[clippy::version = "1.55.0"]
     pub MISSING_ENFORCED_IMPORT_RENAMES,
-    restriction,
+    style,
     "enforce import renames"
 }
 
diff --git a/src/tools/clippy/clippy_lints/src/missing_fields_in_debug.rs b/src/tools/clippy/clippy_lints/src/missing_fields_in_debug.rs
index f0b865be804..d205237a591 100644
--- a/src/tools/clippy/clippy_lints/src/missing_fields_in_debug.rs
+++ b/src/tools/clippy/clippy_lints/src/missing_fields_in_debug.rs
@@ -1,9 +1,9 @@
 use std::ops::ControlFlow;
 
 use clippy_utils::diagnostics::span_lint_and_then;
+use clippy_utils::is_path_lang_item;
 use clippy_utils::ty::is_type_diagnostic_item;
 use clippy_utils::visitors::{for_each_expr, Visitable};
-use clippy_utils::is_path_lang_item;
 use rustc_ast::LitKind;
 use rustc_data_structures::fx::FxHashSet;
 use rustc_hir::def::{DefKind, Res};
diff --git a/src/tools/clippy/clippy_lints/src/multiple_unsafe_ops_per_block.rs b/src/tools/clippy/clippy_lints/src/multiple_unsafe_ops_per_block.rs
index fe35126aab2..2c42a7a3676 100644
--- a/src/tools/clippy/clippy_lints/src/multiple_unsafe_ops_per_block.rs
+++ b/src/tools/clippy/clippy_lints/src/multiple_unsafe_ops_per_block.rs
@@ -9,7 +9,7 @@ use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::lint::in_external_macro;
 use rustc_middle::ty;
 use rustc_session::{declare_lint_pass, declare_tool_lint};
-use rustc_span::Span;
+use rustc_span::{DesugaringKind, Span};
 
 declare_clippy_lint! {
     /// ### What it does
@@ -64,7 +64,10 @@ declare_lint_pass!(MultipleUnsafeOpsPerBlock => [MULTIPLE_UNSAFE_OPS_PER_BLOCK])
 
 impl<'tcx> LateLintPass<'tcx> for MultipleUnsafeOpsPerBlock {
     fn check_block(&mut self, cx: &LateContext<'tcx>, block: &'tcx hir::Block<'_>) {
-        if !matches!(block.rules, BlockCheckMode::UnsafeBlock(_)) || in_external_macro(cx.tcx.sess, block.span) {
+        if !matches!(block.rules, BlockCheckMode::UnsafeBlock(_))
+            || in_external_macro(cx.tcx.sess, block.span)
+            || block.span.is_desugaring(DesugaringKind::Await)
+        {
             return;
         }
         let mut unsafe_ops = vec![];
diff --git a/src/tools/clippy/clippy_lints/src/needless_continue.rs b/src/tools/clippy/clippy_lints/src/needless_continue.rs
index 38a75034cd3..377cbef7b99 100644
--- a/src/tools/clippy/clippy_lints/src/needless_continue.rs
+++ b/src/tools/clippy/clippy_lints/src/needless_continue.rs
@@ -189,7 +189,7 @@ fn needless_continue_in_else(else_expr: &ast::Expr, label: Option<&ast::Label>)
 }
 
 fn is_first_block_stmt_continue(block: &ast::Block, label: Option<&ast::Label>) -> bool {
-    block.stmts.get(0).map_or(false, |stmt| match stmt.kind {
+    block.stmts.first().map_or(false, |stmt| match stmt.kind {
         ast::StmtKind::Semi(ref e) | ast::StmtKind::Expr(ref e) => {
             if let ast::ExprKind::Continue(ref l) = e.kind {
                 compare_labels(label, l.as_ref())
@@ -434,7 +434,7 @@ fn erode_from_back(s: &str) -> String {
 }
 
 fn span_of_first_expr_in_block(block: &ast::Block) -> Option<Span> {
-    block.stmts.get(0).map(|stmt| stmt.span)
+    block.stmts.first().map(|stmt| stmt.span)
 }
 
 #[cfg(test)]
diff --git a/src/tools/clippy/clippy_lints/src/needless_pass_by_ref_mut.rs b/src/tools/clippy/clippy_lints/src/needless_pass_by_ref_mut.rs
index 212d6234bdb..1d5874f6fea 100644
--- a/src/tools/clippy/clippy_lints/src/needless_pass_by_ref_mut.rs
+++ b/src/tools/clippy/clippy_lints/src/needless_pass_by_ref_mut.rs
@@ -7,7 +7,8 @@ use rustc_data_structures::fx::{FxHashSet, FxIndexMap};
 use rustc_errors::Applicability;
 use rustc_hir::intravisit::{walk_qpath, FnKind, Visitor};
 use rustc_hir::{
-    Body, Closure, Expr, ExprKind, FnDecl, HirId, HirIdMap, HirIdSet, Impl, ItemKind, Mutability, Node, PatKind, QPath,
+    BlockCheckMode, Body, Closure, Expr, ExprKind, FnDecl, HirId, HirIdMap, HirIdSet, Impl, ItemKind, Mutability, Node,
+    PatKind, QPath,
 };
 use rustc_hir_typeck::expr_use_visitor as euv;
 use rustc_infer::infer::{InferCtxt, TyCtxtInferExt};
@@ -139,13 +140,23 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessPassByRefMut<'tcx> {
         let hir_id = cx.tcx.hir().local_def_id_to_hir_id(fn_def_id);
         let is_async = match kind {
             FnKind::ItemFn(.., header) => {
+                if header.is_unsafe() {
+                    // We don't check unsafe functions.
+                    return;
+                }
                 let attrs = cx.tcx.hir().attrs(hir_id);
                 if header.abi != Abi::Rust || requires_exact_signature(attrs) {
                     return;
                 }
                 header.is_async()
             },
-            FnKind::Method(.., sig) => sig.header.is_async(),
+            FnKind::Method(.., sig) => {
+                if sig.header.is_unsafe() {
+                    // We don't check unsafe functions.
+                    return;
+                }
+                sig.header.is_async()
+            },
             FnKind::Closure => return,
         };
 
@@ -186,20 +197,21 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessPassByRefMut<'tcx> {
             };
             let infcx = cx.tcx.infer_ctxt().build();
             euv::ExprUseVisitor::new(&mut ctx, &infcx, fn_def_id, cx.param_env, cx.typeck_results()).consume_body(body);
-            if is_async {
-                let mut checked_closures = FxHashSet::default();
-
-                // We retrieve all the closures declared in the async function because they will
-                // not be found by `euv::Delegate`.
-                let mut closures: FxHashSet<LocalDefId> = FxHashSet::default();
-                for_each_expr_with_closures(cx, body, |expr| {
-                    if let ExprKind::Closure(closure) = expr.kind {
-                        closures.insert(closure.def_id);
-                    }
-                    ControlFlow::<()>::Continue(())
-                });
-                check_closures(&mut ctx, cx, &infcx, &mut checked_closures, closures);
 
+            let mut checked_closures = FxHashSet::default();
+
+            // We retrieve all the closures declared in the function because they will not be found
+            // by `euv::Delegate`.
+            let mut closures: FxHashSet<LocalDefId> = FxHashSet::default();
+            for_each_expr_with_closures(cx, body, |expr| {
+                if let ExprKind::Closure(closure) = expr.kind {
+                    closures.insert(closure.def_id);
+                }
+                ControlFlow::<()>::Continue(())
+            });
+            check_closures(&mut ctx, cx, &infcx, &mut checked_closures, closures);
+
+            if is_async {
                 while !ctx.async_closures.is_empty() {
                     let async_closures = ctx.async_closures.clone();
                     ctx.async_closures.clear();
@@ -304,10 +316,27 @@ impl<'tcx> MutablyUsedVariablesCtxt<'tcx> {
         }
         self.aliases.insert(alias, target);
     }
+
+    // The goal here is to find if the current scope is unsafe or not. It stops when it finds
+    // a function or an unsafe block.
+    fn is_in_unsafe_block(&self, item: HirId) -> bool {
+        let hir = self.tcx.hir();
+        for (parent, node) in hir.parent_iter(item) {
+            if let Some(fn_sig) = hir.fn_sig_by_hir_id(parent) {
+                return fn_sig.header.is_unsafe();
+            } else if let Node::Block(block) = node {
+                if matches!(block.rules, BlockCheckMode::UnsafeBlock(_)) {
+                    return true;
+                }
+            }
+        }
+        false
+    }
 }
 
 impl<'tcx> euv::Delegate<'tcx> for MutablyUsedVariablesCtxt<'tcx> {
-    fn consume(&mut self, cmt: &euv::PlaceWithHirId<'tcx>, _id: HirId) {
+    #[allow(clippy::if_same_then_else)]
+    fn consume(&mut self, cmt: &euv::PlaceWithHirId<'tcx>, id: HirId) {
         if let euv::Place {
             base:
                 euv::PlaceBase::Local(vid)
@@ -327,13 +356,18 @@ impl<'tcx> euv::Delegate<'tcx> for MutablyUsedVariablesCtxt<'tcx> {
                 && matches!(base_ty.ref_mutability(), Some(Mutability::Mut))
             {
                 self.add_mutably_used_var(*vid);
+            } else if self.is_in_unsafe_block(id) {
+                // If we are in an unsafe block, any operation on this variable must not be warned
+                // upon!
+                self.add_mutably_used_var(*vid);
             }
             self.prev_bind = None;
             self.prev_move_to_closure.remove(vid);
         }
     }
 
-    fn borrow(&mut self, cmt: &euv::PlaceWithHirId<'tcx>, _id: HirId, borrow: ty::BorrowKind) {
+    #[allow(clippy::if_same_then_else)]
+    fn borrow(&mut self, cmt: &euv::PlaceWithHirId<'tcx>, id: HirId, borrow: ty::BorrowKind) {
         self.prev_bind = None;
         if let euv::Place {
             base:
@@ -355,6 +389,10 @@ impl<'tcx> euv::Delegate<'tcx> for MutablyUsedVariablesCtxt<'tcx> {
                 || (borrow == ty::BorrowKind::UniqueImmBorrow && base_ty.ref_mutability() == Some(Mutability::Mut))
             {
                 self.add_mutably_used_var(*vid);
+            } else if self.is_in_unsafe_block(id) {
+                // If we are in an unsafe block, any operation on this variable must not be warned
+                // upon!
+                self.add_mutably_used_var(*vid);
             }
         } else if borrow == ty::ImmBorrow {
             // If there is an `async block`, it'll contain a call to a closure which we need to
@@ -397,7 +435,21 @@ impl<'tcx> euv::Delegate<'tcx> for MutablyUsedVariablesCtxt<'tcx> {
         }
     }
 
-    fn copy(&mut self, _cmt: &euv::PlaceWithHirId<'tcx>, _id: HirId) {
+    fn copy(&mut self, cmt: &euv::PlaceWithHirId<'tcx>, id: HirId) {
+        if let euv::Place {
+            base:
+                euv::PlaceBase::Local(vid)
+                | euv::PlaceBase::Upvar(UpvarId {
+                    var_path: UpvarPath { hir_id: vid },
+                    ..
+                }),
+            ..
+        } = &cmt.place
+        {
+            if self.is_in_unsafe_block(id) {
+                self.add_mutably_used_var(*vid);
+            }
+        }
         self.prev_bind = None;
     }
 
@@ -427,8 +479,22 @@ impl<'tcx> euv::Delegate<'tcx> for MutablyUsedVariablesCtxt<'tcx> {
         }
     }
 
-    fn bind(&mut self, _cmt: &euv::PlaceWithHirId<'tcx>, id: HirId) {
+    fn bind(&mut self, cmt: &euv::PlaceWithHirId<'tcx>, id: HirId) {
         self.prev_bind = Some(id);
+        if let euv::Place {
+            base:
+                euv::PlaceBase::Local(vid)
+                | euv::PlaceBase::Upvar(UpvarId {
+                    var_path: UpvarPath { hir_id: vid },
+                    ..
+                }),
+            ..
+        } = &cmt.place
+        {
+            if self.is_in_unsafe_block(id) {
+                self.add_mutably_used_var(*vid);
+            }
+        }
     }
 }
 
diff --git a/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs b/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs
index 6d7df2eac62..f3c0d616473 100644
--- a/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs
+++ b/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs
@@ -1,10 +1,10 @@
 use clippy_utils::diagnostics::{multispan_sugg, span_lint_and_then};
+use clippy_utils::is_self;
 use clippy_utils::ptr::get_spans;
 use clippy_utils::source::{snippet, snippet_opt};
 use clippy_utils::ty::{
     implements_trait, implements_trait_with_env_from_iter, is_copy, is_type_diagnostic_item, is_type_lang_item,
 };
-use clippy_utils::is_self;
 use if_chain::if_chain;
 use rustc_ast::ast::Attribute;
 use rustc_errors::{Applicability, Diagnostic};
diff --git a/src/tools/clippy/clippy_lints/src/needless_question_mark.rs b/src/tools/clippy/clippy_lints/src/needless_question_mark.rs
index d267b3de7f2..ed279a3813d 100644
--- a/src/tools/clippy/clippy_lints/src/needless_question_mark.rs
+++ b/src/tools/clippy/clippy_lints/src/needless_question_mark.rs
@@ -4,7 +4,7 @@ use clippy_utils::source::snippet;
 use if_chain::if_chain;
 use rustc_errors::Applicability;
 use rustc_hir::def::{DefKind, Res};
-use rustc_hir::{AsyncCoroutineKind, Block, Body, Expr, ExprKind, CoroutineKind, LangItem, MatchSource, QPath};
+use rustc_hir::{AsyncCoroutineKind, Block, Body, CoroutineKind, Expr, ExprKind, LangItem, MatchSource, QPath};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_session::{declare_lint_pass, declare_tool_lint};
 
diff --git a/src/tools/clippy/clippy_lints/src/non_copy_const.rs b/src/tools/clippy/clippy_lints/src/non_copy_const.rs
index 2b4e3260c56..613afa46a91 100644
--- a/src/tools/clippy/clippy_lints/src/non_copy_const.rs
+++ b/src/tools/clippy/clippy_lints/src/non_copy_const.rs
@@ -5,9 +5,10 @@
 use std::ptr;
 
 use clippy_utils::diagnostics::span_lint_and_then;
-use clippy_utils::in_constant;
 use clippy_utils::macros::macro_backtrace;
+use clippy_utils::{def_path_def_ids, in_constant};
 use if_chain::if_chain;
+use rustc_data_structures::fx::FxHashSet;
 use rustc_hir::def::{DefKind, Res};
 use rustc_hir::def_id::DefId;
 use rustc_hir::{
@@ -15,9 +16,10 @@ use rustc_hir::{
 };
 use rustc_lint::{LateContext, LateLintPass, Lint};
 use rustc_middle::mir::interpret::{ErrorHandled, EvalToValTreeResult, GlobalId};
+use rustc_middle::query::Key;
 use rustc_middle::ty::adjustment::Adjust;
 use rustc_middle::ty::{self, Ty, TyCtxt};
-use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_session::{declare_tool_lint, impl_lint_pass};
 use rustc_span::{sym, InnerSpan, Span};
 use rustc_target::abi::VariantIdx;
 
@@ -126,128 +128,6 @@ declare_clippy_lint! {
     "referencing `const` with interior mutability"
 }
 
-fn is_unfrozen<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool {
-    // Ignore types whose layout is unknown since `is_freeze` reports every generic types as `!Freeze`,
-    // making it indistinguishable from `UnsafeCell`. i.e. it isn't a tool to prove a type is
-    // 'unfrozen'. However, this code causes a false negative in which
-    // a type contains a layout-unknown type, but also an unsafe cell like `const CELL: Cell<T>`.
-    // Yet, it's better than `ty.has_type_flags(TypeFlags::HAS_TY_PARAM | TypeFlags::HAS_PROJECTION)`
-    // since it works when a pointer indirection involves (`Cell<*const T>`).
-    // Making up a `ParamEnv` where every generic params and assoc types are `Freeze`is another option;
-    // but I'm not sure whether it's a decent way, if possible.
-    cx.tcx.layout_of(cx.param_env.and(ty)).is_ok() && !ty.is_freeze(cx.tcx, cx.param_env)
-}
-
-fn is_value_unfrozen_raw<'tcx>(
-    cx: &LateContext<'tcx>,
-    result: Result<Option<ty::ValTree<'tcx>>, ErrorHandled>,
-    ty: Ty<'tcx>,
-) -> bool {
-    fn inner<'tcx>(cx: &LateContext<'tcx>, val: ty::ValTree<'tcx>, ty: Ty<'tcx>) -> bool {
-        match *ty.kind() {
-            // the fact that we have to dig into every structs to search enums
-            // leads us to the point checking `UnsafeCell` directly is the only option.
-            ty::Adt(ty_def, ..) if ty_def.is_unsafe_cell() => true,
-            // As of 2022-09-08 miri doesn't track which union field is active so there's no safe way to check the
-            // contained value.
-            ty::Adt(def, ..) if def.is_union() => false,
-            ty::Array(ty, _) => val.unwrap_branch().iter().any(|field| inner(cx, *field, ty)),
-            ty::Adt(def, _) if def.is_union() => false,
-            ty::Adt(def, args) if def.is_enum() => {
-                let (&variant_index, fields) = val.unwrap_branch().split_first().unwrap();
-                let variant_index = VariantIdx::from_u32(variant_index.unwrap_leaf().try_to_u32().ok().unwrap());
-                fields
-                    .iter()
-                    .copied()
-                    .zip(
-                        def.variants()[variant_index]
-                            .fields
-                            .iter()
-                            .map(|field| field.ty(cx.tcx, args)),
-                    )
-                    .any(|(field, ty)| inner(cx, field, ty))
-            },
-            ty::Adt(def, args) => val
-                .unwrap_branch()
-                .iter()
-                .zip(def.non_enum_variant().fields.iter().map(|field| field.ty(cx.tcx, args)))
-                .any(|(field, ty)| inner(cx, *field, ty)),
-            ty::Tuple(tys) => val
-                .unwrap_branch()
-                .iter()
-                .zip(tys)
-                .any(|(field, ty)| inner(cx, *field, ty)),
-            _ => false,
-        }
-    }
-    result.map_or_else(
-        |err| {
-            // Consider `TooGeneric` cases as being unfrozen.
-            // This causes a false positive where an assoc const whose type is unfrozen
-            // have a value that is a frozen variant with a generic param (an example is
-            // `declare_interior_mutable_const::enums::BothOfCellAndGeneric::GENERIC_VARIANT`).
-            // However, it prevents a number of false negatives that is, I think, important:
-            // 1. assoc consts in trait defs referring to consts of themselves (an example is
-            //    `declare_interior_mutable_const::traits::ConcreteTypes::ANOTHER_ATOMIC`).
-            // 2. a path expr referring to assoc consts whose type is doesn't have any frozen variants in trait
-            //    defs (i.e. without substitute for `Self`). (e.g. borrowing
-            //    `borrow_interior_mutable_const::trait::ConcreteTypes::ATOMIC`)
-            // 3. similar to the false positive above; but the value is an unfrozen variant, or the type has no
-            //    enums. (An example is
-            //    `declare_interior_mutable_const::enums::BothOfCellAndGeneric::UNFROZEN_VARIANT` and
-            //    `declare_interior_mutable_const::enums::BothOfCellAndGeneric::NO_ENUM`).
-            // One might be able to prevent these FNs correctly, and replace this with `false`;
-            // e.g. implementing `has_frozen_variant` described above, and not running this function
-            // when the type doesn't have any frozen variants would be the 'correct' way for the 2nd
-            // case (that actually removes another suboptimal behavior (I won't say 'false positive') where,
-            // similar to 2., but with the a frozen variant) (e.g. borrowing
-            // `borrow_interior_mutable_const::enums::AssocConsts::TO_BE_FROZEN_VARIANT`).
-            // I chose this way because unfrozen enums as assoc consts are rare (or, hopefully, none).
-            matches!(err, ErrorHandled::TooGeneric(..))
-        },
-        |val| val.map_or(true, |val| inner(cx, val, ty)),
-    )
-}
-
-fn is_value_unfrozen_poly<'tcx>(cx: &LateContext<'tcx>, body_id: BodyId, ty: Ty<'tcx>) -> bool {
-    let def_id = body_id.hir_id.owner.to_def_id();
-    let args = ty::GenericArgs::identity_for_item(cx.tcx, def_id);
-    let instance = ty::Instance::new(def_id, args);
-    let cid = rustc_middle::mir::interpret::GlobalId {
-        instance,
-        promoted: None,
-    };
-    let param_env = cx.tcx.param_env(def_id).with_reveal_all_normalized(cx.tcx);
-    let result = cx.tcx.const_eval_global_id_for_typeck(param_env, cid, None);
-    is_value_unfrozen_raw(cx, result, ty)
-}
-
-fn is_value_unfrozen_expr<'tcx>(cx: &LateContext<'tcx>, hir_id: HirId, def_id: DefId, ty: Ty<'tcx>) -> bool {
-    let args = cx.typeck_results().node_args(hir_id);
-
-    let result = const_eval_resolve(cx.tcx, cx.param_env, ty::UnevaluatedConst::new(def_id, args), None);
-    is_value_unfrozen_raw(cx, result, ty)
-}
-
-pub fn const_eval_resolve<'tcx>(
-    tcx: TyCtxt<'tcx>,
-    param_env: ty::ParamEnv<'tcx>,
-    ct: ty::UnevaluatedConst<'tcx>,
-    span: Option<Span>,
-) -> EvalToValTreeResult<'tcx> {
-    match ty::Instance::resolve(tcx, param_env, ct.def, ct.args) {
-        Ok(Some(instance)) => {
-            let cid = GlobalId {
-                instance,
-                promoted: None,
-            };
-            tcx.const_eval_global_id_for_typeck(param_env, cid, span)
-        },
-        Ok(None) => Err(ErrorHandled::TooGeneric(span.unwrap_or(rustc_span::DUMMY_SP))),
-        Err(err) => Err(ErrorHandled::Reported(err.into(), span.unwrap_or(rustc_span::DUMMY_SP))),
-    }
-}
-
 #[derive(Copy, Clone)]
 enum Source {
     Item { item: Span },
@@ -292,13 +172,178 @@ fn lint(cx: &LateContext<'_>, source: Source) {
     });
 }
 
-declare_lint_pass!(NonCopyConst => [DECLARE_INTERIOR_MUTABLE_CONST, BORROW_INTERIOR_MUTABLE_CONST]);
+#[derive(Clone)]
+pub struct NonCopyConst {
+    ignore_interior_mutability: Vec<String>,
+    ignore_mut_def_ids: FxHashSet<DefId>,
+}
+
+impl_lint_pass!(NonCopyConst => [DECLARE_INTERIOR_MUTABLE_CONST, BORROW_INTERIOR_MUTABLE_CONST]);
+
+impl NonCopyConst {
+    pub fn new(ignore_interior_mutability: Vec<String>) -> Self {
+        Self {
+            ignore_interior_mutability,
+            ignore_mut_def_ids: FxHashSet::default(),
+        }
+    }
+
+    fn is_ty_ignored(&self, ty: Ty<'_>) -> bool {
+        matches!(ty.ty_adt_id(), Some(adt_id) if self.ignore_mut_def_ids.contains(&adt_id))
+    }
+
+    fn is_unfrozen<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool {
+        // Ignore types whose layout is unknown since `is_freeze` reports every generic types as `!Freeze`,
+        // making it indistinguishable from `UnsafeCell`. i.e. it isn't a tool to prove a type is
+        // 'unfrozen'. However, this code causes a false negative in which
+        // a type contains a layout-unknown type, but also an unsafe cell like `const CELL: Cell<T>`.
+        // Yet, it's better than `ty.has_type_flags(TypeFlags::HAS_TY_PARAM | TypeFlags::HAS_PROJECTION)`
+        // since it works when a pointer indirection involves (`Cell<*const T>`).
+        // Making up a `ParamEnv` where every generic params and assoc types are `Freeze`is another option;
+        // but I'm not sure whether it's a decent way, if possible.
+        cx.tcx.layout_of(cx.param_env.and(ty)).is_ok() && !ty.is_freeze(cx.tcx, cx.param_env)
+    }
+
+    fn is_value_unfrozen_raw_inner<'tcx>(&self, cx: &LateContext<'tcx>, val: ty::ValTree<'tcx>, ty: Ty<'tcx>) -> bool {
+        if self.is_ty_ignored(ty) {
+            return false;
+        }
+        match *ty.kind() {
+            // the fact that we have to dig into every structs to search enums
+            // leads us to the point checking `UnsafeCell` directly is the only option.
+            ty::Adt(ty_def, ..) if ty_def.is_unsafe_cell() => true,
+            // As of 2022-09-08 miri doesn't track which union field is active so there's no safe way to check the
+            // contained value.
+            ty::Adt(def, ..) if def.is_union() => false,
+            ty::Array(ty, _) => val
+                .unwrap_branch()
+                .iter()
+                .any(|field| self.is_value_unfrozen_raw_inner(cx, *field, ty)),
+            ty::Adt(def, _) if def.is_union() => false,
+            ty::Adt(def, args) if def.is_enum() => {
+                let (&variant_index, fields) = val.unwrap_branch().split_first().unwrap();
+                let variant_index = VariantIdx::from_u32(variant_index.unwrap_leaf().try_to_u32().ok().unwrap());
+                fields
+                    .iter()
+                    .copied()
+                    .zip(
+                        def.variants()[variant_index]
+                            .fields
+                            .iter()
+                            .map(|field| field.ty(cx.tcx, args)),
+                    )
+                    .any(|(field, ty)| self.is_value_unfrozen_raw_inner(cx, field, ty))
+            },
+            ty::Adt(def, args) => val
+                .unwrap_branch()
+                .iter()
+                .zip(def.non_enum_variant().fields.iter().map(|field| field.ty(cx.tcx, args)))
+                .any(|(field, ty)| self.is_value_unfrozen_raw_inner(cx, *field, ty)),
+            ty::Tuple(tys) => val
+                .unwrap_branch()
+                .iter()
+                .zip(tys)
+                .any(|(field, ty)| self.is_value_unfrozen_raw_inner(cx, *field, ty)),
+            _ => false,
+        }
+    }
+
+    fn is_value_unfrozen_raw<'tcx>(
+        &self,
+        cx: &LateContext<'tcx>,
+        result: Result<Option<ty::ValTree<'tcx>>, ErrorHandled>,
+        ty: Ty<'tcx>,
+    ) -> bool {
+        result.map_or_else(
+            |err| {
+                // Consider `TooGeneric` cases as being unfrozen.
+                // This causes a false positive where an assoc const whose type is unfrozen
+                // have a value that is a frozen variant with a generic param (an example is
+                // `declare_interior_mutable_const::enums::BothOfCellAndGeneric::GENERIC_VARIANT`).
+                // However, it prevents a number of false negatives that is, I think, important:
+                // 1. assoc consts in trait defs referring to consts of themselves (an example is
+                //    `declare_interior_mutable_const::traits::ConcreteTypes::ANOTHER_ATOMIC`).
+                // 2. a path expr referring to assoc consts whose type is doesn't have any frozen variants in trait
+                //    defs (i.e. without substitute for `Self`). (e.g. borrowing
+                //    `borrow_interior_mutable_const::trait::ConcreteTypes::ATOMIC`)
+                // 3. similar to the false positive above; but the value is an unfrozen variant, or the type has no
+                //    enums. (An example is
+                //    `declare_interior_mutable_const::enums::BothOfCellAndGeneric::UNFROZEN_VARIANT` and
+                //    `declare_interior_mutable_const::enums::BothOfCellAndGeneric::NO_ENUM`).
+                // One might be able to prevent these FNs correctly, and replace this with `false`;
+                // e.g. implementing `has_frozen_variant` described above, and not running this function
+                // when the type doesn't have any frozen variants would be the 'correct' way for the 2nd
+                // case (that actually removes another suboptimal behavior (I won't say 'false positive') where,
+                // similar to 2., but with the a frozen variant) (e.g. borrowing
+                // `borrow_interior_mutable_const::enums::AssocConsts::TO_BE_FROZEN_VARIANT`).
+                // I chose this way because unfrozen enums as assoc consts are rare (or, hopefully, none).
+                matches!(err, ErrorHandled::TooGeneric(..))
+            },
+            |val| val.map_or(true, |val| self.is_value_unfrozen_raw_inner(cx, val, ty)),
+        )
+    }
+
+    fn is_value_unfrozen_poly<'tcx>(&self, cx: &LateContext<'tcx>, body_id: BodyId, ty: Ty<'tcx>) -> bool {
+        let def_id = body_id.hir_id.owner.to_def_id();
+        let args = ty::GenericArgs::identity_for_item(cx.tcx, def_id);
+        let instance = ty::Instance::new(def_id, args);
+        let cid = rustc_middle::mir::interpret::GlobalId {
+            instance,
+            promoted: None,
+        };
+        let param_env = cx.tcx.param_env(def_id).with_reveal_all_normalized(cx.tcx);
+        let result = cx.tcx.const_eval_global_id_for_typeck(param_env, cid, None);
+        self.is_value_unfrozen_raw(cx, result, ty)
+    }
+
+    fn is_value_unfrozen_expr<'tcx>(&self, cx: &LateContext<'tcx>, hir_id: HirId, def_id: DefId, ty: Ty<'tcx>) -> bool {
+        let args = cx.typeck_results().node_args(hir_id);
+
+        let result = Self::const_eval_resolve(cx.tcx, cx.param_env, ty::UnevaluatedConst::new(def_id, args), None);
+        self.is_value_unfrozen_raw(cx, result, ty)
+    }
+
+    pub fn const_eval_resolve<'tcx>(
+        tcx: TyCtxt<'tcx>,
+        param_env: ty::ParamEnv<'tcx>,
+        ct: ty::UnevaluatedConst<'tcx>,
+        span: Option<Span>,
+    ) -> EvalToValTreeResult<'tcx> {
+        match ty::Instance::resolve(tcx, param_env, ct.def, ct.args) {
+            Ok(Some(instance)) => {
+                let cid = GlobalId {
+                    instance,
+                    promoted: None,
+                };
+                tcx.const_eval_global_id_for_typeck(param_env, cid, span)
+            },
+            Ok(None) => Err(ErrorHandled::TooGeneric(span.unwrap_or(rustc_span::DUMMY_SP))),
+            Err(err) => Err(ErrorHandled::Reported(err.into(), span.unwrap_or(rustc_span::DUMMY_SP))),
+        }
+    }
+}
 
 impl<'tcx> LateLintPass<'tcx> for NonCopyConst {
+    fn check_crate(&mut self, cx: &LateContext<'tcx>) {
+        self.ignore_mut_def_ids.clear();
+        let mut path = Vec::new();
+        for ty in &self.ignore_interior_mutability {
+            path.extend(ty.split("::"));
+            for id in def_path_def_ids(cx, &path[..]) {
+                self.ignore_mut_def_ids.insert(id);
+            }
+            path.clear();
+        }
+    }
+
     fn check_item(&mut self, cx: &LateContext<'tcx>, it: &'tcx Item<'_>) {
         if let ItemKind::Const(.., body_id) = it.kind {
             let ty = cx.tcx.type_of(it.owner_id).instantiate_identity();
-            if !ignored_macro(cx, it) && is_unfrozen(cx, ty) && is_value_unfrozen_poly(cx, body_id, ty) {
+            if !ignored_macro(cx, it)
+                && !self.is_ty_ignored(ty)
+                && Self::is_unfrozen(cx, ty)
+                && self.is_value_unfrozen_poly(cx, body_id, ty)
+            {
                 lint(cx, Source::Item { item: it.span });
             }
         }
@@ -311,7 +356,7 @@ impl<'tcx> LateLintPass<'tcx> for NonCopyConst {
             // Normalize assoc types because ones originated from generic params
             // bounded other traits could have their bound.
             let normalized = cx.tcx.normalize_erasing_regions(cx.param_env, ty);
-            if is_unfrozen(cx, normalized)
+            if !self.is_ty_ignored(ty) && Self::is_unfrozen(cx, normalized)
                 // When there's no default value, lint it only according to its type;
                 // in other words, lint consts whose value *could* be unfrozen, not definitely is.
                 // This feels inconsistent with how the lint treats generic types,
@@ -324,7 +369,7 @@ impl<'tcx> LateLintPass<'tcx> for NonCopyConst {
                 // i.e. having an enum doesn't necessary mean a type has a frozen variant.
                 // And, implementing it isn't a trivial task; it'll probably end up
                 // re-implementing the trait predicate evaluation specific to `Freeze`.
-                && body_id_opt.map_or(true, |body_id| is_value_unfrozen_poly(cx, body_id, normalized))
+                && body_id_opt.map_or(true, |body_id| self.is_value_unfrozen_poly(cx, body_id, normalized))
             {
                 lint(cx, Source::Assoc { item: trait_item.span });
             }
@@ -367,8 +412,8 @@ impl<'tcx> LateLintPass<'tcx> for NonCopyConst {
                             // e.g. `layout_of(...).is_err() || has_frozen_variant(...);`
                         let ty = cx.tcx.type_of(impl_item.owner_id).instantiate_identity();
                         let normalized = cx.tcx.normalize_erasing_regions(cx.param_env, ty);
-                        if is_unfrozen(cx, normalized);
-                        if is_value_unfrozen_poly(cx, *body_id, normalized);
+                        if !self.is_ty_ignored(ty) && Self::is_unfrozen(cx, normalized);
+                        if self.is_value_unfrozen_poly(cx, *body_id, normalized);
                         then {
                             lint(
                                cx,
@@ -384,7 +429,10 @@ impl<'tcx> LateLintPass<'tcx> for NonCopyConst {
                     // Normalize assoc types originated from generic params.
                     let normalized = cx.tcx.normalize_erasing_regions(cx.param_env, ty);
 
-                    if is_unfrozen(cx, ty) && is_value_unfrozen_poly(cx, *body_id, normalized) {
+                    if !self.is_ty_ignored(ty)
+                        && Self::is_unfrozen(cx, ty)
+                        && self.is_value_unfrozen_poly(cx, *body_id, normalized)
+                    {
                         lint(cx, Source::Assoc { item: impl_item.span });
                     }
                 },
@@ -478,7 +526,10 @@ impl<'tcx> LateLintPass<'tcx> for NonCopyConst {
                 cx.typeck_results().expr_ty(dereferenced_expr)
             };
 
-            if is_unfrozen(cx, ty) && is_value_unfrozen_expr(cx, expr.hir_id, item_def_id, ty) {
+            if !self.is_ty_ignored(ty)
+                && Self::is_unfrozen(cx, ty)
+                && self.is_value_unfrozen_expr(cx, expr.hir_id, item_def_id, ty)
+            {
                 lint(cx, Source::Expr { expr: expr.span });
             }
         }
diff --git a/src/tools/clippy/clippy_lints/src/non_send_fields_in_send_ty.rs b/src/tools/clippy/clippy_lints/src/non_send_fields_in_send_ty.rs
index d388dfc08f3..62ef48c8a90 100644
--- a/src/tools/clippy/clippy_lints/src/non_send_fields_in_send_ty.rs
+++ b/src/tools/clippy/clippy_lints/src/non_send_fields_in_send_ty.rs
@@ -1,7 +1,7 @@
 use clippy_utils::diagnostics::span_lint_and_then;
+use clippy_utils::is_lint_allowed;
 use clippy_utils::source::snippet;
 use clippy_utils::ty::{implements_trait, is_copy};
-use clippy_utils::is_lint_allowed;
 use rustc_ast::ImplPolarity;
 use rustc_hir::def_id::DefId;
 use rustc_hir::{FieldDef, Item, ItemKind, Node};
diff --git a/src/tools/clippy/clippy_lints/src/only_used_in_recursion.rs b/src/tools/clippy/clippy_lints/src/only_used_in_recursion.rs
index 3dc652f9dc0..f0f8d510c7e 100644
--- a/src/tools/clippy/clippy_lints/src/only_used_in_recursion.rs
+++ b/src/tools/clippy/clippy_lints/src/only_used_in_recursion.rs
@@ -134,6 +134,7 @@ impl Usage {
 /// The parameters being checked by the lint, indexed by both the parameter's `HirId` and the
 /// `DefId` of the function paired with the parameter's index.
 #[derive(Default)]
+#[allow(clippy::struct_field_names)]
 struct Params {
     params: Vec<Param>,
     by_id: HirIdMap<usize>,
diff --git a/src/tools/clippy/clippy_lints/src/operators/cmp_owned.rs b/src/tools/clippy/clippy_lints/src/operators/cmp_owned.rs
index 136642d69dc..ea8ed28ba62 100644
--- a/src/tools/clippy/clippy_lints/src/operators/cmp_owned.rs
+++ b/src/tools/clippy/clippy_lints/src/operators/cmp_owned.rs
@@ -1,7 +1,7 @@
 use clippy_utils::diagnostics::span_lint_and_then;
+use clippy_utils::path_def_id;
 use clippy_utils::source::snippet;
 use clippy_utils::ty::{implements_trait, is_copy};
-use clippy_utils::path_def_id;
 use rustc_errors::Applicability;
 use rustc_hir::{BinOpKind, Expr, ExprKind, UnOp};
 use rustc_lint::LateContext;
diff --git a/src/tools/clippy/clippy_lints/src/rc_clone_in_vec_init.rs b/src/tools/clippy/clippy_lints/src/rc_clone_in_vec_init.rs
index 1a127c2bcf6..bd0ca66b761 100644
--- a/src/tools/clippy/clippy_lints/src/rc_clone_in_vec_init.rs
+++ b/src/tools/clippy/clippy_lints/src/rc_clone_in_vec_init.rs
@@ -1,8 +1,8 @@
 use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::higher::VecArgs;
+use clippy_utils::last_path_segment;
 use clippy_utils::macros::root_macro_call_first_node;
 use clippy_utils::source::{indent_of, snippet};
-use clippy_utils::last_path_segment;
 use rustc_errors::Applicability;
 use rustc_hir::{Expr, ExprKind, QPath, TyKind};
 use rustc_lint::{LateContext, LateLintPass};
diff --git a/src/tools/clippy/clippy_lints/src/redundant_async_block.rs b/src/tools/clippy/clippy_lints/src/redundant_async_block.rs
index b8f787e1f1f..2e895d5f236 100644
--- a/src/tools/clippy/clippy_lints/src/redundant_async_block.rs
+++ b/src/tools/clippy/clippy_lints/src/redundant_async_block.rs
@@ -5,7 +5,7 @@ use clippy_utils::peel_blocks;
 use clippy_utils::source::{snippet, walk_span_to_context};
 use clippy_utils::visitors::for_each_expr;
 use rustc_errors::Applicability;
-use rustc_hir::{AsyncCoroutineKind, Closure, Expr, ExprKind, CoroutineKind, MatchSource};
+use rustc_hir::{AsyncCoroutineKind, Closure, CoroutineKind, Expr, ExprKind, MatchSource};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::lint::in_external_macro;
 use rustc_middle::ty::UpvarCapture;
diff --git a/src/tools/clippy/clippy_lints/src/redundant_locals.rs b/src/tools/clippy/clippy_lints/src/redundant_locals.rs
index 197742b5dd4..a1a0e8f3520 100644
--- a/src/tools/clippy/clippy_lints/src/redundant_locals.rs
+++ b/src/tools/clippy/clippy_lints/src/redundant_locals.rs
@@ -62,7 +62,7 @@ impl<'tcx> LateLintPass<'tcx> for RedundantLocals {
             if let Res::Local(binding_id) = cx.qpath_res(&qpath, expr.hir_id);
             if let Node::Pat(binding_pat) = cx.tcx.hir().get(binding_id);
             // the previous binding has the same mutability
-            if find_binding(binding_pat, ident).unwrap().1 == mutability;
+            if find_binding(binding_pat, ident).is_some_and(|bind| bind.1 == mutability);
             // the local does not change the effect of assignments to the binding. see #11290
             if !affects_assignments(cx, mutability, binding_id, local.hir_id);
             // the local does not affect the code's drop behavior
diff --git a/src/tools/clippy/clippy_lints/src/slow_vector_initialization.rs b/src/tools/clippy/clippy_lints/src/slow_vector_initialization.rs
index 9db18c2976c..2278e41be37 100644
--- a/src/tools/clippy/clippy_lints/src/slow_vector_initialization.rs
+++ b/src/tools/clippy/clippy_lints/src/slow_vector_initialization.rs
@@ -335,7 +335,7 @@ impl<'a, 'tcx> Visitor<'tcx> for VectorInitializationVisitor<'a, 'tcx> {
 
     fn visit_block(&mut self, block: &'tcx Block<'_>) {
         if self.initialization_found {
-            if let Some(s) = block.stmts.get(0) {
+            if let Some(s) = block.stmts.first() {
                 self.visit_stmt(s);
             }
 
diff --git a/src/tools/clippy/clippy_lints/src/swap_ptr_to_ref.rs b/src/tools/clippy/clippy_lints/src/swap_ptr_to_ref.rs
index 3685432a253..4bfbe3bf37e 100644
--- a/src/tools/clippy/clippy_lints/src/swap_ptr_to_ref.rs
+++ b/src/tools/clippy/clippy_lints/src/swap_ptr_to_ref.rs
@@ -1,6 +1,6 @@
 use clippy_utils::diagnostics::span_lint_and_then;
-use clippy_utils::source::snippet_with_context;
 use clippy_utils::path_def_id;
+use clippy_utils::source::snippet_with_context;
 use rustc_errors::Applicability;
 use rustc_hir::{BorrowKind, Expr, ExprKind, Mutability, UnOp};
 use rustc_lint::{LateContext, LateLintPass};
diff --git a/src/tools/clippy/clippy_lints/src/types/mod.rs b/src/tools/clippy/clippy_lints/src/types/mod.rs
index 71a4b3fba1b..788678a63b7 100644
--- a/src/tools/clippy/clippy_lints/src/types/mod.rs
+++ b/src/tools/clippy/clippy_lints/src/types/mod.rs
@@ -578,7 +578,7 @@ impl Types {
     }
 }
 
-#[allow(clippy::struct_excessive_bools)]
+#[allow(clippy::struct_excessive_bools, clippy::struct_field_names)]
 #[derive(Clone, Copy, Default)]
 struct CheckTyContext {
     is_in_trait_impl: bool,
diff --git a/src/tools/clippy/clippy_lints/src/uninit_vec.rs b/src/tools/clippy/clippy_lints/src/uninit_vec.rs
index 6756df8e716..72569e10f05 100644
--- a/src/tools/clippy/clippy_lints/src/uninit_vec.rs
+++ b/src/tools/clippy/clippy_lints/src/uninit_vec.rs
@@ -201,7 +201,7 @@ fn extract_set_len_self<'tcx>(cx: &LateContext<'_>, expr: &'tcx Expr<'_>) -> Opt
     let expr = peel_hir_expr_while(expr, |e| {
         if let ExprKind::Block(block, _) = e.kind {
             // Extract the first statement/expression
-            match (block.stmts.get(0).map(|stmt| &stmt.kind), block.expr) {
+            match (block.stmts.first().map(|stmt| &stmt.kind), block.expr) {
                 (None, Some(expr)) => Some(expr),
                 (Some(StmtKind::Expr(expr) | StmtKind::Semi(expr)), _) => Some(expr),
                 _ => None,
diff --git a/src/tools/clippy/clippy_lints/src/unnecessary_map_on_constructor.rs b/src/tools/clippy/clippy_lints/src/unnecessary_map_on_constructor.rs
index 5aa057580e9..894de0d85c1 100644
--- a/src/tools/clippy/clippy_lints/src/unnecessary_map_on_constructor.rs
+++ b/src/tools/clippy/clippy_lints/src/unnecessary_map_on_constructor.rs
@@ -40,7 +40,7 @@ impl<'tcx> LateLintPass<'tcx> for UnnecessaryMapOnConstructor {
             let (constructor_path, constructor_item) =
                 if let hir::ExprKind::Call(constructor, constructor_args) = recv.kind
                     && let hir::ExprKind::Path(constructor_path) = constructor.kind
-                    && let Some(arg) = constructor_args.get(0)
+                    && let Some(arg) = constructor_args.first()
                 {
                     if constructor.span.from_expansion() || arg.span.from_expansion() {
                         return;
@@ -66,7 +66,7 @@ impl<'tcx> LateLintPass<'tcx> for UnnecessaryMapOnConstructor {
                 _ => return,
             }
 
-            if let Some(map_arg) = args.get(0)
+            if let Some(map_arg) = args.first()
                 && let hir::ExprKind::Path(fun) = map_arg.kind
             {
                 if map_arg.span.from_expansion() {
diff --git a/src/tools/clippy/clippy_lints/src/use_self.rs b/src/tools/clippy/clippy_lints/src/use_self.rs
index 50231d930d0..f10ed4b3d41 100644
--- a/src/tools/clippy/clippy_lints/src/use_self.rs
+++ b/src/tools/clippy/clippy_lints/src/use_self.rs
@@ -54,7 +54,6 @@ declare_clippy_lint! {
     "unnecessary structure name repetition whereas `Self` is applicable"
 }
 
-#[derive(Default)]
 pub struct UseSelf {
     msrv: Msrv,
     stack: Vec<StackItem>,
@@ -65,7 +64,7 @@ impl UseSelf {
     pub fn new(msrv: Msrv) -> Self {
         Self {
             msrv,
-            ..Self::default()
+            stack: Vec::new(),
         }
     }
 }
diff --git a/src/tools/clippy/clippy_lints/src/utils/author.rs b/src/tools/clippy/clippy_lints/src/utils/author.rs
index f02c33cc674..aecb0c6dbfa 100644
--- a/src/tools/clippy/clippy_lints/src/utils/author.rs
+++ b/src/tools/clippy/clippy_lints/src/utils/author.rs
@@ -268,8 +268,8 @@ impl<'a, 'tcx> PrintVisitor<'a, 'tcx> {
     fn qpath(&self, qpath: &Binding<&QPath<'_>>) {
         if let QPath::LangItem(lang_item, ..) = *qpath.value {
             chain!(self, "matches!({qpath}, QPath::LangItem(LangItem::{lang_item:?}, _))");
-        } else {
-            chain!(self, "match_qpath({qpath}, &[{}])", path_to_string(qpath.value));
+        } else if let Ok(path) = path_to_string(qpath.value) {
+            chain!(self, "match_qpath({qpath}, &[{}])", path);
         }
     }
 
@@ -738,8 +738,8 @@ fn has_attr(cx: &LateContext<'_>, hir_id: hir::HirId) -> bool {
     get_attr(cx.sess(), attrs, "author").count() > 0
 }
 
-fn path_to_string(path: &QPath<'_>) -> String {
-    fn inner(s: &mut String, path: &QPath<'_>) {
+fn path_to_string(path: &QPath<'_>) -> Result<String, ()> {
+    fn inner(s: &mut String, path: &QPath<'_>) -> Result<(), ()> {
         match *path {
             QPath::Resolved(_, path) => {
                 for (i, segment) in path.segments.iter().enumerate() {
@@ -751,16 +751,18 @@ fn path_to_string(path: &QPath<'_>) -> String {
             },
             QPath::TypeRelative(ty, segment) => match &ty.kind {
                 hir::TyKind::Path(inner_path) => {
-                    inner(s, inner_path);
+                    inner(s, inner_path)?;
                     *s += ", ";
                     write!(s, "{:?}", segment.ident.as_str()).unwrap();
                 },
                 other => write!(s, "/* unimplemented: {other:?}*/").unwrap(),
             },
-            QPath::LangItem(..) => panic!("path_to_string: called for lang item qpath"),
+            QPath::LangItem(..) => return Err(()),
         }
+
+        Ok(())
     }
     let mut s = String::new();
-    inner(&mut s, path);
-    s
+    inner(&mut s, path)?;
+    Ok(s)
 }
diff --git a/src/tools/clippy/clippy_lints/src/utils/conf.rs b/src/tools/clippy/clippy_lints/src/utils/conf.rs
index 23da1de7730..8829f188fe7 100644
--- a/src/tools/clippy/clippy_lints/src/utils/conf.rs
+++ b/src/tools/clippy/clippy_lints/src/utils/conf.rs
@@ -8,8 +8,9 @@ use serde::de::{Deserializer, IgnoredAny, IntoDeserializer, MapAccess, Visitor};
 use serde::Deserialize;
 use std::fmt::{Debug, Display, Formatter};
 use std::ops::Range;
-use std::path::{Path, PathBuf};
+use std::path::PathBuf;
 use std::str::FromStr;
+use std::sync::OnceLock;
 use std::{cmp, env, fmt, fs, io};
 
 #[rustfmt::skip]
@@ -78,62 +79,35 @@ pub struct TryConf {
 
 impl TryConf {
     fn from_toml_error(file: &SourceFile, error: &toml::de::Error) -> Self {
-        ConfError::from_toml(file, error).into()
-    }
-}
-
-impl From<ConfError> for TryConf {
-    fn from(value: ConfError) -> Self {
         Self {
             conf: Conf::default(),
-            errors: vec![value],
+            errors: vec![ConfError::from_toml(file, error)],
             warnings: vec![],
         }
     }
 }
 
-impl From<io::Error> for TryConf {
-    fn from(value: io::Error) -> Self {
-        ConfError::from(value).into()
-    }
-}
-
 #[derive(Debug)]
 pub struct ConfError {
     pub message: String,
-    pub span: Option<Span>,
+    pub span: Span,
 }
 
 impl ConfError {
     fn from_toml(file: &SourceFile, error: &toml::de::Error) -> Self {
-        if let Some(span) = error.span() {
-            Self::spanned(file, error.message(), span)
-        } else {
-            Self {
-                message: error.message().to_string(),
-                span: None,
-            }
-        }
+        let span = error.span().unwrap_or(0..file.source_len.0 as usize);
+        Self::spanned(file, error.message(), span)
     }
 
     fn spanned(file: &SourceFile, message: impl Into<String>, span: Range<usize>) -> Self {
         Self {
             message: message.into(),
-            span: Some(Span::new(
+            span: Span::new(
                 file.start_pos + BytePos::from_usize(span.start),
                 file.start_pos + BytePos::from_usize(span.end),
                 SyntaxContext::root(),
                 None,
-            )),
-        }
-    }
-}
-
-impl From<io::Error> for ConfError {
-    fn from(value: io::Error) -> Self {
-        Self {
-            message: value.to_string(),
-            span: None,
+            ),
         }
     }
 }
@@ -297,7 +271,7 @@ define_Conf! {
     /// Lint: MANUAL_SPLIT_ONCE, MANUAL_STR_REPEAT, CLONED_INSTEAD_OF_COPIED, REDUNDANT_FIELD_NAMES, OPTION_MAP_UNWRAP_OR, REDUNDANT_STATIC_LIFETIMES, FILTER_MAP_NEXT, CHECKED_CONVERSIONS, MANUAL_RANGE_CONTAINS, USE_SELF, MEM_REPLACE_WITH_DEFAULT, MANUAL_NON_EXHAUSTIVE, OPTION_AS_REF_DEREF, MAP_UNWRAP_OR, MATCH_LIKE_MATCHES_MACRO, MANUAL_STRIP, MISSING_CONST_FOR_FN, UNNESTED_OR_PATTERNS, FROM_OVER_INTO, PTR_AS_PTR, IF_THEN_SOME_ELSE_NONE, APPROX_CONSTANT, DEPRECATED_CFG_ATTR, INDEX_REFUTABLE_SLICE, MAP_CLONE, BORROW_AS_PTR, MANUAL_BITS, ERR_EXPECT, CAST_ABS_TO_UNSIGNED, UNINLINED_FORMAT_ARGS, MANUAL_CLAMP, MANUAL_LET_ELSE, UNCHECKED_DURATION_SUBTRACTION, COLLAPSIBLE_STR_REPLACE, SEEK_FROM_CURRENT, SEEK_REWIND, UNNECESSARY_LAZY_EVALUATIONS, TRANSMUTE_PTR_TO_REF, ALMOST_COMPLETE_RANGE, NEEDLESS_BORROW, DERIVABLE_IMPLS, MANUAL_IS_ASCII_CHECK, MANUAL_REM_EUCLID, MANUAL_RETAIN, TYPE_REPETITION_IN_BOUNDS, TUPLE_ARRAY_CONVERSIONS, MANUAL_TRY_FOLD, MANUAL_HASH_ONE.
     ///
     /// The minimum rust version that the project supports
-    (msrv: Option<String> = None),
+    (msrv: crate::Msrv = crate::Msrv::empty()),
     /// DEPRECATED LINT: BLACKLISTED_NAME.
     ///
     /// Use the Disallowed Names lint instead
@@ -360,6 +334,10 @@ define_Conf! {
     ///
     /// The minimum number of enum variants for the lints about variant names to trigger
     (enum_variant_name_threshold: u64 = 3),
+    /// Lint: STRUCT_VARIANT_NAMES.
+    ///
+    /// The minimum number of struct fields for the lints about field names to trigger
+    (struct_field_name_threshold: u64 = 3),
     /// Lint: LARGE_ENUM_VARIANT.
     ///
     /// The maximum size of an enum's variant to avoid box suggestion
@@ -641,15 +619,8 @@ pub fn lookup_conf_file() -> io::Result<(Option<PathBuf>, Vec<String>)> {
     }
 }
 
-/// Read the `toml` configuration file.
-///
-/// In case of error, the function tries to continue as much as possible.
-pub fn read(sess: &Session, path: &Path) -> TryConf {
-    let file = match sess.source_map().load_file(path) {
-        Err(e) => return e.into(),
-        Ok(file) => file,
-    };
-    match toml::de::Deserializer::new(file.src.as_ref().unwrap()).deserialize_map(ConfVisitor(&file)) {
+fn deserialize(file: &SourceFile) -> TryConf {
+    match toml::de::Deserializer::new(file.src.as_ref().unwrap()).deserialize_map(ConfVisitor(file)) {
         Ok(mut conf) => {
             extend_vec_if_indicator_present(&mut conf.conf.doc_valid_idents, DEFAULT_DOC_VALID_IDENTS);
             extend_vec_if_indicator_present(&mut conf.conf.disallowed_names, DEFAULT_DISALLOWED_NAMES);
@@ -662,7 +633,7 @@ pub fn read(sess: &Session, path: &Path) -> TryConf {
 
             conf
         },
-        Err(e) => TryConf::from_toml_error(&file, &e),
+        Err(e) => TryConf::from_toml_error(file, &e),
     }
 }
 
@@ -672,6 +643,60 @@ fn extend_vec_if_indicator_present(vec: &mut Vec<String>, default: &[&str]) {
     }
 }
 
+impl Conf {
+    pub fn read(sess: &Session, path: &io::Result<(Option<PathBuf>, Vec<String>)>) -> &'static Conf {
+        static CONF: OnceLock<Conf> = OnceLock::new();
+        CONF.get_or_init(|| Conf::read_inner(sess, path))
+    }
+
+    fn read_inner(sess: &Session, path: &io::Result<(Option<PathBuf>, Vec<String>)>) -> Conf {
+        match path {
+            Ok((_, warnings)) => {
+                for warning in warnings {
+                    sess.warn(warning.clone());
+                }
+            },
+            Err(error) => {
+                sess.err(format!("error finding Clippy's configuration file: {error}"));
+            },
+        }
+
+        let TryConf {
+            mut conf,
+            errors,
+            warnings,
+        } = match path {
+            Ok((Some(path), _)) => match sess.source_map().load_file(path) {
+                Ok(file) => deserialize(&file),
+                Err(error) => {
+                    sess.err(format!("failed to read `{}`: {error}", path.display()));
+                    TryConf::default()
+                },
+            },
+            _ => TryConf::default(),
+        };
+
+        conf.msrv.read_cargo(sess);
+
+        // all conf errors are non-fatal, we just use the default conf in case of error
+        for error in errors {
+            sess.span_err(
+                error.span,
+                format!("error reading Clippy's configuration file: {}", error.message),
+            );
+        }
+
+        for warning in warnings {
+            sess.span_warn(
+                warning.span,
+                format!("error reading Clippy's configuration file: {}", warning.message),
+            );
+        }
+
+        conf
+    }
+}
+
 const SEPARATOR_WIDTH: usize = 4;
 
 #[derive(Debug)]
diff --git a/src/tools/clippy/clippy_lints/src/utils/internal_lints/if_chain_style.rs b/src/tools/clippy/clippy_lints/src/utils/internal_lints/if_chain_style.rs
index fe2f12fe833..8cdd5ea8903 100644
--- a/src/tools/clippy/clippy_lints/src/utils/internal_lints/if_chain_style.rs
+++ b/src/tools/clippy/clippy_lints/src/utils/internal_lints/if_chain_style.rs
@@ -30,7 +30,7 @@ impl<'tcx> LateLintPass<'tcx> for IfChainStyle {
                 if_chain_local_span(cx, local, if_chain_span),
                 "`let` expression should be above the `if_chain!`",
             );
-        } else if local.span.ctxt() == block.span.ctxt() && is_if_chain_then(after, block.expr, if_chain_span) {
+        } else if local.span.eq_ctxt(block.span) && is_if_chain_then(after, block.expr, if_chain_span) {
             span_lint(
                 cx,
                 IF_CHAIN_STYLE,
diff --git a/src/tools/clippy/clippy_lints/src/utils/internal_lints/interning_defined_symbol.rs b/src/tools/clippy/clippy_lints/src/utils/internal_lints/interning_defined_symbol.rs
index 82f9d4e41e8..fc9afe5ca8b 100644
--- a/src/tools/clippy/clippy_lints/src/utils/internal_lints/interning_defined_symbol.rs
+++ b/src/tools/clippy/clippy_lints/src/utils/internal_lints/interning_defined_symbol.rs
@@ -13,6 +13,7 @@ use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::mir::ConstValue;
 use rustc_middle::ty;
 use rustc_session::{declare_tool_lint, impl_lint_pass};
+use rustc_span::sym;
 use rustc_span::symbol::Symbol;
 
 use std::borrow::Cow;
@@ -160,12 +161,8 @@ impl<'tcx> LateLintPass<'tcx> for InterningDefinedSymbol {
 
 impl InterningDefinedSymbol {
     fn symbol_str_expr<'tcx>(&self, expr: &'tcx Expr<'tcx>, cx: &LateContext<'tcx>) -> Option<SymbolStrExpr<'tcx>> {
-        static IDENT_STR_PATHS: &[&[&str]] = &[&paths::IDENT_AS_STR, &paths::TO_STRING_METHOD];
-        static SYMBOL_STR_PATHS: &[&[&str]] = &[
-            &paths::SYMBOL_AS_STR,
-            &paths::SYMBOL_TO_IDENT_STRING,
-            &paths::TO_STRING_METHOD,
-        ];
+        static IDENT_STR_PATHS: &[&[&str]] = &[&paths::IDENT_AS_STR];
+        static SYMBOL_STR_PATHS: &[&[&str]] = &[&paths::SYMBOL_AS_STR, &paths::SYMBOL_TO_IDENT_STRING];
         let call = if_chain! {
             if let ExprKind::AddrOf(_, _, e) = expr.kind;
             if let ExprKind::Unary(UnOp::Deref, e) = e.kind;
@@ -186,9 +183,19 @@ impl InterningDefinedSymbol {
             };
             // ...which converts it to a string
             let paths = if is_ident { IDENT_STR_PATHS } else { SYMBOL_STR_PATHS };
-            if let Some(path) = paths.iter().find(|path| match_def_path(cx, did, path));
+            if let Some(is_to_owned) = paths
+                .iter()
+                .find_map(|path| if match_def_path(cx, did, path) {
+                    Some(path == &paths::SYMBOL_TO_IDENT_STRING)
+                } else {
+                    None
+                })
+                .or_else(|| if cx.tcx.is_diagnostic_item(sym::to_string_method, did) {
+                    Some(true)
+                } else {
+                    None
+                });
             then {
-                let is_to_owned = path.last().unwrap().ends_with("string");
                 return Some(SymbolStrExpr::Expr {
                     item,
                     is_ident,