about summary refs log tree commit diff
path: root/clippy_lints/src
diff options
context:
space:
mode:
authorPhilipp Krones <hello@philkrones.com>2024-07-25 18:09:52 +0200
committerPhilipp Krones <hello@philkrones.com>2024-07-25 18:23:27 +0200
commit9f53fc32cfb62724d95de44779259ce4e24bc085 (patch)
treedf5069c84c1a281c78b72e8935a9664b3110f66a /clippy_lints/src
parent6d674685ae4e9156dbb6ecd3aa38d87864ecab3e (diff)
parentdf0cb6c51ee798264586ee9144466cf003d68181 (diff)
Merge remote-tracking branch 'upstream/master' into rustup
Diffstat (limited to 'clippy_lints/src')
-rw-r--r--clippy_lints/src/absolute_paths.rs12
-rw-r--r--clippy_lints/src/almost_complete_range.rs7
-rw-r--r--clippy_lints/src/approx_const.rs8
-rw-r--r--clippy_lints/src/arc_with_non_send_sync.rs15
-rw-r--r--clippy_lints/src/assigning_clones.rs8
-rw-r--r--clippy_lints/src/attrs/mod.rs19
-rw-r--r--clippy_lints/src/await_holding_invalid.rs39
-rw-r--r--clippy_lints/src/borrow_deref_ref.rs44
-rw-r--r--clippy_lints/src/cargo/mod.rs16
-rw-r--r--clippy_lints/src/casts/cast_lossless.rs111
-rw-r--r--clippy_lints/src/casts/mod.rs48
-rw-r--r--clippy_lints/src/casts/ptr_cast_constness.rs3
-rw-r--r--clippy_lints/src/checked_conversions.rs141
-rw-r--r--clippy_lints/src/cognitive_complexity.rs6
-rw-r--r--clippy_lints/src/collapsible_if.rs33
-rw-r--r--clippy_lints/src/collection_is_never_read.rs6
-rw-r--r--clippy_lints/src/copies.rs14
-rw-r--r--clippy_lints/src/crate_in_macro_def.rs7
-rw-r--r--clippy_lints/src/dbg_macro.rs6
-rw-r--r--clippy_lints/src/declared_lints.rs1
-rw-r--r--clippy_lints/src/derivable_impls.rs8
-rw-r--r--clippy_lints/src/disallowed_macros.rs31
-rw-r--r--clippy_lints/src/disallowed_methods.rs42
-rw-r--r--clippy_lints/src/disallowed_names.rs11
-rw-r--r--clippy_lints/src/disallowed_script_idents.rs18
-rw-r--r--clippy_lints/src/disallowed_types.rs91
-rw-r--r--clippy_lints/src/doc/mod.rs12
-rw-r--r--clippy_lints/src/double_parens.rs48
-rw-r--r--clippy_lints/src/else_if_without_else.rs5
-rw-r--r--clippy_lints/src/empty_enum.rs34
-rw-r--r--clippy_lints/src/endian_bytes.rs39
-rw-r--r--clippy_lints/src/equatable_if_let.rs4
-rw-r--r--clippy_lints/src/error_impl_error.rs9
-rw-r--r--clippy_lints/src/escape.rs12
-rw-r--r--clippy_lints/src/excessive_bools.rs103
-rw-r--r--clippy_lints/src/excessive_nesting.rs9
-rw-r--r--clippy_lints/src/exhaustive_items.rs26
-rw-r--r--clippy_lints/src/exit.rs6
-rw-r--r--clippy_lints/src/extra_unused_type_parameters.rs35
-rw-r--r--clippy_lints/src/float_literal.rs5
-rw-r--r--clippy_lints/src/format_args.rs8
-rw-r--r--clippy_lints/src/format_impl.rs1
-rw-r--r--clippy_lints/src/from_over_into.rs24
-rw-r--r--clippy_lints/src/from_str_radix_10.rs19
-rw-r--r--clippy_lints/src/functions/mod.rs37
-rw-r--r--clippy_lints/src/future_not_send.rs14
-rw-r--r--clippy_lints/src/if_let_mutex.rs65
-rw-r--r--clippy_lints/src/if_not_else.rs63
-rw-r--r--clippy_lints/src/if_then_some_else_none.rs33
-rw-r--r--clippy_lints/src/ignored_unit_patterns.rs31
-rw-r--r--clippy_lints/src/incompatible_msrv.rs5
-rw-r--r--clippy_lints/src/inconsistent_struct_constructor.rs6
-rw-r--r--clippy_lints/src/index_refutable_slice.rs11
-rw-r--r--clippy_lints/src/indexing_slicing.rs14
-rw-r--r--clippy_lints/src/infinite_iter.rs5
-rw-r--r--clippy_lints/src/instant_subtraction.rs8
-rw-r--r--clippy_lints/src/item_name_repetitions.rs20
-rw-r--r--clippy_lints/src/large_const_arrays.rs12
-rw-r--r--clippy_lints/src/large_enum_variant.rs7
-rw-r--r--clippy_lints/src/large_futures.rs8
-rw-r--r--clippy_lints/src/large_include_file.rs8
-rw-r--r--clippy_lints/src/large_stack_arrays.rs12
-rw-r--r--clippy_lints/src/large_stack_frames.rs6
-rw-r--r--clippy_lints/src/legacy_numeric_constants.rs8
-rw-r--r--clippy_lints/src/lib.rs464
-rw-r--r--clippy_lints/src/lifetimes.rs18
-rw-r--r--clippy_lints/src/literal_representation.rs18
-rw-r--r--clippy_lints/src/loops/mod.rs7
-rw-r--r--clippy_lints/src/loops/mut_range_bound.rs15
-rw-r--r--clippy_lints/src/loops/single_element_loop.rs7
-rw-r--r--clippy_lints/src/loops/while_immutable_condition.rs24
-rw-r--r--clippy_lints/src/macro_metavars_in_unsafe.rs20
-rw-r--r--clippy_lints/src/manual_bits.rs9
-rw-r--r--clippy_lints/src/manual_clamp.rs7
-rw-r--r--clippy_lints/src/manual_hash_one.rs8
-rw-r--r--clippy_lints/src/manual_is_ascii_check.rs8
-rw-r--r--clippy_lints/src/manual_main_separator_str.rs8
-rw-r--r--clippy_lints/src/manual_non_exhaustive.rs13
-rw-r--r--clippy_lints/src/manual_rem_euclid.rs8
-rw-r--r--clippy_lints/src/manual_retain.rs8
-rw-r--r--clippy_lints/src/manual_strip.rs8
-rw-r--r--clippy_lints/src/matches/manual_unwrap_or.rs11
-rw-r--r--clippy_lints/src/matches/mod.rs6
-rw-r--r--clippy_lints/src/matches/significant_drop_in_scrutinee.rs6
-rw-r--r--clippy_lints/src/mem_replace.rs8
-rw-r--r--clippy_lints/src/methods/bind_instead_of_map.rs109
-rw-r--r--clippy_lints/src/methods/mod.rs31
-rw-r--r--clippy_lints/src/methods/option_map_unwrap_or.rs32
-rw-r--r--clippy_lints/src/methods/or_fun_call.rs133
-rw-r--r--clippy_lints/src/methods/path_ends_with_ext.rs2
-rw-r--r--clippy_lints/src/methods/unnecessary_sort_by.rs3
-rw-r--r--clippy_lints/src/min_ident_chars.rs19
-rw-r--r--clippy_lints/src/misc.rs43
-rw-r--r--clippy_lints/src/mismatching_type_param_order.rs6
-rw-r--r--clippy_lints/src/missing_const_for_fn.rs8
-rw-r--r--clippy_lints/src/missing_const_for_thread_local.rs8
-rw-r--r--clippy_lints/src/missing_doc.rs13
-rw-r--r--clippy_lints/src/missing_enforced_import_rename.rs29
-rw-r--r--clippy_lints/src/mut_key.rs13
-rw-r--r--clippy_lints/src/mut_mut.rs37
-rw-r--r--clippy_lints/src/mutable_debug_assertion.rs4
-rw-r--r--clippy_lints/src/needless_borrowed_ref.rs142
-rw-r--r--clippy_lints/src/needless_borrows_for_generic_args.rs6
-rw-r--r--clippy_lints/src/needless_for_each.rs16
-rw-r--r--clippy_lints/src/needless_pass_by_ref_mut.rs9
-rw-r--r--clippy_lints/src/neg_cmp_op_on_partial_ord.rs4
-rw-r--r--clippy_lints/src/non_copy_const.rs11
-rw-r--r--clippy_lints/src/non_expressive_names.rs23
-rw-r--r--clippy_lints/src/non_send_fields_in_send_ty.rs6
-rw-r--r--clippy_lints/src/nonstandard_macro_braces.rs7
-rw-r--r--clippy_lints/src/operators/arithmetic_side_effects.rs55
-rw-r--r--clippy_lints/src/operators/mod.rs21
-rw-r--r--clippy_lints/src/option_env_unwrap.rs24
-rw-r--r--clippy_lints/src/panic_unimplemented.rs12
-rw-r--r--clippy_lints/src/pass_by_ref_or_value.rs19
-rw-r--r--clippy_lints/src/pathbuf_init_then_push.rs193
-rw-r--r--clippy_lints/src/permissions_set_readonly_false.rs4
-rw-r--r--clippy_lints/src/pub_underscore_fields.rs11
-rw-r--r--clippy_lints/src/question_mark.rs8
-rw-r--r--clippy_lints/src/ranges.rs8
-rw-r--r--clippy_lints/src/raw_strings.rs45
-rw-r--r--clippy_lints/src/redundant_closure_call.rs25
-rw-r--r--clippy_lints/src/redundant_field_names.rs8
-rw-r--r--clippy_lints/src/redundant_static_lifetimes.rs8
-rw-r--r--clippy_lints/src/regex.rs2
-rw-r--r--clippy_lints/src/semicolon_block.rs12
-rw-r--r--clippy_lints/src/serde_api.rs2
-rw-r--r--clippy_lints/src/single_call_fn.rs13
-rw-r--r--clippy_lints/src/single_range_in_vec_init.rs2
-rw-r--r--clippy_lints/src/string_patterns.rs8
-rw-r--r--clippy_lints/src/trait_bounds.rs10
-rw-r--r--clippy_lints/src/transmute/mod.rs10
-rw-r--r--clippy_lints/src/transmute/transmute_ptr_to_ptr.rs43
-rw-r--r--clippy_lints/src/tuple_array_conversions.rs11
-rw-r--r--clippy_lints/src/types/mod.rs9
-rw-r--r--clippy_lints/src/unconditional_recursion.rs14
-rw-r--r--clippy_lints/src/undocumented_unsafe_blocks.rs8
-rw-r--r--clippy_lints/src/unnecessary_box_returns.rs7
-rw-r--r--clippy_lints/src/unnecessary_struct_initialization.rs187
-rw-r--r--clippy_lints/src/unnecessary_wraps.rs5
-rw-r--r--clippy_lints/src/unnested_or_patterns.rs8
-rw-r--r--clippy_lints/src/unused_peekable.rs61
-rw-r--r--clippy_lints/src/unused_self.rs5
-rw-r--r--clippy_lints/src/upper_case_acronyms.rs8
-rw-r--r--clippy_lints/src/use_self.rs6
-rw-r--r--clippy_lints/src/utils/internal_lints/interning_defined_symbol.rs2
-rw-r--r--clippy_lints/src/utils/internal_lints/invalid_paths.rs2
-rw-r--r--clippy_lints/src/utils/internal_lints/unnecessary_def_path.rs4
-rw-r--r--clippy_lints/src/vec.rs20
-rw-r--r--clippy_lints/src/wildcard_imports.rs12
-rw-r--r--clippy_lints/src/write.rs8
-rw-r--r--clippy_lints/src/zero_repeat_side_effects.rs28
152 files changed, 1933 insertions, 1927 deletions
diff --git a/clippy_lints/src/absolute_paths.rs b/clippy_lints/src/absolute_paths.rs
index 461117cf965..c0a9d888e0b 100644
--- a/clippy_lints/src/absolute_paths.rs
+++ b/clippy_lints/src/absolute_paths.rs
@@ -1,3 +1,4 @@
+use clippy_config::Conf;
 use clippy_utils::diagnostics::span_lint;
 use clippy_utils::source::snippet_opt;
 use rustc_data_structures::fx::FxHashSet;
@@ -47,7 +48,16 @@ impl_lint_pass!(AbsolutePaths => [ABSOLUTE_PATHS]);
 
 pub struct AbsolutePaths {
     pub absolute_paths_max_segments: u64,
-    pub absolute_paths_allowed_crates: FxHashSet<String>,
+    pub absolute_paths_allowed_crates: &'static FxHashSet<String>,
+}
+
+impl AbsolutePaths {
+    pub fn new(conf: &'static Conf) -> Self {
+        Self {
+            absolute_paths_max_segments: conf.absolute_paths_max_segments,
+            absolute_paths_allowed_crates: &conf.absolute_paths_allowed_crates,
+        }
+    }
 }
 
 impl LateLintPass<'_> for AbsolutePaths {
diff --git a/clippy_lints/src/almost_complete_range.rs b/clippy_lints/src/almost_complete_range.rs
index 96e9c949b75..451bae95987 100644
--- a/clippy_lints/src/almost_complete_range.rs
+++ b/clippy_lints/src/almost_complete_range.rs
@@ -1,4 +1,5 @@
 use clippy_config::msrvs::{self, Msrv};
+use clippy_config::Conf;
 use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::source::{trim_span, walk_span_to_context};
 use rustc_ast::ast::{Expr, ExprKind, LitKind, Pat, PatKind, RangeEnd, RangeLimits};
@@ -34,8 +35,10 @@ pub struct AlmostCompleteRange {
     msrv: Msrv,
 }
 impl AlmostCompleteRange {
-    pub fn new(msrv: Msrv) -> Self {
-        Self { msrv }
+    pub fn new(conf: &'static Conf) -> Self {
+        Self {
+            msrv: conf.msrv.clone(),
+        }
     }
 }
 impl EarlyLintPass for AlmostCompleteRange {
diff --git a/clippy_lints/src/approx_const.rs b/clippy_lints/src/approx_const.rs
index ec28fd46111..e6d52bcef71 100644
--- a/clippy_lints/src/approx_const.rs
+++ b/clippy_lints/src/approx_const.rs
@@ -1,4 +1,5 @@
 use clippy_config::msrvs::{self, Msrv};
+use clippy_config::Conf;
 use clippy_utils::diagnostics::span_lint_and_help;
 use rustc_ast::ast::{FloatTy, LitFloatType, LitKind};
 use rustc_hir::{Expr, ExprKind};
@@ -67,9 +68,10 @@ pub struct ApproxConstant {
 }
 
 impl ApproxConstant {
-    #[must_use]
-    pub fn new(msrv: Msrv) -> Self {
-        Self { msrv }
+    pub fn new(conf: &'static Conf) -> Self {
+        Self {
+            msrv: conf.msrv.clone(),
+        }
     }
 
     fn check_lit(&self, cx: &LateContext<'_>, lit: &LitKind, e: &Expr<'_>) {
diff --git a/clippy_lints/src/arc_with_non_send_sync.rs b/clippy_lints/src/arc_with_non_send_sync.rs
index d57ab539fff..4eafa330faf 100644
--- a/clippy_lints/src/arc_with_non_send_sync.rs
+++ b/clippy_lints/src/arc_with_non_send_sync.rs
@@ -1,7 +1,7 @@
 use clippy_utils::diagnostics::span_lint_and_then;
+use clippy_utils::is_from_proc_macro;
 use clippy_utils::ty::{implements_trait, is_type_diagnostic_item};
-use clippy_utils::{is_from_proc_macro, last_path_segment};
-use rustc_hir::{Expr, ExprKind};
+use rustc_hir::{Expr, ExprKind, QPath};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::ty;
 use rustc_middle::ty::print::with_forced_trimmed_paths;
@@ -42,12 +42,11 @@ declare_lint_pass!(ArcWithNonSendSync => [ARC_WITH_NON_SEND_SYNC]);
 
 impl<'tcx> LateLintPass<'tcx> for ArcWithNonSendSync {
     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) {
-        if !expr.span.from_expansion()
-            && let ty = cx.typeck_results().expr_ty(expr)
-            && is_type_diagnostic_item(cx, ty, sym::Arc)
-            && let ExprKind::Call(func, [arg]) = expr.kind
-            && let ExprKind::Path(func_path) = func.kind
-            && last_path_segment(&func_path).ident.name == sym::new
+        if let ExprKind::Call(func, [arg]) = expr.kind
+            && let ExprKind::Path(QPath::TypeRelative(func_ty, func_name)) = func.kind
+            && func_name.ident.name == sym::new
+            && !expr.span.from_expansion()
+            && is_type_diagnostic_item(cx, cx.typeck_results().node_type(func_ty.hir_id), sym::Arc)
             && let arg_ty = cx.typeck_results().expr_ty(arg)
             // make sure that the type is not and does not contain any type parameters
             && arg_ty.walk().all(|arg| {
diff --git a/clippy_lints/src/assigning_clones.rs b/clippy_lints/src/assigning_clones.rs
index 0de0031ed24..03f777600f0 100644
--- a/clippy_lints/src/assigning_clones.rs
+++ b/clippy_lints/src/assigning_clones.rs
@@ -1,4 +1,5 @@
 use clippy_config::msrvs::{self, Msrv};
+use clippy_config::Conf;
 use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::mir::{enclosing_mir, PossibleBorrowerMap};
 use clippy_utils::sugg::Sugg;
@@ -57,9 +58,10 @@ pub struct AssigningClones {
 }
 
 impl AssigningClones {
-    #[must_use]
-    pub fn new(msrv: Msrv) -> Self {
-        Self { msrv }
+    pub fn new(conf: &'static Conf) -> Self {
+        Self {
+            msrv: conf.msrv.clone(),
+        }
     }
 }
 
diff --git a/clippy_lints/src/attrs/mod.rs b/clippy_lints/src/attrs/mod.rs
index 8ec60314cc9..8f430ae601a 100644
--- a/clippy_lints/src/attrs/mod.rs
+++ b/clippy_lints/src/attrs/mod.rs
@@ -16,6 +16,7 @@ mod useless_attribute;
 mod utils;
 
 use clippy_config::msrvs::{self, Msrv};
+use clippy_config::Conf;
 use rustc_ast::{Attribute, MetaItemKind, NestedMetaItem};
 use rustc_hir::{ImplItem, Item, ItemKind, TraitItem};
 use rustc_lint::{EarlyContext, EarlyLintPass, LateContext, LateLintPass};
@@ -499,7 +500,6 @@ declare_clippy_lint! {
     "duplicated attribute"
 }
 
-#[derive(Clone)]
 pub struct Attributes {
     msrv: Msrv,
 }
@@ -517,9 +517,10 @@ impl_lint_pass!(Attributes => [
 ]);
 
 impl Attributes {
-    #[must_use]
-    pub fn new(msrv: Msrv) -> Self {
-        Self { msrv }
+    pub fn new(conf: &'static Conf) -> Self {
+        Self {
+            msrv: conf.msrv.clone(),
+        }
     }
 }
 
@@ -589,7 +590,15 @@ impl<'tcx> LateLintPass<'tcx> for Attributes {
 }
 
 pub struct EarlyAttributes {
-    pub msrv: Msrv,
+    msrv: Msrv,
+}
+
+impl EarlyAttributes {
+    pub fn new(conf: &'static Conf) -> Self {
+        Self {
+            msrv: conf.msrv.clone(),
+        }
+    }
 }
 
 impl_lint_pass!(EarlyAttributes => [
diff --git a/clippy_lints/src/await_holding_invalid.rs b/clippy_lints/src/await_holding_invalid.rs
index d4a1e2780d0..d5f017b2650 100644
--- a/clippy_lints/src/await_holding_invalid.rs
+++ b/clippy_lints/src/await_holding_invalid.rs
@@ -1,11 +1,11 @@
-use clippy_config::types::DisallowedPath;
+use clippy_config::Conf;
 use clippy_utils::diagnostics::span_lint_and_then;
-use clippy_utils::{match_def_path, paths};
-use rustc_data_structures::fx::FxHashMap;
+use clippy_utils::{create_disallowed_map, match_def_path, paths};
 use rustc_hir as hir;
-use rustc_hir::def_id::DefId;
+use rustc_hir::def_id::{DefId, DefIdMap};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::mir::CoroutineLayout;
+use rustc_middle::ty::TyCtxt;
 use rustc_session::impl_lint_pass;
 use rustc_span::{sym, Span};
 
@@ -172,31 +172,19 @@ declare_clippy_lint! {
 
 impl_lint_pass!(AwaitHolding => [AWAIT_HOLDING_LOCK, AWAIT_HOLDING_REFCELL_REF, AWAIT_HOLDING_INVALID_TYPE]);
 
-#[derive(Debug)]
 pub struct AwaitHolding {
-    conf_invalid_types: Vec<DisallowedPath>,
-    def_ids: FxHashMap<DefId, DisallowedPath>,
+    def_ids: DefIdMap<(&'static str, Option<&'static str>)>,
 }
 
 impl AwaitHolding {
-    pub(crate) fn new(conf_invalid_types: Vec<DisallowedPath>) -> Self {
+    pub(crate) fn new(tcx: TyCtxt<'_>, conf: &'static Conf) -> Self {
         Self {
-            conf_invalid_types,
-            def_ids: FxHashMap::default(),
+            def_ids: create_disallowed_map(tcx, &conf.await_holding_invalid_types),
         }
     }
 }
 
 impl<'tcx> LateLintPass<'tcx> for AwaitHolding {
-    fn check_crate(&mut self, cx: &LateContext<'tcx>) {
-        for conf in &self.conf_invalid_types {
-            let segs: Vec<_> = conf.path().split("::").collect();
-            for id in clippy_utils::def_path_def_ids(cx, &segs) {
-                self.def_ids.insert(id, conf.clone());
-            }
-        }
-    }
-
     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'tcx>) {
         if let hir::ExprKind::Closure(hir::Closure {
             kind: hir::ClosureKind::Coroutine(hir::CoroutineKind::Desugared(hir::CoroutineDesugaring::Async, _)),
@@ -258,25 +246,22 @@ impl AwaitHolding {
                             );
                         },
                     );
-                } else if let Some(disallowed) = self.def_ids.get(&adt.did()) {
-                    emit_invalid_type(cx, ty_cause.source_info.span, disallowed);
+                } else if let Some(&(path, reason)) = self.def_ids.get(&adt.did()) {
+                    emit_invalid_type(cx, ty_cause.source_info.span, path, reason);
                 }
             }
         }
     }
 }
 
-fn emit_invalid_type(cx: &LateContext<'_>, span: Span, disallowed: &DisallowedPath) {
+fn emit_invalid_type(cx: &LateContext<'_>, span: Span, path: &'static str, reason: Option<&'static str>) {
     span_lint_and_then(
         cx,
         AWAIT_HOLDING_INVALID_TYPE,
         span,
-        format!(
-            "`{}` may not be held across an await point per `clippy.toml`",
-            disallowed.path()
-        ),
+        format!("holding a disallowed type across an await point `{path}`"),
         |diag| {
-            if let Some(reason) = disallowed.reason() {
+            if let Some(reason) = reason {
                 diag.note(reason);
             }
         },
diff --git a/clippy_lints/src/borrow_deref_ref.rs b/clippy_lints/src/borrow_deref_ref.rs
index 0ca4a0e067d..bd123a725a7 100644
--- a/clippy_lints/src/borrow_deref_ref.rs
+++ b/clippy_lints/src/borrow_deref_ref.rs
@@ -49,35 +49,31 @@ declare_lint_pass!(BorrowDerefRef => [BORROW_DEREF_REF]);
 
 impl<'tcx> LateLintPass<'tcx> for BorrowDerefRef {
     fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &rustc_hir::Expr<'tcx>) {
-        if !e.span.from_expansion()
-            && let ExprKind::AddrOf(_, Mutability::Not, addrof_target) = e.kind
-            && !addrof_target.span.from_expansion()
+        if let ExprKind::AddrOf(_, Mutability::Not, addrof_target) = e.kind
             && let ExprKind::Unary(UnOp::Deref, deref_target) = addrof_target.kind
-            && !deref_target.span.from_expansion()
             && !matches!(deref_target.kind, ExprKind::Unary(UnOp::Deref, ..))
+            && !e.span.from_expansion()
+            && !deref_target.span.from_expansion()
+            && !addrof_target.span.from_expansion()
             && let ref_ty = cx.typeck_results().expr_ty(deref_target)
             && let ty::Ref(_, inner_ty, Mutability::Not) = ref_ty.kind()
-        {
-            if let Some(parent_expr) = get_parent_expr(cx, e) {
-                if matches!(parent_expr.kind, ExprKind::Unary(UnOp::Deref, ..))
-                    && !is_lint_allowed(cx, DEREF_ADDROF, parent_expr.hir_id)
-                {
-                    return;
+            && get_parent_expr(cx, e).map_or(true, |parent| {
+                match parent.kind {
+                    // `*&*foo` should lint `deref_addrof` instead.
+                    ExprKind::Unary(UnOp::Deref, _) => is_lint_allowed(cx, DEREF_ADDROF, parent.hir_id),
+                    // `&*foo` creates a distinct temporary from `foo`
+                    ExprKind::AddrOf(_, Mutability::Mut, _) => !matches!(
+                        deref_target.kind,
+                        ExprKind::Path(..)
+                            | ExprKind::Field(..)
+                            | ExprKind::Index(..)
+                            | ExprKind::Unary(UnOp::Deref, ..)
+                    ),
+                    _ => true,
                 }
-
-                // modification to `&mut &*x` is different from `&mut x`
-                if matches!(
-                    deref_target.kind,
-                    ExprKind::Path(..) | ExprKind::Field(..) | ExprKind::Index(..) | ExprKind::Unary(UnOp::Deref, ..)
-                ) && matches!(parent_expr.kind, ExprKind::AddrOf(_, Mutability::Mut, _))
-                {
-                    return;
-                }
-            }
-            if is_from_proc_macro(cx, e) {
-                return;
-            }
-
+            })
+            && !is_from_proc_macro(cx, e)
+        {
             span_lint_and_then(
                 cx,
                 BORROW_DEREF_REF,
diff --git a/clippy_lints/src/cargo/mod.rs b/clippy_lints/src/cargo/mod.rs
index 593bc6c81ee..312ad4c2990 100644
--- a/clippy_lints/src/cargo/mod.rs
+++ b/clippy_lints/src/cargo/mod.rs
@@ -5,6 +5,7 @@ mod multiple_crate_versions;
 mod wildcard_dependencies;
 
 use cargo_metadata::MetadataCommand;
+use clippy_config::Conf;
 use clippy_utils::diagnostics::span_lint;
 use clippy_utils::is_lint_allowed;
 use rustc_data_structures::fx::FxHashSet;
@@ -204,8 +205,8 @@ declare_clippy_lint! {
 }
 
 pub struct Cargo {
-    pub allowed_duplicate_crates: FxHashSet<String>,
-    pub ignore_publish: bool,
+    allowed_duplicate_crates: &'static FxHashSet<String>,
+    ignore_publish: bool,
 }
 
 impl_lint_pass!(Cargo => [
@@ -217,6 +218,15 @@ impl_lint_pass!(Cargo => [
     LINT_GROUPS_PRIORITY,
 ]);
 
+impl Cargo {
+    pub fn new(conf: &'static Conf) -> Self {
+        Self {
+            allowed_duplicate_crates: &conf.allowed_duplicate_crates,
+            ignore_publish: conf.cargo_ignore_publish,
+        }
+    }
+}
+
 impl LateLintPass<'_> for Cargo {
     fn check_crate(&mut self, cx: &LateContext<'_>) {
         static NO_DEPS_LINTS: &[&Lint] = &[
@@ -253,7 +263,7 @@ impl LateLintPass<'_> for Cargo {
         {
             match MetadataCommand::new().exec() {
                 Ok(metadata) => {
-                    multiple_crate_versions::check(cx, &metadata, &self.allowed_duplicate_crates);
+                    multiple_crate_versions::check(cx, &metadata, self.allowed_duplicate_crates);
                 },
                 Err(e) => {
                     for lint in WITH_DEPS_LINTS {
diff --git a/clippy_lints/src/casts/cast_lossless.rs b/clippy_lints/src/casts/cast_lossless.rs
index d52ad1c6f23..ff460a3fd8e 100644
--- a/clippy_lints/src/casts/cast_lossless.rs
+++ b/clippy_lints/src/casts/cast_lossless.rs
@@ -1,19 +1,21 @@
 use clippy_config::msrvs::{self, Msrv};
-use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::in_constant;
-use clippy_utils::source::{snippet_opt, snippet_with_applicability};
+use clippy_utils::source::snippet_opt;
+use clippy_utils::sugg::Sugg;
 use clippy_utils::ty::is_isize_or_usize;
 use rustc_errors::Applicability;
-use rustc_hir::{Expr, ExprKind, QPath, TyKind};
+use rustc_hir::{Expr, QPath, TyKind};
 use rustc_lint::LateContext;
-use rustc_middle::ty::{self, FloatTy, Ty, UintTy};
+use rustc_middle::ty::{self, FloatTy, Ty};
+use rustc_span::hygiene;
 
 use super::{utils, CAST_LOSSLESS};
 
 pub(super) fn check(
     cx: &LateContext<'_>,
     expr: &Expr<'_>,
-    cast_op: &Expr<'_>,
+    cast_from_expr: &Expr<'_>,
     cast_from: Ty<'_>,
     cast_to: Ty<'_>,
     cast_to_hir: &rustc_hir::Ty<'_>,
@@ -23,64 +25,54 @@ pub(super) fn check(
         return;
     }
 
-    // The suggestion is to use a function call, so if the original expression
-    // has parens on the outside, they are no longer needed.
-    let mut app = Applicability::MachineApplicable;
-    let opt = snippet_opt(cx, cast_op.span.source_callsite());
-    let sugg = opt.as_ref().map_or_else(
-        || {
-            app = Applicability::HasPlaceholders;
-            ".."
-        },
-        |snip| {
-            if should_strip_parens(cast_op, snip) {
-                &snip[1..snip.len() - 1]
-            } else {
-                snip.as_str()
-            }
-        },
-    );
-
-    // Display the type alias instead of the aliased type. Fixes #11285
-    //
-    // FIXME: Once `lazy_type_alias` is stabilized(?) we should use `rustc_middle` types instead,
-    // this will allow us to display the right type with `cast_from` as well.
-    let cast_to_fmt = if let TyKind::Path(QPath::Resolved(None, path)) = cast_to_hir.kind
-        // It's a bit annoying but the turbofish is optional for types. A type in an `as` cast
-        // shouldn't have these if they're primitives, which are the only things we deal with.
-        //
-        // This could be removed for performance if this check is determined to have a pretty major
-        // effect.
-        && path.segments.iter().all(|segment| segment.args.is_none())
-    {
-        snippet_with_applicability(cx, cast_to_hir.span, "..", &mut app)
-    } else {
-        cast_to.to_string().into()
-    };
-
-    let message = if cast_from.is_bool() {
-        format!("casting `{cast_from}` to `{cast_to_fmt}` is more cleanly stated with `{cast_to_fmt}::from(_)`")
-    } else {
-        format!("casting `{cast_from}` to `{cast_to_fmt}` may become silently lossy if you later change the type")
-    };
-
-    span_lint_and_sugg(
+    span_lint_and_then(
         cx,
         CAST_LOSSLESS,
         expr.span,
-        message,
-        "try",
-        format!("{cast_to_fmt}::from({sugg})"),
-        app,
+        format!("casts from `{cast_from}` to `{cast_to}` can be expressed infallibly using `From`"),
+        |diag| {
+            diag.help("an `as` cast can become silently lossy if the types change in the future");
+            let mut applicability = Applicability::MachineApplicable;
+            let from_sugg = Sugg::hir_with_context(cx, cast_from_expr, expr.span.ctxt(), "<from>", &mut applicability);
+            let Some(ty) = snippet_opt(cx, hygiene::walk_chain(cast_to_hir.span, expr.span.ctxt())) else {
+                return;
+            };
+            match cast_to_hir.kind {
+                TyKind::Infer => {
+                    diag.span_suggestion_verbose(
+                        expr.span,
+                        "use `Into::into` instead",
+                        format!("{}.into()", from_sugg.maybe_par()),
+                        applicability,
+                    );
+                },
+                // Don't suggest `A<_>::B::From(x)` or `macro!()::from(x)`
+                kind if matches!(kind, TyKind::Path(QPath::Resolved(_, path)) if path.segments.iter().any(|s| s.args.is_some()))
+                    || !cast_to_hir.span.eq_ctxt(expr.span) =>
+                {
+                    diag.span_suggestion_verbose(
+                        expr.span,
+                        format!("use `<{ty}>::from` instead"),
+                        format!("<{ty}>::from({from_sugg})"),
+                        applicability,
+                    );
+                },
+                _ => {
+                    diag.span_suggestion_verbose(
+                        expr.span,
+                        format!("use `{ty}::from` instead"),
+                        format!("{ty}::from({from_sugg})"),
+                        applicability,
+                    );
+                },
+            }
+        },
     );
 }
 
 fn should_lint(cx: &LateContext<'_>, expr: &Expr<'_>, cast_from: Ty<'_>, cast_to: Ty<'_>, msrv: &Msrv) -> bool {
     // Do not suggest using From in consts/statics until it is valid to do so (see #2267).
-    //
-    // If destination is u128, do not lint because source type cannot be larger
-    // If source is bool, still lint due to the lint message differing (refers to style)
-    if in_constant(cx, expr.hir_id) || (!cast_from.is_bool() && matches!(cast_to.kind(), ty::Uint(UintTy::U128))) {
+    if in_constant(cx, expr.hir_id) {
         return false;
     }
 
@@ -110,12 +102,3 @@ fn should_lint(cx: &LateContext<'_>, expr: &Expr<'_>, cast_from: Ty<'_>, cast_to
         },
     }
 }
-
-fn should_strip_parens(cast_expr: &Expr<'_>, snip: &str) -> bool {
-    if let ExprKind::Binary(_, _, _) = cast_expr.kind {
-        if snip.starts_with('(') && snip.ends_with(')') {
-            return true;
-        }
-    }
-    false
-}
diff --git a/clippy_lints/src/casts/mod.rs b/clippy_lints/src/casts/mod.rs
index 54f0c7c4687..c31716fbcee 100644
--- a/clippy_lints/src/casts/mod.rs
+++ b/clippy_lints/src/casts/mod.rs
@@ -24,6 +24,7 @@ mod utils;
 mod zero_ptr;
 
 use clippy_config::msrvs::{self, Msrv};
+use clippy_config::Conf;
 use clippy_utils::is_hir_ty_cfg_dependant;
 use rustc_hir::{Expr, ExprKind};
 use rustc_lint::{LateContext, LateLintPass, LintContext};
@@ -658,11 +659,11 @@ declare_clippy_lint! {
     ///
     /// ### Example
     /// ```rust,ignore
-    /// let _: (0.0_f32 / 0.0) as u64;
+    /// let _ = (0.0_f32 / 0.0) as u64;
     /// ```
     /// Use instead:
     /// ```rust,ignore
-    /// let _: = 0_u64;
+    /// let _ = 0_u64;
     /// ```
     #[clippy::version = "1.66.0"]
     pub CAST_NAN_TO_INT,
@@ -722,9 +723,10 @@ pub struct Casts {
 }
 
 impl Casts {
-    #[must_use]
-    pub fn new(msrv: Msrv) -> Self {
-        Self { msrv }
+    pub fn new(conf: &'static Conf) -> Self {
+        Self {
+            msrv: conf.msrv.clone(),
+        }
     }
 }
 
@@ -761,45 +763,45 @@ impl<'tcx> LateLintPass<'tcx> for Casts {
             return;
         }
 
-        if let ExprKind::Cast(cast_expr, cast_to_hir) = expr.kind {
+        if let ExprKind::Cast(cast_from_expr, cast_to_hir) = expr.kind {
             if is_hir_ty_cfg_dependant(cx, cast_to_hir) {
                 return;
             }
             let (cast_from, cast_to) = (
-                cx.typeck_results().expr_ty(cast_expr),
+                cx.typeck_results().expr_ty(cast_from_expr),
                 cx.typeck_results().expr_ty(expr),
             );
 
-            if !expr.span.from_expansion() && unnecessary_cast::check(cx, expr, cast_expr, cast_from, cast_to) {
+            if !expr.span.from_expansion() && unnecessary_cast::check(cx, expr, cast_from_expr, cast_from, cast_to) {
                 return;
             }
-            cast_slice_from_raw_parts::check(cx, expr, cast_expr, cast_to, &self.msrv);
-            ptr_cast_constness::check(cx, expr, cast_expr, cast_from, cast_to, &self.msrv);
-            as_ptr_cast_mut::check(cx, expr, cast_expr, cast_to);
-            fn_to_numeric_cast_any::check(cx, expr, cast_expr, cast_from, cast_to);
-            fn_to_numeric_cast::check(cx, expr, cast_expr, cast_from, cast_to);
-            fn_to_numeric_cast_with_truncation::check(cx, expr, cast_expr, cast_from, cast_to);
-            zero_ptr::check(cx, expr, cast_expr, cast_to_hir);
+            cast_slice_from_raw_parts::check(cx, expr, cast_from_expr, cast_to, &self.msrv);
+            ptr_cast_constness::check(cx, expr, cast_from_expr, cast_from, cast_to, &self.msrv);
+            as_ptr_cast_mut::check(cx, expr, cast_from_expr, cast_to);
+            fn_to_numeric_cast_any::check(cx, expr, cast_from_expr, cast_from, cast_to);
+            fn_to_numeric_cast::check(cx, expr, cast_from_expr, cast_from, cast_to);
+            fn_to_numeric_cast_with_truncation::check(cx, expr, cast_from_expr, cast_from, cast_to);
+            zero_ptr::check(cx, expr, cast_from_expr, cast_to_hir);
 
             if cast_to.is_numeric() {
-                cast_possible_truncation::check(cx, expr, cast_expr, cast_from, cast_to, cast_to_hir.span);
+                cast_possible_truncation::check(cx, expr, cast_from_expr, cast_from, cast_to, cast_to_hir.span);
                 if cast_from.is_numeric() {
                     cast_possible_wrap::check(cx, expr, cast_from, cast_to);
                     cast_precision_loss::check(cx, expr, cast_from, cast_to);
-                    cast_sign_loss::check(cx, expr, cast_expr, cast_from, cast_to);
-                    cast_abs_to_unsigned::check(cx, expr, cast_expr, cast_from, cast_to, &self.msrv);
-                    cast_nan_to_int::check(cx, expr, cast_expr, cast_from, cast_to);
+                    cast_sign_loss::check(cx, expr, cast_from_expr, cast_from, cast_to);
+                    cast_abs_to_unsigned::check(cx, expr, cast_from_expr, cast_from, cast_to, &self.msrv);
+                    cast_nan_to_int::check(cx, expr, cast_from_expr, cast_from, cast_to);
                 }
-                cast_lossless::check(cx, expr, cast_expr, cast_from, cast_to, cast_to_hir, &self.msrv);
-                cast_enum_constructor::check(cx, expr, cast_expr, cast_from);
+                cast_lossless::check(cx, expr, cast_from_expr, cast_from, cast_to, cast_to_hir, &self.msrv);
+                cast_enum_constructor::check(cx, expr, cast_from_expr, cast_from);
             }
 
             as_underscore::check(cx, expr, cast_to_hir);
 
             if self.msrv.meets(msrvs::PTR_FROM_REF) {
-                ref_as_ptr::check(cx, expr, cast_expr, cast_to_hir);
+                ref_as_ptr::check(cx, expr, cast_from_expr, cast_to_hir);
             } else if self.msrv.meets(msrvs::BORROW_AS_PTR) {
-                borrow_as_ptr::check(cx, expr, cast_expr, cast_to_hir);
+                borrow_as_ptr::check(cx, expr, cast_from_expr, cast_to_hir);
             }
         }
 
diff --git a/clippy_lints/src/casts/ptr_cast_constness.rs b/clippy_lints/src/casts/ptr_cast_constness.rs
index 921693567fc..7513e18d408 100644
--- a/clippy_lints/src/casts/ptr_cast_constness.rs
+++ b/clippy_lints/src/casts/ptr_cast_constness.rs
@@ -4,7 +4,7 @@ use clippy_utils::sugg::Sugg;
 use rustc_errors::Applicability;
 use rustc_hir::{Expr, Mutability};
 use rustc_lint::LateContext;
-use rustc_middle::ty::{self, Ty};
+use rustc_middle::ty::{self, Ty, TypeVisitableExt};
 
 use super::PTR_CAST_CONSTNESS;
 
@@ -24,6 +24,7 @@ pub(super) fn check<'tcx>(
             (Mutability::Not, Mutability::Mut) | (Mutability::Mut, Mutability::Not)
         )
         && from_ty == to_ty
+        && !from_ty.has_erased_regions()
     {
         let sugg = Sugg::hir(cx, cast_expr, "_");
         let constness = match *to_mutbl {
diff --git a/clippy_lints/src/checked_conversions.rs b/clippy_lints/src/checked_conversions.rs
index 92810ea2aa0..0b1ab5411bf 100644
--- a/clippy_lints/src/checked_conversions.rs
+++ b/clippy_lints/src/checked_conversions.rs
@@ -1,11 +1,12 @@
 //! lint on manually implemented checked conversions that could be transformed into `try_from`
 
 use clippy_config::msrvs::{self, Msrv};
+use clippy_config::Conf;
 use clippy_utils::diagnostics::span_lint_and_sugg;
 use clippy_utils::source::snippet_with_applicability;
 use clippy_utils::{in_constant, is_integer_literal, SpanlessEq};
 use rustc_errors::Applicability;
-use rustc_hir::{BinOp, BinOpKind, Expr, ExprKind, QPath, TyKind};
+use rustc_hir::{BinOpKind, Expr, ExprKind, QPath, TyKind};
 use rustc_lint::{LateContext, LateLintPass, LintContext};
 use rustc_middle::lint::in_external_macro;
 use rustc_session::impl_lint_pass;
@@ -40,9 +41,10 @@ pub struct CheckedConversions {
 }
 
 impl CheckedConversions {
-    #[must_use]
-    pub fn new(msrv: Msrv) -> Self {
-        Self { msrv }
+    pub fn new(conf: &'static Conf) -> Self {
+        Self {
+            msrv: conf.msrv.clone(),
+        }
     }
 }
 
@@ -50,61 +52,54 @@ impl_lint_pass!(CheckedConversions => [CHECKED_CONVERSIONS]);
 
 impl<'tcx> LateLintPass<'tcx> for CheckedConversions {
     fn check_expr(&mut self, cx: &LateContext<'_>, item: &Expr<'_>) {
-        if !self.msrv.meets(msrvs::TRY_FROM) {
-            return;
-        }
-
-        let result = if !in_constant(cx, item.hir_id)
-            && !in_external_macro(cx.sess(), item.span)
-            && let ExprKind::Binary(op, left, right) = &item.kind
-        {
-            match op.node {
-                BinOpKind::Ge | BinOpKind::Le => single_check(item),
-                BinOpKind::And => double_check(cx, left, right),
-                _ => None,
+        if let ExprKind::Binary(op, lhs, rhs) = item.kind
+            && let (lt1, gt1, op2) = match op.node {
+                BinOpKind::Le => (lhs, rhs, None),
+                BinOpKind::Ge => (rhs, lhs, None),
+                BinOpKind::And
+                    if let ExprKind::Binary(op1, lhs1, rhs1) = lhs.kind
+                        && let ExprKind::Binary(op2, lhs2, rhs2) = rhs.kind
+                        && let Some((lt1, gt1)) = read_le_ge(op1.node, lhs1, rhs1)
+                        && let Some((lt2, gt2)) = read_le_ge(op2.node, lhs2, rhs2) =>
+                {
+                    (lt1, gt1, Some((lt2, gt2)))
+                },
+                _ => return,
             }
-        } else {
-            None
-        };
-
-        if let Some(cv) = result {
-            if let Some(to_type) = cv.to_type {
-                let mut applicability = Applicability::MachineApplicable;
-                let snippet = snippet_with_applicability(cx, cv.expr_to_cast.span, "_", &mut applicability);
-                span_lint_and_sugg(
-                    cx,
-                    CHECKED_CONVERSIONS,
-                    item.span,
-                    "checked cast can be simplified",
-                    "try",
-                    format!("{to_type}::try_from({snippet}).is_ok()"),
-                    applicability,
-                );
+            && !in_external_macro(cx.sess(), item.span)
+            && !in_constant(cx, item.hir_id)
+            && self.msrv.meets(msrvs::TRY_FROM)
+            && let Some(cv) = match op2 {
+                // todo: check for case signed -> larger unsigned == only x >= 0
+                None => check_upper_bound(lt1, gt1).filter(|cv| cv.cvt == ConversionType::FromUnsigned),
+                Some((lt2, gt2)) => {
+                    let upper_lower = |lt1, gt1, lt2, gt2| {
+                        check_upper_bound(lt1, gt1)
+                            .zip(check_lower_bound(lt2, gt2))
+                            .and_then(|(l, r)| l.combine(r, cx))
+                    };
+                    upper_lower(lt1, gt1, lt2, gt2).or_else(|| upper_lower(lt2, gt2, lt1, gt1))
+                },
             }
+            && let Some(to_type) = cv.to_type
+        {
+            let mut applicability = Applicability::MachineApplicable;
+            let snippet = snippet_with_applicability(cx, cv.expr_to_cast.span, "_", &mut applicability);
+            span_lint_and_sugg(
+                cx,
+                CHECKED_CONVERSIONS,
+                item.span,
+                "checked cast can be simplified",
+                "try",
+                format!("{to_type}::try_from({snippet}).is_ok()"),
+                applicability,
+            );
         }
     }
 
     extract_msrv_attr!(LateContext);
 }
 
-/// Searches for a single check from unsigned to _ is done
-/// todo: check for case signed -> larger unsigned == only x >= 0
-fn single_check<'tcx>(expr: &'tcx Expr<'tcx>) -> Option<Conversion<'tcx>> {
-    check_upper_bound(expr).filter(|cv| cv.cvt == ConversionType::FromUnsigned)
-}
-
-/// Searches for a combination of upper & lower bound checks
-fn double_check<'a>(cx: &LateContext<'_>, left: &'a Expr<'_>, right: &'a Expr<'_>) -> Option<Conversion<'a>> {
-    let upper_lower = |l, r| {
-        let upper = check_upper_bound(l);
-        let lower = check_lower_bound(r);
-
-        upper.zip(lower).and_then(|(l, r)| l.combine(r, cx))
-    };
-
-    upper_lower(left, right).or_else(|| upper_lower(right, left))
-}
-
 /// Contains the result of a tried conversion check
 #[derive(Clone, Debug)]
 struct Conversion<'a> {
@@ -121,6 +116,19 @@ enum ConversionType {
     FromUnsigned,
 }
 
+/// Attempts to read either `<=` or `>=` with a normalized operand order.
+fn read_le_ge<'tcx>(
+    op: BinOpKind,
+    lhs: &'tcx Expr<'tcx>,
+    rhs: &'tcx Expr<'tcx>,
+) -> Option<(&'tcx Expr<'tcx>, &'tcx Expr<'tcx>)> {
+    match op {
+        BinOpKind::Le => Some((lhs, rhs)),
+        BinOpKind::Ge => Some((rhs, lhs)),
+        _ => None,
+    }
+}
+
 impl<'a> Conversion<'a> {
     /// Combine multiple conversions if the are compatible
     pub fn combine(self, other: Self, cx: &LateContext<'_>) -> Option<Conversion<'a>> {
@@ -188,29 +196,17 @@ impl ConversionType {
 }
 
 /// Check for `expr <= (to_type::MAX as from_type)`
-fn check_upper_bound<'tcx>(expr: &'tcx Expr<'tcx>) -> Option<Conversion<'tcx>> {
-    if let ExprKind::Binary(ref op, left, right) = &expr.kind
-        && let Some((candidate, check)) = normalize_le_ge(op, left, right)
-        && let Some((from, to)) = get_types_from_cast(check, INTS, "max_value", "MAX")
-    {
-        Conversion::try_new(candidate, from, to)
+fn check_upper_bound<'tcx>(lt: &'tcx Expr<'tcx>, gt: &'tcx Expr<'tcx>) -> Option<Conversion<'tcx>> {
+    if let Some((from, to)) = get_types_from_cast(gt, INTS, "max_value", "MAX") {
+        Conversion::try_new(lt, from, to)
     } else {
         None
     }
 }
 
 /// Check for `expr >= 0|(to_type::MIN as from_type)`
-fn check_lower_bound<'tcx>(expr: &'tcx Expr<'tcx>) -> Option<Conversion<'tcx>> {
-    fn check_function<'a>(candidate: &'a Expr<'a>, check: &'a Expr<'a>) -> Option<Conversion<'a>> {
-        (check_lower_bound_zero(candidate, check)).or_else(|| (check_lower_bound_min(candidate, check)))
-    }
-
-    // First of we need a binary containing the expression & the cast
-    if let ExprKind::Binary(ref op, left, right) = &expr.kind {
-        normalize_le_ge(op, right, left).and_then(|(l, r)| check_function(l, r))
-    } else {
-        None
-    }
+fn check_lower_bound<'tcx>(lt: &'tcx Expr<'tcx>, gt: &'tcx Expr<'tcx>) -> Option<Conversion<'tcx>> {
+    check_lower_bound_zero(gt, lt).or_else(|| check_lower_bound_min(gt, lt))
 }
 
 /// Check for `expr >= 0`
@@ -309,15 +305,6 @@ fn int_ty_to_sym<'tcx>(path: &QPath<'_>) -> Option<&'tcx str> {
     }
 }
 
-/// Will return the expressions as if they were expr1 <= expr2
-fn normalize_le_ge<'a>(op: &BinOp, left: &'a Expr<'a>, right: &'a Expr<'a>) -> Option<(&'a Expr<'a>, &'a Expr<'a>)> {
-    match op.node {
-        BinOpKind::Le => Some((left, right)),
-        BinOpKind::Ge => Some((right, left)),
-        _ => None,
-    }
-}
-
 // Constants
 const UINTS: &[&str] = &["u8", "u16", "u32", "u64", "usize"];
 const SINTS: &[&str] = &["i8", "i16", "i32", "i64", "isize"];
diff --git a/clippy_lints/src/cognitive_complexity.rs b/clippy_lints/src/cognitive_complexity.rs
index 60815f4f2af..5fa0522e4e5 100644
--- a/clippy_lints/src/cognitive_complexity.rs
+++ b/clippy_lints/src/cognitive_complexity.rs
@@ -1,5 +1,6 @@
 //! calculate cognitive complexity and warn about overly complex functions
 
+use clippy_config::Conf;
 use clippy_utils::diagnostics::span_lint_and_help;
 use clippy_utils::source::{IntoSpan, SpanRangeExt};
 use clippy_utils::ty::is_type_diagnostic_item;
@@ -39,10 +40,9 @@ pub struct CognitiveComplexity {
 }
 
 impl CognitiveComplexity {
-    #[must_use]
-    pub fn new(limit: u64) -> Self {
+    pub fn new(conf: &'static Conf) -> Self {
         Self {
-            limit: LimitStack::new(limit),
+            limit: LimitStack::new(conf.cognitive_complexity_threshold),
         }
     }
 }
diff --git a/clippy_lints/src/collapsible_if.rs b/clippy_lints/src/collapsible_if.rs
index 07b02c98df1..f311c052ad6 100644
--- a/clippy_lints/src/collapsible_if.rs
+++ b/clippy_lints/src/collapsible_if.rs
@@ -93,20 +93,14 @@ declare_lint_pass!(CollapsibleIf => [COLLAPSIBLE_IF, COLLAPSIBLE_ELSE_IF]);
 
 impl EarlyLintPass for CollapsibleIf {
     fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &ast::Expr) {
-        if !expr.span.from_expansion() {
-            check_if(cx, expr);
-        }
-    }
-}
-
-fn check_if(cx: &EarlyContext<'_>, expr: &ast::Expr) {
-    if let ast::ExprKind::If(check, then, else_) = &expr.kind {
-        if let Some(else_) = else_ {
-            check_collapsible_maybe_if_let(cx, then.span, else_);
-        } else if let ast::ExprKind::Let(..) = check.kind {
-            // Prevent triggering on `if let a = b { if c { .. } }`.
-        } else {
-            check_collapsible_no_if_let(cx, expr, check, then);
+        if let ast::ExprKind::If(cond, then, else_) = &expr.kind
+            && !expr.span.from_expansion()
+        {
+            if let Some(else_) = else_ {
+                check_collapsible_maybe_if_let(cx, then.span, else_);
+            } else if !matches!(cond.kind, ast::ExprKind::Let(..)) {
+                check_collapsible_no_if_let(cx, expr, cond, then);
+            }
         }
     }
 }
@@ -189,13 +183,10 @@ fn check_collapsible_no_if_let(cx: &EarlyContext<'_>, expr: &ast::Expr, check: &
 
 /// If the block contains only one expression, return it.
 fn expr_block(block: &ast::Block) -> Option<&ast::Expr> {
-    let mut it = block.stmts.iter();
-
-    if let (Some(stmt), None) = (it.next(), it.next()) {
-        match stmt.kind {
-            ast::StmtKind::Expr(ref expr) | ast::StmtKind::Semi(ref expr) => Some(expr),
-            _ => None,
-        }
+    if let [stmt] = &*block.stmts
+        && let ast::StmtKind::Expr(expr) | ast::StmtKind::Semi(expr) = &stmt.kind
+    {
+        Some(expr)
     } else {
         None
     }
diff --git a/clippy_lints/src/collection_is_never_read.rs b/clippy_lints/src/collection_is_never_read.rs
index 28d9f68d504..eebda3ff76f 100644
--- a/clippy_lints/src/collection_is_never_read.rs
+++ b/clippy_lints/src/collection_is_never_read.rs
@@ -59,9 +59,9 @@ static COLLECTIONS: [Symbol; 9] = [
 
 impl<'tcx> LateLintPass<'tcx> for CollectionIsNeverRead {
     fn check_local(&mut self, cx: &LateContext<'tcx>, local: &'tcx LetStmt<'tcx>) {
-        // Look for local variables whose type is a container. Search surrounding bock for read access.
-        if match_acceptable_type(cx, local, &COLLECTIONS)
-            && let PatKind::Binding(_, local_id, _, _) = local.pat.kind
+        // Look for local variables whose type is a container. Search surrounding block for read access.
+        if let PatKind::Binding(_, local_id, _, _) = local.pat.kind
+            && match_acceptable_type(cx, local, &COLLECTIONS)
             && let Some(enclosing_block) = get_enclosing_block(cx, local.hir_id)
             && has_no_read_access(cx, local_id, enclosing_block)
         {
diff --git a/clippy_lints/src/copies.rs b/clippy_lints/src/copies.rs
index d896452be92..86e0368c4e4 100644
--- a/clippy_lints/src/copies.rs
+++ b/clippy_lints/src/copies.rs
@@ -1,3 +1,4 @@
+use clippy_config::Conf;
 use clippy_utils::diagnostics::{span_lint_and_note, span_lint_and_then};
 use clippy_utils::source::{first_line_of_span, indent_of, reindent_multiline, snippet, IntoSpan, SpanRangeExt};
 use clippy_utils::ty::{needs_ordered_drop, InteriorMut};
@@ -11,6 +12,7 @@ use core::ops::ControlFlow;
 use rustc_errors::Applicability;
 use rustc_hir::{intravisit, BinOpKind, Block, Expr, ExprKind, HirId, HirIdSet, Stmt, StmtKind};
 use rustc_lint::{LateContext, LateLintPass};
+use rustc_middle::ty::TyCtxt;
 use rustc_session::impl_lint_pass;
 use rustc_span::hygiene::walk_chain;
 use rustc_span::source_map::SourceMap;
@@ -159,15 +161,13 @@ declare_clippy_lint! {
 }
 
 pub struct CopyAndPaste<'tcx> {
-    ignore_interior_mutability: Vec<String>,
     interior_mut: InteriorMut<'tcx>,
 }
 
-impl CopyAndPaste<'_> {
-    pub fn new(ignore_interior_mutability: Vec<String>) -> Self {
+impl<'tcx> CopyAndPaste<'tcx> {
+    pub fn new(tcx: TyCtxt<'tcx>, conf: &'static Conf) -> Self {
         Self {
-            ignore_interior_mutability,
-            interior_mut: InteriorMut::default(),
+            interior_mut: InteriorMut::new(tcx, &conf.ignore_interior_mutability),
         }
     }
 }
@@ -180,10 +180,6 @@ impl_lint_pass!(CopyAndPaste<'_> => [
 ]);
 
 impl<'tcx> LateLintPass<'tcx> for CopyAndPaste<'tcx> {
-    fn check_crate(&mut self, cx: &LateContext<'tcx>) {
-        self.interior_mut = InteriorMut::new(cx, &self.ignore_interior_mutability);
-    }
-
     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
         if !expr.span.from_expansion() && matches!(expr.kind, ExprKind::If(..)) && !is_else_clause(cx.tcx, expr) {
             let (conds, blocks) = if_sequence(expr);
diff --git a/clippy_lints/src/crate_in_macro_def.rs b/clippy_lints/src/crate_in_macro_def.rs
index adf6f7c4737..678bdbc0ffb 100644
--- a/clippy_lints/src/crate_in_macro_def.rs
+++ b/clippy_lints/src/crate_in_macro_def.rs
@@ -53,10 +53,9 @@ declare_lint_pass!(CrateInMacroDef => [CRATE_IN_MACRO_DEF]);
 
 impl EarlyLintPass for CrateInMacroDef {
     fn check_item(&mut self, cx: &EarlyContext<'_>, item: &Item) {
-        if item.attrs.iter().any(is_macro_export)
-            && let ItemKind::MacroDef(macro_def) = &item.kind
-            && let tts = macro_def.body.tokens.clone()
-            && let Some(span) = contains_unhygienic_crate_reference(&tts)
+        if let ItemKind::MacroDef(macro_def) = &item.kind
+            && item.attrs.iter().any(is_macro_export)
+            && let Some(span) = contains_unhygienic_crate_reference(&macro_def.body.tokens)
         {
             span_lint_and_sugg(
                 cx,
diff --git a/clippy_lints/src/dbg_macro.rs b/clippy_lints/src/dbg_macro.rs
index b0590b0a71c..788c6f3ada2 100644
--- a/clippy_lints/src/dbg_macro.rs
+++ b/clippy_lints/src/dbg_macro.rs
@@ -1,3 +1,4 @@
+use clippy_config::Conf;
 use clippy_utils::diagnostics::span_lint_and_sugg;
 use clippy_utils::is_in_test;
 use clippy_utils::macros::{macro_backtrace, MacroCall};
@@ -33,7 +34,6 @@ declare_clippy_lint! {
     "`dbg!` macro is intended as a debugging tool"
 }
 
-#[derive(Clone)]
 pub struct DbgMacro {
     allow_dbg_in_tests: bool,
     /// Tracks the `dbg!` macro callsites that are already checked.
@@ -45,9 +45,9 @@ pub struct DbgMacro {
 impl_lint_pass!(DbgMacro => [DBG_MACRO]);
 
 impl DbgMacro {
-    pub fn new(allow_dbg_in_tests: bool) -> Self {
+    pub fn new(conf: &'static Conf) -> Self {
         DbgMacro {
-            allow_dbg_in_tests,
+            allow_dbg_in_tests: conf.allow_dbg_in_tests,
             checked_dbg_call_site: FxHashSet::default(),
             prev_ctxt: SyntaxContext::root(),
         }
diff --git a/clippy_lints/src/declared_lints.rs b/clippy_lints/src/declared_lints.rs
index eabc67601a2..69f9eb6842b 100644
--- a/clippy_lints/src/declared_lints.rs
+++ b/clippy_lints/src/declared_lints.rs
@@ -598,6 +598,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[
     crate::partialeq_to_none::PARTIALEQ_TO_NONE_INFO,
     crate::pass_by_ref_or_value::LARGE_TYPES_PASSED_BY_VALUE_INFO,
     crate::pass_by_ref_or_value::TRIVIALLY_COPY_PASS_BY_REF_INFO,
+    crate::pathbuf_init_then_push::PATHBUF_INIT_THEN_PUSH_INFO,
     crate::pattern_type_mismatch::PATTERN_TYPE_MISMATCH_INFO,
     crate::permissions_set_readonly_false::PERMISSIONS_SET_READONLY_FALSE_INFO,
     crate::precedence::PRECEDENCE_INFO,
diff --git a/clippy_lints/src/derivable_impls.rs b/clippy_lints/src/derivable_impls.rs
index 0c9ad5e8d00..f27f68e2cbc 100644
--- a/clippy_lints/src/derivable_impls.rs
+++ b/clippy_lints/src/derivable_impls.rs
@@ -1,4 +1,5 @@
 use clippy_config::msrvs::{self, Msrv};
+use clippy_config::Conf;
 use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::source::indent_of;
 use clippy_utils::{is_default_equivalent, peel_blocks};
@@ -60,9 +61,10 @@ pub struct DerivableImpls {
 }
 
 impl DerivableImpls {
-    #[must_use]
-    pub fn new(msrv: Msrv) -> Self {
-        DerivableImpls { msrv }
+    pub fn new(conf: &'static Conf) -> Self {
+        DerivableImpls {
+            msrv: conf.msrv.clone(),
+        }
     }
 }
 
diff --git a/clippy_lints/src/disallowed_macros.rs b/clippy_lints/src/disallowed_macros.rs
index 871f529da6c..b51d343132b 100644
--- a/clippy_lints/src/disallowed_macros.rs
+++ b/clippy_lints/src/disallowed_macros.rs
@@ -1,4 +1,5 @@
-use clippy_config::types::DisallowedPath;
+use clippy_config::Conf;
+use clippy_utils::create_disallowed_map;
 use clippy_utils::diagnostics::{span_lint_and_then, span_lint_hir_and_then};
 use clippy_utils::macros::macro_backtrace;
 use rustc_ast::Attribute;
@@ -9,6 +10,7 @@ use rustc_hir::{
     Expr, ExprKind, ForeignItem, HirId, ImplItem, Item, ItemKind, OwnerId, Pat, Path, Stmt, TraitItem, Ty,
 };
 use rustc_lint::{LateContext, LateLintPass};
+use rustc_middle::ty::TyCtxt;
 use rustc_session::impl_lint_pass;
 use rustc_span::{ExpnId, MacroKind, Span};
 
@@ -57,27 +59,24 @@ declare_clippy_lint! {
 }
 
 pub struct DisallowedMacros {
-    conf_disallowed: Vec<DisallowedPath>,
-    disallowed: DefIdMap<usize>,
+    disallowed: DefIdMap<(&'static str, Option<&'static str>)>,
     seen: FxHashSet<ExpnId>,
-
     // Track the most recently seen node that can have a `derive` attribute.
     // Needed to use the correct lint level.
     derive_src: Option<OwnerId>,
 }
 
 impl DisallowedMacros {
-    pub fn new(conf_disallowed: Vec<DisallowedPath>) -> Self {
+    pub fn new(tcx: TyCtxt<'_>, conf: &'static Conf) -> Self {
         Self {
-            conf_disallowed,
-            disallowed: DefIdMap::default(),
+            disallowed: create_disallowed_map(tcx, &conf.disallowed_macros),
             seen: FxHashSet::default(),
             derive_src: None,
         }
     }
 
     fn check(&mut self, cx: &LateContext<'_>, span: Span, derive_src: Option<OwnerId>) {
-        if self.conf_disallowed.is_empty() {
+        if self.disallowed.is_empty() {
             return;
         }
 
@@ -86,11 +85,10 @@ impl DisallowedMacros {
                 return;
             }
 
-            if let Some(&index) = self.disallowed.get(&mac.def_id) {
-                let conf = &self.conf_disallowed[index];
-                let msg = format!("use of a disallowed macro `{}`", conf.path());
+            if let Some(&(path, reason)) = self.disallowed.get(&mac.def_id) {
+                let msg = format!("use of a disallowed macro `{path}`");
                 let add_note = |diag: &mut Diag<'_, _>| {
-                    if let Some(reason) = conf.reason() {
+                    if let Some(reason) = reason {
                         diag.note(reason);
                     }
                 };
@@ -116,15 +114,6 @@ impl DisallowedMacros {
 impl_lint_pass!(DisallowedMacros => [DISALLOWED_MACROS]);
 
 impl LateLintPass<'_> for DisallowedMacros {
-    fn check_crate(&mut self, cx: &LateContext<'_>) {
-        for (index, conf) in self.conf_disallowed.iter().enumerate() {
-            let segs: Vec<_> = conf.path().split("::").collect();
-            for id in clippy_utils::def_path_def_ids(cx, &segs) {
-                self.disallowed.insert(id, index);
-            }
-        }
-    }
-
     fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) {
         self.check(cx, expr.span, None);
         // `$t + $t` can have the context of $t, check also the span of the binary operator
diff --git a/clippy_lints/src/disallowed_methods.rs b/clippy_lints/src/disallowed_methods.rs
index 38fe687f7cc..5a01d76a2a6 100644
--- a/clippy_lints/src/disallowed_methods.rs
+++ b/clippy_lints/src/disallowed_methods.rs
@@ -1,9 +1,11 @@
-use clippy_config::types::DisallowedPath;
+use clippy_config::Conf;
+use clippy_utils::create_disallowed_map;
 use clippy_utils::diagnostics::span_lint_and_then;
 use rustc_hir::def::{CtorKind, DefKind, Res};
 use rustc_hir::def_id::DefIdMap;
 use rustc_hir::{Expr, ExprKind};
 use rustc_lint::{LateContext, LateLintPass};
+use rustc_middle::ty::TyCtxt;
 use rustc_session::impl_lint_pass;
 
 declare_clippy_lint! {
@@ -55,17 +57,14 @@ declare_clippy_lint! {
     "use of a disallowed method call"
 }
 
-#[derive(Clone, Debug)]
 pub struct DisallowedMethods {
-    conf_disallowed: Vec<DisallowedPath>,
-    disallowed: DefIdMap<usize>,
+    disallowed: DefIdMap<(&'static str, Option<&'static str>)>,
 }
 
 impl DisallowedMethods {
-    pub fn new(conf_disallowed: Vec<DisallowedPath>) -> Self {
+    pub fn new(tcx: TyCtxt<'_>, conf: &'static Conf) -> Self {
         Self {
-            conf_disallowed,
-            disallowed: DefIdMap::default(),
+            disallowed: create_disallowed_map(tcx, &conf.disallowed_methods),
         }
     }
 }
@@ -73,15 +72,6 @@ impl DisallowedMethods {
 impl_lint_pass!(DisallowedMethods => [DISALLOWED_METHODS]);
 
 impl<'tcx> LateLintPass<'tcx> for DisallowedMethods {
-    fn check_crate(&mut self, cx: &LateContext<'_>) {
-        for (index, conf) in self.conf_disallowed.iter().enumerate() {
-            let segs: Vec<_> = conf.path().split("::").collect();
-            for id in clippy_utils::def_path_def_ids(cx, &segs) {
-                self.disallowed.insert(id, index);
-            }
-        }
-    }
-
     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
         let (id, span) = match &expr.kind {
             ExprKind::Path(path)
@@ -95,14 +85,18 @@ impl<'tcx> LateLintPass<'tcx> for DisallowedMethods {
             },
             _ => return,
         };
-        if let Some(&index) = self.disallowed.get(&id) {
-            let conf = &self.conf_disallowed[index];
-            let msg = format!("use of a disallowed method `{}`", conf.path());
-            span_lint_and_then(cx, DISALLOWED_METHODS, span, msg, |diag| {
-                if let Some(reason) = conf.reason() {
-                    diag.note(reason);
-                }
-            });
+        if let Some(&(path, reason)) = self.disallowed.get(&id) {
+            span_lint_and_then(
+                cx,
+                DISALLOWED_METHODS,
+                span,
+                format!("use of a disallowed method `{path}`"),
+                |diag| {
+                    if let Some(reason) = reason {
+                        diag.note(reason);
+                    }
+                },
+            );
         }
     }
 }
diff --git a/clippy_lints/src/disallowed_names.rs b/clippy_lints/src/disallowed_names.rs
index 58809604c37..f55b0cf1c50 100644
--- a/clippy_lints/src/disallowed_names.rs
+++ b/clippy_lints/src/disallowed_names.rs
@@ -1,9 +1,11 @@
+use clippy_config::Conf;
 use clippy_utils::diagnostics::span_lint;
 use clippy_utils::is_in_test;
 use rustc_data_structures::fx::FxHashSet;
 use rustc_hir::{Pat, PatKind};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_session::impl_lint_pass;
+use rustc_span::Symbol;
 
 declare_clippy_lint! {
     /// ### What it does
@@ -24,15 +26,14 @@ declare_clippy_lint! {
     "usage of a disallowed/placeholder name"
 }
 
-#[derive(Clone, Debug)]
 pub struct DisallowedNames {
-    disallow: FxHashSet<String>,
+    disallow: FxHashSet<Symbol>,
 }
 
 impl DisallowedNames {
-    pub fn new(disallowed_names: &[String]) -> Self {
+    pub fn new(conf: &'static Conf) -> Self {
         Self {
-            disallow: disallowed_names.iter().cloned().collect(),
+            disallow: conf.disallowed_names.iter().map(|x| Symbol::intern(x)).collect(),
         }
     }
 }
@@ -42,7 +43,7 @@ impl_lint_pass!(DisallowedNames => [DISALLOWED_NAMES]);
 impl<'tcx> LateLintPass<'tcx> for DisallowedNames {
     fn check_pat(&mut self, cx: &LateContext<'tcx>, pat: &'tcx Pat<'_>) {
         if let PatKind::Binding(.., ident, _) = pat.kind
-            && self.disallow.contains(&ident.name.to_string())
+            && self.disallow.contains(&ident.name)
             && !is_in_test(cx.tcx, pat.hir_id)
         {
             span_lint(
diff --git a/clippy_lints/src/disallowed_script_idents.rs b/clippy_lints/src/disallowed_script_idents.rs
index 5ce11900adf..f79264e6b04 100644
--- a/clippy_lints/src/disallowed_script_idents.rs
+++ b/clippy_lints/src/disallowed_script_idents.rs
@@ -1,3 +1,4 @@
+use clippy_config::Conf;
 use clippy_utils::diagnostics::span_lint;
 use rustc_ast::ast;
 use rustc_data_structures::fx::FxHashSet;
@@ -44,19 +45,20 @@ declare_clippy_lint! {
     "usage of non-allowed Unicode scripts"
 }
 
-#[derive(Clone, Debug)]
 pub struct DisallowedScriptIdents {
     whitelist: FxHashSet<Script>,
 }
 
 impl DisallowedScriptIdents {
-    pub fn new(whitelist: &[String]) -> Self {
-        let whitelist = whitelist
-            .iter()
-            .map(String::as_str)
-            .filter_map(Script::from_full_name)
-            .collect();
-        Self { whitelist }
+    pub fn new(conf: &'static Conf) -> Self {
+        Self {
+            whitelist: conf
+                .allowed_scripts
+                .iter()
+                .map(String::as_str)
+                .filter_map(Script::from_full_name)
+                .collect(),
+        }
     }
 }
 
diff --git a/clippy_lints/src/disallowed_types.rs b/clippy_lints/src/disallowed_types.rs
index 4196309a22a..3265404f2b2 100644
--- a/clippy_lints/src/disallowed_types.rs
+++ b/clippy_lints/src/disallowed_types.rs
@@ -1,10 +1,11 @@
-use clippy_config::types::DisallowedPath;
+use clippy_config::Conf;
 use clippy_utils::diagnostics::span_lint_and_then;
 use rustc_data_structures::fx::FxHashMap;
 use rustc_hir::def::Res;
-use rustc_hir::def_id::DefId;
+use rustc_hir::def_id::DefIdMap;
 use rustc_hir::{Item, ItemKind, PolyTraitRef, PrimTy, Ty, TyKind, UseKind};
 use rustc_lint::{LateContext, LateLintPass};
+use rustc_middle::ty::TyCtxt;
 use rustc_session::impl_lint_pass;
 use rustc_span::Span;
 
@@ -49,60 +50,56 @@ declare_clippy_lint! {
     "use of disallowed types"
 }
 
-#[derive(Clone, Debug)]
 pub struct DisallowedTypes {
-    conf_disallowed: Vec<DisallowedPath>,
-    def_ids: FxHashMap<DefId, usize>,
-    prim_tys: FxHashMap<PrimTy, usize>,
+    def_ids: DefIdMap<(&'static str, Option<&'static str>)>,
+    prim_tys: FxHashMap<PrimTy, (&'static str, Option<&'static str>)>,
 }
 
 impl DisallowedTypes {
-    pub fn new(conf_disallowed: Vec<DisallowedPath>) -> Self {
-        Self {
-            conf_disallowed,
-            def_ids: FxHashMap::default(),
-            prim_tys: FxHashMap::default(),
+    pub fn new(tcx: TyCtxt<'_>, conf: &'static Conf) -> Self {
+        let mut def_ids = DefIdMap::default();
+        let mut prim_tys = FxHashMap::default();
+        for x in &conf.disallowed_types {
+            let path: Vec<_> = x.path().split("::").collect::<Vec<_>>();
+            let reason = x.reason();
+            for res in clippy_utils::def_path_res(tcx, &path) {
+                match res {
+                    Res::Def(_, id) => {
+                        def_ids.insert(id, (x.path(), reason));
+                    },
+                    Res::PrimTy(ty) => {
+                        prim_tys.insert(ty, (x.path(), reason));
+                    },
+                    _ => {},
+                }
+            }
         }
+        Self { def_ids, prim_tys }
     }
 
     fn check_res_emit(&self, cx: &LateContext<'_>, res: &Res, span: Span) {
-        match res {
-            Res::Def(_, did) => {
-                if let Some(&index) = self.def_ids.get(did) {
-                    emit(cx, &cx.tcx.def_path_str(*did), span, &self.conf_disallowed[index]);
-                }
-            },
-            Res::PrimTy(prim) => {
-                if let Some(&index) = self.prim_tys.get(prim) {
-                    emit(cx, prim.name_str(), span, &self.conf_disallowed[index]);
+        let (path, reason) = match res {
+            Res::Def(_, did) if let Some(&x) = self.def_ids.get(did) => x,
+            Res::PrimTy(prim) if let Some(&x) = self.prim_tys.get(prim) => x,
+            _ => return,
+        };
+        span_lint_and_then(
+            cx,
+            DISALLOWED_TYPES,
+            span,
+            format!("use of a disallowed type `{path}`"),
+            |diag| {
+                if let Some(reason) = reason {
+                    diag.note(reason);
                 }
             },
-            _ => {},
-        }
+        );
     }
 }
 
 impl_lint_pass!(DisallowedTypes => [DISALLOWED_TYPES]);
 
 impl<'tcx> LateLintPass<'tcx> for DisallowedTypes {
-    fn check_crate(&mut self, cx: &LateContext<'_>) {
-        for (index, conf) in self.conf_disallowed.iter().enumerate() {
-            let segs: Vec<_> = conf.path().split("::").collect();
-
-            for res in clippy_utils::def_path_res(cx, &segs) {
-                match res {
-                    Res::Def(_, id) => {
-                        self.def_ids.insert(id, index);
-                    },
-                    Res::PrimTy(ty) => {
-                        self.prim_tys.insert(ty, index);
-                    },
-                    _ => {},
-                }
-            }
-        }
-    }
-
     fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'tcx>) {
         if let ItemKind::Use(path, UseKind::Single) = &item.kind {
             for res in &path.res {
@@ -121,17 +118,3 @@ impl<'tcx> LateLintPass<'tcx> for DisallowedTypes {
         self.check_res_emit(cx, &poly.trait_ref.path.res, poly.trait_ref.path.span);
     }
 }
-
-fn emit(cx: &LateContext<'_>, name: &str, span: Span, conf: &DisallowedPath) {
-    span_lint_and_then(
-        cx,
-        DISALLOWED_TYPES,
-        span,
-        format!("`{name}` is not allowed according to config"),
-        |diag| {
-            if let Some(reason) = conf.reason() {
-                diag.note(reason);
-            }
-        },
-    );
-}
diff --git a/clippy_lints/src/doc/mod.rs b/clippy_lints/src/doc/mod.rs
index a2a1a51920f..5b6a5b08aa9 100644
--- a/clippy_lints/src/doc/mod.rs
+++ b/clippy_lints/src/doc/mod.rs
@@ -1,4 +1,5 @@
 mod lazy_continuation;
+use clippy_config::Conf;
 use clippy_utils::attrs::is_doc_hidden;
 use clippy_utils::diagnostics::{span_lint, span_lint_and_help};
 use clippy_utils::macros::{is_panic, root_macro_call_first_node};
@@ -421,17 +422,16 @@ declare_clippy_lint! {
     "require every line of a paragraph to be indented and marked"
 }
 
-#[derive(Clone)]
 pub struct Documentation {
-    valid_idents: FxHashSet<String>,
+    valid_idents: &'static FxHashSet<String>,
     check_private_items: bool,
 }
 
 impl Documentation {
-    pub fn new(valid_idents: &[String], check_private_items: bool) -> Self {
+    pub fn new(conf: &'static Conf) -> Self {
         Self {
-            valid_idents: valid_idents.iter().cloned().collect(),
-            check_private_items,
+            valid_idents: &conf.doc_valid_idents,
+            check_private_items: conf.check_private_items,
         }
     }
 }
@@ -452,7 +452,7 @@ impl_lint_pass!(Documentation => [
 
 impl<'tcx> LateLintPass<'tcx> for Documentation {
     fn check_attributes(&mut self, cx: &LateContext<'tcx>, attrs: &'tcx [Attribute]) {
-        let Some(headers) = check_attrs(cx, &self.valid_idents, attrs) else {
+        let Some(headers) = check_attrs(cx, self.valid_idents, attrs) else {
             return;
         };
 
diff --git a/clippy_lints/src/double_parens.rs b/clippy_lints/src/double_parens.rs
index b51bb7951b7..4dd8f01ee70 100644
--- a/clippy_lints/src/double_parens.rs
+++ b/clippy_lints/src/double_parens.rs
@@ -40,35 +40,29 @@ declare_lint_pass!(DoubleParens => [DOUBLE_PARENS]);
 
 impl EarlyLintPass for DoubleParens {
     fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &Expr) {
-        if expr.span.from_expansion() {
-            return;
-        }
-
-        let msg: &str = "consider removing unnecessary double parentheses";
-
-        match expr.kind {
-            ExprKind::Paren(ref in_paren) => match in_paren.kind {
-                ExprKind::Paren(_) | ExprKind::Tup(_) => {
-                    span_lint(cx, DOUBLE_PARENS, expr.span, msg);
-                },
-                _ => {},
-            },
-            ExprKind::Call(_, ref params) => {
-                if params.len() == 1 {
-                    let param = &params[0];
-                    if let ExprKind::Paren(_) = param.kind {
-                        span_lint(cx, DOUBLE_PARENS, param.span, msg);
-                    }
-                }
+        let span = match &expr.kind {
+            ExprKind::Paren(in_paren) if matches!(in_paren.kind, ExprKind::Paren(_) | ExprKind::Tup(_)) => expr.span,
+            ExprKind::Call(_, params)
+                if let [param] = &**params
+                    && let ExprKind::Paren(_) = param.kind =>
+            {
+                param.span
             },
-            ExprKind::MethodCall(ref call) => {
-                if let [ref arg] = call.args[..] {
-                    if let ExprKind::Paren(_) = arg.kind {
-                        span_lint(cx, DOUBLE_PARENS, arg.span, msg);
-                    }
-                }
+            ExprKind::MethodCall(call)
+                if let [arg] = &*call.args
+                    && let ExprKind::Paren(_) = arg.kind =>
+            {
+                arg.span
             },
-            _ => {},
+            _ => return,
+        };
+        if !expr.span.from_expansion() {
+            span_lint(
+                cx,
+                DOUBLE_PARENS,
+                span,
+                "consider removing unnecessary double parentheses",
+            );
         }
     }
 }
diff --git a/clippy_lints/src/else_if_without_else.rs b/clippy_lints/src/else_if_without_else.rs
index bb6f9aac223..7a6dc469727 100644
--- a/clippy_lints/src/else_if_without_else.rs
+++ b/clippy_lints/src/else_if_without_else.rs
@@ -50,12 +50,9 @@ declare_lint_pass!(ElseIfWithoutElse => [ELSE_IF_WITHOUT_ELSE]);
 
 impl EarlyLintPass for ElseIfWithoutElse {
     fn check_expr(&mut self, cx: &EarlyContext<'_>, item: &Expr) {
-        if in_external_macro(cx.sess(), item.span) {
-            return;
-        }
-
         if let ExprKind::If(_, _, Some(ref els)) = item.kind
             && let ExprKind::If(_, _, None) = els.kind
+            && !in_external_macro(cx.sess(), item.span)
         {
             span_lint_and_help(
                 cx,
diff --git a/clippy_lints/src/empty_enum.rs b/clippy_lints/src/empty_enum.rs
index d16714695cb..1869faab1d3 100644
--- a/clippy_lints/src/empty_enum.rs
+++ b/clippy_lints/src/empty_enum.rs
@@ -64,25 +64,21 @@ declare_lint_pass!(EmptyEnum => [EMPTY_ENUM]);
 
 impl<'tcx> LateLintPass<'tcx> for EmptyEnum {
     fn check_item(&mut self, cx: &LateContext<'_>, item: &Item<'_>) {
-        // Only suggest the `never_type` if the feature is enabled
-        if !cx.tcx.features().never_type {
-            return;
-        }
-
-        if let ItemKind::Enum(..) = item.kind {
-            let ty = cx.tcx.type_of(item.owner_id).instantiate_identity();
-            let adt = ty.ty_adt_def().expect("already checked whether this is an enum");
-            if adt.variants().is_empty() {
-                span_lint_and_help(
-                    cx,
-                    EMPTY_ENUM,
-                    item.span,
-                    "enum with no variants",
-                    None,
-                    "consider using the uninhabited type `!` (never type) or a wrapper \
-                    around it to introduce a type which can't be instantiated",
-                );
-            }
+        if let ItemKind::Enum(..) = item.kind
+            // Only suggest the `never_type` if the feature is enabled
+            && cx.tcx.features().never_type
+            && let Some(adt) = cx.tcx.type_of(item.owner_id).instantiate_identity().ty_adt_def()
+            && adt.variants().is_empty()
+        {
+            span_lint_and_help(
+                cx,
+                EMPTY_ENUM,
+                item.span,
+                "enum with no variants",
+                None,
+                "consider using the uninhabited type `!` (never type) or a wrapper \
+                around it to introduce a type which can't be instantiated",
+            );
         }
     }
 }
diff --git a/clippy_lints/src/endian_bytes.rs b/clippy_lints/src/endian_bytes.rs
index 99328e3e643..5bba9c562b9 100644
--- a/clippy_lints/src/endian_bytes.rs
+++ b/clippy_lints/src/endian_bytes.rs
@@ -109,32 +109,27 @@ impl LintKind {
 
 impl LateLintPass<'_> for EndianBytes {
     fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) {
-        if in_external_macro(cx.sess(), expr.span) {
-            return;
-        }
-
-        if let ExprKind::MethodCall(method_name, receiver, args, ..) = expr.kind
-            && args.is_empty()
-            && let ty = cx.typeck_results().expr_ty(receiver)
+        let (prefix, name, ty_expr) = match expr.kind {
+            ExprKind::MethodCall(method_name, receiver, [], ..) => (Prefix::To, method_name.ident.name, receiver),
+            ExprKind::Call(function, ..)
+                if let ExprKind::Path(qpath) = function.kind
+                    && let Some(def_id) = cx.qpath_res(&qpath, function.hir_id).opt_def_id()
+                    && let Some(function_name) = cx.get_def_path(def_id).last() =>
+            {
+                (Prefix::From, *function_name, expr)
+            },
+            _ => return,
+        };
+        if !in_external_macro(cx.sess(), expr.span)
+            && let ty = cx.typeck_results().expr_ty(ty_expr)
             && ty.is_primitive_ty()
-            && maybe_lint_endian_bytes(cx, expr, Prefix::To, method_name.ident.name, ty)
         {
-            return;
-        }
-
-        if let ExprKind::Call(function, ..) = expr.kind
-            && let ExprKind::Path(qpath) = function.kind
-            && let Some(def_id) = cx.qpath_res(&qpath, function.hir_id).opt_def_id()
-            && let Some(function_name) = cx.get_def_path(def_id).last()
-            && let ty = cx.typeck_results().expr_ty(expr)
-            && ty.is_primitive_ty()
-        {
-            maybe_lint_endian_bytes(cx, expr, Prefix::From, *function_name, ty);
+            maybe_lint_endian_bytes(cx, expr, prefix, name, ty);
         }
     }
 }
 
-fn maybe_lint_endian_bytes(cx: &LateContext<'_>, expr: &Expr<'_>, prefix: Prefix, name: Symbol, ty: Ty<'_>) -> bool {
+fn maybe_lint_endian_bytes(cx: &LateContext<'_>, expr: &Expr<'_>, prefix: Prefix, name: Symbol, ty: Ty<'_>) {
     let ne = LintKind::Host.as_name(prefix);
     let le = LintKind::Little.as_name(prefix);
     let be = LintKind::Big.as_name(prefix);
@@ -143,7 +138,7 @@ fn maybe_lint_endian_bytes(cx: &LateContext<'_>, expr: &Expr<'_>, prefix: Prefix
         name if name == ne => ((&LintKind::Host), [(&LintKind::Little), (&LintKind::Big)]),
         name if name == le => ((&LintKind::Little), [(&LintKind::Host), (&LintKind::Big)]),
         name if name == be => ((&LintKind::Big), [(&LintKind::Host), (&LintKind::Little)]),
-        _ => return false,
+        _ => return,
     };
 
     let mut help = None;
@@ -208,6 +203,4 @@ fn maybe_lint_endian_bytes(cx: &LateContext<'_>, expr: &Expr<'_>, prefix: Prefix
             }
         },
     );
-
-    true
 }
diff --git a/clippy_lints/src/equatable_if_let.rs b/clippy_lints/src/equatable_if_let.rs
index 37442bf3e28..fb9f2b1526e 100644
--- a/clippy_lints/src/equatable_if_let.rs
+++ b/clippy_lints/src/equatable_if_let.rs
@@ -70,9 +70,9 @@ fn is_structural_partial_eq<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>, other: T
 
 impl<'tcx> LateLintPass<'tcx> for PatternEquality {
     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) {
-        if !in_external_macro(cx.sess(), expr.span)
-            && let ExprKind::Let(let_expr) = expr.kind
+        if let ExprKind::Let(let_expr) = expr.kind
             && unary_pattern(let_expr.pat)
+            && !in_external_macro(cx.sess(), expr.span)
         {
             let exp_ty = cx.typeck_results().expr_ty(let_expr.init);
             let pat_ty = cx.typeck_results().pat_ty(let_expr.pat);
diff --git a/clippy_lints/src/error_impl_error.rs b/clippy_lints/src/error_impl_error.rs
index 8e49138cd26..1e6447dc253 100644
--- a/clippy_lints/src/error_impl_error.rs
+++ b/clippy_lints/src/error_impl_error.rs
@@ -36,15 +36,12 @@ declare_lint_pass!(ErrorImplError => [ERROR_IMPL_ERROR]);
 
 impl<'tcx> LateLintPass<'tcx> for ErrorImplError {
     fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'tcx>) {
-        let Some(error_def_id) = cx.tcx.get_diagnostic_item(sym::Error) else {
-            return;
-        };
-
         match item.kind {
             ItemKind::TyAlias(..)
                 if item.ident.name == sym::Error
                     && is_visible_outside_module(cx, item.owner_id.def_id)
                     && let ty = cx.tcx.type_of(item.owner_id).instantiate_identity()
+                    && let Some(error_def_id) = cx.tcx.get_diagnostic_item(sym::Error)
                     && implements_trait(cx, ty, error_def_id, &[]) =>
             {
                 span_lint(
@@ -56,9 +53,9 @@ impl<'tcx> LateLintPass<'tcx> for ErrorImplError {
             },
             ItemKind::Impl(imp)
                 if let Some(trait_def_id) = imp.of_trait.and_then(|t| t.trait_def_id())
+                    && let Some(error_def_id) = cx.tcx.get_diagnostic_item(sym::Error)
                     && error_def_id == trait_def_id
                     && let Some(def_id) = path_res(cx, imp.self_ty).opt_def_id().and_then(DefId::as_local)
-                    && let hir_id = cx.tcx.local_def_id_to_hir_id(def_id)
                     && let Some(ident) = cx.tcx.opt_item_ident(def_id.to_def_id())
                     && ident.name == sym::Error
                     && is_visible_outside_module(cx, def_id) =>
@@ -66,7 +63,7 @@ impl<'tcx> LateLintPass<'tcx> for ErrorImplError {
                 span_lint_hir_and_then(
                     cx,
                     ERROR_IMPL_ERROR,
-                    hir_id,
+                    cx.tcx.local_def_id_to_hir_id(def_id),
                     ident.span,
                     "exported type named `Error` that implements `Error`",
                     |diag| {
diff --git a/clippy_lints/src/escape.rs b/clippy_lints/src/escape.rs
index 8d6e27700d8..a5da52b0be5 100644
--- a/clippy_lints/src/escape.rs
+++ b/clippy_lints/src/escape.rs
@@ -1,3 +1,4 @@
+use clippy_config::Conf;
 use clippy_utils::diagnostics::span_lint_hir;
 use rustc_hir::{intravisit, AssocItemKind, Body, FnDecl, HirId, HirIdSet, Impl, ItemKind, Node, Pat, PatKind};
 use rustc_hir_typeck::expr_use_visitor::{Delegate, ExprUseVisitor, PlaceBase, PlaceWithHirId};
@@ -11,9 +12,16 @@ use rustc_span::symbol::kw;
 use rustc_span::Span;
 use rustc_target::spec::abi::Abi;
 
-#[derive(Copy, Clone)]
 pub struct BoxedLocal {
-    pub too_large_for_stack: u64,
+    too_large_for_stack: u64,
+}
+
+impl BoxedLocal {
+    pub fn new(conf: &'static Conf) -> Self {
+        Self {
+            too_large_for_stack: conf.too_large_for_stack,
+        }
+    }
 }
 
 declare_clippy_lint! {
diff --git a/clippy_lints/src/excessive_bools.rs b/clippy_lints/src/excessive_bools.rs
index 62d5ce24d40..8f469efb1b5 100644
--- a/clippy_lints/src/excessive_bools.rs
+++ b/clippy_lints/src/excessive_bools.rs
@@ -1,3 +1,4 @@
+use clippy_config::Conf;
 use clippy_utils::diagnostics::span_lint_and_help;
 use clippy_utils::{get_parent_as_impl, has_repr_attr, is_bool};
 use rustc_hir::intravisit::FnKind;
@@ -87,69 +88,57 @@ pub struct ExcessiveBools {
     max_fn_params_bools: u64,
 }
 
-#[derive(Eq, PartialEq, Debug, Copy, Clone)]
-enum Kind {
-    Struct,
-    Fn,
-}
-
 impl ExcessiveBools {
-    #[must_use]
-    pub fn new(max_struct_bools: u64, max_fn_params_bools: u64) -> Self {
+    pub fn new(conf: &'static Conf) -> Self {
         Self {
-            max_struct_bools,
-            max_fn_params_bools,
+            max_struct_bools: conf.max_struct_bools,
+            max_fn_params_bools: conf.max_fn_params_bools,
         }
     }
+}
 
-    fn too_many_bools<'tcx>(&self, tys: impl Iterator<Item = &'tcx Ty<'tcx>>, kind: Kind) -> bool {
-        if let Ok(bools) = tys.filter(|ty| is_bool(ty)).count().try_into() {
-            (if Kind::Fn == kind {
-                self.max_fn_params_bools
-            } else {
-                self.max_struct_bools
-            }) < bools
-        } else {
-            false
-        }
-    }
+impl_lint_pass!(ExcessiveBools => [STRUCT_EXCESSIVE_BOOLS, FN_PARAMS_EXCESSIVE_BOOLS]);
 
-    fn check_fn_sig(&self, cx: &LateContext<'_>, fn_decl: &FnDecl<'_>, span: Span) {
-        if !span.from_expansion() && self.too_many_bools(fn_decl.inputs.iter(), Kind::Fn) {
-            span_lint_and_help(
-                cx,
-                FN_PARAMS_EXCESSIVE_BOOLS,
-                span,
-                format!("more than {} bools in function parameters", self.max_fn_params_bools),
-                None,
-                "consider refactoring bools into two-variant enums",
-            );
-        }
-    }
+fn has_n_bools<'tcx>(iter: impl Iterator<Item = &'tcx Ty<'tcx>>, mut count: u64) -> bool {
+    iter.filter(|ty| is_bool(ty)).any(|_| {
+        let (x, overflow) = count.overflowing_sub(1);
+        count = x;
+        overflow
+    })
 }
 
-impl_lint_pass!(ExcessiveBools => [STRUCT_EXCESSIVE_BOOLS, FN_PARAMS_EXCESSIVE_BOOLS]);
+fn check_fn_decl(cx: &LateContext<'_>, decl: &FnDecl<'_>, sp: Span, max: u64) {
+    if has_n_bools(decl.inputs.iter(), max) && !sp.from_expansion() {
+        span_lint_and_help(
+            cx,
+            FN_PARAMS_EXCESSIVE_BOOLS,
+            sp,
+            format!("more than {max} bools in function parameters"),
+            None,
+            "consider refactoring bools into two-variant enums",
+        );
+    }
+}
 
 impl<'tcx> LateLintPass<'tcx> for ExcessiveBools {
     fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'tcx>) {
-        if item.span.from_expansion() {
-            return;
-        }
-        if let ItemKind::Struct(variant_data, _) = &item.kind {
-            if has_repr_attr(cx, item.hir_id()) {
-                return;
-            }
-
-            if self.too_many_bools(variant_data.fields().iter().map(|field| field.ty), Kind::Struct) {
-                span_lint_and_help(
-                    cx,
-                    STRUCT_EXCESSIVE_BOOLS,
-                    item.span,
-                    format!("more than {} bools in a struct", self.max_struct_bools),
-                    None,
-                    "consider using a state machine or refactoring bools into two-variant enums",
-                );
-            }
+        if let ItemKind::Struct(variant_data, _) = &item.kind
+            && variant_data.fields().len() as u64 > self.max_struct_bools
+            && has_n_bools(
+                variant_data.fields().iter().map(|field| field.ty),
+                self.max_struct_bools,
+            )
+            && !has_repr_attr(cx, item.hir_id())
+            && !item.span.from_expansion()
+        {
+            span_lint_and_help(
+                cx,
+                STRUCT_EXCESSIVE_BOOLS,
+                item.span,
+                format!("more than {} bools in a struct", self.max_struct_bools),
+                None,
+                "consider using a state machine or refactoring bools into two-variant enums",
+            );
         }
     }
 
@@ -157,8 +146,9 @@ impl<'tcx> LateLintPass<'tcx> for ExcessiveBools {
         // functions with a body are already checked by `check_fn`
         if let TraitItemKind::Fn(fn_sig, TraitFn::Required(_)) = &trait_item.kind
             && fn_sig.header.abi == Abi::Rust
+            && fn_sig.decl.inputs.len() as u64 > self.max_fn_params_bools
         {
-            self.check_fn_sig(cx, fn_sig.decl, fn_sig.span);
+            check_fn_decl(cx, fn_sig.decl, fn_sig.span, self.max_fn_params_bools);
         }
     }
 
@@ -171,12 +161,13 @@ impl<'tcx> LateLintPass<'tcx> for ExcessiveBools {
         span: Span,
         def_id: LocalDefId,
     ) {
-        let hir_id = cx.tcx.local_def_id_to_hir_id(def_id);
         if let Some(fn_header) = fn_kind.header()
             && fn_header.abi == Abi::Rust
-            && get_parent_as_impl(cx.tcx, hir_id).map_or(true, |impl_item| impl_item.of_trait.is_none())
+            && fn_decl.inputs.len() as u64 > self.max_fn_params_bools
+            && get_parent_as_impl(cx.tcx, cx.tcx.local_def_id_to_hir_id(def_id))
+                .map_or(true, |impl_item| impl_item.of_trait.is_none())
         {
-            self.check_fn_sig(cx, fn_decl, span);
+            check_fn_decl(cx, fn_decl, span, self.max_fn_params_bools);
         }
     }
 }
diff --git a/clippy_lints/src/excessive_nesting.rs b/clippy_lints/src/excessive_nesting.rs
index 4b0d11c5d1b..5154edd4399 100644
--- a/clippy_lints/src/excessive_nesting.rs
+++ b/clippy_lints/src/excessive_nesting.rs
@@ -1,3 +1,4 @@
+use clippy_config::Conf;
 use clippy_utils::diagnostics::span_lint_and_help;
 use clippy_utils::source::snippet;
 use rustc_ast::node_id::NodeSet;
@@ -63,13 +64,19 @@ declare_clippy_lint! {
 }
 impl_lint_pass!(ExcessiveNesting => [EXCESSIVE_NESTING]);
 
-#[derive(Clone)]
 pub struct ExcessiveNesting {
     pub excessive_nesting_threshold: u64,
     pub nodes: NodeSet,
 }
 
 impl ExcessiveNesting {
+    pub fn new(conf: &'static Conf) -> Self {
+        Self {
+            excessive_nesting_threshold: conf.excessive_nesting_threshold,
+            nodes: NodeSet::default(),
+        }
+    }
+
     pub fn check_node_id(&self, cx: &EarlyContext<'_>, span: Span, node_id: NodeId) {
         if self.nodes.contains(&node_id) {
             span_lint_and_help(
diff --git a/clippy_lints/src/exhaustive_items.rs b/clippy_lints/src/exhaustive_items.rs
index 436dc8611bd..0f4176ec73b 100644
--- a/clippy_lints/src/exhaustive_items.rs
+++ b/clippy_lints/src/exhaustive_items.rs
@@ -70,20 +70,24 @@ declare_lint_pass!(ExhaustiveItems => [EXHAUSTIVE_ENUMS, EXHAUSTIVE_STRUCTS]);
 
 impl LateLintPass<'_> for ExhaustiveItems {
     fn check_item(&mut self, cx: &LateContext<'_>, item: &Item<'_>) {
-        if let ItemKind::Enum(..) | ItemKind::Struct(..) = item.kind
-            && cx.effective_visibilities.is_exported(item.owner_id.def_id)
+        let (lint, msg, fields) = match item.kind {
+            ItemKind::Enum(..) => (
+                EXHAUSTIVE_ENUMS,
+                "exported enums should not be exhaustive",
+                [].as_slice(),
+            ),
+            ItemKind::Struct(v, ..) => (
+                EXHAUSTIVE_STRUCTS,
+                "exported structs should not be exhaustive",
+                v.fields(),
+            ),
+            _ => return,
+        };
+        if cx.effective_visibilities.is_exported(item.owner_id.def_id)
             && let attrs = cx.tcx.hir().attrs(item.hir_id())
             && !attrs.iter().any(|a| a.has_name(sym::non_exhaustive))
+            && fields.iter().all(|f| cx.tcx.visibility(f.def_id).is_public())
         {
-            let (lint, msg) = if let ItemKind::Struct(ref v, ..) = item.kind {
-                if v.fields().iter().any(|f| !cx.tcx.visibility(f.def_id).is_public()) {
-                    // skip structs with private fields
-                    return;
-                }
-                (EXHAUSTIVE_STRUCTS, "exported structs should not be exhaustive")
-            } else {
-                (EXHAUSTIVE_ENUMS, "exported enums should not be exhaustive")
-            };
             let suggestion_span = item.span.shrink_to_lo();
             let indent = " ".repeat(indent_of(cx, item.span).unwrap_or(0));
             span_lint_and_then(cx, lint, item.span, msg, |diag| {
diff --git a/clippy_lints/src/exit.rs b/clippy_lints/src/exit.rs
index 91c94d66458..f37d11f7eb9 100644
--- a/clippy_lints/src/exit.rs
+++ b/clippy_lints/src/exit.rs
@@ -1,6 +1,6 @@
 use clippy_utils::diagnostics::span_lint;
 use clippy_utils::is_entrypoint_fn;
-use rustc_hir::{Expr, ExprKind, Item, ItemKind, Node};
+use rustc_hir::{Expr, ExprKind, Item, ItemKind, OwnerNode};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_session::declare_lint_pass;
 use rustc_span::sym;
@@ -47,8 +47,8 @@ impl<'tcx> LateLintPass<'tcx> for Exit {
             && let ExprKind::Path(ref path) = path_expr.kind
             && let Some(def_id) = cx.qpath_res(path, path_expr.hir_id).opt_def_id()
             && cx.tcx.is_diagnostic_item(sym::process_exit, def_id)
-            && let parent = cx.tcx.hir().get_parent_item(e.hir_id).def_id
-            && let Node::Item(Item{kind: ItemKind::Fn(..), ..}) = cx.tcx.hir_node_by_def_id(parent)
+            && let parent = cx.tcx.hir().get_parent_item(e.hir_id)
+            && let OwnerNode::Item(Item{kind: ItemKind::Fn(..), ..}) = cx.tcx.hir_owner_node(parent)
             // If the next item up is a function we check if it is an entry point
             // and only then emit a linter warning
             && !is_entrypoint_fn(cx, parent.to_def_id())
diff --git a/clippy_lints/src/extra_unused_type_parameters.rs b/clippy_lints/src/extra_unused_type_parameters.rs
index 7484f772e08..bfe4e253ae4 100644
--- a/clippy_lints/src/extra_unused_type_parameters.rs
+++ b/clippy_lints/src/extra_unused_type_parameters.rs
@@ -1,3 +1,4 @@
+use clippy_config::Conf;
 use clippy_utils::diagnostics::{span_lint_and_help, span_lint_and_then};
 use clippy_utils::{is_from_proc_macro, trait_ref_of_method};
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
@@ -45,26 +46,11 @@ pub struct ExtraUnusedTypeParameters {
 }
 
 impl ExtraUnusedTypeParameters {
-    pub fn new(avoid_breaking_exported_api: bool) -> Self {
+    pub fn new(conf: &'static Conf) -> Self {
         Self {
-            avoid_breaking_exported_api,
+            avoid_breaking_exported_api: conf.avoid_breaking_exported_api,
         }
     }
-
-    /// Don't lint external macros or functions with empty bodies. Also, don't lint exported items
-    /// if the `avoid_breaking_exported_api` config option is set.
-    fn is_empty_exported_or_macro(
-        &self,
-        cx: &LateContext<'_>,
-        span: Span,
-        def_id: LocalDefId,
-        body_id: BodyId,
-    ) -> bool {
-        let body = cx.tcx.hir().body(body_id).value;
-        let fn_empty = matches!(&body.kind, ExprKind::Block(blk, None) if blk.stmts.is_empty() && blk.expr.is_none());
-        let is_exported = cx.effective_visibilities.is_exported(def_id);
-        in_external_macro(cx.sess(), span) || fn_empty || (is_exported && self.avoid_breaking_exported_api)
-    }
 }
 
 impl_lint_pass!(ExtraUnusedTypeParameters => [EXTRA_UNUSED_TYPE_PARAMETERS]);
@@ -266,10 +252,17 @@ impl<'cx, 'tcx> Visitor<'tcx> for TypeWalker<'cx, 'tcx> {
     }
 }
 
+fn is_empty_body(cx: &LateContext<'_>, body: BodyId) -> bool {
+    matches!(cx.tcx.hir().body(body).value.kind, ExprKind::Block(b, _) if b.stmts.is_empty() && b.expr.is_none())
+}
+
 impl<'tcx> LateLintPass<'tcx> for ExtraUnusedTypeParameters {
     fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'tcx>) {
         if let ItemKind::Fn(_, generics, body_id) = item.kind
-            && !self.is_empty_exported_or_macro(cx, item.span, item.owner_id.def_id, body_id)
+            && !generics.params.is_empty()
+            && !is_empty_body(cx, body_id)
+            && (!self.avoid_breaking_exported_api || !cx.effective_visibilities.is_exported(item.owner_id.def_id))
+            && !in_external_macro(cx.sess(), item.span)
             && !is_from_proc_macro(cx, item)
         {
             let mut walker = TypeWalker::new(cx, generics);
@@ -281,8 +274,12 @@ impl<'tcx> LateLintPass<'tcx> for ExtraUnusedTypeParameters {
     fn check_impl_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx ImplItem<'tcx>) {
         // Only lint on inherent methods, not trait methods.
         if let ImplItemKind::Fn(.., body_id) = item.kind
+            && !item.generics.params.is_empty()
             && trait_ref_of_method(cx, item.owner_id.def_id).is_none()
-            && !self.is_empty_exported_or_macro(cx, item.span, item.owner_id.def_id, body_id)
+            && !is_empty_body(cx, body_id)
+            && (!self.avoid_breaking_exported_api || !cx.effective_visibilities.is_exported(item.owner_id.def_id))
+            && !in_external_macro(cx.sess(), item.span)
+            && !is_from_proc_macro(cx, item)
         {
             let mut walker = TypeWalker::new(cx, item.generics);
             walk_impl_item(&mut walker, item);
diff --git a/clippy_lints/src/float_literal.rs b/clippy_lints/src/float_literal.rs
index 2261fcdbdab..6adcd2235dc 100644
--- a/clippy_lints/src/float_literal.rs
+++ b/clippy_lints/src/float_literal.rs
@@ -62,10 +62,9 @@ declare_lint_pass!(FloatLiteral => [EXCESSIVE_PRECISION, LOSSY_FLOAT_LITERAL]);
 
 impl<'tcx> LateLintPass<'tcx> for FloatLiteral {
     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>) {
-        let ty = cx.typeck_results().expr_ty(expr);
-        if let ty::Float(fty) = *ty.kind()
-            && let hir::ExprKind::Lit(lit) = expr.kind
+        if let hir::ExprKind::Lit(lit) = expr.kind
             && let LitKind::Float(sym, lit_float_ty) = lit.node
+            && let ty::Float(fty) = *cx.typeck_results().expr_ty(expr).kind()
         {
             let sym_str = sym.as_str();
             let formatter = FloatFormat::new(sym_str);
diff --git a/clippy_lints/src/format_args.rs b/clippy_lints/src/format_args.rs
index 99def199af0..a31d5cb6ec7 100644
--- a/clippy_lints/src/format_args.rs
+++ b/clippy_lints/src/format_args.rs
@@ -1,5 +1,6 @@
 use arrayvec::ArrayVec;
 use clippy_config::msrvs::{self, Msrv};
+use clippy_config::Conf;
 use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then};
 use clippy_utils::is_diag_trait_item;
 use clippy_utils::macros::{
@@ -175,12 +176,11 @@ pub struct FormatArgs {
 }
 
 impl FormatArgs {
-    #[must_use]
-    pub fn new(format_args: FormatArgsStorage, msrv: Msrv, allow_mixed_uninlined_format_args: bool) -> Self {
+    pub fn new(conf: &'static Conf, format_args: FormatArgsStorage) -> Self {
         Self {
             format_args,
-            msrv,
-            ignore_mixed: allow_mixed_uninlined_format_args,
+            msrv: conf.msrv.clone(),
+            ignore_mixed: conf.allow_mixed_uninlined_format_args,
         }
     }
 }
diff --git a/clippy_lints/src/format_impl.rs b/clippy_lints/src/format_impl.rs
index 09be7237b5c..e6f27cb82d1 100644
--- a/clippy_lints/src/format_impl.rs
+++ b/clippy_lints/src/format_impl.rs
@@ -97,7 +97,6 @@ struct FormatTraitNames {
     formatter_name: Option<Symbol>,
 }
 
-#[derive(Default)]
 pub struct FormatImpl {
     format_args: FormatArgsStorage,
     // Whether we are inside Display or Debug trait impl - None for neither
diff --git a/clippy_lints/src/from_over_into.rs b/clippy_lints/src/from_over_into.rs
index 1933a00891b..b6c8437fb8f 100644
--- a/clippy_lints/src/from_over_into.rs
+++ b/clippy_lints/src/from_over_into.rs
@@ -1,4 +1,5 @@
 use clippy_config::msrvs::{self, Msrv};
+use clippy_config::Conf;
 use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::macros::span_is_local;
 use clippy_utils::path_def_id;
@@ -54,9 +55,10 @@ pub struct FromOverInto {
 }
 
 impl FromOverInto {
-    #[must_use]
-    pub fn new(msrv: Msrv) -> Self {
-        FromOverInto { msrv }
+    pub fn new(conf: &'static Conf) -> Self {
+        FromOverInto {
+            msrv: conf.msrv.clone(),
+        }
     }
 }
 
@@ -64,10 +66,6 @@ impl_lint_pass!(FromOverInto => [FROM_OVER_INTO]);
 
 impl<'tcx> LateLintPass<'tcx> for FromOverInto {
     fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) {
-        if !self.msrv.meets(msrvs::RE_REBALANCING_COHERENCE) || !span_is_local(item.span) {
-            return;
-        }
-
         if let ItemKind::Impl(Impl {
             of_trait: Some(hir_trait_ref),
             self_ty,
@@ -77,6 +75,8 @@ impl<'tcx> LateLintPass<'tcx> for FromOverInto {
             && let Some(into_trait_seg) = hir_trait_ref.path.segments.last()
             // `impl Into<target_ty> for self_ty`
             && let Some(GenericArgs { args: [GenericArg::Type(target_ty)], .. }) = into_trait_seg.args
+            && self.msrv.meets(msrvs::RE_REBALANCING_COHERENCE)
+            && span_is_local(item.span)
             && let Some(middle_trait_ref) = cx.tcx.impl_trait_ref(item.owner_id)
                                                   .map(ty::EarlyBinder::instantiate_identity)
             && cx.tcx.is_diagnostic_item(sym::Into, middle_trait_ref.def_id)
@@ -181,6 +181,9 @@ fn convert_to_from(
     let from = snippet_opt(cx, self_ty.span)?;
     let into = snippet_opt(cx, target_ty.span)?;
 
+    let return_type = matches!(sig.decl.output, FnRetTy::Return(_))
+        .then_some(String::from("Self"))
+        .unwrap_or_default();
     let mut suggestions = vec![
         // impl Into<T> for U  ->  impl From<T> for U
         //      ~~~~                    ~~~~
@@ -197,13 +200,10 @@ fn convert_to_from(
         // fn into([mut] self) -> T  ->  fn into([mut] v: T) -> T
         //               ~~~~                          ~~~~
         (self_ident.span, format!("val: {from}")),
-    ];
-
-    if let FnRetTy::Return(_) = sig.decl.output {
         // fn into(self) -> T  ->  fn into(self) -> Self
         //                  ~                       ~~~~
-        suggestions.push((sig.decl.output.span(), String::from("Self")));
-    }
+        (sig.decl.output.span(), return_type),
+    ];
 
     let mut finder = SelfFinder {
         cx,
diff --git a/clippy_lints/src/from_str_radix_10.rs b/clippy_lints/src/from_str_radix_10.rs
index 82ce501bac5..9acb72b2e37 100644
--- a/clippy_lints/src/from_str_radix_10.rs
+++ b/clippy_lints/src/from_str_radix_10.rs
@@ -47,9 +47,13 @@ impl<'tcx> LateLintPass<'tcx> for FromStrRadix10 {
     fn check_expr(&mut self, cx: &LateContext<'tcx>, exp: &Expr<'tcx>) {
         if let ExprKind::Call(maybe_path, [src, radix]) = &exp.kind
             && let ExprKind::Path(QPath::TypeRelative(ty, pathseg)) = &maybe_path.kind
-            // do not lint in constant context, because the suggestion won't work.
-            // NB: keep this check until a new `const_trait_impl` is available and stablized.
-            && !in_constant(cx, exp.hir_id)
+
+            // check if the second argument is a primitive `10`
+            && is_integer_literal(radix, 10)
+
+            // check if the second part of the path indeed calls the associated
+            // function `from_str_radix`
+            && pathseg.ident.name.as_str() == "from_str_radix"
 
             // check if the first part of the path is some integer primitive
             && let TyKind::Path(ty_qpath) = &ty.kind
@@ -57,12 +61,9 @@ impl<'tcx> LateLintPass<'tcx> for FromStrRadix10 {
             && let def::Res::PrimTy(prim_ty) = ty_res
             && matches!(prim_ty, PrimTy::Int(_) | PrimTy::Uint(_))
 
-            // check if the second part of the path indeed calls the associated
-            // function `from_str_radix`
-            && pathseg.ident.name.as_str() == "from_str_radix"
-
-            // check if the second argument is a primitive `10`
-            && is_integer_literal(radix, 10)
+            // do not lint in constant context, because the suggestion won't work.
+            // NB: keep this check until a new `const_trait_impl` is available and stablized.
+            && !in_constant(cx, exp.hir_id)
         {
             let expr = if let ExprKind::AddrOf(_, _, expr) = &src.kind {
                 let ty = cx.typeck_results().expr_ty(expr);
diff --git a/clippy_lints/src/functions/mod.rs b/clippy_lints/src/functions/mod.rs
index 26534492ddd..0f48941783b 100644
--- a/clippy_lints/src/functions/mod.rs
+++ b/clippy_lints/src/functions/mod.rs
@@ -7,10 +7,12 @@ mod result;
 mod too_many_arguments;
 mod too_many_lines;
 
+use clippy_config::Conf;
 use clippy_utils::def_path_def_ids;
 use rustc_hir as hir;
 use rustc_hir::intravisit;
 use rustc_lint::{LateContext, LateLintPass};
+use rustc_middle::ty::TyCtxt;
 use rustc_session::impl_lint_pass;
 use rustc_span::def_id::{DefIdSet, LocalDefId};
 use rustc_span::Span;
@@ -391,39 +393,34 @@ declare_clippy_lint! {
     ///     }
     /// }
     /// ```
-    #[clippy::version = "1.74.0"]
+    #[clippy::version = "1.80.0"]
     pub RENAMED_FUNCTION_PARAMS,
     restriction,
     "renamed function parameters in trait implementation"
 }
 
-#[derive(Clone)]
 pub struct Functions {
     too_many_arguments_threshold: u64,
     too_many_lines_threshold: u64,
     large_error_threshold: u64,
     avoid_breaking_exported_api: bool,
-    allow_renamed_params_for: Vec<String>,
     /// A set of resolved `def_id` of traits that are configured to allow
     /// function params renaming.
     trait_ids: DefIdSet,
 }
 
 impl Functions {
-    pub fn new(
-        too_many_arguments_threshold: u64,
-        too_many_lines_threshold: u64,
-        large_error_threshold: u64,
-        avoid_breaking_exported_api: bool,
-        allow_renamed_params_for: Vec<String>,
-    ) -> Self {
+    pub fn new(tcx: TyCtxt<'_>, conf: &'static Conf) -> Self {
         Self {
-            too_many_arguments_threshold,
-            too_many_lines_threshold,
-            large_error_threshold,
-            avoid_breaking_exported_api,
-            allow_renamed_params_for,
-            trait_ids: DefIdSet::default(),
+            too_many_arguments_threshold: conf.too_many_arguments_threshold,
+            too_many_lines_threshold: conf.too_many_lines_threshold,
+            large_error_threshold: conf.large_error_threshold,
+            avoid_breaking_exported_api: conf.avoid_breaking_exported_api,
+            trait_ids: conf
+                .allow_renamed_params_for
+                .iter()
+                .flat_map(|p| def_path_def_ids(tcx, &p.split("::").collect::<Vec<_>>()))
+                .collect(),
         }
     }
 }
@@ -479,12 +476,4 @@ impl<'tcx> LateLintPass<'tcx> for Functions {
         result::check_trait_item(cx, item, self.large_error_threshold);
         impl_trait_in_params::check_trait_item(cx, item, self.avoid_breaking_exported_api);
     }
-
-    fn check_crate(&mut self, cx: &LateContext<'tcx>) {
-        for path in &self.allow_renamed_params_for {
-            let path_segments: Vec<&str> = path.split("::").collect();
-            let ids = def_path_def_ids(cx, &path_segments);
-            self.trait_ids.extend(ids);
-        }
-    }
 }
diff --git a/clippy_lints/src/future_not_send.rs b/clippy_lints/src/future_not_send.rs
index e6506709774..9488ba75686 100644
--- a/clippy_lints/src/future_not_send.rs
+++ b/clippy_lints/src/future_not_send.rs
@@ -66,15 +66,11 @@ impl<'tcx> LateLintPass<'tcx> for FutureNotSend {
         let ret_ty = return_ty(cx, cx.tcx.local_def_id_to_hir_id(fn_def_id).expect_owner());
         if let ty::Alias(ty::Opaque, AliasTy { def_id, args, .. }) = *ret_ty.kind() {
             let preds = cx.tcx.explicit_item_super_predicates(def_id);
-            let mut is_future = false;
-            for (p, _span) in preds.iter_instantiated_copied(cx.tcx, args) {
-                if let Some(trait_pred) = p.as_trait_clause() {
-                    if Some(trait_pred.skip_binder().trait_ref.def_id) == cx.tcx.lang_items().future_trait() {
-                        is_future = true;
-                        break;
-                    }
-                }
-            }
+            let is_future = preds.iter_instantiated_copied(cx.tcx, args).any(|(p, _)| {
+                p.as_trait_clause().is_some_and(|trait_pred| {
+                    Some(trait_pred.skip_binder().trait_ref.def_id) == cx.tcx.lang_items().future_trait()
+                })
+            });
             if is_future {
                 let send_trait = cx.tcx.get_diagnostic_item(sym::Send).unwrap();
                 let span = decl.output.span();
diff --git a/clippy_lints/src/if_let_mutex.rs b/clippy_lints/src/if_let_mutex.rs
index a55836a972f..b38cc7b36a1 100644
--- a/clippy_lints/src/if_let_mutex.rs
+++ b/clippy_lints/src/if_let_mutex.rs
@@ -1,8 +1,9 @@
 use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::ty::is_type_diagnostic_item;
+use clippy_utils::visitors::for_each_expr_without_closures;
 use clippy_utils::{higher, SpanlessEq};
+use core::ops::ControlFlow;
 use rustc_errors::Diag;
-use rustc_hir::intravisit::{self as visit, Visitor};
 use rustc_hir::{Expr, ExprKind};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_session::declare_lint_pass;
@@ -44,8 +45,6 @@ declare_lint_pass!(IfLetMutex => [IF_LET_MUTEX]);
 
 impl<'tcx> LateLintPass<'tcx> for IfLetMutex {
     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) {
-        let mut arm_visit = ArmVisitor { found_mutex: None, cx };
-        let mut op_visit = OppVisitor { found_mutex: None, cx };
         if let Some(higher::IfLet {
             let_expr,
             if_then,
@@ -53,12 +52,20 @@ impl<'tcx> LateLintPass<'tcx> for IfLetMutex {
             ..
         }) = higher::IfLet::hir(cx, expr)
         {
-            op_visit.visit_expr(let_expr);
-            if let Some(op_mutex) = op_visit.found_mutex {
-                arm_visit.visit_expr(if_then);
-                arm_visit.visit_expr(if_else);
+            let is_mutex_lock = |e: &'tcx Expr<'tcx>| {
+                if let Some(mutex) = is_mutex_lock_call(cx, e) {
+                    ControlFlow::Break(mutex)
+                } else {
+                    ControlFlow::Continue(())
+                }
+            };
 
-                if let Some(arm_mutex) = arm_visit.found_mutex_if_same_as(op_mutex) {
+            let op_mutex = for_each_expr_without_closures(let_expr, is_mutex_lock);
+            if let Some(op_mutex) = op_mutex {
+                let arm_mutex = for_each_expr_without_closures((if_then, if_else), is_mutex_lock);
+                if let Some(arm_mutex) = arm_mutex
+                    && SpanlessEq::new(cx).eq_expr(op_mutex, arm_mutex)
+                {
                     let diag = |diag: &mut Diag<'_, ()>| {
                         diag.span_label(
                             op_mutex.span,
@@ -83,48 +90,6 @@ impl<'tcx> LateLintPass<'tcx> for IfLetMutex {
     }
 }
 
-/// Checks if `Mutex::lock` is called in the `if let` expr.
-pub struct OppVisitor<'a, 'tcx> {
-    found_mutex: Option<&'tcx Expr<'tcx>>,
-    cx: &'a LateContext<'tcx>,
-}
-
-impl<'tcx> Visitor<'tcx> for OppVisitor<'_, 'tcx> {
-    fn visit_expr(&mut self, expr: &'tcx Expr<'_>) {
-        if let Some(mutex) = is_mutex_lock_call(self.cx, expr) {
-            self.found_mutex = Some(mutex);
-            return;
-        }
-        visit::walk_expr(self, expr);
-    }
-}
-
-/// Checks if `Mutex::lock` is called in any of the branches.
-pub struct ArmVisitor<'a, 'tcx> {
-    found_mutex: Option<&'tcx Expr<'tcx>>,
-    cx: &'a LateContext<'tcx>,
-}
-
-impl<'tcx> Visitor<'tcx> for ArmVisitor<'_, 'tcx> {
-    fn visit_expr(&mut self, expr: &'tcx Expr<'tcx>) {
-        if let Some(mutex) = is_mutex_lock_call(self.cx, expr) {
-            self.found_mutex = Some(mutex);
-            return;
-        }
-        visit::walk_expr(self, expr);
-    }
-}
-
-impl<'tcx, 'l> ArmVisitor<'tcx, 'l> {
-    fn found_mutex_if_same_as(&self, op_mutex: &Expr<'_>) -> Option<&Expr<'_>> {
-        self.found_mutex.and_then(|arm_mutex| {
-            SpanlessEq::new(self.cx)
-                .eq_expr(op_mutex, arm_mutex)
-                .then_some(arm_mutex)
-        })
-    }
-}
-
 fn is_mutex_lock_call<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> Option<&'tcx Expr<'tcx>> {
     if let ExprKind::MethodCall(path, self_arg, ..) = &expr.kind
         && path.ident.as_str() == "lock"
diff --git a/clippy_lints/src/if_not_else.rs b/clippy_lints/src/if_not_else.rs
index 4dc1ff83771..2f6daeeb90d 100644
--- a/clippy_lints/src/if_not_else.rs
+++ b/clippy_lints/src/if_not_else.rs
@@ -56,44 +56,33 @@ fn is_zero_const(expr: &Expr<'_>, cx: &LateContext<'_>) -> bool {
 }
 
 impl LateLintPass<'_> for IfNotElse {
-    fn check_expr(&mut self, cx: &LateContext<'_>, item: &Expr<'_>) {
-        // While loops will be desugared to ExprKind::If. This will cause the lint to fire.
-        // To fix this, return early if this span comes from a macro or desugaring.
-        if item.span.from_expansion() {
-            return;
-        }
-        if let ExprKind::If(cond, _, Some(els)) = item.kind {
-            if let ExprKind::Block(..) = els.kind {
-                // Disable firing the lint in "else if" expressions.
-                if is_else_clause(cx.tcx, item) {
-                    return;
-                }
+    fn check_expr(&mut self, cx: &LateContext<'_>, e: &Expr<'_>) {
+        if let ExprKind::If(cond, _, Some(els)) = e.kind
+            && let ExprKind::DropTemps(cond) = cond.kind
+            && let ExprKind::Block(..) = els.kind
+        {
+            let (msg, help) = match cond.kind {
+                ExprKind::Unary(UnOp::Not, _) => (
+                    "unnecessary boolean `not` operation",
+                    "remove the `!` and swap the blocks of the `if`/`else`",
+                ),
+                // Don't lint on `… != 0`, as these are likely to be bit tests.
+                // For example, `if foo & 0x0F00 != 0 { … } else { … }` is already in the "proper" order.
+                ExprKind::Binary(op, _, rhs) if op.node == BinOpKind::Ne && !is_zero_const(rhs, cx) => (
+                    "unnecessary `!=` operation",
+                    "change to `==` and swap the blocks of the `if`/`else`",
+                ),
+                _ => return,
+            };
 
-                match cond.peel_drop_temps().kind {
-                    ExprKind::Unary(UnOp::Not, _) => {
-                        span_lint_and_help(
-                            cx,
-                            IF_NOT_ELSE,
-                            item.span,
-                            "unnecessary boolean `not` operation",
-                            None,
-                            "remove the `!` and swap the blocks of the `if`/`else`",
-                        );
-                    },
-                    ExprKind::Binary(ref kind, _, lhs) if kind.node == BinOpKind::Ne && !is_zero_const(lhs, cx) => {
-                        // Disable firing the lint on `… != 0`, as these are likely to be bit tests.
-                        // For example, `if foo & 0x0F00 != 0 { … } else { … }` already is in the "proper" order.
-                        span_lint_and_help(
-                            cx,
-                            IF_NOT_ELSE,
-                            item.span,
-                            "unnecessary `!=` operation",
-                            None,
-                            "change to `==` and swap the blocks of the `if`/`else`",
-                        );
-                    },
-                    _ => (),
-                }
+            // `from_expansion` will also catch `while` loops which appear in the HIR as:
+            // ```rust
+            // loop {
+            //     if cond { ... } else { break; }
+            // }
+            // ```
+            if !e.span.from_expansion() && !is_else_clause(cx.tcx, e) {
+                span_lint_and_help(cx, IF_NOT_ELSE, e.span, msg, None, help);
             }
         }
     }
diff --git a/clippy_lints/src/if_then_some_else_none.rs b/clippy_lints/src/if_then_some_else_none.rs
index 0b200815219..39ea16b05d1 100644
--- a/clippy_lints/src/if_then_some_else_none.rs
+++ b/clippy_lints/src/if_then_some_else_none.rs
@@ -1,4 +1,5 @@
 use clippy_config::msrvs::{self, Msrv};
+use clippy_config::Conf;
 use clippy_utils::diagnostics::span_lint_and_help;
 use clippy_utils::eager_or_lazy::switch_to_eager_eval;
 use clippy_utils::source::snippet_with_context;
@@ -51,9 +52,10 @@ pub struct IfThenSomeElseNone {
 }
 
 impl IfThenSomeElseNone {
-    #[must_use]
-    pub fn new(msrv: Msrv) -> Self {
-        Self { msrv }
+    pub fn new(conf: &'static Conf) -> Self {
+        Self {
+            msrv: conf.msrv.clone(),
+        }
     }
 }
 
@@ -61,26 +63,6 @@ impl_lint_pass!(IfThenSomeElseNone => [IF_THEN_SOME_ELSE_NONE]);
 
 impl<'tcx> LateLintPass<'tcx> for IfThenSomeElseNone {
     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) {
-        if !self.msrv.meets(msrvs::BOOL_THEN) {
-            return;
-        }
-
-        if in_external_macro(cx.sess(), expr.span) {
-            return;
-        }
-
-        // We only care about the top-most `if` in the chain
-        if is_else_clause(cx.tcx, expr) {
-            return;
-        }
-
-        // `bool::then()` and `bool::then_some()` are not const
-        if in_constant(cx, expr.hir_id) {
-            return;
-        }
-
-        let ctxt = expr.span.ctxt();
-
         if let Some(higher::If {
             cond,
             then,
@@ -89,9 +71,14 @@ impl<'tcx> LateLintPass<'tcx> for IfThenSomeElseNone {
             && let ExprKind::Block(then_block, _) = then.kind
             && let Some(then_expr) = then_block.expr
             && let ExprKind::Call(then_call, [then_arg]) = then_expr.kind
+            && let ctxt = expr.span.ctxt()
             && then_expr.span.ctxt() == ctxt
             && is_res_lang_ctor(cx, path_res(cx, then_call), OptionSome)
             && is_res_lang_ctor(cx, path_res(cx, peel_blocks(els)), OptionNone)
+            && !is_else_clause(cx.tcx, expr)
+            && !in_constant(cx, expr.hir_id)
+            && !in_external_macro(cx.sess(), expr.span)
+            && self.msrv.meets(msrvs::BOOL_THEN)
             && !contains_return(then_block.stmts)
         {
             let mut app = Applicability::Unspecified;
diff --git a/clippy_lints/src/ignored_unit_patterns.rs b/clippy_lints/src/ignored_unit_patterns.rs
index a32201d8079..54b8adbc8ac 100644
--- a/clippy_lints/src/ignored_unit_patterns.rs
+++ b/clippy_lints/src/ignored_unit_patterns.rs
@@ -37,22 +37,21 @@ declare_lint_pass!(IgnoredUnitPatterns => [IGNORED_UNIT_PATTERNS]);
 
 impl<'tcx> LateLintPass<'tcx> for IgnoredUnitPatterns {
     fn check_pat(&mut self, cx: &LateContext<'tcx>, pat: &'tcx hir::Pat<'tcx>) {
-        if pat.span.from_expansion() {
-            return;
-        }
-
-        match cx.tcx.parent_hir_node(pat.hir_id) {
-            Node::Param(param) if matches!(cx.tcx.parent_hir_node(param.hir_id), Node::Item(_)) => {
-                // Ignore function parameters
-                return;
-            },
-            Node::LetStmt(local) if local.ty.is_some() => {
-                // Ignore let bindings with explicit type
-                return;
-            },
-            _ => {},
-        }
-        if matches!(pat.kind, PatKind::Wild) && cx.typeck_results().pat_ty(pat).peel_refs().is_unit() {
+        if matches!(pat.kind, PatKind::Wild)
+            && !pat.span.from_expansion()
+            && cx.typeck_results().pat_ty(pat).peel_refs().is_unit()
+        {
+            match cx.tcx.parent_hir_node(pat.hir_id) {
+                Node::Param(param) if matches!(cx.tcx.parent_hir_node(param.hir_id), Node::Item(_)) => {
+                    // Ignore function parameters
+                    return;
+                },
+                Node::LetStmt(local) if local.ty.is_some() => {
+                    // Ignore let bindings with explicit type
+                    return;
+                },
+                _ => {},
+            }
             span_lint_and_sugg(
                 cx,
                 IGNORED_UNIT_PATTERNS,
diff --git a/clippy_lints/src/incompatible_msrv.rs b/clippy_lints/src/incompatible_msrv.rs
index 5c63d48adaf..12ca6d43b27 100644
--- a/clippy_lints/src/incompatible_msrv.rs
+++ b/clippy_lints/src/incompatible_msrv.rs
@@ -1,4 +1,5 @@
 use clippy_config::msrvs::Msrv;
+use clippy_config::Conf;
 use clippy_utils::diagnostics::span_lint;
 use clippy_utils::is_in_test;
 use rustc_attr::{StabilityLevel, StableSince};
@@ -47,9 +48,9 @@ pub struct IncompatibleMsrv {
 impl_lint_pass!(IncompatibleMsrv => [INCOMPATIBLE_MSRV]);
 
 impl IncompatibleMsrv {
-    pub fn new(msrv: Msrv) -> Self {
+    pub fn new(conf: &'static Conf) -> Self {
         Self {
-            msrv,
+            msrv: conf.msrv.clone(),
             is_above_msrv: FxHashMap::default(),
         }
     }
diff --git a/clippy_lints/src/inconsistent_struct_constructor.rs b/clippy_lints/src/inconsistent_struct_constructor.rs
index 1075975f0a2..5b0aadf35c6 100644
--- a/clippy_lints/src/inconsistent_struct_constructor.rs
+++ b/clippy_lints/src/inconsistent_struct_constructor.rs
@@ -65,13 +65,13 @@ declare_lint_pass!(InconsistentStructConstructor => [INCONSISTENT_STRUCT_CONSTRU
 
 impl<'tcx> LateLintPass<'tcx> for InconsistentStructConstructor {
     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>) {
-        if !expr.span.from_expansion()
-            && let ExprKind::Struct(qpath, fields, base) = expr.kind
+        if let ExprKind::Struct(qpath, fields, base) = expr.kind
+            && fields.iter().all(|f| f.is_shorthand)
+            && !expr.span.from_expansion()
             && let ty = cx.typeck_results().expr_ty(expr)
             && let Some(adt_def) = ty.ty_adt_def()
             && adt_def.is_struct()
             && let Some(variant) = adt_def.variants().iter().next()
-            && fields.iter().all(|f| f.is_shorthand)
         {
             let mut def_order_map = FxHashMap::default();
             for (idx, field) in variant.fields.iter().enumerate() {
diff --git a/clippy_lints/src/index_refutable_slice.rs b/clippy_lints/src/index_refutable_slice.rs
index 128461ce7bc..526b4e1fba0 100644
--- a/clippy_lints/src/index_refutable_slice.rs
+++ b/clippy_lints/src/index_refutable_slice.rs
@@ -1,4 +1,5 @@
 use clippy_config::msrvs::{self, Msrv};
+use clippy_config::Conf;
 use clippy_utils::consts::{constant, Constant};
 use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::higher::IfLet;
@@ -58,10 +59,10 @@ pub struct IndexRefutableSlice {
 }
 
 impl IndexRefutableSlice {
-    pub fn new(max_suggested_slice_pattern_length: u64, msrv: Msrv) -> Self {
+    pub fn new(conf: &'static Conf) -> Self {
         Self {
-            max_suggested_slice: max_suggested_slice_pattern_length,
-            msrv,
+            max_suggested_slice: conf.max_suggested_slice_pattern_length,
+            msrv: conf.msrv.clone(),
         }
     }
 }
@@ -70,8 +71,8 @@ impl_lint_pass!(IndexRefutableSlice => [INDEX_REFUTABLE_SLICE]);
 
 impl<'tcx> LateLintPass<'tcx> for IndexRefutableSlice {
     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>) {
-        if (!expr.span.from_expansion() || is_expn_of(expr.span, "if_chain").is_some())
-            && let Some(IfLet { let_pat, if_then, .. }) = IfLet::hir(cx, expr)
+        if let Some(IfLet { let_pat, if_then, .. }) = IfLet::hir(cx, expr)
+            && (!expr.span.from_expansion() || is_expn_of(expr.span, "if_chain").is_some())
             && !is_lint_allowed(cx, INDEX_REFUTABLE_SLICE, expr.hir_id)
             && self.msrv.meets(msrvs::SLICE_PATTERNS)
             && let found_slices = find_slice_values(cx, let_pat)
diff --git a/clippy_lints/src/indexing_slicing.rs b/clippy_lints/src/indexing_slicing.rs
index d54f2af65cd..6729c7c8d10 100644
--- a/clippy_lints/src/indexing_slicing.rs
+++ b/clippy_lints/src/indexing_slicing.rs
@@ -1,5 +1,6 @@
 //! lint on indexing and slicing operations
 
+use clippy_config::Conf;
 use clippy_utils::consts::{constant, Constant};
 use clippy_utils::diagnostics::{span_lint, span_lint_and_then};
 use clippy_utils::ty::{deref_chain, get_adt_inherent_method};
@@ -87,28 +88,22 @@ declare_clippy_lint! {
 
 impl_lint_pass!(IndexingSlicing => [INDEXING_SLICING, OUT_OF_BOUNDS_INDEXING]);
 
-#[derive(Copy, Clone)]
 pub struct IndexingSlicing {
     suppress_restriction_lint_in_const: bool,
 }
 
 impl IndexingSlicing {
-    pub fn new(suppress_restriction_lint_in_const: bool) -> Self {
+    pub fn new(conf: &'static Conf) -> Self {
         Self {
-            suppress_restriction_lint_in_const,
+            suppress_restriction_lint_in_const: conf.suppress_restriction_lint_in_const,
         }
     }
 }
 
 impl<'tcx> LateLintPass<'tcx> for IndexingSlicing {
     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
-        if (self.suppress_restriction_lint_in_const && cx.tcx.hir().is_inside_const_context(expr.hir_id))
-            || is_from_proc_macro(cx, expr)
-        {
-            return;
-        }
-
         if let ExprKind::Index(array, index, _) = &expr.kind
+            && (!self.suppress_restriction_lint_in_const || !cx.tcx.hir().is_inside_const_context(expr.hir_id))
             && let expr_ty = cx.typeck_results().expr_ty(array)
             && let mut deref = deref_chain(cx, expr_ty)
             && deref.any(|l| {
@@ -116,6 +111,7 @@ impl<'tcx> LateLintPass<'tcx> for IndexingSlicing {
                     || l.peel_refs().is_array()
                     || ty_has_applicable_get_function(cx, l.peel_refs(), expr_ty, expr)
             })
+            && !is_from_proc_macro(cx, expr)
         {
             let note = "the suggestion might not be applicable in constant blocks";
             let ty = cx.typeck_results().expr_ty(array).peel_refs();
diff --git a/clippy_lints/src/infinite_iter.rs b/clippy_lints/src/infinite_iter.rs
index 9ad02735878..fa7e7f6b76d 100644
--- a/clippy_lints/src/infinite_iter.rs
+++ b/clippy_lints/src/infinite_iter.rs
@@ -226,13 +226,14 @@ const INFINITE_COLLECTORS: &[Symbol] = &[
 fn complete_infinite_iter(cx: &LateContext<'_>, expr: &Expr<'_>) -> Finiteness {
     match expr.kind {
         ExprKind::MethodCall(method, receiver, args, _) => {
+            let method_str = method.ident.name.as_str();
             for &(name, len) in &COMPLETING_METHODS {
-                if method.ident.name.as_str() == name && args.len() == len {
+                if method_str == name && args.len() == len {
                     return is_infinite(cx, receiver);
                 }
             }
             for &(name, len) in &POSSIBLY_COMPLETING_METHODS {
-                if method.ident.name.as_str() == name && args.len() == len {
+                if method_str == name && args.len() == len {
                     return MaybeInfinite.and(is_infinite(cx, receiver));
                 }
             }
diff --git a/clippy_lints/src/instant_subtraction.rs b/clippy_lints/src/instant_subtraction.rs
index 5fe152d1e30..f41fdf3203c 100644
--- a/clippy_lints/src/instant_subtraction.rs
+++ b/clippy_lints/src/instant_subtraction.rs
@@ -1,4 +1,5 @@
 use clippy_config::msrvs::{self, Msrv};
+use clippy_config::Conf;
 use clippy_utils::diagnostics::span_lint_and_sugg;
 use clippy_utils::source::snippet_with_context;
 use clippy_utils::sugg::Sugg;
@@ -68,9 +69,10 @@ pub struct InstantSubtraction {
 }
 
 impl InstantSubtraction {
-    #[must_use]
-    pub fn new(msrv: Msrv) -> Self {
-        Self { msrv }
+    pub fn new(conf: &'static Conf) -> Self {
+        Self {
+            msrv: conf.msrv.clone(),
+        }
     }
 }
 
diff --git a/clippy_lints/src/item_name_repetitions.rs b/clippy_lints/src/item_name_repetitions.rs
index 33764d3eb09..4d44bae02b8 100644
--- a/clippy_lints/src/item_name_repetitions.rs
+++ b/clippy_lints/src/item_name_repetitions.rs
@@ -1,5 +1,6 @@
 //! lint on enum variants that are prefixed or suffixed by the same characters
 
+use clippy_config::Conf;
 use clippy_utils::diagnostics::{span_lint, span_lint_and_help, span_lint_hir};
 use clippy_utils::is_bool;
 use clippy_utils::macros::span_is_local;
@@ -152,21 +153,14 @@ pub struct ItemNameRepetitions {
 }
 
 impl ItemNameRepetitions {
-    #[must_use]
-    pub fn new(
-        enum_threshold: u64,
-        struct_threshold: u64,
-        avoid_breaking_exported_api: bool,
-        allow_private_module_inception: bool,
-        allowed_prefixes: &[String],
-    ) -> Self {
+    pub fn new(conf: &'static Conf) -> Self {
         Self {
             modules: Vec::new(),
-            enum_threshold,
-            struct_threshold,
-            avoid_breaking_exported_api,
-            allow_private_module_inception,
-            allowed_prefixes: allowed_prefixes.iter().map(|s| to_camel_case(s)).collect(),
+            enum_threshold: conf.enum_variant_name_threshold,
+            struct_threshold: conf.struct_field_name_threshold,
+            avoid_breaking_exported_api: conf.avoid_breaking_exported_api,
+            allow_private_module_inception: conf.allow_private_module_inception,
+            allowed_prefixes: conf.allowed_prefixes.iter().map(|s| to_camel_case(s)).collect(),
         }
     }
 
diff --git a/clippy_lints/src/large_const_arrays.rs b/clippy_lints/src/large_const_arrays.rs
index b18ab625e60..5d2b521b250 100644
--- a/clippy_lints/src/large_const_arrays.rs
+++ b/clippy_lints/src/large_const_arrays.rs
@@ -1,3 +1,4 @@
+use clippy_config::Conf;
 use clippy_utils::diagnostics::span_lint_and_then;
 use rustc_errors::Applicability;
 use rustc_hir::{Item, ItemKind};
@@ -32,13 +33,14 @@ declare_clippy_lint! {
 }
 
 pub struct LargeConstArrays {
-    maximum_allowed_size: u128,
+    maximum_allowed_size: u64,
 }
 
 impl LargeConstArrays {
-    #[must_use]
-    pub fn new(maximum_allowed_size: u128) -> Self {
-        Self { maximum_allowed_size }
+    pub fn new(conf: &'static Conf) -> Self {
+        Self {
+            maximum_allowed_size: conf.array_size_threshold,
+        }
     }
 }
 
@@ -57,7 +59,7 @@ impl<'tcx> LateLintPass<'tcx> for LargeConstArrays {
             && let ConstKind::Value(_, ty::ValTree::Leaf(element_count)) = cst.kind()
             && let element_count = element_count.to_target_usize(cx.tcx)
             && let Ok(element_size) = cx.layout_of(*element_type).map(|l| l.size.bytes())
-            && self.maximum_allowed_size < u128::from(element_count) * u128::from(element_size)
+            && u128::from(self.maximum_allowed_size) < u128::from(element_count) * u128::from(element_size)
         {
             let hi_pos = item.ident.span.lo() - BytePos::from_usize(1);
             let sugg_span = Span::new(
diff --git a/clippy_lints/src/large_enum_variant.rs b/clippy_lints/src/large_enum_variant.rs
index 85daadcc537..225d79aa71d 100644
--- a/clippy_lints/src/large_enum_variant.rs
+++ b/clippy_lints/src/large_enum_variant.rs
@@ -1,5 +1,6 @@
 //! lint when there is a large size difference between variants on an enum
 
+use clippy_config::Conf;
 use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::source::snippet_with_applicability;
 use clippy_utils::ty::{approx_ty_size, is_copy, AdtVariantInfo};
@@ -59,16 +60,14 @@ declare_clippy_lint! {
     "large size difference between variants on an enum"
 }
 
-#[derive(Copy, Clone)]
 pub struct LargeEnumVariant {
     maximum_size_difference_allowed: u64,
 }
 
 impl LargeEnumVariant {
-    #[must_use]
-    pub fn new(maximum_size_difference_allowed: u64) -> Self {
+    pub fn new(conf: &'static Conf) -> Self {
         Self {
-            maximum_size_difference_allowed,
+            maximum_size_difference_allowed: conf.enum_variant_size_threshold,
         }
     }
 }
diff --git a/clippy_lints/src/large_futures.rs b/clippy_lints/src/large_futures.rs
index 602227e4249..6f5065e4936 100644
--- a/clippy_lints/src/large_futures.rs
+++ b/clippy_lints/src/large_futures.rs
@@ -1,3 +1,4 @@
+use clippy_config::Conf;
 use clippy_utils::diagnostics::span_lint_and_sugg;
 use clippy_utils::source::snippet;
 use clippy_utils::ty::implements_trait;
@@ -39,14 +40,15 @@ declare_clippy_lint! {
     "large future may lead to unexpected stack overflows"
 }
 
-#[derive(Copy, Clone)]
 pub struct LargeFuture {
     future_size_threshold: u64,
 }
 
 impl LargeFuture {
-    pub fn new(future_size_threshold: u64) -> Self {
-        Self { future_size_threshold }
+    pub fn new(conf: &'static Conf) -> Self {
+        Self {
+            future_size_threshold: conf.future_size_threshold,
+        }
     }
 }
 
diff --git a/clippy_lints/src/large_include_file.rs b/clippy_lints/src/large_include_file.rs
index 2688283a6ce..c67da689aae 100644
--- a/clippy_lints/src/large_include_file.rs
+++ b/clippy_lints/src/large_include_file.rs
@@ -1,3 +1,4 @@
+use clippy_config::Conf;
 use clippy_utils::diagnostics::span_lint_and_note;
 use clippy_utils::macros::root_macro_call_first_node;
 use rustc_ast::LitKind;
@@ -41,9 +42,10 @@ pub struct LargeIncludeFile {
 }
 
 impl LargeIncludeFile {
-    #[must_use]
-    pub fn new(max_file_size: u64) -> Self {
-        Self { max_file_size }
+    pub fn new(conf: &'static Conf) -> Self {
+        Self {
+            max_file_size: conf.max_include_file_size,
+        }
     }
 }
 
diff --git a/clippy_lints/src/large_stack_arrays.rs b/clippy_lints/src/large_stack_arrays.rs
index d94b0cce948..15a75b06089 100644
--- a/clippy_lints/src/large_stack_arrays.rs
+++ b/clippy_lints/src/large_stack_arrays.rs
@@ -1,3 +1,4 @@
+use clippy_config::Conf;
 use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::is_from_proc_macro;
 use clippy_utils::macros::macro_backtrace;
@@ -27,15 +28,14 @@ declare_clippy_lint! {
 }
 
 pub struct LargeStackArrays {
-    maximum_allowed_size: u128,
+    maximum_allowed_size: u64,
     prev_vec_macro_callsite: Option<Span>,
 }
 
 impl LargeStackArrays {
-    #[must_use]
-    pub fn new(maximum_allowed_size: u128) -> Self {
+    pub fn new(conf: &'static Conf) -> Self {
         Self {
-            maximum_allowed_size,
+            maximum_allowed_size: conf.array_size_threshold,
             prev_vec_macro_callsite: None,
         }
     }
@@ -76,7 +76,7 @@ impl<'tcx> LateLintPass<'tcx> for LargeStackArrays {
                     })
                 )
             })
-            && self.maximum_allowed_size < u128::from(element_count) * u128::from(element_size)
+            && u128::from(self.maximum_allowed_size) < u128::from(element_count) * u128::from(element_size)
         {
             span_lint_and_then(
                 cx,
@@ -106,7 +106,7 @@ fn might_be_expanded<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'tcx>) -> bool {
     ///
     /// This is a fail-safe to a case where even the `is_from_proc_macro` is unable to determain the
     /// correct result.
-    fn repeat_expr_might_be_expanded<'tcx>(expr: &Expr<'tcx>) -> bool {
+    fn repeat_expr_might_be_expanded(expr: &Expr<'_>) -> bool {
         let ExprKind::Repeat(_, ArrayLen::Body(len_ct)) = expr.kind else {
             return false;
         };
diff --git a/clippy_lints/src/large_stack_frames.rs b/clippy_lints/src/large_stack_frames.rs
index 49408d7e243..4abf7edc9b4 100644
--- a/clippy_lints/src/large_stack_frames.rs
+++ b/clippy_lints/src/large_stack_frames.rs
@@ -1,5 +1,6 @@
 use std::{fmt, ops};
 
+use clippy_config::Conf;
 use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::fn_has_unsatisfiable_preds;
 use clippy_utils::source::snippet_opt;
@@ -85,10 +86,9 @@ pub struct LargeStackFrames {
 }
 
 impl LargeStackFrames {
-    #[must_use]
-    pub fn new(size: u64) -> Self {
+    pub fn new(conf: &'static Conf) -> Self {
         Self {
-            maximum_allowed_size: size,
+            maximum_allowed_size: conf.stack_size_threshold,
         }
     }
 }
diff --git a/clippy_lints/src/legacy_numeric_constants.rs b/clippy_lints/src/legacy_numeric_constants.rs
index a08b40bef37..752e1326e3e 100644
--- a/clippy_lints/src/legacy_numeric_constants.rs
+++ b/clippy_lints/src/legacy_numeric_constants.rs
@@ -1,4 +1,5 @@
 use clippy_config::msrvs::{Msrv, NUMERIC_ASSOCIATED_CONSTANTS};
+use clippy_config::Conf;
 use clippy_utils::diagnostics::{span_lint_and_then, span_lint_hir_and_then};
 use clippy_utils::{get_parent_expr, is_from_proc_macro};
 use hir::def_id::DefId;
@@ -38,9 +39,10 @@ pub struct LegacyNumericConstants {
 }
 
 impl LegacyNumericConstants {
-    #[must_use]
-    pub fn new(msrv: Msrv) -> Self {
-        Self { msrv }
+    pub fn new(conf: &'static Conf) -> Self {
+        Self {
+            msrv: conf.msrv.clone(),
+        }
     }
 }
 
diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs
index c2dc26d6605..ecfb6cdbdf0 100644
--- a/clippy_lints/src/lib.rs
+++ b/clippy_lints/src/lib.rs
@@ -1,6 +1,7 @@
 #![feature(array_windows)]
 #![feature(binary_heap_into_iter_sorted)]
 #![feature(box_patterns)]
+#![feature(control_flow_enum)]
 #![feature(f128)]
 #![feature(f16)]
 #![feature(if_let_guard)]
@@ -8,7 +9,6 @@
 #![feature(iter_intersperse)]
 #![feature(iter_partition_in_place)]
 #![feature(let_chains)]
-#![cfg_attr(bootstrap, feature(lint_reasons))]
 #![feature(never_type)]
 #![feature(rustc_private)]
 #![feature(stmt_expr_attributes)]
@@ -288,6 +288,7 @@ mod partial_pub_fields;
 mod partialeq_ne_impl;
 mod partialeq_to_none;
 mod pass_by_ref_or_value;
+mod pathbuf_init_then_push;
 mod pattern_type_mismatch;
 mod permissions_set_readonly_false;
 mod precedence;
@@ -394,7 +395,6 @@ use clippy_config::{get_configuration_metadata, Conf};
 use clippy_utils::macros::FormatArgsStorage;
 use rustc_data_structures::fx::FxHashSet;
 use rustc_lint::{Lint, LintId};
-use std::collections::BTreeMap;
 
 /// Register all pre expansion lints
 ///
@@ -406,9 +406,7 @@ use std::collections::BTreeMap;
 /// Used in `./src/driver.rs`.
 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 = || conf.msrv.clone();
-
-    store.register_pre_expansion_pass(move || Box::new(attrs::EarlyAttributes { msrv: msrv() }));
+    store.register_pre_expansion_pass(move || Box::new(attrs::EarlyAttributes::new(conf)));
 }
 
 #[derive(Default)]
@@ -534,88 +532,6 @@ fn register_categories(store: &mut rustc_lint::LintStore) {
 /// Used in `./src/driver.rs`.
 #[expect(clippy::too_many_lines)]
 pub fn register_lints(store: &mut rustc_lint::LintStore, conf: &'static Conf) {
-    let Conf {
-        ref absolute_paths_allowed_crates,
-        absolute_paths_max_segments,
-        accept_comment_above_attributes,
-        accept_comment_above_statement,
-        allow_dbg_in_tests,
-        allow_expect_in_tests,
-        allow_mixed_uninlined_format_args,
-        allow_one_hash_in_raw_strings,
-        allow_panic_in_tests,
-        allow_print_in_tests,
-        allow_private_module_inception,
-        allow_unwrap_in_tests,
-        allow_useless_vec_in_tests,
-        ref allowed_dotfiles,
-        ref allowed_idents_below_min_chars,
-        ref allowed_scripts,
-        ref allowed_wildcard_imports,
-        ref arithmetic_side_effects_allowed_binary,
-        ref arithmetic_side_effects_allowed_unary,
-        ref arithmetic_side_effects_allowed,
-        array_size_threshold,
-        avoid_breaking_exported_api,
-        ref await_holding_invalid_types,
-        cargo_ignore_publish,
-        cognitive_complexity_threshold,
-        ref disallowed_macros,
-        ref disallowed_methods,
-        ref disallowed_names,
-        ref disallowed_types,
-        ref doc_valid_idents,
-        enable_raw_pointer_heuristic_for_send,
-        enforce_iter_loop_reborrow,
-        ref enforced_import_renames,
-        enum_variant_name_threshold,
-        enum_variant_size_threshold,
-        excessive_nesting_threshold,
-        future_size_threshold,
-        ref ignore_interior_mutability,
-        large_error_threshold,
-        literal_representation_threshold,
-        matches_for_let_else,
-        max_fn_params_bools,
-        max_include_file_size,
-        max_struct_bools,
-        max_suggested_slice_pattern_length,
-        max_trait_bounds,
-        min_ident_chars_threshold,
-        missing_docs_in_crate_items,
-        ref msrv,
-        pass_by_value_size_limit,
-        semicolon_inside_block_ignore_singleline,
-        semicolon_outside_block_ignore_multiline,
-        single_char_binding_names_threshold,
-        stack_size_threshold,
-        ref standard_macro_braces,
-        struct_field_name_threshold,
-        suppress_restriction_lint_in_const,
-        too_large_for_stack,
-        too_many_arguments_threshold,
-        too_many_lines_threshold,
-        trivial_copy_size_limit,
-        type_complexity_threshold,
-        unnecessary_box_size,
-        unreadable_literal_lint_fractions,
-        upper_case_acronyms_aggressive,
-        vec_box_size_threshold,
-        verbose_bit_mask_threshold,
-        warn_on_all_wildcard_imports,
-        check_private_items,
-        pub_underscore_fields_behavior,
-        ref allowed_duplicate_crates,
-        allow_comparison_to_zero,
-        ref allowed_prefixes,
-        ref allow_renamed_params_for,
-
-        blacklisted_names: _,
-        cyclomatic_complexity_threshold: _,
-        warn_unsafe_macro_metavars_in_private_macros,
-    } = *conf;
-    let msrv = || msrv.clone();
-
     register_removed_non_tool_lints(store);
     register_categories(store);
 
@@ -660,35 +576,12 @@ pub fn register_lints(store: &mut rustc_lint::LintStore, conf: &'static Conf) {
         });
     }
 
-    store.register_late_pass(move |_| {
-        Box::new(operators::arithmetic_side_effects::ArithmeticSideEffects::new(
-            arithmetic_side_effects_allowed
-                .iter()
-                .flat_map(|el| [[el.clone(), "*".to_string()], ["*".to_string(), el.clone()]])
-                .chain(arithmetic_side_effects_allowed_binary.clone())
-                .collect(),
-            arithmetic_side_effects_allowed
-                .iter()
-                .chain(arithmetic_side_effects_allowed_unary.iter())
-                .cloned()
-                .collect(),
-        ))
-    });
+    store.register_late_pass(move |_| Box::new(operators::arithmetic_side_effects::ArithmeticSideEffects::new(conf)));
     store.register_late_pass(|_| Box::new(utils::dump_hir::DumpHir));
     store.register_late_pass(|_| Box::new(utils::author::Author));
-    store.register_late_pass(move |_| {
-        Box::new(await_holding_invalid::AwaitHolding::new(
-            await_holding_invalid_types.clone(),
-        ))
-    });
+    store.register_late_pass(move |tcx| Box::new(await_holding_invalid::AwaitHolding::new(tcx, conf)));
     store.register_late_pass(|_| Box::new(serde_api::SerdeApi));
-    store.register_late_pass(move |_| {
-        Box::new(types::Types::new(
-            vec_box_size_threshold,
-            type_complexity_threshold,
-            avoid_breaking_exported_api,
-        ))
-    });
+    store.register_late_pass(move |_| Box::new(types::Types::new(conf)));
     store.register_late_pass(|_| Box::new(booleans::NonminimalBool));
     store.register_late_pass(|_| Box::new(enum_clike::UnportableVariant));
     store.register_late_pass(|_| Box::new(float_literal::FloatLiteral));
@@ -702,7 +595,7 @@ pub fn register_lints(store: &mut rustc_lint::LintStore, conf: &'static Conf) {
     store.register_late_pass(|_| Box::new(mut_reference::UnnecessaryMutPassed));
     store.register_late_pass(|_| Box::<significant_drop_tightening::SignificantDropTightening<'_>>::default());
     store.register_late_pass(|_| Box::new(len_zero::LenZero));
-    store.register_late_pass(move |_| Box::new(attrs::Attributes::new(msrv())));
+    store.register_late_pass(move |_| Box::new(attrs::Attributes::new(conf)));
     store.register_late_pass(|_| Box::new(blocks_in_conditions::BlocksInConditions));
     store.register_late_pass(|_| Box::new(unicode::Unicode));
     store.register_late_pass(|_| Box::new(uninit_vec::UninitVec));
@@ -714,44 +607,30 @@ pub fn register_lints(store: &mut rustc_lint::LintStore, conf: &'static Conf) {
     store.register_late_pass(|_| Box::new(inconsistent_struct_constructor::InconsistentStructConstructor));
     store.register_late_pass(|_| Box::new(non_octal_unix_permissions::NonOctalUnixPermissions));
     store.register_early_pass(|| Box::new(unnecessary_self_imports::UnnecessarySelfImports));
-    store.register_late_pass(move |_| Box::new(approx_const::ApproxConstant::new(msrv())));
+    store.register_late_pass(move |_| Box::new(approx_const::ApproxConstant::new(conf)));
     let format_args = format_args_storage.clone();
-    store.register_late_pass(move |_| {
-        Box::new(methods::Methods::new(
-            avoid_breaking_exported_api,
-            msrv(),
-            allow_expect_in_tests,
-            allow_unwrap_in_tests,
-            allowed_dotfiles.clone(),
-            format_args.clone(),
-        ))
-    });
-    store.register_late_pass(move |_| Box::new(matches::Matches::new(msrv())));
-    store.register_early_pass(move || Box::new(manual_non_exhaustive::ManualNonExhaustiveStruct::new(msrv())));
-    store.register_late_pass(move |_| Box::new(manual_non_exhaustive::ManualNonExhaustiveEnum::new(msrv())));
-    store.register_late_pass(move |_| Box::new(manual_strip::ManualStrip::new(msrv())));
-    store.register_early_pass(move || Box::new(redundant_static_lifetimes::RedundantStaticLifetimes::new(msrv())));
-    store.register_early_pass(move || Box::new(redundant_field_names::RedundantFieldNames::new(msrv())));
-    store.register_late_pass(move |_| Box::new(checked_conversions::CheckedConversions::new(msrv())));
-    store.register_late_pass(move |_| Box::new(mem_replace::MemReplace::new(msrv())));
-    store.register_late_pass(move |_| Box::new(ranges::Ranges::new(msrv())));
-    store.register_late_pass(move |_| Box::new(from_over_into::FromOverInto::new(msrv())));
-    store.register_late_pass(move |_| Box::new(use_self::UseSelf::new(msrv())));
-    store.register_late_pass(move |_| Box::new(missing_const_for_fn::MissingConstForFn::new(msrv())));
+    store.register_late_pass(move |_| Box::new(methods::Methods::new(conf, format_args.clone())));
+    store.register_late_pass(move |_| Box::new(matches::Matches::new(conf)));
+    store.register_early_pass(move || Box::new(manual_non_exhaustive::ManualNonExhaustiveStruct::new(conf)));
+    store.register_late_pass(move |_| Box::new(manual_non_exhaustive::ManualNonExhaustiveEnum::new(conf)));
+    store.register_late_pass(move |_| Box::new(manual_strip::ManualStrip::new(conf)));
+    store.register_early_pass(move || Box::new(redundant_static_lifetimes::RedundantStaticLifetimes::new(conf)));
+    store.register_early_pass(move || Box::new(redundant_field_names::RedundantFieldNames::new(conf)));
+    store.register_late_pass(move |_| Box::new(checked_conversions::CheckedConversions::new(conf)));
+    store.register_late_pass(move |_| Box::new(mem_replace::MemReplace::new(conf)));
+    store.register_late_pass(move |_| Box::new(ranges::Ranges::new(conf)));
+    store.register_late_pass(move |_| Box::new(from_over_into::FromOverInto::new(conf)));
+    store.register_late_pass(move |_| Box::new(use_self::UseSelf::new(conf)));
+    store.register_late_pass(move |_| Box::new(missing_const_for_fn::MissingConstForFn::new(conf)));
     store.register_late_pass(move |_| Box::new(needless_question_mark::NeedlessQuestionMark));
-    store.register_late_pass(move |_| Box::new(casts::Casts::new(msrv())));
-    store.register_early_pass(move || Box::new(unnested_or_patterns::UnnestedOrPatterns::new(msrv())));
+    store.register_late_pass(move |_| Box::new(casts::Casts::new(conf)));
+    store.register_early_pass(move || Box::new(unnested_or_patterns::UnnestedOrPatterns::new(conf)));
     store.register_late_pass(|_| Box::new(size_of_in_element_count::SizeOfInElementCount));
     store.register_late_pass(|_| Box::new(same_name_method::SameNameMethod));
-    store.register_late_pass(move |_| {
-        Box::new(index_refutable_slice::IndexRefutableSlice::new(
-            max_suggested_slice_pattern_length,
-            msrv(),
-        ))
-    });
+    store.register_late_pass(move |_| Box::new(index_refutable_slice::IndexRefutableSlice::new(conf)));
     store.register_late_pass(|_| Box::<shadow::Shadow>::default());
     store.register_late_pass(|_| Box::new(unit_types::UnitTypes));
-    store.register_late_pass(move |_| Box::new(loops::Loops::new(msrv(), enforce_iter_loop_reborrow)));
+    store.register_late_pass(move |_| Box::new(loops::Loops::new(conf)));
     store.register_late_pass(|_| Box::<main_recursion::MainRecursion>::default());
     store.register_late_pass(|_| Box::new(lifetimes::Lifetimes));
     store.register_late_pass(|_| Box::new(entry::HashMapPass));
@@ -763,75 +642,49 @@ pub fn register_lints(store: &mut rustc_lint::LintStore, conf: &'static Conf) {
     store.register_late_pass(|_| Box::new(borrow_deref_ref::BorrowDerefRef));
     store.register_late_pass(|_| Box::<no_effect::NoEffect>::default());
     store.register_late_pass(|_| Box::new(temporary_assignment::TemporaryAssignment));
-    store.register_late_pass(move |_| Box::new(transmute::Transmute::new(msrv())));
-    store.register_late_pass(move |_| {
-        Box::new(cognitive_complexity::CognitiveComplexity::new(
-            cognitive_complexity_threshold,
-        ))
-    });
-    store.register_late_pass(move |_| Box::new(escape::BoxedLocal { too_large_for_stack }));
-    store.register_late_pass(move |_| {
-        Box::new(vec::UselessVec {
-            too_large_for_stack,
-            msrv: msrv(),
-            span_to_lint_map: BTreeMap::new(),
-            allow_in_test: allow_useless_vec_in_tests,
-        })
-    });
-    store.register_late_pass(move |_| Box::new(panic_unimplemented::PanicUnimplemented { allow_panic_in_tests }));
+    store.register_late_pass(move |_| Box::new(transmute::Transmute::new(conf)));
+    store.register_late_pass(move |_| Box::new(cognitive_complexity::CognitiveComplexity::new(conf)));
+    store.register_late_pass(move |_| Box::new(escape::BoxedLocal::new(conf)));
+    store.register_late_pass(move |_| Box::new(vec::UselessVec::new(conf)));
+    store.register_late_pass(move |_| Box::new(panic_unimplemented::PanicUnimplemented::new(conf)));
     store.register_late_pass(|_| Box::new(strings::StringLitAsBytes));
     store.register_late_pass(|_| Box::new(derive::Derive));
-    store.register_late_pass(move |_| Box::new(derivable_impls::DerivableImpls::new(msrv())));
+    store.register_late_pass(move |_| Box::new(derivable_impls::DerivableImpls::new(conf)));
     store.register_late_pass(|_| Box::new(drop_forget_ref::DropForgetRef));
     store.register_late_pass(|_| Box::new(empty_enum::EmptyEnum));
     store.register_late_pass(|_| Box::new(invalid_upcast_comparisons::InvalidUpcastComparisons));
     store.register_late_pass(|_| Box::<regex::Regex>::default());
-    store.register_late_pass(move |_| Box::new(copies::CopyAndPaste::new(ignore_interior_mutability.clone())));
+    store.register_late_pass(move |tcx| Box::new(copies::CopyAndPaste::new(tcx, conf)));
     store.register_late_pass(|_| Box::new(copy_iterator::CopyIterator));
     let format_args = format_args_storage.clone();
     store.register_late_pass(move |_| Box::new(format::UselessFormat::new(format_args.clone())));
     store.register_late_pass(|_| Box::new(swap::Swap));
     store.register_late_pass(|_| Box::new(panicking_overflow_checks::PanickingOverflowChecks));
     store.register_late_pass(|_| Box::<new_without_default::NewWithoutDefault>::default());
-    store.register_late_pass(move |_| Box::new(disallowed_names::DisallowedNames::new(disallowed_names)));
-    store.register_late_pass(move |_| {
-        Box::new(functions::Functions::new(
-            too_many_arguments_threshold,
-            too_many_lines_threshold,
-            large_error_threshold,
-            avoid_breaking_exported_api,
-            allow_renamed_params_for.clone(),
-        ))
-    });
-    store.register_late_pass(move |_| Box::new(doc::Documentation::new(doc_valid_idents, check_private_items)));
+    store.register_late_pass(move |_| Box::new(disallowed_names::DisallowedNames::new(conf)));
+    store.register_late_pass(move |tcx| Box::new(functions::Functions::new(tcx, conf)));
+    store.register_late_pass(move |_| Box::new(doc::Documentation::new(conf)));
     store.register_late_pass(|_| Box::new(neg_multiply::NegMultiply));
     store.register_late_pass(|_| Box::new(let_if_seq::LetIfSeq));
     store.register_late_pass(|_| Box::new(mixed_read_write_in_expression::EvalOrderDependence));
-    store.register_late_pass(move |_| Box::new(missing_doc::MissingDoc::new(missing_docs_in_crate_items)));
+    store.register_late_pass(move |_| Box::new(missing_doc::MissingDoc::new(conf)));
     store.register_late_pass(|_| Box::new(missing_inline::MissingInline));
     store.register_late_pass(move |_| Box::new(exhaustive_items::ExhaustiveItems));
     store.register_late_pass(|_| Box::new(match_result_ok::MatchResultOk));
     store.register_late_pass(|_| Box::new(partialeq_ne_impl::PartialEqNeImpl));
     store.register_late_pass(|_| Box::new(unused_io_amount::UnusedIoAmount));
-    store.register_late_pass(move |_| Box::new(large_enum_variant::LargeEnumVariant::new(enum_variant_size_threshold)));
+    store.register_late_pass(move |_| Box::new(large_enum_variant::LargeEnumVariant::new(conf)));
     let format_args = format_args_storage.clone();
     store.register_late_pass(move |_| Box::new(explicit_write::ExplicitWrite::new(format_args.clone())));
     store.register_late_pass(|_| Box::new(needless_pass_by_value::NeedlessPassByValue));
-    store.register_late_pass(move |tcx| {
-        Box::new(pass_by_ref_or_value::PassByRefOrValue::new(
-            trivial_copy_size_limit,
-            pass_by_value_size_limit,
-            avoid_breaking_exported_api,
-            tcx.sess.target.pointer_width,
-        ))
-    });
+    store.register_late_pass(move |tcx| Box::new(pass_by_ref_or_value::PassByRefOrValue::new(tcx, conf)));
     store.register_late_pass(|_| Box::new(ref_option_ref::RefOptionRef));
     store.register_late_pass(|_| Box::new(infinite_iter::InfiniteIter));
     store.register_late_pass(|_| Box::new(inline_fn_without_body::InlineFnWithoutBody));
     store.register_late_pass(|_| Box::<useless_conversion::UselessConversion>::default());
     store.register_late_pass(|_| Box::new(implicit_hasher::ImplicitHasher));
     store.register_late_pass(|_| Box::new(fallible_impl_from::FallibleImplFrom));
-    store.register_late_pass(move |_| Box::new(question_mark::QuestionMark::new(msrv(), matches_for_let_else)));
+    store.register_late_pass(move |_| Box::new(question_mark::QuestionMark::new(conf)));
     store.register_late_pass(|_| Box::new(question_mark_used::QuestionMarkUsed));
     store.register_early_pass(|| Box::new(suspicious_operation_groupings::SuspiciousOperationGroupings));
     store.register_late_pass(|_| Box::new(suspicious_trait_impl::SuspiciousImpl));
@@ -839,22 +692,18 @@ pub fn register_lints(store: &mut rustc_lint::LintStore, conf: &'static Conf) {
     store.register_late_pass(|_| Box::new(inherent_impl::MultipleInherentImpl));
     store.register_late_pass(|_| Box::new(neg_cmp_op_on_partial_ord::NoNegCompOpForPartialOrd));
     store.register_late_pass(|_| Box::new(unwrap::Unwrap));
-    store.register_late_pass(move |_| {
-        Box::new(indexing_slicing::IndexingSlicing::new(
-            suppress_restriction_lint_in_const,
-        ))
-    });
-    store.register_late_pass(move |_| Box::new(non_copy_const::NonCopyConst::new(ignore_interior_mutability.clone())));
+    store.register_late_pass(move |_| Box::new(indexing_slicing::IndexingSlicing::new(conf)));
+    store.register_late_pass(move |tcx| Box::new(non_copy_const::NonCopyConst::new(tcx, conf)));
     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));
-    store.register_late_pass(move |_| Box::new(unnecessary_wraps::UnnecessaryWraps::new(avoid_breaking_exported_api)));
+    store.register_late_pass(move |_| Box::new(unnecessary_wraps::UnnecessaryWraps::new(conf)));
     store.register_late_pass(|_| Box::new(assertions_on_constants::AssertionsOnConstants));
     store.register_late_pass(|_| Box::new(assertions_on_result_states::AssertionsOnResultStates));
     store.register_late_pass(|_| Box::new(inherent_to_string::InherentToString));
-    store.register_late_pass(move |_| Box::new(trait_bounds::TraitBounds::new(max_trait_bounds, msrv())));
+    store.register_late_pass(move |_| Box::new(trait_bounds::TraitBounds::new(conf)));
     store.register_late_pass(|_| Box::new(comparison_chain::ComparisonChain));
-    store.register_late_pass(move |_| Box::new(mut_key::MutableKeyType::new(ignore_interior_mutability.clone())));
+    store.register_late_pass(move |tcx| Box::new(mut_key::MutableKeyType::new(tcx, conf)));
     store.register_early_pass(|| Box::new(reference::DerefAddrOf));
     store.register_early_pass(|| Box::new(double_parens::DoubleParens));
     let format_args = format_args_storage.clone();
@@ -875,80 +724,45 @@ pub fn register_lints(store: &mut rustc_lint::LintStore, conf: &'static Conf) {
     store.register_early_pass(|| Box::new(redundant_else::RedundantElse));
     store.register_late_pass(|_| Box::new(create_dir::CreateDir));
     store.register_early_pass(|| Box::new(needless_arbitrary_self_type::NeedlessArbitrarySelfType));
-    store.register_early_pass(move || {
-        Box::new(literal_representation::LiteralDigitGrouping::new(
-            unreadable_literal_lint_fractions,
-        ))
-    });
-    store.register_early_pass(move || {
-        Box::new(literal_representation::DecimalLiteralRepresentation::new(
-            literal_representation_threshold,
-        ))
-    });
-    store.register_late_pass(move |_| {
-        Box::new(item_name_repetitions::ItemNameRepetitions::new(
-            enum_variant_name_threshold,
-            struct_field_name_threshold,
-            avoid_breaking_exported_api,
-            allow_private_module_inception,
-            allowed_prefixes,
-        ))
-    });
+    store.register_early_pass(move || Box::new(literal_representation::LiteralDigitGrouping::new(conf)));
+    store.register_early_pass(move || Box::new(literal_representation::DecimalLiteralRepresentation::new(conf)));
+    store.register_late_pass(move |_| Box::new(item_name_repetitions::ItemNameRepetitions::new(conf)));
     store.register_early_pass(|| Box::new(tabs_in_doc_comments::TabsInDocComments));
-    store.register_late_pass(move |_| {
-        Box::new(upper_case_acronyms::UpperCaseAcronyms::new(
-            avoid_breaking_exported_api,
-            upper_case_acronyms_aggressive,
-        ))
-    });
+    store.register_late_pass(move |_| Box::new(upper_case_acronyms::UpperCaseAcronyms::new(conf)));
     store.register_late_pass(|_| Box::<default::Default>::default());
-    store.register_late_pass(move |_| Box::new(unused_self::UnusedSelf::new(avoid_breaking_exported_api)));
+    store.register_late_pass(move |_| Box::new(unused_self::UnusedSelf::new(conf)));
     store.register_late_pass(|_| Box::new(mutable_debug_assertion::DebugAssertWithMutCall));
     store.register_late_pass(|_| Box::new(exit::Exit));
     store.register_late_pass(|_| Box::new(to_digit_is_some::ToDigitIsSome));
-    store.register_late_pass(move |_| Box::new(large_stack_arrays::LargeStackArrays::new(array_size_threshold.into())));
-    store.register_late_pass(move |_| Box::new(large_const_arrays::LargeConstArrays::new(array_size_threshold.into())));
+    store.register_late_pass(move |_| Box::new(large_stack_arrays::LargeStackArrays::new(conf)));
+    store.register_late_pass(move |_| Box::new(large_const_arrays::LargeConstArrays::new(conf)));
     store.register_late_pass(|_| Box::new(floating_point_arithmetic::FloatingPointArithmetic));
     store.register_late_pass(|_| Box::new(as_conversions::AsConversions));
     store.register_late_pass(|_| Box::new(let_underscore::LetUnderscore));
     store.register_early_pass(|| Box::<single_component_path_imports::SingleComponentPathImports>::default());
-    store.register_late_pass(move |_| {
-        Box::new(excessive_bools::ExcessiveBools::new(
-            max_struct_bools,
-            max_fn_params_bools,
-        ))
-    });
+    store.register_late_pass(move |_| Box::new(excessive_bools::ExcessiveBools::new(conf)));
     store.register_early_pass(|| Box::new(option_env_unwrap::OptionEnvUnwrap));
-    store.register_late_pass(move |_| {
-        Box::new(wildcard_imports::WildcardImports::new(
-            warn_on_all_wildcard_imports,
-            allowed_wildcard_imports.clone(),
-        ))
-    });
+    store.register_late_pass(move |_| Box::new(wildcard_imports::WildcardImports::new(conf)));
     store.register_late_pass(|_| Box::<redundant_pub_crate::RedundantPubCrate>::default());
     store.register_late_pass(|_| Box::new(unnamed_address::UnnamedAddress));
     store.register_late_pass(|_| Box::<dereference::Dereferencing<'_>>::default());
     store.register_late_pass(|_| Box::new(option_if_let_else::OptionIfLetElse));
     store.register_late_pass(|_| Box::new(future_not_send::FutureNotSend));
-    store.register_late_pass(move |_| Box::new(large_futures::LargeFuture::new(future_size_threshold)));
+    store.register_late_pass(move |_| Box::new(large_futures::LargeFuture::new(conf)));
     store.register_late_pass(|_| Box::new(if_let_mutex::IfLetMutex));
     store.register_late_pass(|_| Box::new(if_not_else::IfNotElse));
     store.register_late_pass(|_| Box::new(equatable_if_let::PatternEquality));
     store.register_late_pass(|_| Box::new(manual_async_fn::ManualAsyncFn));
     store.register_late_pass(|_| Box::new(panic_in_result_fn::PanicInResultFn));
-    store.register_early_pass(move || {
-        Box::new(non_expressive_names::NonExpressiveNames {
-            single_char_binding_names_threshold,
-        })
-    });
-    store.register_early_pass(move || Box::new(nonstandard_macro_braces::MacroBraces::new(standard_macro_braces)));
+    store.register_early_pass(move || Box::new(non_expressive_names::NonExpressiveNames::new(conf)));
+    store.register_early_pass(move || Box::new(nonstandard_macro_braces::MacroBraces::new(conf)));
     store.register_late_pass(|_| Box::<macro_use::MacroUseImports>::default());
     store.register_late_pass(|_| Box::new(pattern_type_mismatch::PatternTypeMismatch));
     store.register_late_pass(|_| Box::new(unwrap_in_result::UnwrapInResult));
     store.register_late_pass(|_| Box::new(semicolon_if_nothing_returned::SemicolonIfNothingReturned));
     store.register_late_pass(|_| Box::new(async_yields_async::AsyncYieldsAsync));
-    store.register_late_pass(move |_| Box::new(disallowed_macros::DisallowedMacros::new(disallowed_macros.clone())));
-    store.register_late_pass(move |_| Box::new(disallowed_methods::DisallowedMethods::new(disallowed_methods.clone())));
+    store.register_late_pass(move |tcx| Box::new(disallowed_macros::DisallowedMacros::new(tcx, conf)));
+    store.register_late_pass(move |tcx| Box::new(disallowed_methods::DisallowedMethods::new(tcx, conf)));
     store.register_early_pass(|| Box::new(asm_syntax::InlineAsmX86AttSyntax));
     store.register_early_pass(|| Box::new(asm_syntax::InlineAsmX86IntelSyntax));
     store.register_late_pass(|_| Box::new(empty_drop::EmptyDrop));
@@ -958,86 +772,57 @@ pub fn register_lints(store: &mut rustc_lint::LintStore, conf: &'static Conf) {
     store.register_late_pass(|_| Box::<vec_init_then_push::VecInitThenPush>::default());
     store.register_late_pass(|_| Box::new(redundant_slicing::RedundantSlicing));
     store.register_late_pass(|_| Box::new(from_str_radix_10::FromStrRadix10));
-    store.register_late_pass(move |_| Box::new(if_then_some_else_none::IfThenSomeElseNone::new(msrv())));
+    store.register_late_pass(move |_| Box::new(if_then_some_else_none::IfThenSomeElseNone::new(conf)));
     store.register_late_pass(|_| Box::new(bool_assert_comparison::BoolAssertComparison));
     store.register_early_pass(move || Box::new(module_style::ModStyle));
     store.register_late_pass(|_| Box::<unused_async::UnusedAsync>::default());
-    store.register_late_pass(move |_| Box::new(disallowed_types::DisallowedTypes::new(disallowed_types.clone())));
-    store.register_late_pass(move |_| {
-        Box::new(missing_enforced_import_rename::ImportRename::new(
-            enforced_import_renames.clone(),
-        ))
-    });
-    store.register_early_pass(move || Box::new(disallowed_script_idents::DisallowedScriptIdents::new(allowed_scripts)));
+    store.register_late_pass(move |tcx| Box::new(disallowed_types::DisallowedTypes::new(tcx, conf)));
+    store.register_late_pass(move |tcx| Box::new(missing_enforced_import_rename::ImportRename::new(tcx, conf)));
+    store.register_early_pass(move || Box::new(disallowed_script_idents::DisallowedScriptIdents::new(conf)));
     store.register_late_pass(|_| Box::new(strlen_on_c_strings::StrlenOnCStrings));
     store.register_late_pass(move |_| Box::new(self_named_constructors::SelfNamedConstructors));
     store.register_late_pass(move |_| Box::new(iter_not_returning_iterator::IterNotReturningIterator));
     store.register_late_pass(move |_| Box::new(manual_assert::ManualAssert));
-    store.register_late_pass(move |_| {
-        Box::new(non_send_fields_in_send_ty::NonSendFieldInSendTy::new(
-            enable_raw_pointer_heuristic_for_send,
-        ))
-    });
-    store.register_late_pass(move |_| {
-        Box::new(undocumented_unsafe_blocks::UndocumentedUnsafeBlocks::new(
-            accept_comment_above_statement,
-            accept_comment_above_attributes,
-        ))
-    });
+    store.register_late_pass(move |_| Box::new(non_send_fields_in_send_ty::NonSendFieldInSendTy::new(conf)));
+    store.register_late_pass(move |_| Box::new(undocumented_unsafe_blocks::UndocumentedUnsafeBlocks::new(conf)));
     let format_args = format_args_storage.clone();
-    store.register_late_pass(move |_| {
-        Box::new(format_args::FormatArgs::new(
-            format_args.clone(),
-            msrv(),
-            allow_mixed_uninlined_format_args,
-        ))
-    });
+    store.register_late_pass(move |_| Box::new(format_args::FormatArgs::new(conf, format_args.clone())));
     store.register_late_pass(|_| Box::new(trailing_empty_array::TrailingEmptyArray));
     store.register_early_pass(|| Box::new(octal_escapes::OctalEscapes));
     store.register_late_pass(|_| Box::new(needless_late_init::NeedlessLateInit));
     store.register_late_pass(|_| Box::new(return_self_not_must_use::ReturnSelfNotMustUse));
     store.register_late_pass(|_| Box::new(init_numbered_fields::NumberedFields));
     store.register_early_pass(|| Box::new(single_char_lifetime_names::SingleCharLifetimeNames));
-    store.register_late_pass(move |_| Box::new(manual_bits::ManualBits::new(msrv())));
+    store.register_late_pass(move |_| Box::new(manual_bits::ManualBits::new(conf)));
     store.register_late_pass(|_| Box::new(default_union_representation::DefaultUnionRepresentation));
     store.register_late_pass(|_| Box::<only_used_in_recursion::OnlyUsedInRecursion>::default());
-    store.register_late_pass(move |_| Box::new(dbg_macro::DbgMacro::new(allow_dbg_in_tests)));
+    store.register_late_pass(move |_| Box::new(dbg_macro::DbgMacro::new(conf)));
     let format_args = format_args_storage.clone();
-    store.register_late_pass(move |_| Box::new(write::Write::new(format_args.clone(), allow_print_in_tests)));
-    store.register_late_pass(move |_| {
-        Box::new(cargo::Cargo {
-            ignore_publish: cargo_ignore_publish,
-            allowed_duplicate_crates: allowed_duplicate_crates.clone(),
-        })
-    });
+    store.register_late_pass(move |_| Box::new(write::Write::new(conf, format_args.clone())));
+    store.register_late_pass(move |_| Box::new(cargo::Cargo::new(conf)));
     store.register_early_pass(|| Box::new(crate_in_macro_def::CrateInMacroDef));
     store.register_early_pass(|| Box::new(empty_with_brackets::EmptyWithBrackets));
     store.register_late_pass(|_| Box::new(unnecessary_owned_empty_strings::UnnecessaryOwnedEmptyStrings));
     store.register_early_pass(|| Box::new(pub_use::PubUse));
     store.register_late_pass(|_| Box::new(format_push_string::FormatPushString));
-    store.register_late_pass(move |_| Box::new(large_include_file::LargeIncludeFile::new(max_include_file_size)));
+    store.register_late_pass(move |_| Box::new(large_include_file::LargeIncludeFile::new(conf)));
     store.register_late_pass(|_| Box::new(strings::TrimSplitWhitespace));
     store.register_late_pass(|_| Box::new(rc_clone_in_vec_init::RcCloneInVecInit));
     store.register_early_pass(|| Box::<duplicate_mod::DuplicateMod>::default());
     store.register_early_pass(|| Box::new(unused_rounding::UnusedRounding));
-    store.register_early_pass(move || Box::new(almost_complete_range::AlmostCompleteRange::new(msrv())));
+    store.register_early_pass(move || Box::new(almost_complete_range::AlmostCompleteRange::new(conf)));
     store.register_late_pass(|_| Box::new(swap_ptr_to_ref::SwapPtrToRef));
     store.register_late_pass(|_| Box::new(mismatching_type_param_order::TypeParamMismatch));
     store.register_late_pass(|_| Box::new(read_zero_byte_vec::ReadZeroByteVec));
     store.register_late_pass(|_| Box::new(default_instead_of_iter_empty::DefaultIterEmpty));
-    store.register_late_pass(move |_| Box::new(manual_rem_euclid::ManualRemEuclid::new(msrv())));
-    store.register_late_pass(move |_| Box::new(manual_retain::ManualRetain::new(msrv())));
+    store.register_late_pass(move |_| Box::new(manual_rem_euclid::ManualRemEuclid::new(conf)));
+    store.register_late_pass(move |_| Box::new(manual_retain::ManualRetain::new(conf)));
     store.register_late_pass(move |_| Box::new(manual_rotate::ManualRotate));
-    store.register_late_pass(move |_| {
-        Box::new(operators::Operators::new(
-            verbose_bit_mask_threshold,
-            allow_comparison_to_zero,
-        ))
-    });
+    store.register_late_pass(move |_| Box::new(operators::Operators::new(conf)));
     store.register_late_pass(|_| Box::<std_instead_of_core::StdReexports>::default());
-    store.register_late_pass(move |_| Box::new(instant_subtraction::InstantSubtraction::new(msrv())));
+    store.register_late_pass(move |_| Box::new(instant_subtraction::InstantSubtraction::new(conf)));
     store.register_late_pass(|_| Box::new(partialeq_to_none::PartialeqToNone));
-    store.register_late_pass(move |_| Box::new(manual_clamp::ManualClamp::new(msrv())));
+    store.register_late_pass(move |_| Box::new(manual_clamp::ManualClamp::new(conf)));
     store.register_late_pass(|_| Box::new(manual_string_new::ManualStringNew));
     store.register_late_pass(|_| Box::new(unused_peekable::UnusedPeekable));
     store.register_early_pass(|| Box::new(multi_assignments::MultiAssignments));
@@ -1048,44 +833,25 @@ pub fn register_lints(store: &mut rustc_lint::LintStore, conf: &'static Conf) {
     store.register_late_pass(|_| Box::new(missing_trait_methods::MissingTraitMethods));
     store.register_late_pass(|_| Box::new(from_raw_with_void_ptr::FromRawWithVoidPtr));
     store.register_late_pass(|_| Box::new(suspicious_xor_used_as_pow::ConfusingXorAndPow));
-    store.register_late_pass(move |_| Box::new(manual_is_ascii_check::ManualIsAsciiCheck::new(msrv())));
-    store.register_late_pass(move |_| {
-        Box::new(semicolon_block::SemicolonBlock::new(
-            semicolon_inside_block_ignore_singleline,
-            semicolon_outside_block_ignore_multiline,
-        ))
-    });
+    store.register_late_pass(move |_| Box::new(manual_is_ascii_check::ManualIsAsciiCheck::new(conf)));
+    store.register_late_pass(move |_| Box::new(semicolon_block::SemicolonBlock::new(conf)));
     store.register_late_pass(|_| Box::new(permissions_set_readonly_false::PermissionsSetReadonlyFalse));
     store.register_late_pass(|_| Box::new(size_of_ref::SizeOfRef));
     store.register_late_pass(|_| Box::new(multiple_unsafe_ops_per_block::MultipleUnsafeOpsPerBlock));
-    store.register_late_pass(move |_| {
-        Box::new(extra_unused_type_parameters::ExtraUnusedTypeParameters::new(
-            avoid_breaking_exported_api,
-        ))
-    });
+    store.register_late_pass(move |_| Box::new(extra_unused_type_parameters::ExtraUnusedTypeParameters::new(conf)));
     store.register_late_pass(|_| Box::new(no_mangle_with_rust_abi::NoMangleWithRustAbi));
     store.register_late_pass(|_| Box::new(collection_is_never_read::CollectionIsNeverRead));
     store.register_late_pass(|_| Box::new(missing_assert_message::MissingAssertMessage));
     store.register_late_pass(|_| Box::new(needless_maybe_sized::NeedlessMaybeSized));
     store.register_late_pass(|_| Box::new(redundant_async_block::RedundantAsyncBlock));
     store.register_late_pass(|_| Box::new(let_with_type_underscore::UnderscoreTyped));
-    store.register_late_pass(move |_| Box::new(manual_main_separator_str::ManualMainSeparatorStr::new(msrv())));
+    store.register_late_pass(move |_| Box::new(manual_main_separator_str::ManualMainSeparatorStr::new(conf)));
     store.register_late_pass(|_| Box::new(unnecessary_struct_initialization::UnnecessaryStruct));
-    store.register_late_pass(move |_| {
-        Box::new(unnecessary_box_returns::UnnecessaryBoxReturns::new(
-            avoid_breaking_exported_api,
-            unnecessary_box_size,
-        ))
-    });
+    store.register_late_pass(move |_| Box::new(unnecessary_box_returns::UnnecessaryBoxReturns::new(conf)));
     store.register_late_pass(|_| Box::new(lines_filter_map_ok::LinesFilterMapOk));
     store.register_late_pass(|_| Box::new(tests_outside_test_module::TestsOutsideTestModule));
     store.register_late_pass(|_| Box::new(manual_slice_size_calculation::ManualSliceSizeCalculation));
-    store.register_early_pass(move || {
-        Box::new(excessive_nesting::ExcessiveNesting {
-            excessive_nesting_threshold,
-            nodes: rustc_ast::node_id::NodeSet::new(),
-        })
-    });
+    store.register_early_pass(move || Box::new(excessive_nesting::ExcessiveNesting::new(conf)));
     store.register_late_pass(|_| Box::new(items_after_test_module::ItemsAfterTestModule));
     store.register_early_pass(|| Box::new(ref_patterns::RefPatterns));
     store.register_late_pass(|_| Box::new(default_constructed_unit_structs::DefaultConstructedUnitStructs));
@@ -1095,44 +861,21 @@ pub fn register_lints(store: &mut rustc_lint::LintStore, conf: &'static Conf) {
     store.register_late_pass(|_| Box::new(redundant_type_annotations::RedundantTypeAnnotations));
     store.register_late_pass(|_| Box::new(arc_with_non_send_sync::ArcWithNonSendSync));
     store.register_late_pass(|_| Box::new(needless_if::NeedlessIf));
-    store.register_late_pass(move |_| {
-        Box::new(min_ident_chars::MinIdentChars {
-            allowed_idents_below_min_chars: allowed_idents_below_min_chars.clone(),
-            min_ident_chars_threshold,
-        })
-    });
-    store.register_late_pass(move |_| Box::new(large_stack_frames::LargeStackFrames::new(stack_size_threshold)));
+    store.register_late_pass(move |_| Box::new(min_ident_chars::MinIdentChars::new(conf)));
+    store.register_late_pass(move |_| Box::new(large_stack_frames::LargeStackFrames::new(conf)));
     store.register_late_pass(|_| Box::new(single_range_in_vec_init::SingleRangeInVecInit));
-    store.register_late_pass(move |_| {
-        Box::new(needless_pass_by_ref_mut::NeedlessPassByRefMut::new(
-            avoid_breaking_exported_api,
-        ))
-    });
+    store.register_late_pass(move |_| Box::new(needless_pass_by_ref_mut::NeedlessPassByRefMut::new(conf)));
     store.register_late_pass(|_| Box::new(non_canonical_impls::NonCanonicalImpls));
-    store.register_late_pass(move |_| {
-        Box::new(single_call_fn::SingleCallFn {
-            avoid_breaking_exported_api,
-            def_id_to_usage: rustc_data_structures::fx::FxIndexMap::default(),
-        })
-    });
-    store.register_early_pass(move || {
-        Box::new(raw_strings::RawStrings {
-            allow_one_hash_in_raw_strings,
-        })
-    });
-    store.register_late_pass(move |_| Box::new(legacy_numeric_constants::LegacyNumericConstants::new(msrv())));
+    store.register_late_pass(move |_| Box::new(single_call_fn::SingleCallFn::new(conf)));
+    store.register_early_pass(move || Box::new(raw_strings::RawStrings::new(conf)));
+    store.register_late_pass(move |_| Box::new(legacy_numeric_constants::LegacyNumericConstants::new(conf)));
     store.register_late_pass(|_| Box::new(manual_range_patterns::ManualRangePatterns));
     store.register_early_pass(|| Box::new(visibility::Visibility));
-    store.register_late_pass(move |_| Box::new(tuple_array_conversions::TupleArrayConversions { msrv: msrv() }));
+    store.register_late_pass(move |_| Box::new(tuple_array_conversions::TupleArrayConversions::new(conf)));
     store.register_late_pass(|_| Box::new(manual_float_methods::ManualFloatMethods));
     store.register_late_pass(|_| Box::new(four_forward_slashes::FourForwardSlashes));
     store.register_late_pass(|_| Box::new(error_impl_error::ErrorImplError));
-    store.register_late_pass(move |_| {
-        Box::new(absolute_paths::AbsolutePaths {
-            absolute_paths_max_segments,
-            absolute_paths_allowed_crates: absolute_paths_allowed_crates.clone(),
-        })
-    });
+    store.register_late_pass(move |_| Box::new(absolute_paths::AbsolutePaths::new(conf)));
     store.register_late_pass(|_| Box::new(redundant_locals::RedundantLocals));
     store.register_late_pass(|_| Box::new(ignored_unit_patterns::IgnoredUnitPatterns));
     store.register_late_pass(|_| Box::<reserve_after_initialization::ReserveAfterInitialization>::default());
@@ -1141,38 +884,29 @@ pub fn register_lints(store: &mut rustc_lint::LintStore, conf: &'static Conf) {
     store.register_late_pass(|_| Box::new(unnecessary_map_on_constructor::UnnecessaryMapOnConstructor));
     store.register_late_pass(move |_| {
         Box::new(needless_borrows_for_generic_args::NeedlessBorrowsForGenericArgs::new(
-            msrv(),
+            conf,
         ))
     });
-    store.register_late_pass(move |_| Box::new(manual_hash_one::ManualHashOne::new(msrv())));
+    store.register_late_pass(move |_| Box::new(manual_hash_one::ManualHashOne::new(conf)));
     store.register_late_pass(|_| Box::new(iter_without_into_iter::IterWithoutIntoIter));
+    store.register_late_pass(|_| Box::<pathbuf_init_then_push::PathbufThenPush<'_>>::default());
     store.register_late_pass(|_| Box::new(iter_over_hash_type::IterOverHashType));
     store.register_late_pass(|_| Box::new(impl_hash_with_borrow_str_and_bytes::ImplHashWithBorrowStrBytes));
     store.register_late_pass(|_| Box::new(repeat_vec_with_capacity::RepeatVecWithCapacity));
     store.register_late_pass(|_| Box::new(uninhabited_references::UninhabitedReferences));
     store.register_late_pass(|_| Box::new(ineffective_open_options::IneffectiveOpenOptions));
     store.register_late_pass(|_| Box::<unconditional_recursion::UnconditionalRecursion>::default());
-    store.register_late_pass(move |_| {
-        Box::new(pub_underscore_fields::PubUnderscoreFields {
-            behavior: pub_underscore_fields_behavior,
-        })
-    });
-    store
-        .register_late_pass(move |_| Box::new(missing_const_for_thread_local::MissingConstForThreadLocal::new(msrv())));
-    store.register_late_pass(move |_| Box::new(incompatible_msrv::IncompatibleMsrv::new(msrv())));
+    store.register_late_pass(move |_| Box::new(pub_underscore_fields::PubUnderscoreFields::new(conf)));
+    store.register_late_pass(move |_| Box::new(missing_const_for_thread_local::MissingConstForThreadLocal::new(conf)));
+    store.register_late_pass(move |_| Box::new(incompatible_msrv::IncompatibleMsrv::new(conf)));
     store.register_late_pass(|_| Box::new(to_string_trait_impl::ToStringTraitImpl));
     store.register_early_pass(|| Box::new(multiple_bound_locations::MultipleBoundLocations));
-    store.register_late_pass(move |_| Box::new(assigning_clones::AssigningClones::new(msrv())));
+    store.register_late_pass(move |_| Box::new(assigning_clones::AssigningClones::new(conf)));
     store.register_late_pass(|_| Box::new(zero_repeat_side_effects::ZeroRepeatSideEffects));
     store.register_late_pass(|_| Box::new(manual_unwrap_or_default::ManualUnwrapOrDefault));
     store.register_late_pass(|_| Box::new(integer_division_remainder_used::IntegerDivisionRemainderUsed));
-    store.register_late_pass(move |_| {
-        Box::new(macro_metavars_in_unsafe::ExprMetavarsInUnsafe {
-            warn_unsafe_macro_metavars_in_private_macros,
-            ..Default::default()
-        })
-    });
-    store.register_late_pass(move |_| Box::new(string_patterns::StringPatterns::new(msrv())));
+    store.register_late_pass(move |_| Box::new(macro_metavars_in_unsafe::ExprMetavarsInUnsafe::new(conf)));
+    store.register_late_pass(move |_| Box::new(string_patterns::StringPatterns::new(conf)));
     store.register_early_pass(|| Box::new(field_scoped_visibility_modifiers::FieldScopedVisibilityModifiers));
     store.register_late_pass(|_| Box::new(set_contains_or_insert::HashsetInsertAfterContains));
     store.register_early_pass(|| Box::new(byte_char_slices::ByteCharSlice));
diff --git a/clippy_lints/src/lifetimes.rs b/clippy_lints/src/lifetimes.rs
index 443d6189c1f..9f063ced313 100644
--- a/clippy_lints/src/lifetimes.rs
+++ b/clippy_lints/src/lifetimes.rs
@@ -22,6 +22,7 @@ use rustc_session::declare_lint_pass;
 use rustc_span::def_id::LocalDefId;
 use rustc_span::symbol::{kw, Ident, Symbol};
 use rustc_span::Span;
+use std::ops::ControlFlow;
 
 declare_clippy_lint! {
     /// ### What it does
@@ -380,11 +381,8 @@ fn could_use_elision<'tcx>(
             return None;
         }
 
-        let mut checker = BodyLifetimeChecker {
-            lifetimes_used_in_body: false,
-        };
-        checker.visit_expr(body.value);
-        if checker.lifetimes_used_in_body {
+        let mut checker = BodyLifetimeChecker;
+        if checker.visit_expr(body.value).is_break() {
             return None;
         }
     }
@@ -694,15 +692,15 @@ fn report_extra_impl_lifetimes<'tcx>(cx: &LateContext<'tcx>, impl_: &'tcx Impl<'
     }
 }
 
-struct BodyLifetimeChecker {
-    lifetimes_used_in_body: bool,
-}
+struct BodyLifetimeChecker;
 
 impl<'tcx> Visitor<'tcx> for BodyLifetimeChecker {
+    type Result = ControlFlow<()>;
     // for lifetimes as parameters of generics
-    fn visit_lifetime(&mut self, lifetime: &'tcx Lifetime) {
+    fn visit_lifetime(&mut self, lifetime: &'tcx Lifetime) -> ControlFlow<()> {
         if !lifetime.is_anonymous() && lifetime.ident.name != kw::StaticLifetime {
-            self.lifetimes_used_in_body = true;
+            return ControlFlow::Break(());
         }
+        ControlFlow::Continue(())
     }
 }
diff --git a/clippy_lints/src/literal_representation.rs b/clippy_lints/src/literal_representation.rs
index 7481543941a..b685d1dad1a 100644
--- a/clippy_lints/src/literal_representation.rs
+++ b/clippy_lints/src/literal_representation.rs
@@ -1,6 +1,7 @@
 //! Lints concerned with the grouping of digits with underscores in integral or
 //! floating-point literal expressions.
 
+use clippy_config::Conf;
 use clippy_utils::diagnostics::span_lint_and_sugg;
 use clippy_utils::numeric_literal::{NumericLiteral, Radix};
 use clippy_utils::source::snippet_opt;
@@ -218,7 +219,6 @@ impl WarningType {
     }
 }
 
-#[derive(Copy, Clone)]
 pub struct LiteralDigitGrouping {
     lint_fraction_readability: bool,
 }
@@ -245,13 +245,13 @@ impl EarlyLintPass for LiteralDigitGrouping {
 const UUID_GROUP_LENS: [usize; 5] = [8, 4, 4, 4, 12];
 
 impl LiteralDigitGrouping {
-    pub fn new(lint_fraction_readability: bool) -> Self {
+    pub fn new(conf: &'static Conf) -> Self {
         Self {
-            lint_fraction_readability,
+            lint_fraction_readability: conf.unreadable_literal_lint_fractions,
         }
     }
 
-    fn check_lit(self, cx: &EarlyContext<'_>, lit: token::Lit, span: Span) {
+    fn check_lit(&self, cx: &EarlyContext<'_>, lit: token::Lit, span: Span) {
         if let Some(src) = snippet_opt(cx, span)
             && let Ok(lit_kind) = LitKind::from_token_lit(lit)
             && let Some(mut num_lit) = NumericLiteral::from_lit_kind(&src, &lit_kind)
@@ -437,7 +437,6 @@ impl LiteralDigitGrouping {
 }
 
 #[expect(clippy::module_name_repetitions)]
-#[derive(Copy, Clone)]
 pub struct DecimalLiteralRepresentation {
     threshold: u64,
 }
@@ -455,11 +454,12 @@ impl EarlyLintPass for DecimalLiteralRepresentation {
 }
 
 impl DecimalLiteralRepresentation {
-    #[must_use]
-    pub fn new(threshold: u64) -> Self {
-        Self { threshold }
+    pub fn new(conf: &'static Conf) -> Self {
+        Self {
+            threshold: conf.literal_representation_threshold,
+        }
     }
-    fn check_lit(self, cx: &EarlyContext<'_>, lit: token::Lit, span: Span) {
+    fn check_lit(&self, cx: &EarlyContext<'_>, lit: token::Lit, span: Span) {
         // Lint integral literals.
         if let Ok(lit_kind) = LitKind::from_token_lit(lit)
             && let LitKind::Int(val, _) = lit_kind
diff --git a/clippy_lints/src/loops/mod.rs b/clippy_lints/src/loops/mod.rs
index 64ea591993d..7c2a8098af2 100644
--- a/clippy_lints/src/loops/mod.rs
+++ b/clippy_lints/src/loops/mod.rs
@@ -23,6 +23,7 @@ mod while_let_loop;
 mod while_let_on_iterator;
 
 use clippy_config::msrvs::Msrv;
+use clippy_config::Conf;
 use clippy_utils::higher;
 use rustc_hir::{Expr, ExprKind, LoopSource, Pat};
 use rustc_lint::{LateContext, LateLintPass};
@@ -717,10 +718,10 @@ pub struct Loops {
     enforce_iter_loop_reborrow: bool,
 }
 impl Loops {
-    pub fn new(msrv: Msrv, enforce_iter_loop_reborrow: bool) -> Self {
+    pub fn new(conf: &'static Conf) -> Self {
         Self {
-            msrv,
-            enforce_iter_loop_reborrow,
+            msrv: conf.msrv.clone(),
+            enforce_iter_loop_reborrow: conf.enforce_iter_loop_reborrow,
         }
     }
 }
diff --git a/clippy_lints/src/loops/mut_range_bound.rs b/clippy_lints/src/loops/mut_range_bound.rs
index 6c6a9a1a2e0..21f9a71f2c5 100644
--- a/clippy_lints/src/loops/mut_range_bound.rs
+++ b/clippy_lints/src/loops/mut_range_bound.rs
@@ -8,6 +8,7 @@ use rustc_lint::LateContext;
 use rustc_middle::mir::FakeReadCause;
 use rustc_middle::ty;
 use rustc_span::Span;
+use std::ops::ControlFlow;
 
 pub(super) fn check(cx: &LateContext<'_>, arg: &Expr<'_>, body: &Expr<'_>) {
     if let Some(higher::Range {
@@ -114,7 +115,6 @@ impl MutatePairDelegate<'_, '_> {
 struct BreakAfterExprVisitor {
     hir_id: HirId,
     past_expr: bool,
-    past_candidate: bool,
     break_after_expr: bool,
 }
 
@@ -123,7 +123,6 @@ impl BreakAfterExprVisitor {
         let mut visitor = BreakAfterExprVisitor {
             hir_id,
             past_expr: false,
-            past_candidate: false,
             break_after_expr: false,
         };
 
@@ -135,21 +134,19 @@ impl BreakAfterExprVisitor {
 }
 
 impl<'tcx> Visitor<'tcx> for BreakAfterExprVisitor {
-    fn visit_expr(&mut self, expr: &'tcx Expr<'tcx>) {
-        if self.past_candidate {
-            return;
-        }
-
+    type Result = ControlFlow<()>;
+    fn visit_expr(&mut self, expr: &'tcx Expr<'tcx>) -> ControlFlow<()> {
         if expr.hir_id == self.hir_id {
             self.past_expr = true;
+            ControlFlow::Continue(())
         } else if self.past_expr {
             if matches!(&expr.kind, ExprKind::Break(..)) {
                 self.break_after_expr = true;
             }
 
-            self.past_candidate = true;
+            ControlFlow::Break(())
         } else {
-            intravisit::walk_expr(self, expr);
+            intravisit::walk_expr(self, expr)
         }
     }
 }
diff --git a/clippy_lints/src/loops/single_element_loop.rs b/clippy_lints/src/loops/single_element_loop.rs
index 108fdb69775..2b41911e8ec 100644
--- a/clippy_lints/src/loops/single_element_loop.rs
+++ b/clippy_lints/src/loops/single_element_loop.rs
@@ -5,7 +5,7 @@ use clippy_utils::visitors::contains_break_or_continue;
 use rustc_ast::util::parser::PREC_PREFIX;
 use rustc_ast::Mutability;
 use rustc_errors::Applicability;
-use rustc_hir::{is_range_literal, BorrowKind, Expr, ExprKind, Pat};
+use rustc_hir::{is_range_literal, BorrowKind, Expr, ExprKind, Pat, PatKind};
 use rustc_lint::LateContext;
 use rustc_span::edition::Edition;
 use rustc_span::sym;
@@ -70,7 +70,10 @@ pub(super) fn check<'tcx>(
         && !contains_break_or_continue(body)
     {
         let mut applicability = Applicability::MachineApplicable;
-        let pat_snip = snippet_with_applicability(cx, pat.span, "..", &mut applicability);
+        let mut pat_snip = snippet_with_applicability(cx, pat.span, "..", &mut applicability);
+        if matches!(pat.kind, PatKind::Or(..)) {
+            pat_snip = format!("({pat_snip})").into();
+        }
         let mut arg_snip = snippet_with_applicability(cx, arg_expression.span, "..", &mut applicability);
         let mut block_str = snippet_with_applicability(cx, block.span, "..", &mut applicability).into_owned();
         block_str.remove(0);
diff --git a/clippy_lints/src/loops/while_immutable_condition.rs b/clippy_lints/src/loops/while_immutable_condition.rs
index 3dff826cb85..e7b3a2c4973 100644
--- a/clippy_lints/src/loops/while_immutable_condition.rs
+++ b/clippy_lints/src/loops/while_immutable_condition.rs
@@ -7,6 +7,7 @@ use rustc_hir::def_id::DefIdMap;
 use rustc_hir::intravisit::{walk_expr, Visitor};
 use rustc_hir::{Expr, ExprKind, HirIdSet, QPath};
 use rustc_lint::LateContext;
+use std::ops::ControlFlow;
 
 pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, cond: &'tcx Expr<'_>, expr: &'tcx Expr<'_>) {
     if constant(cx, cx.typeck_results(), cond).is_some() {
@@ -35,11 +36,8 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, cond: &'tcx Expr<'_>, expr: &'
         };
     let mutable_static_in_cond = var_visitor.def_ids.items().any(|(_, v)| *v);
 
-    let mut has_break_or_return_visitor = HasBreakOrReturnVisitor {
-        has_break_or_return: false,
-    };
-    has_break_or_return_visitor.visit_expr(expr);
-    let has_break_or_return = has_break_or_return_visitor.has_break_or_return;
+    let mut has_break_or_return_visitor = HasBreakOrReturnVisitor;
+    let has_break_or_return = has_break_or_return_visitor.visit_expr(expr).is_break();
 
     if no_cond_variable_mutated && !mutable_static_in_cond {
         span_lint_and_then(
@@ -59,25 +57,19 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, cond: &'tcx Expr<'_>, expr: &'
     }
 }
 
-struct HasBreakOrReturnVisitor {
-    has_break_or_return: bool,
-}
+struct HasBreakOrReturnVisitor;
 
 impl<'tcx> Visitor<'tcx> for HasBreakOrReturnVisitor {
-    fn visit_expr(&mut self, expr: &'tcx Expr<'_>) {
-        if self.has_break_or_return {
-            return;
-        }
-
+    type Result = ControlFlow<()>;
+    fn visit_expr(&mut self, expr: &'tcx Expr<'_>) -> ControlFlow<()> {
         match expr.kind {
             ExprKind::Ret(_) | ExprKind::Break(_, _) => {
-                self.has_break_or_return = true;
-                return;
+                return ControlFlow::Break(());
             },
             _ => {},
         }
 
-        walk_expr(self, expr);
+        walk_expr(self, expr)
     }
 }
 
diff --git a/clippy_lints/src/macro_metavars_in_unsafe.rs b/clippy_lints/src/macro_metavars_in_unsafe.rs
index d1ae243877d..fed58f7ff14 100644
--- a/clippy_lints/src/macro_metavars_in_unsafe.rs
+++ b/clippy_lints/src/macro_metavars_in_unsafe.rs
@@ -1,6 +1,4 @@
-use std::collections::btree_map::Entry;
-use std::collections::BTreeMap;
-
+use clippy_config::Conf;
 use clippy_utils::diagnostics::span_lint_hir_and_then;
 use clippy_utils::is_lint_allowed;
 use itertools::Itertools;
@@ -10,6 +8,8 @@ use rustc_hir::{BlockCheckMode, Expr, ExprKind, HirId, Stmt, UnsafeSource};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_session::impl_lint_pass;
 use rustc_span::{sym, Span, SyntaxContext};
+use std::collections::btree_map::Entry;
+use std::collections::BTreeMap;
 
 declare_clippy_lint! {
     /// ### What it does
@@ -90,9 +90,8 @@ pub enum MetavarState {
     ReferencedInSafe,
 }
 
-#[derive(Default)]
 pub struct ExprMetavarsInUnsafe {
-    pub warn_unsafe_macro_metavars_in_private_macros: bool,
+    warn_unsafe_macro_metavars_in_private_macros: bool,
     /// A metavariable can be expanded more than once, potentially across multiple bodies, so it
     /// requires some state kept across HIR nodes to make it possible to delay a warning
     /// and later undo:
@@ -106,7 +105,16 @@ pub struct ExprMetavarsInUnsafe {
     ///     }
     /// }
     /// ```
-    pub metavar_expns: BTreeMap<Span, MetavarState>,
+    metavar_expns: BTreeMap<Span, MetavarState>,
+}
+
+impl ExprMetavarsInUnsafe {
+    pub fn new(conf: &'static Conf) -> Self {
+        Self {
+            warn_unsafe_macro_metavars_in_private_macros: conf.warn_unsafe_macro_metavars_in_private_macros,
+            metavar_expns: BTreeMap::new(),
+        }
+    }
 }
 
 struct BodyVisitor<'a, 'tcx> {
diff --git a/clippy_lints/src/manual_bits.rs b/clippy_lints/src/manual_bits.rs
index d9f6be6dc2b..5cbdc7f864a 100644
--- a/clippy_lints/src/manual_bits.rs
+++ b/clippy_lints/src/manual_bits.rs
@@ -1,4 +1,5 @@
 use clippy_config::msrvs::{self, Msrv};
+use clippy_config::Conf;
 use clippy_utils::diagnostics::span_lint_and_sugg;
 use clippy_utils::get_parent_expr;
 use clippy_utils::source::snippet_with_context;
@@ -34,15 +35,15 @@ declare_clippy_lint! {
     "manual implementation of `size_of::<T>() * 8` can be simplified with `T::BITS`"
 }
 
-#[derive(Clone)]
 pub struct ManualBits {
     msrv: Msrv,
 }
 
 impl ManualBits {
-    #[must_use]
-    pub fn new(msrv: Msrv) -> Self {
-        Self { msrv }
+    pub fn new(conf: &'static Conf) -> Self {
+        Self {
+            msrv: conf.msrv.clone(),
+        }
     }
 }
 
diff --git a/clippy_lints/src/manual_clamp.rs b/clippy_lints/src/manual_clamp.rs
index e2ab4415518..a79ad018a04 100644
--- a/clippy_lints/src/manual_clamp.rs
+++ b/clippy_lints/src/manual_clamp.rs
@@ -1,4 +1,5 @@
 use clippy_config::msrvs::{self, Msrv};
+use clippy_config::Conf;
 use clippy_utils::consts::{constant, Constant};
 use clippy_utils::diagnostics::{span_lint_and_then, span_lint_hir_and_then};
 use clippy_utils::higher::If;
@@ -97,8 +98,10 @@ pub struct ManualClamp {
 }
 
 impl ManualClamp {
-    pub fn new(msrv: Msrv) -> Self {
-        Self { msrv }
+    pub fn new(conf: &'static Conf) -> Self {
+        Self {
+            msrv: conf.msrv.clone(),
+        }
     }
 }
 
diff --git a/clippy_lints/src/manual_hash_one.rs b/clippy_lints/src/manual_hash_one.rs
index daa8101aa5f..1c568b1b74f 100644
--- a/clippy_lints/src/manual_hash_one.rs
+++ b/clippy_lints/src/manual_hash_one.rs
@@ -1,4 +1,5 @@
 use clippy_config::msrvs::{self, Msrv};
+use clippy_config::Conf;
 use clippy_utils::diagnostics::span_lint_hir_and_then;
 use clippy_utils::source::snippet_opt;
 use clippy_utils::visitors::{is_local_used, local_used_once};
@@ -51,9 +52,10 @@ pub struct ManualHashOne {
 }
 
 impl ManualHashOne {
-    #[must_use]
-    pub fn new(msrv: Msrv) -> Self {
-        Self { msrv }
+    pub fn new(conf: &'static Conf) -> Self {
+        Self {
+            msrv: conf.msrv.clone(),
+        }
     }
 }
 
diff --git a/clippy_lints/src/manual_is_ascii_check.rs b/clippy_lints/src/manual_is_ascii_check.rs
index 6f6ba1852a6..a9f21d34e4c 100644
--- a/clippy_lints/src/manual_is_ascii_check.rs
+++ b/clippy_lints/src/manual_is_ascii_check.rs
@@ -1,4 +1,5 @@
 use clippy_config::msrvs::{self, Msrv};
+use clippy_config::Conf;
 use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::macros::matching_root_macro_call;
 use clippy_utils::sugg::Sugg;
@@ -62,9 +63,10 @@ pub struct ManualIsAsciiCheck {
 }
 
 impl ManualIsAsciiCheck {
-    #[must_use]
-    pub fn new(msrv: Msrv) -> Self {
-        Self { msrv }
+    pub fn new(conf: &'static Conf) -> Self {
+        Self {
+            msrv: conf.msrv.clone(),
+        }
     }
 }
 
diff --git a/clippy_lints/src/manual_main_separator_str.rs b/clippy_lints/src/manual_main_separator_str.rs
index 8e8cdc3fb07..db491a8c8f6 100644
--- a/clippy_lints/src/manual_main_separator_str.rs
+++ b/clippy_lints/src/manual_main_separator_str.rs
@@ -1,4 +1,5 @@
 use clippy_config::msrvs::{self, Msrv};
+use clippy_config::Conf;
 use clippy_utils::diagnostics::span_lint_and_sugg;
 use clippy_utils::{is_trait_method, match_def_path, paths, peel_hir_expr_refs};
 use rustc_errors::Applicability;
@@ -37,9 +38,10 @@ pub struct ManualMainSeparatorStr {
 }
 
 impl ManualMainSeparatorStr {
-    #[must_use]
-    pub fn new(msrv: Msrv) -> Self {
-        Self { msrv }
+    pub fn new(conf: &'static Conf) -> Self {
+        Self {
+            msrv: conf.msrv.clone(),
+        }
     }
 }
 
diff --git a/clippy_lints/src/manual_non_exhaustive.rs b/clippy_lints/src/manual_non_exhaustive.rs
index 73a505fd73f..28cfe22835a 100644
--- a/clippy_lints/src/manual_non_exhaustive.rs
+++ b/clippy_lints/src/manual_non_exhaustive.rs
@@ -1,4 +1,5 @@
 use clippy_config::msrvs::{self, Msrv};
+use clippy_config::Conf;
 use clippy_utils::diagnostics::{span_lint_and_then, span_lint_hir_and_then};
 use clippy_utils::is_doc_hidden;
 use clippy_utils::source::snippet_opt;
@@ -67,9 +68,10 @@ pub struct ManualNonExhaustiveStruct {
 }
 
 impl ManualNonExhaustiveStruct {
-    #[must_use]
-    pub fn new(msrv: Msrv) -> Self {
-        Self { msrv }
+    pub fn new(conf: &'static Conf) -> Self {
+        Self {
+            msrv: conf.msrv.clone(),
+        }
     }
 }
 
@@ -83,10 +85,9 @@ pub struct ManualNonExhaustiveEnum {
 }
 
 impl ManualNonExhaustiveEnum {
-    #[must_use]
-    pub fn new(msrv: Msrv) -> Self {
+    pub fn new(conf: &'static Conf) -> Self {
         Self {
-            msrv,
+            msrv: conf.msrv.clone(),
             constructed_enum_variants: FxHashSet::default(),
             potential_enums: Vec::new(),
         }
diff --git a/clippy_lints/src/manual_rem_euclid.rs b/clippy_lints/src/manual_rem_euclid.rs
index b518dc26937..78a750f0dcd 100644
--- a/clippy_lints/src/manual_rem_euclid.rs
+++ b/clippy_lints/src/manual_rem_euclid.rs
@@ -1,4 +1,5 @@
 use clippy_config::msrvs::{self, Msrv};
+use clippy_config::Conf;
 use clippy_utils::consts::{constant_full_int, FullInt};
 use clippy_utils::diagnostics::span_lint_and_sugg;
 use clippy_utils::source::snippet_with_context;
@@ -38,9 +39,10 @@ pub struct ManualRemEuclid {
 }
 
 impl ManualRemEuclid {
-    #[must_use]
-    pub fn new(msrv: Msrv) -> Self {
-        Self { msrv }
+    pub fn new(conf: &'static Conf) -> Self {
+        Self {
+            msrv: conf.msrv.clone(),
+        }
     }
 }
 
diff --git a/clippy_lints/src/manual_retain.rs b/clippy_lints/src/manual_retain.rs
index 8f7b8abd0c3..09f6362b4dd 100644
--- a/clippy_lints/src/manual_retain.rs
+++ b/clippy_lints/src/manual_retain.rs
@@ -1,4 +1,5 @@
 use clippy_config::msrvs::{self, Msrv};
+use clippy_config::Conf;
 use clippy_utils::diagnostics::span_lint_and_sugg;
 use clippy_utils::source::snippet;
 use clippy_utils::ty::{is_type_diagnostic_item, is_type_lang_item};
@@ -59,9 +60,10 @@ pub struct ManualRetain {
 }
 
 impl ManualRetain {
-    #[must_use]
-    pub fn new(msrv: Msrv) -> Self {
-        Self { msrv }
+    pub fn new(conf: &'static Conf) -> Self {
+        Self {
+            msrv: conf.msrv.clone(),
+        }
     }
 }
 
diff --git a/clippy_lints/src/manual_strip.rs b/clippy_lints/src/manual_strip.rs
index 6a523ad1564..686ecccf829 100644
--- a/clippy_lints/src/manual_strip.rs
+++ b/clippy_lints/src/manual_strip.rs
@@ -1,4 +1,5 @@
 use clippy_config::msrvs::{self, Msrv};
+use clippy_config::Conf;
 use clippy_utils::consts::{constant, Constant};
 use clippy_utils::diagnostics::{multispan_sugg, span_lint_and_then};
 use clippy_utils::source::snippet;
@@ -50,9 +51,10 @@ pub struct ManualStrip {
 }
 
 impl ManualStrip {
-    #[must_use]
-    pub fn new(msrv: Msrv) -> Self {
-        Self { msrv }
+    pub fn new(conf: &'static Conf) -> Self {
+        Self {
+            msrv: conf.msrv.clone(),
+        }
     }
 }
 
diff --git a/clippy_lints/src/matches/manual_unwrap_or.rs b/clippy_lints/src/matches/manual_unwrap_or.rs
index 0940fc3219b..85a08f81c2f 100644
--- a/clippy_lints/src/matches/manual_unwrap_or.rs
+++ b/clippy_lints/src/matches/manual_unwrap_or.rs
@@ -35,6 +35,17 @@ pub(super) fn check_if_let<'tcx>(
     else_expr: &'tcx Expr<'_>,
 ) {
     let ty = cx.typeck_results().expr_ty(let_expr);
+    let then_ty = cx.typeck_results().expr_ty(then_expr);
+    // The signature is `fn unwrap_or<T>(self: Option<T>, default: T) -> T`.
+    // When `expr_adjustments(then_expr).is_empty()`, `T` should equate to `default`'s type.
+    // Otherwise, type error will occur.
+    if cx.typeck_results().expr_adjustments(then_expr).is_empty()
+        && let rustc_middle::ty::Adt(_did, args) = ty.kind()
+        && let Some(some_ty) = args.first().and_then(|arg| arg.as_type())
+        && some_ty != then_ty
+    {
+        return;
+    }
     check_and_lint(cx, expr, let_pat, let_expr, then_expr, peel_blocks(else_expr), ty);
 }
 
diff --git a/clippy_lints/src/matches/mod.rs b/clippy_lints/src/matches/mod.rs
index 22a299ae3d8..cec3504ed8d 100644
--- a/clippy_lints/src/matches/mod.rs
+++ b/clippy_lints/src/matches/mod.rs
@@ -25,6 +25,7 @@ mod try_err;
 mod wild_in_or_pats;
 
 use clippy_config::msrvs::{self, Msrv};
+use clippy_config::Conf;
 use clippy_utils::source::walk_span_to_context;
 use clippy_utils::{higher, in_constant, is_direct_expn_of, is_span_match, span_contains_cfg};
 use rustc_hir::{Arm, Expr, ExprKind, LetStmt, MatchSource, Pat, PatKind};
@@ -980,10 +981,9 @@ pub struct Matches {
 }
 
 impl Matches {
-    #[must_use]
-    pub fn new(msrv: Msrv) -> Self {
+    pub fn new(conf: &'static Conf) -> Self {
         Self {
-            msrv,
+            msrv: conf.msrv.clone(),
             infallible_destructuring_match_linted: false,
         }
     }
diff --git a/clippy_lints/src/matches/significant_drop_in_scrutinee.rs b/clippy_lints/src/matches/significant_drop_in_scrutinee.rs
index 9047c9627d9..9c2f42d2187 100644
--- a/clippy_lints/src/matches/significant_drop_in_scrutinee.rs
+++ b/clippy_lints/src/matches/significant_drop_in_scrutinee.rs
@@ -232,7 +232,7 @@ impl<'a, 'tcx> SigDropChecker<'a, 'tcx> {
 enum SigDropHolder {
     /// No values with significant drop present in this expression.
     ///
-    /// Expressions that we've emited lints do not count.
+    /// Expressions that we've emitted lints do not count.
     None,
     /// Some field in this expression references to values with significant drop.
     ///
@@ -426,7 +426,7 @@ fn ty_has_erased_regions(ty: Ty<'_>) -> bool {
 
 impl<'a, 'tcx> Visitor<'tcx> for SigDropHelper<'a, 'tcx> {
     fn visit_expr(&mut self, ex: &'tcx Expr<'_>) {
-        // We've emited a lint on some neighborhood expression. That lint will suggest to move out the
+        // We've emitted a lint on some neighborhood expression. That lint will suggest to move out the
         // _parent_ expression (not the expression itself). Since we decide to move out the parent
         // expression, it is pointless to continue to process the current expression.
         if self.sig_drop_holder == SigDropHolder::Moved {
@@ -450,7 +450,7 @@ impl<'a, 'tcx> Visitor<'tcx> for SigDropHelper<'a, 'tcx> {
                 ExprKind::Assign(lhs, _, _) | ExprKind::AssignOp(_, lhs, _)
                     if lhs.hir_id == ex.hir_id && self.sig_drop_holder == SigDropHolder::Moved =>
                 {
-                    // Never move out only the assignee. Instead, we should always move out the whole assigment.
+                    // Never move out only the assignee. Instead, we should always move out the whole assignment.
                     self.replace_current_sig_drop(parent_ex.span, true, 0);
                 },
                 _ => {
diff --git a/clippy_lints/src/mem_replace.rs b/clippy_lints/src/mem_replace.rs
index 578aa7989e7..72a5945ad9b 100644
--- a/clippy_lints/src/mem_replace.rs
+++ b/clippy_lints/src/mem_replace.rs
@@ -1,4 +1,5 @@
 use clippy_config::msrvs::{self, Msrv};
+use clippy_config::Conf;
 use clippy_utils::diagnostics::{span_lint_and_help, span_lint_and_sugg, span_lint_and_then};
 use clippy_utils::source::{snippet, snippet_with_applicability};
 use clippy_utils::sugg::Sugg;
@@ -217,9 +218,10 @@ pub struct MemReplace {
 }
 
 impl MemReplace {
-    #[must_use]
-    pub fn new(msrv: Msrv) -> Self {
-        Self { msrv }
+    pub fn new(conf: &'static Conf) -> Self {
+        Self {
+            msrv: conf.msrv.clone(),
+        }
     }
 }
 
diff --git a/clippy_lints/src/methods/bind_instead_of_map.rs b/clippy_lints/src/methods/bind_instead_of_map.rs
index fb440ce656e..20f3722e173 100644
--- a/clippy_lints/src/methods/bind_instead_of_map.rs
+++ b/clippy_lints/src/methods/bind_instead_of_map.rs
@@ -10,59 +10,80 @@ use rustc_hir::{LangItem, QPath};
 use rustc_lint::LateContext;
 use rustc_span::Span;
 
-pub(crate) struct OptionAndThenSome;
-
-impl BindInsteadOfMap for OptionAndThenSome {
-    const VARIANT_LANG_ITEM: LangItem = LangItem::OptionSome;
-    const BAD_METHOD_NAME: &'static str = "and_then";
-    const GOOD_METHOD_NAME: &'static str = "map";
+pub(super) fn check_and_then_some(
+    cx: &LateContext<'_>,
+    expr: &hir::Expr<'_>,
+    recv: &hir::Expr<'_>,
+    arg: &hir::Expr<'_>,
+) -> bool {
+    BindInsteadOfMap {
+        variant_lang_item: LangItem::OptionSome,
+        bad_method_name: "and_then",
+        good_method_name: "map",
+    }
+    .check(cx, expr, recv, arg)
 }
 
-pub(crate) struct ResultAndThenOk;
-
-impl BindInsteadOfMap for ResultAndThenOk {
-    const VARIANT_LANG_ITEM: LangItem = LangItem::ResultOk;
-    const BAD_METHOD_NAME: &'static str = "and_then";
-    const GOOD_METHOD_NAME: &'static str = "map";
+pub(super) fn check_and_then_ok(
+    cx: &LateContext<'_>,
+    expr: &hir::Expr<'_>,
+    recv: &hir::Expr<'_>,
+    arg: &hir::Expr<'_>,
+) -> bool {
+    BindInsteadOfMap {
+        variant_lang_item: LangItem::ResultOk,
+        bad_method_name: "and_then",
+        good_method_name: "map",
+    }
+    .check(cx, expr, recv, arg)
 }
 
-pub(crate) struct ResultOrElseErrInfo;
-
-impl BindInsteadOfMap for ResultOrElseErrInfo {
-    const VARIANT_LANG_ITEM: LangItem = LangItem::ResultErr;
-    const BAD_METHOD_NAME: &'static str = "or_else";
-    const GOOD_METHOD_NAME: &'static str = "map_err";
+pub(super) fn check_or_else_err(
+    cx: &LateContext<'_>,
+    expr: &hir::Expr<'_>,
+    recv: &hir::Expr<'_>,
+    arg: &hir::Expr<'_>,
+) -> bool {
+    BindInsteadOfMap {
+        variant_lang_item: LangItem::ResultErr,
+        bad_method_name: "or_else",
+        good_method_name: "map_err",
+    }
+    .check(cx, expr, recv, arg)
 }
 
-pub(crate) trait BindInsteadOfMap {
-    const VARIANT_LANG_ITEM: LangItem;
-    const BAD_METHOD_NAME: &'static str;
-    const GOOD_METHOD_NAME: &'static str;
+struct BindInsteadOfMap {
+    variant_lang_item: LangItem,
+    bad_method_name: &'static str,
+    good_method_name: &'static str,
+}
 
-    fn no_op_msg(cx: &LateContext<'_>) -> Option<String> {
-        let variant_id = cx.tcx.lang_items().get(Self::VARIANT_LANG_ITEM)?;
+impl BindInsteadOfMap {
+    fn no_op_msg(&self, cx: &LateContext<'_>) -> Option<String> {
+        let variant_id = cx.tcx.lang_items().get(self.variant_lang_item)?;
         let item_id = cx.tcx.parent(variant_id);
         Some(format!(
             "using `{}.{}({})`, which is a no-op",
             cx.tcx.item_name(item_id),
-            Self::BAD_METHOD_NAME,
+            self.bad_method_name,
             cx.tcx.item_name(variant_id),
         ))
     }
 
-    fn lint_msg(cx: &LateContext<'_>) -> Option<String> {
-        let variant_id = cx.tcx.lang_items().get(Self::VARIANT_LANG_ITEM)?;
+    fn lint_msg(&self, cx: &LateContext<'_>) -> Option<String> {
+        let variant_id = cx.tcx.lang_items().get(self.variant_lang_item)?;
         let item_id = cx.tcx.parent(variant_id);
         Some(format!(
             "using `{}.{}(|x| {}(y))`, which is more succinctly expressed as `{}(|x| y)`",
             cx.tcx.item_name(item_id),
-            Self::BAD_METHOD_NAME,
+            self.bad_method_name,
             cx.tcx.item_name(variant_id),
-            Self::GOOD_METHOD_NAME
+            self.good_method_name,
         ))
     }
 
     fn lint_closure_autofixable(
+        &self,
         cx: &LateContext<'_>,
         expr: &hir::Expr<'_>,
         recv: &hir::Expr<'_>,
@@ -71,9 +92,9 @@ pub(crate) trait BindInsteadOfMap {
     ) -> bool {
         if let hir::ExprKind::Call(some_expr, [inner_expr]) = closure_expr.kind
             && let hir::ExprKind::Path(QPath::Resolved(_, path)) = some_expr.kind
-            && Self::is_variant(cx, path.res)
+            && self.is_variant(cx, path.res)
             && !contains_return(inner_expr)
-            && let Some(msg) = Self::lint_msg(cx)
+            && let Some(msg) = self.lint_msg(cx)
         {
             let mut app = Applicability::MachineApplicable;
             let some_inner_snip = snippet_with_context(cx, inner_expr.span, closure_expr.span.ctxt(), "_", &mut app).0;
@@ -82,7 +103,7 @@ pub(crate) trait BindInsteadOfMap {
             let option_snip = snippet(cx, recv.span, "..");
             let note = format!(
                 "{option_snip}.{}({closure_args_snip} {some_inner_snip})",
-                Self::GOOD_METHOD_NAME
+                self.good_method_name
             );
             span_lint_and_sugg(cx, BIND_INSTEAD_OF_MAP, expr.span, msg, "try", note, app);
             true
@@ -91,13 +112,13 @@ pub(crate) trait BindInsteadOfMap {
         }
     }
 
-    fn lint_closure(cx: &LateContext<'_>, expr: &hir::Expr<'_>, closure_expr: &hir::Expr<'_>) -> bool {
+    fn lint_closure(&self, cx: &LateContext<'_>, expr: &hir::Expr<'_>, closure_expr: &hir::Expr<'_>) -> bool {
         let mut suggs = Vec::new();
         let can_sugg: bool = find_all_ret_expressions(cx, closure_expr, |ret_expr| {
             if !ret_expr.span.from_expansion()
                 && let hir::ExprKind::Call(func_path, [arg]) = ret_expr.kind
                 && let hir::ExprKind::Path(QPath::Resolved(_, path)) = func_path.kind
-                && Self::is_variant(cx, path.res)
+                && self.is_variant(cx, path.res)
                 && !contains_return(arg)
             {
                 suggs.push((ret_expr.span, arg.span.source_callsite()));
@@ -108,7 +129,7 @@ pub(crate) trait BindInsteadOfMap {
         });
         let (span, msg) = if can_sugg
             && let hir::ExprKind::MethodCall(segment, ..) = expr.kind
-            && let Some(msg) = Self::lint_msg(cx)
+            && let Some(msg) = self.lint_msg(cx)
         {
             (segment.ident.span, msg)
         } else {
@@ -119,7 +140,7 @@ pub(crate) trait BindInsteadOfMap {
                 diag,
                 "try",
                 Applicability::MachineApplicable,
-                std::iter::once((span, Self::GOOD_METHOD_NAME.into())).chain(
+                std::iter::once((span, self.good_method_name.into())).chain(
                     suggs
                         .into_iter()
                         .map(|(span1, span2)| (span1, snippet(cx, span2, "_").into())),
@@ -130,9 +151,9 @@ pub(crate) trait BindInsteadOfMap {
     }
 
     /// Lint use of `_.and_then(|x| Some(y))` for `Option`s
-    fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, recv: &hir::Expr<'_>, arg: &hir::Expr<'_>) -> bool {
+    fn check(&self, cx: &LateContext<'_>, expr: &hir::Expr<'_>, recv: &hir::Expr<'_>, arg: &hir::Expr<'_>) -> bool {
         if let Some(adt) = cx.typeck_results().expr_ty(recv).ty_adt_def()
-            && let Some(vid) = cx.tcx.lang_items().get(Self::VARIANT_LANG_ITEM)
+            && let Some(vid) = cx.tcx.lang_items().get(self.variant_lang_item)
             && adt.did() == cx.tcx.parent(vid)
         {
         } else {
@@ -144,15 +165,15 @@ pub(crate) trait BindInsteadOfMap {
                 let closure_body = cx.tcx.hir().body(body);
                 let closure_expr = peel_blocks(closure_body.value);
 
-                if Self::lint_closure_autofixable(cx, expr, recv, closure_expr, fn_decl_span) {
+                if self.lint_closure_autofixable(cx, expr, recv, closure_expr, fn_decl_span) {
                     true
                 } else {
-                    Self::lint_closure(cx, expr, closure_expr)
+                    self.lint_closure(cx, expr, closure_expr)
                 }
             },
             // `_.and_then(Some)` case, which is no-op.
-            hir::ExprKind::Path(QPath::Resolved(_, path)) if Self::is_variant(cx, path.res) => {
-                if let Some(msg) = Self::no_op_msg(cx) {
+            hir::ExprKind::Path(QPath::Resolved(_, path)) if self.is_variant(cx, path.res) => {
+                if let Some(msg) = self.no_op_msg(cx) {
                     span_lint_and_sugg(
                         cx,
                         BIND_INSTEAD_OF_MAP,
@@ -169,9 +190,9 @@ pub(crate) trait BindInsteadOfMap {
         }
     }
 
-    fn is_variant(cx: &LateContext<'_>, res: Res) -> bool {
+    fn is_variant(&self, cx: &LateContext<'_>, res: Res) -> bool {
         if let Res::Def(DefKind::Ctor(CtorOf::Variant, CtorKind::Fn), id) = res {
-            if let Some(variant_id) = cx.tcx.lang_items().get(Self::VARIANT_LANG_ITEM) {
+            if let Some(variant_id) = cx.tcx.lang_items().get(self.variant_lang_item) {
                 return cx.tcx.parent(id) == variant_id;
             }
         }
diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs
index a846552cddf..aa4cad9342a 100644
--- a/clippy_lints/src/methods/mod.rs
+++ b/clippy_lints/src/methods/mod.rs
@@ -131,8 +131,8 @@ mod waker_clone_wake;
 mod wrong_self_convention;
 mod zst_offset;
 
-use bind_instead_of_map::BindInsteadOfMap;
 use clippy_config::msrvs::{self, Msrv};
+use clippy_config::Conf;
 use clippy_utils::consts::{constant, Constant};
 use clippy_utils::diagnostics::{span_lint, span_lint_and_help};
 use clippy_utils::macros::FormatArgsStorage;
@@ -4131,27 +4131,20 @@ pub struct Methods {
     msrv: Msrv,
     allow_expect_in_tests: bool,
     allow_unwrap_in_tests: bool,
-    allowed_dotfiles: FxHashSet<String>,
+    allowed_dotfiles: FxHashSet<&'static str>,
     format_args: FormatArgsStorage,
 }
 
 impl Methods {
-    #[must_use]
-    pub fn new(
-        avoid_breaking_exported_api: bool,
-        msrv: Msrv,
-        allow_expect_in_tests: bool,
-        allow_unwrap_in_tests: bool,
-        mut allowed_dotfiles: FxHashSet<String>,
-        format_args: FormatArgsStorage,
-    ) -> Self {
-        allowed_dotfiles.extend(DEFAULT_ALLOWED_DOTFILES.iter().map(ToString::to_string));
+    pub fn new(conf: &'static Conf, format_args: FormatArgsStorage) -> Self {
+        let mut allowed_dotfiles: FxHashSet<_> = conf.allowed_dotfiles.iter().map(|s| &**s).collect();
+        allowed_dotfiles.extend(DEFAULT_ALLOWED_DOTFILES);
 
         Self {
-            avoid_breaking_exported_api,
-            msrv,
-            allow_expect_in_tests,
-            allow_unwrap_in_tests,
+            avoid_breaking_exported_api: conf.avoid_breaking_exported_api,
+            msrv: conf.msrv.clone(),
+            allow_expect_in_tests: conf.allow_expect_in_tests,
+            allow_unwrap_in_tests: conf.allow_unwrap_in_tests,
             allowed_dotfiles,
             format_args,
         }
@@ -4512,8 +4505,8 @@ impl Methods {
                     }
                 },
                 ("and_then", [arg]) => {
-                    let biom_option_linted = bind_instead_of_map::OptionAndThenSome::check(cx, expr, recv, arg);
-                    let biom_result_linted = bind_instead_of_map::ResultAndThenOk::check(cx, expr, recv, arg);
+                    let biom_option_linted = bind_instead_of_map::check_and_then_some(cx, expr, recv, arg);
+                    let biom_result_linted = bind_instead_of_map::check_and_then_ok(cx, expr, recv, arg);
                     if !biom_option_linted && !biom_result_linted {
                         unnecessary_lazy_eval::check(cx, expr, recv, arg, "and");
                     }
@@ -4853,7 +4846,7 @@ impl Methods {
                     open_options::check(cx, expr, recv);
                 },
                 ("or_else", [arg]) => {
-                    if !bind_instead_of_map::ResultOrElseErrInfo::check(cx, expr, recv, arg) {
+                    if !bind_instead_of_map::check_or_else_err(cx, expr, recv, arg) {
                         unnecessary_lazy_eval::check(cx, expr, recv, arg, "or");
                     }
                 },
diff --git a/clippy_lints/src/methods/option_map_unwrap_or.rs b/clippy_lints/src/methods/option_map_unwrap_or.rs
index 3d326bc99f9..ed3bed42eb3 100644
--- a/clippy_lints/src/methods/option_map_unwrap_or.rs
+++ b/clippy_lints/src/methods/option_map_unwrap_or.rs
@@ -10,6 +10,7 @@ use rustc_hir::{ExprKind, HirId, Node, PatKind, Path, QPath};
 use rustc_lint::LateContext;
 use rustc_middle::hir::nested_filter;
 use rustc_span::{sym, Span};
+use std::ops::ControlFlow;
 
 use super::MAP_UNWRAP_OR;
 
@@ -54,15 +55,14 @@ pub(super) fn check<'tcx>(
             let mut reference_visitor = ReferenceVisitor {
                 cx,
                 identifiers: unwrap_visitor.identifiers,
-                found_reference: false,
                 unwrap_or_span: unwrap_arg.span,
             };
 
             let map = cx.tcx.hir();
             let body = map.body_owned_by(map.enclosing_body_owner(expr.hir_id));
-            reference_visitor.visit_body(body);
 
-            if reference_visitor.found_reference {
+            // Visit the body, and return if we've found a reference
+            if reference_visitor.visit_body(body).is_break() {
                 return;
             }
         }
@@ -151,29 +151,27 @@ impl<'a, 'tcx> Visitor<'tcx> for UnwrapVisitor<'a, 'tcx> {
 struct ReferenceVisitor<'a, 'tcx> {
     cx: &'a LateContext<'tcx>,
     identifiers: FxHashSet<HirId>,
-    found_reference: bool,
     unwrap_or_span: Span,
 }
 
 impl<'a, 'tcx> Visitor<'tcx> for ReferenceVisitor<'a, 'tcx> {
     type NestedFilter = nested_filter::All;
-    fn visit_expr(&mut self, expr: &'tcx rustc_hir::Expr<'_>) {
+    type Result = ControlFlow<()>;
+    fn visit_expr(&mut self, expr: &'tcx rustc_hir::Expr<'_>) -> ControlFlow<()> {
         // If we haven't found a reference yet, check if this references
         // one of the locals that was moved in the `unwrap_or` argument.
         // We are only interested in exprs that appear before the `unwrap_or` call.
-        if !self.found_reference {
-            if expr.span < self.unwrap_or_span
-                && let ExprKind::Path(ref path) = expr.kind
-                && let QPath::Resolved(_, path) = path
-                && let Res::Local(local_id) = path.res
-                && let Node::Pat(pat) = self.cx.tcx.hir_node(local_id)
-                && let PatKind::Binding(_, local_id, ..) = pat.kind
-                && self.identifiers.contains(&local_id)
-            {
-                self.found_reference = true;
-            }
-            rustc_hir::intravisit::walk_expr(self, expr);
+        if expr.span < self.unwrap_or_span
+            && let ExprKind::Path(ref path) = expr.kind
+            && let QPath::Resolved(_, path) = path
+            && let Res::Local(local_id) = path.res
+            && let Node::Pat(pat) = self.cx.tcx.hir_node(local_id)
+            && let PatKind::Binding(_, local_id, ..) = pat.kind
+            && self.identifiers.contains(&local_id)
+        {
+            return ControlFlow::Break(());
         }
+        rustc_hir::intravisit::walk_expr(self, expr)
     }
 
     fn nested_visit_map(&mut self) -> Self::Map {
diff --git a/clippy_lints/src/methods/or_fun_call.rs b/clippy_lints/src/methods/or_fun_call.rs
index 583e04fb4b1..e4326cb958e 100644
--- a/clippy_lints/src/methods/or_fun_call.rs
+++ b/clippy_lints/src/methods/or_fun_call.rs
@@ -1,8 +1,13 @@
+use std::ops::ControlFlow;
+
 use clippy_utils::diagnostics::span_lint_and_sugg;
 use clippy_utils::eager_or_lazy::switch_to_lazy_eval;
 use clippy_utils::source::snippet_with_context;
 use clippy_utils::ty::{expr_type_is_certain, implements_trait, is_type_diagnostic_item};
-use clippy_utils::{contains_return, is_default_equivalent, is_default_equivalent_call, last_path_segment};
+use clippy_utils::visitors::for_each_expr;
+use clippy_utils::{
+    contains_return, is_default_equivalent, is_default_equivalent_call, last_path_segment, peel_blocks,
+};
 use rustc_errors::Applicability;
 use rustc_lint::LateContext;
 use rustc_middle::ty;
@@ -13,7 +18,7 @@ use {rustc_ast as ast, rustc_hir as hir};
 use super::{OR_FUN_CALL, UNWRAP_OR_DEFAULT};
 
 /// Checks for the `OR_FUN_CALL` lint.
-#[allow(clippy::too_many_lines)]
+#[expect(clippy::too_many_lines)]
 pub(super) fn check<'tcx>(
     cx: &LateContext<'tcx>,
     expr: &hir::Expr<'_>,
@@ -26,7 +31,6 @@ pub(super) fn check<'tcx>(
     /// `or_insert(T::new())` or `or_insert(T::default())`.
     /// Similarly checks for `unwrap_or_else(T::new)`, `unwrap_or_else(T::default)`,
     /// `or_insert_with(T::new)` or `or_insert_with(T::default)`.
-    #[allow(clippy::too_many_arguments)]
     fn check_unwrap_or_default(
         cx: &LateContext<'_>,
         name: &str,
@@ -70,18 +74,31 @@ pub(super) fn check<'tcx>(
         };
 
         let receiver_ty = cx.typeck_results().expr_ty_adjusted(receiver).peel_refs();
-        let has_suggested_method = receiver_ty.ty_adt_def().is_some_and(|adt_def| {
+        let Some(suggested_method_def_id) = receiver_ty.ty_adt_def().and_then(|adt_def| {
             cx.tcx
                 .inherent_impls(adt_def.did())
                 .into_iter()
                 .flatten()
                 .flat_map(|impl_id| cx.tcx.associated_items(impl_id).filter_by_name_unhygienic(sugg))
-                .any(|assoc| {
-                    assoc.fn_has_self_parameter
+                .find_map(|assoc| {
+                    if assoc.fn_has_self_parameter
                         && cx.tcx.fn_sig(assoc.def_id).skip_binder().inputs().skip_binder().len() == 1
+                    {
+                        Some(assoc.def_id)
+                    } else {
+                        None
+                    }
                 })
-        });
-        if !has_suggested_method {
+        }) else {
+            return false;
+        };
+        let in_sugg_method_implementation = {
+            matches!(
+                suggested_method_def_id.as_local(),
+                Some(local_def_id) if local_def_id == cx.tcx.hir().get_parent_item(receiver.hir_id).def_id
+            )
+        };
+        if in_sugg_method_implementation {
             return false;
         }
 
@@ -110,8 +127,8 @@ pub(super) fn check<'tcx>(
     }
 
     /// Checks for `*or(foo())`.
-    #[allow(clippy::too_many_arguments)]
-    fn check_general_case<'tcx>(
+    #[expect(clippy::too_many_arguments)]
+    fn check_or_fn_call<'tcx>(
         cx: &LateContext<'tcx>,
         name: &str,
         method_span: Span,
@@ -122,7 +139,7 @@ pub(super) fn check<'tcx>(
         span: Span,
         // None if lambda is required
         fun_span: Option<Span>,
-    ) {
+    ) -> bool {
         // (path, fn_has_argument, methods, suffix)
         const KNOW_TYPES: [(Symbol, bool, &[&str], &str); 4] = [
             (sym::BTreeEntry, false, &["or_insert"], "with"),
@@ -172,54 +189,68 @@ pub(super) fn check<'tcx>(
                 format!("{name}_{suffix}({sugg})"),
                 app,
             );
-        }
-    }
-
-    let extract_inner_arg = |arg: &'tcx hir::Expr<'_>| {
-        if let hir::ExprKind::Block(
-            hir::Block {
-                stmts: [],
-                expr: Some(expr),
-                ..
-            },
-            _,
-        ) = arg.kind
-        {
-            expr
+            true
         } else {
-            arg
+            false
         }
-    };
+    }
 
     if let [arg] = args {
-        let inner_arg = extract_inner_arg(arg);
-        match inner_arg.kind {
-            hir::ExprKind::Call(fun, or_args) => {
-                let or_has_args = !or_args.is_empty();
-                if or_has_args
-                    || !check_unwrap_or_default(cx, name, receiver, fun, Some(inner_arg), expr.span, method_span)
-                {
-                    let fun_span = if or_has_args { None } else { Some(fun.span) };
-                    check_general_case(cx, name, method_span, receiver, arg, None, expr.span, fun_span);
-                }
-            },
-            hir::ExprKind::Path(..) | hir::ExprKind::Closure(..) => {
-                check_unwrap_or_default(cx, name, receiver, inner_arg, None, expr.span, method_span);
-            },
-            hir::ExprKind::Index(..) | hir::ExprKind::MethodCall(..) => {
-                check_general_case(cx, name, method_span, receiver, arg, None, expr.span, None);
-            },
-            _ => (),
-        }
+        let inner_arg = peel_blocks(arg);
+        for_each_expr(cx, inner_arg, |ex| {
+            // `or_fun_call` lint needs to take nested expr into account,
+            // but `unwrap_or_default` lint doesn't, we don't want something like:
+            // `opt.unwrap_or(Foo { inner: String::default(), other: 1 })` to get replaced by
+            // `opt.unwrap_or_default()`.
+            let is_nested_expr = ex.hir_id != inner_arg.hir_id;
+
+            let is_triggered = match ex.kind {
+                hir::ExprKind::Call(fun, fun_args) => {
+                    let inner_fun_has_args = !fun_args.is_empty();
+                    let fun_span = if inner_fun_has_args || is_nested_expr {
+                        None
+                    } else {
+                        Some(fun.span)
+                    };
+                    (!inner_fun_has_args
+                        && !is_nested_expr
+                        && check_unwrap_or_default(cx, name, receiver, fun, Some(ex), expr.span, method_span))
+                        || check_or_fn_call(cx, name, method_span, receiver, arg, None, expr.span, fun_span)
+                },
+                hir::ExprKind::Path(..) | hir::ExprKind::Closure(..) if !is_nested_expr => {
+                    check_unwrap_or_default(cx, name, receiver, ex, None, expr.span, method_span)
+                },
+                hir::ExprKind::Index(..) | hir::ExprKind::MethodCall(..) => {
+                    check_or_fn_call(cx, name, method_span, receiver, arg, None, expr.span, None)
+                },
+                _ => false,
+            };
+
+            if is_triggered {
+                ControlFlow::Break(())
+            } else {
+                ControlFlow::Continue(())
+            }
+        });
     }
 
     // `map_or` takes two arguments
     if let [arg, lambda] = args {
-        let inner_arg = extract_inner_arg(arg);
-        if let hir::ExprKind::Call(fun, or_args) = inner_arg.kind {
-            let fun_span = if or_args.is_empty() { Some(fun.span) } else { None };
-            check_general_case(cx, name, method_span, receiver, arg, Some(lambda), expr.span, fun_span);
-        }
+        let inner_arg = peel_blocks(arg);
+        for_each_expr(cx, inner_arg, |ex| {
+            let is_top_most_expr = ex.hir_id == inner_arg.hir_id;
+            if let hir::ExprKind::Call(fun, fun_args) = ex.kind {
+                let fun_span = if fun_args.is_empty() && is_top_most_expr {
+                    Some(fun.span)
+                } else {
+                    None
+                };
+                if check_or_fn_call(cx, name, method_span, receiver, arg, Some(lambda), expr.span, fun_span) {
+                    return ControlFlow::Break(());
+                }
+            }
+            ControlFlow::Continue(())
+        });
     }
 }
 
diff --git a/clippy_lints/src/methods/path_ends_with_ext.rs b/clippy_lints/src/methods/path_ends_with_ext.rs
index 29f44ec2a4d..cfb823dbf5d 100644
--- a/clippy_lints/src/methods/path_ends_with_ext.rs
+++ b/clippy_lints/src/methods/path_ends_with_ext.rs
@@ -21,7 +21,7 @@ pub(super) fn check(
     path: &Expr<'_>,
     expr: &Expr<'_>,
     msrv: &Msrv,
-    allowed_dotfiles: &FxHashSet<String>,
+    allowed_dotfiles: &FxHashSet<&'static str>,
 ) {
     if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(recv).peel_refs(), sym::Path)
         && !path.span.from_expansion()
diff --git a/clippy_lints/src/methods/unnecessary_sort_by.rs b/clippy_lints/src/methods/unnecessary_sort_by.rs
index 6911da69b94..a92fe9e55a4 100644
--- a/clippy_lints/src/methods/unnecessary_sort_by.rs
+++ b/clippy_lints/src/methods/unnecessary_sort_by.rs
@@ -5,7 +5,8 @@ use clippy_utils::ty::implements_trait;
 use rustc_errors::Applicability;
 use rustc_hir::{Closure, Expr, ExprKind, Mutability, Param, Pat, PatKind, Path, PathSegment, QPath};
 use rustc_lint::LateContext;
-use rustc_middle::ty::{self, GenericArgKind};
+use rustc_middle::ty;
+use rustc_middle::ty::GenericArgKind;
 use rustc_span::sym;
 use rustc_span::symbol::Ident;
 use std::iter;
diff --git a/clippy_lints/src/min_ident_chars.rs b/clippy_lints/src/min_ident_chars.rs
index e43b712021a..53fa444e93c 100644
--- a/clippy_lints/src/min_ident_chars.rs
+++ b/clippy_lints/src/min_ident_chars.rs
@@ -1,3 +1,4 @@
+use clippy_config::Conf;
 use clippy_utils::diagnostics::span_lint;
 use clippy_utils::is_from_proc_macro;
 use rustc_data_structures::fx::FxHashSet;
@@ -39,13 +40,19 @@ declare_clippy_lint! {
 }
 impl_lint_pass!(MinIdentChars => [MIN_IDENT_CHARS]);
 
-#[derive(Clone)]
 pub struct MinIdentChars {
-    pub allowed_idents_below_min_chars: FxHashSet<String>,
-    pub min_ident_chars_threshold: u64,
+    allowed_idents_below_min_chars: &'static FxHashSet<String>,
+    min_ident_chars_threshold: u64,
 }
 
 impl MinIdentChars {
+    pub fn new(conf: &'static Conf) -> Self {
+        Self {
+            allowed_idents_below_min_chars: &conf.allowed_idents_below_min_chars,
+            min_ident_chars_threshold: conf.min_ident_chars_threshold,
+        }
+    }
+
     #[expect(clippy::cast_possible_truncation)]
     fn is_ident_too_short(&self, cx: &LateContext<'_>, str: &str, span: Span) -> bool {
         !in_external_macro(cx.sess(), span)
@@ -132,11 +139,11 @@ impl Visitor<'_> for IdentVisitor<'_, '_> {
                 return;
             }
 
-            // `struct Awa<T>(T)`
-            //                ^
+            // `struct Array<T, const N: usize>([T; N])`
+            //                                   ^  ^
             if let Node::PathSegment(path) = node {
                 if let Res::Def(def_kind, ..) = path.res
-                    && let DefKind::TyParam = def_kind
+                    && let DefKind::TyParam | DefKind::ConstParam = def_kind
                 {
                     return;
                 }
diff --git a/clippy_lints/src/misc.rs b/clippy_lints/src/misc.rs
index 32c8731c537..a9aafe7ed56 100644
--- a/clippy_lints/src/misc.rs
+++ b/clippy_lints/src/misc.rs
@@ -1,4 +1,4 @@
-use clippy_utils::diagnostics::{span_lint, span_lint_and_then, span_lint_hir_and_then};
+use clippy_utils::diagnostics::{span_lint_and_then, span_lint_hir, span_lint_hir_and_then};
 use clippy_utils::source::{snippet, snippet_with_context};
 use clippy_utils::sugg::Sugg;
 use clippy_utils::{
@@ -114,40 +114,35 @@ impl<'tcx> LateLintPass<'tcx> for LintPass {
         k: FnKind<'tcx>,
         decl: &'tcx FnDecl<'_>,
         body: &'tcx Body<'_>,
-        span: Span,
+        _: Span,
         _: LocalDefId,
     ) {
-        if let FnKind::Closure = k {
-            // Does not apply to closures
-            return;
-        }
-        if in_external_macro(cx.tcx.sess, span) {
-            return;
-        }
-        for arg in iter_input_pats(decl, body) {
-            // Do not emit if clippy::ref_patterns is not allowed to avoid having two lints for the same issue.
-            if !is_lint_allowed(cx, REF_PATTERNS, arg.pat.hir_id) {
-                return;
-            }
-            if let PatKind::Binding(BindingMode(ByRef::Yes(_), _), ..) = arg.pat.kind {
-                span_lint(
-                    cx,
-                    TOPLEVEL_REF_ARG,
-                    arg.pat.span,
-                    "`ref` directly on a function argument is ignored. \
-                    Consider using a reference type instead",
-                );
+        if !matches!(k, FnKind::Closure) {
+            for arg in iter_input_pats(decl, body) {
+                if let PatKind::Binding(BindingMode(ByRef::Yes(_), _), ..) = arg.pat.kind
+                    && is_lint_allowed(cx, REF_PATTERNS, arg.pat.hir_id)
+                    && !in_external_macro(cx.tcx.sess, arg.span)
+                {
+                    span_lint_hir(
+                        cx,
+                        TOPLEVEL_REF_ARG,
+                        arg.hir_id,
+                        arg.pat.span,
+                        "`ref` directly on a function argument is ignored. \
+                        Consider using a reference type instead",
+                    );
+                }
             }
         }
     }
 
     fn check_stmt(&mut self, cx: &LateContext<'tcx>, stmt: &'tcx Stmt<'_>) {
-        if !in_external_macro(cx.tcx.sess, stmt.span)
-            && let StmtKind::Let(local) = stmt.kind
+        if let StmtKind::Let(local) = stmt.kind
             && let PatKind::Binding(BindingMode(ByRef::Yes(mutabl), _), .., name, None) = local.pat.kind
             && let Some(init) = local.init
             // Do not emit if clippy::ref_patterns is not allowed to avoid having two lints for the same issue.
             && is_lint_allowed(cx, REF_PATTERNS, local.pat.hir_id)
+            && !in_external_macro(cx.tcx.sess, stmt.span)
         {
             let ctxt = local.span.ctxt();
             let mut app = Applicability::MachineApplicable;
diff --git a/clippy_lints/src/mismatching_type_param_order.rs b/clippy_lints/src/mismatching_type_param_order.rs
index 934b9f490ad..748289454be 100644
--- a/clippy_lints/src/mismatching_type_param_order.rs
+++ b/clippy_lints/src/mismatching_type_param_order.rs
@@ -49,12 +49,12 @@ declare_lint_pass!(TypeParamMismatch => [MISMATCHING_TYPE_PARAM_ORDER]);
 
 impl<'tcx> LateLintPass<'tcx> for TypeParamMismatch {
     fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'tcx>) {
-        if !item.span.from_expansion()
-            && let ItemKind::Impl(imp) = &item.kind
+        if let ItemKind::Impl(imp) = &item.kind
             && let TyKind::Path(QPath::Resolved(_, path)) = &imp.self_ty.kind
-            && let Some(segment) = path.segments.iter().next()
+            && let [segment, ..] = path.segments
             && let Some(generic_args) = segment.args
             && !generic_args.args.is_empty()
+            && !item.span.from_expansion()
         {
             // get the name and span of the generic parameters in the Impl
             let mut impl_params = Vec::new();
diff --git a/clippy_lints/src/missing_const_for_fn.rs b/clippy_lints/src/missing_const_for_fn.rs
index ed5f46ddc8d..68c158330ab 100644
--- a/clippy_lints/src/missing_const_for_fn.rs
+++ b/clippy_lints/src/missing_const_for_fn.rs
@@ -1,4 +1,5 @@
 use clippy_config::msrvs::{self, Msrv};
+use clippy_config::Conf;
 use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::qualify_min_const_fn::is_min_const_fn;
 use clippy_utils::{fn_has_unsatisfiable_preds, is_entrypoint_fn, is_from_proc_macro, trait_ref_of_method};
@@ -79,9 +80,10 @@ pub struct MissingConstForFn {
 }
 
 impl MissingConstForFn {
-    #[must_use]
-    pub fn new(msrv: Msrv) -> Self {
-        Self { msrv }
+    pub fn new(conf: &'static Conf) -> Self {
+        Self {
+            msrv: conf.msrv.clone(),
+        }
     }
 }
 
diff --git a/clippy_lints/src/missing_const_for_thread_local.rs b/clippy_lints/src/missing_const_for_thread_local.rs
index ab1b4aa3dee..954216038fb 100644
--- a/clippy_lints/src/missing_const_for_thread_local.rs
+++ b/clippy_lints/src/missing_const_for_thread_local.rs
@@ -1,4 +1,5 @@
 use clippy_config::msrvs::{self, Msrv};
+use clippy_config::Conf;
 use clippy_utils::diagnostics::span_lint_and_sugg;
 use clippy_utils::macros::macro_backtrace;
 use clippy_utils::qualify_min_const_fn::is_min_const_fn;
@@ -49,9 +50,10 @@ pub struct MissingConstForThreadLocal {
 }
 
 impl MissingConstForThreadLocal {
-    #[must_use]
-    pub fn new(msrv: Msrv) -> Self {
-        Self { msrv }
+    pub fn new(conf: &'static Conf) -> Self {
+        Self {
+            msrv: conf.msrv.clone(),
+        }
     }
 }
 
diff --git a/clippy_lints/src/missing_doc.rs b/clippy_lints/src/missing_doc.rs
index 250fd5cbd48..2166b0fe5a0 100644
--- a/clippy_lints/src/missing_doc.rs
+++ b/clippy_lints/src/missing_doc.rs
@@ -5,6 +5,7 @@
 // [`missing_doc`]: https://github.com/rust-lang/rust/blob/cf9cf7c923eb01146971429044f216a3ca905e06/compiler/rustc_lint/src/builtin.rs#L415
 //
 
+use clippy_config::Conf;
 use clippy_utils::attrs::is_doc_hidden;
 use clippy_utils::diagnostics::span_lint;
 use clippy_utils::is_from_proc_macro;
@@ -51,18 +52,10 @@ pub struct MissingDoc {
     prev_span: Option<Span>,
 }
 
-impl Default for MissingDoc {
-    #[must_use]
-    fn default() -> Self {
-        Self::new(false)
-    }
-}
-
 impl MissingDoc {
-    #[must_use]
-    pub fn new(crate_items_only: bool) -> Self {
+    pub fn new(conf: &'static Conf) -> Self {
         Self {
-            crate_items_only,
+            crate_items_only: conf.missing_docs_in_crate_items,
             doc_hidden_stack: vec![false],
             prev_span: None,
         }
diff --git a/clippy_lints/src/missing_enforced_import_rename.rs b/clippy_lints/src/missing_enforced_import_rename.rs
index c6c188854fd..cdf6645b3df 100644
--- a/clippy_lints/src/missing_enforced_import_rename.rs
+++ b/clippy_lints/src/missing_enforced_import_rename.rs
@@ -1,12 +1,13 @@
-use clippy_config::types::Rename;
+use clippy_config::Conf;
+use clippy_utils::def_path_def_ids;
 use clippy_utils::diagnostics::span_lint_and_sugg;
 use clippy_utils::source::snippet_opt;
-use rustc_data_structures::fx::FxHashMap;
 use rustc_errors::Applicability;
 use rustc_hir::def::Res;
-use rustc_hir::def_id::DefId;
+use rustc_hir::def_id::DefIdMap;
 use rustc_hir::{Item, ItemKind, UseKind};
 use rustc_lint::{LateContext, LateLintPass, LintContext};
+use rustc_middle::ty::TyCtxt;
 use rustc_session::impl_lint_pass;
 use rustc_span::Symbol;
 
@@ -46,15 +47,18 @@ declare_clippy_lint! {
 }
 
 pub struct ImportRename {
-    conf_renames: Vec<Rename>,
-    renames: FxHashMap<DefId, Symbol>,
+    renames: DefIdMap<Symbol>,
 }
 
 impl ImportRename {
-    pub fn new(conf_renames: Vec<Rename>) -> Self {
+    pub fn new(tcx: TyCtxt<'_>, conf: &'static Conf) -> Self {
         Self {
-            conf_renames,
-            renames: FxHashMap::default(),
+            renames: conf
+                .enforced_import_renames
+                .iter()
+                .map(|x| (x.path.split("::").collect::<Vec<_>>(), Symbol::intern(&x.rename)))
+                .flat_map(|(path, rename)| def_path_def_ids(tcx, &path).map(move |id| (id, rename)))
+                .collect(),
         }
     }
 }
@@ -62,15 +66,6 @@ impl ImportRename {
 impl_lint_pass!(ImportRename => [MISSING_ENFORCED_IMPORT_RENAMES]);
 
 impl LateLintPass<'_> for ImportRename {
-    fn check_crate(&mut self, cx: &LateContext<'_>) {
-        for Rename { path, rename } in &self.conf_renames {
-            let segs = path.split("::").collect::<Vec<_>>();
-            for id in clippy_utils::def_path_def_ids(cx, &segs) {
-                self.renames.insert(id, Symbol::intern(rename));
-            }
-        }
-    }
-
     fn check_item(&mut self, cx: &LateContext<'_>, item: &Item<'_>) {
         if let ItemKind::Use(path, UseKind::Single) = &item.kind {
             for &res in &path.res {
diff --git a/clippy_lints/src/mut_key.rs b/clippy_lints/src/mut_key.rs
index 2eb534da092..83af9979b9e 100644
--- a/clippy_lints/src/mut_key.rs
+++ b/clippy_lints/src/mut_key.rs
@@ -1,9 +1,10 @@
+use clippy_config::Conf;
 use clippy_utils::diagnostics::span_lint;
 use clippy_utils::trait_ref_of_method;
 use clippy_utils::ty::InteriorMut;
 use rustc_hir as hir;
 use rustc_lint::{LateContext, LateLintPass};
-use rustc_middle::ty::{self, Ty};
+use rustc_middle::ty::{self, Ty, TyCtxt};
 use rustc_session::impl_lint_pass;
 use rustc_span::def_id::LocalDefId;
 use rustc_span::symbol::sym;
@@ -67,17 +68,12 @@ declare_clippy_lint! {
 }
 
 pub struct MutableKeyType<'tcx> {
-    ignore_interior_mutability: Vec<String>,
     interior_mut: InteriorMut<'tcx>,
 }
 
 impl_lint_pass!(MutableKeyType<'_> => [ MUTABLE_KEY_TYPE ]);
 
 impl<'tcx> LateLintPass<'tcx> for MutableKeyType<'tcx> {
-    fn check_crate(&mut self, cx: &LateContext<'tcx>) {
-        self.interior_mut = InteriorMut::without_pointers(cx, &self.ignore_interior_mutability);
-    }
-
     fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::Item<'tcx>) {
         if let hir::ItemKind::Fn(ref sig, ..) = item.kind {
             self.check_sig(cx, item.owner_id.def_id, sig.decl);
@@ -107,10 +103,9 @@ impl<'tcx> LateLintPass<'tcx> for MutableKeyType<'tcx> {
 }
 
 impl<'tcx> MutableKeyType<'tcx> {
-    pub fn new(ignore_interior_mutability: Vec<String>) -> Self {
+    pub fn new(tcx: TyCtxt<'tcx>, conf: &'static Conf) -> Self {
         Self {
-            ignore_interior_mutability,
-            interior_mut: InteriorMut::default(),
+            interior_mut: InteriorMut::without_pointers(tcx, &conf.ignore_interior_mutability),
         }
     }
 
diff --git a/clippy_lints/src/mut_mut.rs b/clippy_lints/src/mut_mut.rs
index bc7b2c6b7c1..60372121a7a 100644
--- a/clippy_lints/src/mut_mut.rs
+++ b/clippy_lints/src/mut_mut.rs
@@ -35,33 +35,18 @@ impl<'tcx> LateLintPass<'tcx> for MutMut {
     }
 
     fn check_ty(&mut self, cx: &LateContext<'tcx>, ty: &'tcx hir::Ty<'_>) {
-        if in_external_macro(cx.sess(), ty.span) {
-            return;
-        }
-
-        if let hir::TyKind::Ref(
-            _,
-            hir::MutTy {
-                ty: pty,
-                mutbl: hir::Mutability::Mut,
-            },
-        ) = ty.kind
+        if let hir::TyKind::Ref(_, mty) = ty.kind
+            && mty.mutbl == hir::Mutability::Mut
+            && let hir::TyKind::Ref(_, mty) = mty.ty.kind
+            && mty.mutbl == hir::Mutability::Mut
+            && !in_external_macro(cx.sess(), ty.span)
         {
-            if let hir::TyKind::Ref(
-                _,
-                hir::MutTy {
-                    mutbl: hir::Mutability::Mut,
-                    ..
-                },
-            ) = pty.kind
-            {
-                span_lint(
-                    cx,
-                    MUT_MUT,
-                    ty.span,
-                    "generally you want to avoid `&mut &mut _` if possible",
-                );
-            }
+            span_lint(
+                cx,
+                MUT_MUT,
+                ty.span,
+                "generally you want to avoid `&mut &mut _` if possible",
+            );
         }
     }
 }
diff --git a/clippy_lints/src/mutable_debug_assertion.rs b/clippy_lints/src/mutable_debug_assertion.rs
index e92ba93942e..563ce2d82ea 100644
--- a/clippy_lints/src/mutable_debug_assertion.rs
+++ b/clippy_lints/src/mutable_debug_assertion.rs
@@ -96,10 +96,6 @@ impl<'a, 'tcx> Visitor<'tcx> for MutArgVisitor<'a, 'tcx> {
                 self.found = true;
                 return;
             },
-            ExprKind::If(..) => {
-                self.found = true;
-                return;
-            },
             ExprKind::Path(_) => {
                 if let Some(adj) = self.cx.typeck_results().adjustments().get(expr.hir_id) {
                     if adj
diff --git a/clippy_lints/src/needless_borrowed_ref.rs b/clippy_lints/src/needless_borrowed_ref.rs
index fb02f24c9dc..098098718af 100644
--- a/clippy_lints/src/needless_borrowed_ref.rs
+++ b/clippy_lints/src/needless_borrowed_ref.rs
@@ -37,83 +37,75 @@ declare_lint_pass!(NeedlessBorrowedRef => [NEEDLESS_BORROWED_REFERENCE]);
 
 impl<'tcx> LateLintPass<'tcx> for NeedlessBorrowedRef {
     fn check_pat(&mut self, cx: &LateContext<'tcx>, ref_pat: &'tcx Pat<'_>) {
-        if ref_pat.span.from_expansion() {
-            // OK, simple enough, lints doesn't check in macro.
-            return;
-        }
-
-        // Do not lint patterns that are part of an OR `|` pattern, the binding mode must match in all arms
-        for (_, node) in cx.tcx.hir().parent_iter(ref_pat.hir_id) {
-            let Node::Pat(pat) = node else { break };
-
-            if matches!(pat.kind, PatKind::Or(_)) {
-                return;
+        if let PatKind::Ref(pat, Mutability::Not) = ref_pat.kind
+            && !ref_pat.span.from_expansion()
+            && cx
+                .tcx
+                .hir()
+                .parent_iter(ref_pat.hir_id)
+                .map_while(|(_, parent)| if let Node::Pat(pat) = parent { Some(pat) } else { None })
+                // Do not lint patterns that are part of an OR `|` pattern, the binding mode must match in all arms
+                .all(|pat| !matches!(pat.kind, PatKind::Or(_)))
+        {
+            match pat.kind {
+                // Check sub_pat got a `ref` keyword (excluding `ref mut`).
+                PatKind::Binding(BindingMode::REF, _, ident, None) => {
+                    span_lint_and_then(
+                        cx,
+                        NEEDLESS_BORROWED_REFERENCE,
+                        ref_pat.span,
+                        "this pattern takes a reference on something that is being dereferenced",
+                        |diag| {
+                            // `&ref ident`
+                            //  ^^^^^
+                            let span = ref_pat.span.until(ident.span);
+                            diag.span_suggestion_verbose(
+                                span,
+                                "try removing the `&ref` part",
+                                String::new(),
+                                Applicability::MachineApplicable,
+                            );
+                        },
+                    );
+                },
+                // Slices where each element is `ref`: `&[ref a, ref b, ..., ref z]`
+                PatKind::Slice(
+                    before,
+                    None
+                    | Some(Pat {
+                        kind: PatKind::Wild, ..
+                    }),
+                    after,
+                ) => {
+                    check_subpatterns(
+                        cx,
+                        "dereferencing a slice pattern where every element takes a reference",
+                        ref_pat,
+                        pat,
+                        itertools::chain(before, after),
+                    );
+                },
+                PatKind::Tuple(subpatterns, _) | PatKind::TupleStruct(_, subpatterns, _) => {
+                    check_subpatterns(
+                        cx,
+                        "dereferencing a tuple pattern where every element takes a reference",
+                        ref_pat,
+                        pat,
+                        subpatterns,
+                    );
+                },
+                PatKind::Struct(_, fields, _) => {
+                    check_subpatterns(
+                        cx,
+                        "dereferencing a struct pattern where every field's pattern takes a reference",
+                        ref_pat,
+                        pat,
+                        fields.iter().map(|field| field.pat),
+                    );
+                },
+                _ => {},
             }
         }
-
-        // Only lint immutable refs, because `&mut ref T` may be useful.
-        let PatKind::Ref(pat, Mutability::Not) = ref_pat.kind else {
-            return;
-        };
-
-        match pat.kind {
-            // Check sub_pat got a `ref` keyword (excluding `ref mut`).
-            PatKind::Binding(BindingMode::REF, _, ident, None) => {
-                span_lint_and_then(
-                    cx,
-                    NEEDLESS_BORROWED_REFERENCE,
-                    ref_pat.span,
-                    "this pattern takes a reference on something that is being dereferenced",
-                    |diag| {
-                        // `&ref ident`
-                        //  ^^^^^
-                        let span = ref_pat.span.until(ident.span);
-                        diag.span_suggestion_verbose(
-                            span,
-                            "try removing the `&ref` part",
-                            String::new(),
-                            Applicability::MachineApplicable,
-                        );
-                    },
-                );
-            },
-            // Slices where each element is `ref`: `&[ref a, ref b, ..., ref z]`
-            PatKind::Slice(
-                before,
-                None
-                | Some(Pat {
-                    kind: PatKind::Wild, ..
-                }),
-                after,
-            ) => {
-                check_subpatterns(
-                    cx,
-                    "dereferencing a slice pattern where every element takes a reference",
-                    ref_pat,
-                    pat,
-                    itertools::chain(before, after),
-                );
-            },
-            PatKind::Tuple(subpatterns, _) | PatKind::TupleStruct(_, subpatterns, _) => {
-                check_subpatterns(
-                    cx,
-                    "dereferencing a tuple pattern where every element takes a reference",
-                    ref_pat,
-                    pat,
-                    subpatterns,
-                );
-            },
-            PatKind::Struct(_, fields, _) => {
-                check_subpatterns(
-                    cx,
-                    "dereferencing a struct pattern where every field's pattern takes a reference",
-                    ref_pat,
-                    pat,
-                    fields.iter().map(|field| field.pat),
-                );
-            },
-            _ => {},
-        }
     }
 }
 
diff --git a/clippy_lints/src/needless_borrows_for_generic_args.rs b/clippy_lints/src/needless_borrows_for_generic_args.rs
index 064ce59c234..67f9b52c352 100644
--- a/clippy_lints/src/needless_borrows_for_generic_args.rs
+++ b/clippy_lints/src/needless_borrows_for_generic_args.rs
@@ -1,4 +1,5 @@
 use clippy_config::msrvs::{self, Msrv};
+use clippy_config::Conf;
 use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::mir::PossibleBorrowerMap;
 use clippy_utils::source::snippet_with_context;
@@ -67,11 +68,10 @@ pub struct NeedlessBorrowsForGenericArgs<'tcx> {
 impl_lint_pass!(NeedlessBorrowsForGenericArgs<'_> => [NEEDLESS_BORROWS_FOR_GENERIC_ARGS]);
 
 impl NeedlessBorrowsForGenericArgs<'_> {
-    #[must_use]
-    pub fn new(msrv: Msrv) -> Self {
+    pub fn new(conf: &'static Conf) -> Self {
         Self {
             possible_borrowers: Vec::new(),
-            msrv,
+            msrv: conf.msrv.clone(),
         }
     }
 }
diff --git a/clippy_lints/src/needless_for_each.rs b/clippy_lints/src/needless_for_each.rs
index 143acc2b1cb..6390e51f916 100644
--- a/clippy_lints/src/needless_for_each.rs
+++ b/clippy_lints/src/needless_for_each.rs
@@ -3,7 +3,7 @@ use rustc_hir::intravisit::{walk_expr, Visitor};
 use rustc_hir::{Block, BlockCheckMode, Closure, Expr, ExprKind, Stmt, StmtKind};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_session::declare_lint_pass;
-use rustc_span::{sym, Span, Symbol};
+use rustc_span::{sym, Span};
 
 use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::is_trait_method;
@@ -55,16 +55,8 @@ declare_lint_pass!(NeedlessForEach => [NEEDLESS_FOR_EACH]);
 
 impl<'tcx> LateLintPass<'tcx> for NeedlessForEach {
     fn check_stmt(&mut self, cx: &LateContext<'tcx>, stmt: &'tcx Stmt<'_>) {
-        let (StmtKind::Expr(expr) | StmtKind::Semi(expr)) = stmt.kind else {
-            return;
-        };
-
-        if let ExprKind::MethodCall(method_name, for_each_recv, [for_each_arg], _) = expr.kind
-            // Check the method name is `for_each`.
-            && method_name.ident.name == Symbol::intern("for_each")
-            // Check `for_each` is an associated function of `Iterator`.
-            && is_trait_method(cx, expr, sym::Iterator)
-            // Checks the receiver of `for_each` is also a method call.
+        if let StmtKind::Expr(expr) | StmtKind::Semi(expr) = stmt.kind
+            && let ExprKind::MethodCall(method_name, for_each_recv, [for_each_arg], _) = expr.kind
             && let ExprKind::MethodCall(_, iter_recv, [], _) = for_each_recv.kind
             // Skip the lint if the call chain is too long. e.g. `v.field.iter().for_each()` or
             // `v.foo().iter().for_each()` must be skipped.
@@ -72,6 +64,8 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessForEach {
                 iter_recv.kind,
                 ExprKind::Array(..) | ExprKind::Call(..) | ExprKind::Path(..)
             )
+            && method_name.ident.name.as_str() == "for_each"
+            && is_trait_method(cx, expr, sym::Iterator)
             // Checks the type of the `iter` method receiver is NOT a user defined type.
             && has_iter_method(cx, cx.typeck_results().expr_ty(iter_recv)).is_some()
             // Skip the lint if the body is not block because this is simpler than `for` loop.
diff --git a/clippy_lints/src/needless_pass_by_ref_mut.rs b/clippy_lints/src/needless_pass_by_ref_mut.rs
index 5ffd41d78e0..d543fd467ab 100644
--- a/clippy_lints/src/needless_pass_by_ref_mut.rs
+++ b/clippy_lints/src/needless_pass_by_ref_mut.rs
@@ -1,8 +1,10 @@
 use super::needless_pass_by_value::requires_exact_signature;
+use clippy_config::Conf;
 use clippy_utils::diagnostics::span_lint_hir_and_then;
 use clippy_utils::source::snippet;
 use clippy_utils::visitors::for_each_expr;
 use clippy_utils::{inherits_cfg, is_from_proc_macro, is_self};
+use core::ops::ControlFlow;
 use rustc_data_structures::fx::{FxHashSet, FxIndexMap};
 use rustc_errors::Applicability;
 use rustc_hir::intravisit::FnKind;
@@ -20,8 +22,6 @@ use rustc_span::symbol::kw;
 use rustc_span::Span;
 use rustc_target::spec::abi::Abi;
 
-use core::ops::ControlFlow;
-
 declare_clippy_lint! {
     /// ### What it does
     /// Check if a `&mut` function argument is actually used mutably.
@@ -51,7 +51,6 @@ declare_clippy_lint! {
     "using a `&mut` argument when it's not mutated"
 }
 
-#[derive(Clone)]
 pub struct NeedlessPassByRefMut<'tcx> {
     avoid_breaking_exported_api: bool,
     used_fn_def_ids: FxHashSet<LocalDefId>,
@@ -59,9 +58,9 @@ pub struct NeedlessPassByRefMut<'tcx> {
 }
 
 impl NeedlessPassByRefMut<'_> {
-    pub fn new(avoid_breaking_exported_api: bool) -> Self {
+    pub fn new(conf: &'static Conf) -> Self {
         Self {
-            avoid_breaking_exported_api,
+            avoid_breaking_exported_api: conf.avoid_breaking_exported_api,
             used_fn_def_ids: FxHashSet::default(),
             fn_def_ids_to_maybe_unused_mut: FxIndexMap::default(),
         }
diff --git a/clippy_lints/src/neg_cmp_op_on_partial_ord.rs b/clippy_lints/src/neg_cmp_op_on_partial_ord.rs
index f7621822b66..fa90ee60612 100644
--- a/clippy_lints/src/neg_cmp_op_on_partial_ord.rs
+++ b/clippy_lints/src/neg_cmp_op_on_partial_ord.rs
@@ -45,10 +45,10 @@ declare_lint_pass!(NoNegCompOpForPartialOrd => [NEG_CMP_OP_ON_PARTIAL_ORD]);
 
 impl<'tcx> LateLintPass<'tcx> for NoNegCompOpForPartialOrd {
     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
-        if !in_external_macro(cx.sess(), expr.span)
-            && let ExprKind::Unary(UnOp::Not, inner) = expr.kind
+        if let ExprKind::Unary(UnOp::Not, inner) = expr.kind
             && let ExprKind::Binary(ref op, left, _) = inner.kind
             && let BinOpKind::Le | BinOpKind::Ge | BinOpKind::Lt | BinOpKind::Gt = op.node
+            && !in_external_macro(cx.sess(), expr.span)
         {
             let ty = cx.typeck_results().expr_ty(left);
 
diff --git a/clippy_lints/src/non_copy_const.rs b/clippy_lints/src/non_copy_const.rs
index 6f5505e8a63..15bb328b446 100644
--- a/clippy_lints/src/non_copy_const.rs
+++ b/clippy_lints/src/non_copy_const.rs
@@ -4,6 +4,7 @@
 
 use std::ptr;
 
+use clippy_config::Conf;
 use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::in_constant;
 use clippy_utils::macros::macro_backtrace;
@@ -179,17 +180,15 @@ fn lint<'tcx>(cx: &LateContext<'tcx>, source: Source<'tcx>) {
 }
 
 pub struct NonCopyConst<'tcx> {
-    ignore_interior_mutability: Vec<String>,
     interior_mut: InteriorMut<'tcx>,
 }
 
 impl_lint_pass!(NonCopyConst<'_> => [DECLARE_INTERIOR_MUTABLE_CONST, BORROW_INTERIOR_MUTABLE_CONST]);
 
 impl<'tcx> NonCopyConst<'tcx> {
-    pub fn new(ignore_interior_mutability: Vec<String>) -> Self {
+    pub fn new(tcx: TyCtxt<'tcx>, conf: &'static Conf) -> Self {
         Self {
-            ignore_interior_mutability,
-            interior_mut: InteriorMut::default(),
+            interior_mut: InteriorMut::new(tcx, &conf.ignore_interior_mutability),
         }
     }
 
@@ -308,10 +307,6 @@ impl<'tcx> NonCopyConst<'tcx> {
 }
 
 impl<'tcx> LateLintPass<'tcx> for NonCopyConst<'tcx> {
-    fn check_crate(&mut self, cx: &LateContext<'tcx>) {
-        self.interior_mut = InteriorMut::new(cx, &self.ignore_interior_mutability);
-    }
-
     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();
diff --git a/clippy_lints/src/non_expressive_names.rs b/clippy_lints/src/non_expressive_names.rs
index eacfe9ff328..832518d2d35 100644
--- a/clippy_lints/src/non_expressive_names.rs
+++ b/clippy_lints/src/non_expressive_names.rs
@@ -1,3 +1,4 @@
+use clippy_config::Conf;
 use clippy_utils::diagnostics::{span_lint, span_lint_and_then};
 use rustc_ast::ast::{
     self, Arm, AssocItem, AssocItemKind, Attribute, Block, FnDecl, Item, ItemKind, Local, Pat, PatKind,
@@ -73,13 +74,20 @@ declare_clippy_lint! {
     "unclear name"
 }
 
-#[derive(Copy, Clone)]
 pub struct NonExpressiveNames {
     pub single_char_binding_names_threshold: u64,
 }
 
 impl_lint_pass!(NonExpressiveNames => [SIMILAR_NAMES, MANY_SINGLE_CHAR_NAMES, JUST_UNDERSCORES_AND_DIGITS]);
 
+impl NonExpressiveNames {
+    pub fn new(conf: &'static Conf) -> Self {
+        Self {
+            single_char_binding_names_threshold: conf.single_char_binding_names_threshold,
+        }
+    }
+}
+
 struct ExistingName {
     interned: Symbol,
     span: Span,
@@ -90,7 +98,7 @@ struct ExistingName {
 struct SimilarNamesLocalVisitor<'a, 'tcx> {
     names: Vec<ExistingName>,
     cx: &'a EarlyContext<'tcx>,
-    lint: NonExpressiveNames,
+    threshold: u64,
 
     /// A stack of scopes containing the single-character bindings in each scope.
     single_char_names: Vec<Vec<Ident>>,
@@ -103,8 +111,7 @@ impl<'a, 'tcx> SimilarNamesLocalVisitor<'a, 'tcx> {
         }
 
         let num_single_char_names = self.single_char_names.iter().flatten().count();
-        let threshold = self.lint.single_char_binding_names_threshold;
-        if num_single_char_names as u64 > threshold {
+        if num_single_char_names as u64 > self.threshold {
             let span = self
                 .single_char_names
                 .iter()
@@ -384,7 +391,7 @@ impl EarlyLintPass for NonExpressiveNames {
             ..
         }) = item.kind
         {
-            do_check(*self, cx, &item.attrs, &sig.decl, blk);
+            do_check(self, cx, &item.attrs, &sig.decl, blk);
         }
     }
 
@@ -399,17 +406,17 @@ impl EarlyLintPass for NonExpressiveNames {
             ..
         }) = item.kind
         {
-            do_check(*self, cx, &item.attrs, &sig.decl, blk);
+            do_check(self, cx, &item.attrs, &sig.decl, blk);
         }
     }
 }
 
-fn do_check(lint: NonExpressiveNames, cx: &EarlyContext<'_>, attrs: &[Attribute], decl: &FnDecl, blk: &Block) {
+fn do_check(lint: &NonExpressiveNames, cx: &EarlyContext<'_>, attrs: &[Attribute], decl: &FnDecl, blk: &Block) {
     if !attrs.iter().any(|attr| attr.has_name(sym::test)) {
         let mut visitor = SimilarNamesLocalVisitor {
             names: Vec::new(),
             cx,
-            lint,
+            threshold: lint.single_char_binding_names_threshold,
             single_char_names: vec![vec![]],
         };
 
diff --git a/clippy_lints/src/non_send_fields_in_send_ty.rs b/clippy_lints/src/non_send_fields_in_send_ty.rs
index 74e6c57b52d..a60988ac5db 100644
--- a/clippy_lints/src/non_send_fields_in_send_ty.rs
+++ b/clippy_lints/src/non_send_fields_in_send_ty.rs
@@ -1,3 +1,4 @@
+use clippy_config::Conf;
 use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::is_lint_allowed;
 use clippy_utils::source::snippet;
@@ -54,15 +55,14 @@ declare_clippy_lint! {
     "there is a field that is not safe to be sent to another thread in a `Send` struct"
 }
 
-#[derive(Copy, Clone)]
 pub struct NonSendFieldInSendTy {
     enable_raw_pointer_heuristic: bool,
 }
 
 impl NonSendFieldInSendTy {
-    pub fn new(enable_raw_pointer_heuristic: bool) -> Self {
+    pub fn new(conf: &'static Conf) -> Self {
         Self {
-            enable_raw_pointer_heuristic,
+            enable_raw_pointer_heuristic: conf.enable_raw_pointer_heuristic_for_send,
         }
     }
 }
diff --git a/clippy_lints/src/nonstandard_macro_braces.rs b/clippy_lints/src/nonstandard_macro_braces.rs
index 88f2eabaccb..2aaf1e6ff46 100644
--- a/clippy_lints/src/nonstandard_macro_braces.rs
+++ b/clippy_lints/src/nonstandard_macro_braces.rs
@@ -1,4 +1,5 @@
 use clippy_config::types::MacroMatcher;
+use clippy_config::Conf;
 use clippy_utils::diagnostics::span_lint_and_sugg;
 use clippy_utils::source::snippet_opt;
 use rustc_ast::ast;
@@ -35,17 +36,15 @@ declare_clippy_lint! {
 /// The (callsite span, (open brace, close brace), source snippet)
 type MacroInfo = (Span, (char, char), String);
 
-#[derive(Debug)]
 pub struct MacroBraces {
     macro_braces: FxHashMap<String, (char, char)>,
     done: FxHashSet<Span>,
 }
 
 impl MacroBraces {
-    pub fn new(conf: &[MacroMatcher]) -> Self {
-        let macro_braces = macro_braces(conf);
+    pub fn new(conf: &'static Conf) -> Self {
         Self {
-            macro_braces,
+            macro_braces: macro_braces(&conf.standard_macro_braces),
             done: FxHashSet::default(),
         }
     }
diff --git a/clippy_lints/src/operators/arithmetic_side_effects.rs b/clippy_lints/src/operators/arithmetic_side_effects.rs
index 7d6f26cde3e..a7e381be743 100644
--- a/clippy_lints/src/operators/arithmetic_side_effects.rs
+++ b/clippy_lints/src/operators/arithmetic_side_effects.rs
@@ -1,4 +1,5 @@
 use super::ARITHMETIC_SIDE_EFFECTS;
+use clippy_config::Conf;
 use clippy_utils::consts::{constant, constant_simple, Constant};
 use clippy_utils::diagnostics::span_lint;
 use clippy_utils::ty::is_type_diagnostic_item;
@@ -11,19 +12,9 @@ use rustc_span::symbol::sym;
 use rustc_span::{Span, Symbol};
 use {rustc_ast as ast, rustc_hir as hir};
 
-const HARD_CODED_ALLOWED_BINARY: &[[&str; 2]] = &[["f32", "f32"], ["f64", "f64"], ["std::string::String", "str"]];
-const HARD_CODED_ALLOWED_UNARY: &[&str] = &["f32", "f64", "std::num::Saturating", "std::num::Wrapping"];
-const DISALLOWED_INT_METHODS: &[Symbol] = &[
-    sym::saturating_div,
-    sym::wrapping_div,
-    sym::wrapping_rem,
-    sym::wrapping_rem_euclid,
-];
-
-#[derive(Debug)]
 pub struct ArithmeticSideEffects {
-    allowed_binary: FxHashMap<String, FxHashSet<String>>,
-    allowed_unary: FxHashSet<String>,
+    allowed_binary: FxHashMap<&'static str, FxHashSet<&'static str>>,
+    allowed_unary: FxHashSet<&'static str>,
     // Used to check whether expressions are constants, such as in enum discriminants and consts
     const_span: Option<Span>,
     disallowed_int_methods: FxHashSet<Symbol>,
@@ -33,26 +24,38 @@ pub struct ArithmeticSideEffects {
 impl_lint_pass!(ArithmeticSideEffects => [ARITHMETIC_SIDE_EFFECTS]);
 
 impl ArithmeticSideEffects {
-    #[must_use]
-    pub fn new(user_allowed_binary: Vec<[String; 2]>, user_allowed_unary: Vec<String>) -> Self {
-        let mut allowed_binary: FxHashMap<String, FxHashSet<String>> = <_>::default();
-        for [lhs, rhs] in user_allowed_binary.into_iter().chain(
-            HARD_CODED_ALLOWED_BINARY
-                .iter()
-                .copied()
-                .map(|[lhs, rhs]| [lhs.to_string(), rhs.to_string()]),
-        ) {
+    pub fn new(conf: &'static Conf) -> Self {
+        let mut allowed_binary = FxHashMap::<&'static str, FxHashSet<&'static str>>::default();
+        let mut allowed_unary = FxHashSet::<&'static str>::default();
+
+        allowed_unary.extend(["f32", "f64", "std::num::Saturating", "std::num::Wrapping"]);
+        allowed_unary.extend(conf.arithmetic_side_effects_allowed_unary.iter().map(|x| &**x));
+        allowed_binary.extend([
+            ("f32", FxHashSet::from_iter(["f32"])),
+            ("f64", FxHashSet::from_iter(["f64"])),
+            ("std::string::String", FxHashSet::from_iter(["str"])),
+        ]);
+        for [lhs, rhs] in &conf.arithmetic_side_effects_allowed_binary {
             allowed_binary.entry(lhs).or_default().insert(rhs);
         }
-        let allowed_unary = user_allowed_unary
-            .into_iter()
-            .chain(HARD_CODED_ALLOWED_UNARY.iter().copied().map(String::from))
-            .collect();
+        for s in &conf.arithmetic_side_effects_allowed {
+            allowed_binary.entry(s).or_default().insert("*");
+            allowed_binary.entry("*").or_default().insert(s);
+            allowed_unary.insert(s);
+        }
+
         Self {
             allowed_binary,
             allowed_unary,
+            disallowed_int_methods: [
+                sym::saturating_div,
+                sym::wrapping_div,
+                sym::wrapping_rem,
+                sym::wrapping_rem_euclid,
+            ]
+            .into_iter()
+            .collect(),
             const_span: None,
-            disallowed_int_methods: DISALLOWED_INT_METHODS.iter().copied().collect(),
             expr_span: None,
         }
     }
diff --git a/clippy_lints/src/operators/mod.rs b/clippy_lints/src/operators/mod.rs
index 59834781a58..9baecff801f 100644
--- a/clippy_lints/src/operators/mod.rs
+++ b/clippy_lints/src/operators/mod.rs
@@ -23,6 +23,7 @@ mod verbose_bit_mask;
 
 pub(crate) mod arithmetic_side_effects;
 
+use clippy_config::Conf;
 use rustc_hir::{Body, Expr, ExprKind, UnOp};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_session::impl_lint_pass;
@@ -841,6 +842,16 @@ pub struct Operators {
     verbose_bit_mask_threshold: u64,
     modulo_arithmetic_allow_comparison_to_zero: bool,
 }
+impl Operators {
+    pub fn new(conf: &'static Conf) -> Self {
+        Self {
+            arithmetic_context: numeric_arithmetic::Context::default(),
+            verbose_bit_mask_threshold: conf.verbose_bit_mask_threshold,
+            modulo_arithmetic_allow_comparison_to_zero: conf.allow_comparison_to_zero,
+        }
+    }
+}
+
 impl_lint_pass!(Operators => [
     ABSURD_EXTREME_COMPARISONS,
     ARITHMETIC_SIDE_EFFECTS,
@@ -869,15 +880,7 @@ impl_lint_pass!(Operators => [
     PTR_EQ,
     SELF_ASSIGNMENT,
 ]);
-impl Operators {
-    pub fn new(verbose_bit_mask_threshold: u64, modulo_arithmetic_allow_comparison_to_zero: bool) -> Self {
-        Self {
-            arithmetic_context: numeric_arithmetic::Context::default(),
-            verbose_bit_mask_threshold,
-            modulo_arithmetic_allow_comparison_to_zero,
-        }
-    }
-}
+
 impl<'tcx> LateLintPass<'tcx> for Operators {
     fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) {
         eq_op::check_assert(cx, e);
diff --git a/clippy_lints/src/option_env_unwrap.rs b/clippy_lints/src/option_env_unwrap.rs
index 4bfb26209d2..d16f5f8e112 100644
--- a/clippy_lints/src/option_env_unwrap.rs
+++ b/clippy_lints/src/option_env_unwrap.rs
@@ -3,7 +3,7 @@ use clippy_utils::is_direct_expn_of;
 use rustc_ast::ast::{Expr, ExprKind, MethodCall};
 use rustc_lint::{EarlyContext, EarlyLintPass};
 use rustc_session::declare_lint_pass;
-use rustc_span::{sym, Span};
+use rustc_span::sym;
 
 declare_clippy_lint! {
     /// ### What it does
@@ -35,30 +35,18 @@ declare_lint_pass!(OptionEnvUnwrap => [OPTION_ENV_UNWRAP]);
 
 impl EarlyLintPass for OptionEnvUnwrap {
     fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &Expr) {
-        fn lint(cx: &EarlyContext<'_>, span: Span) {
+        if let ExprKind::MethodCall(box MethodCall { seg, receiver, .. }) = &expr.kind
+            && matches!(seg.ident.name, sym::expect | sym::unwrap)
+            && is_direct_expn_of(receiver.span, "option_env").is_some()
+        {
             span_lint_and_help(
                 cx,
                 OPTION_ENV_UNWRAP,
-                span,
+                expr.span,
                 "this will panic at run-time if the environment variable doesn't exist at compile-time",
                 None,
                 "consider using the `env!` macro instead",
             );
         }
-
-        if let ExprKind::MethodCall(box MethodCall { seg, receiver, .. }) = &expr.kind
-            && matches!(seg.ident.name, sym::expect | sym::unwrap)
-        {
-            if let ExprKind::Call(caller, _) = &receiver.kind &&
-            // If it exists, it will be ::core::option::Option::Some("<env var>").unwrap() (A method call in the HIR)
-            is_direct_expn_of(caller.span, "option_env").is_some()
-            {
-                lint(cx, expr.span);
-            } else if let ExprKind::Path(_, caller) = &receiver.kind && // If it doesn't exist, it will be ::core::option::Option::None::<&'static str>.unwrap() (A path in the HIR)
-            is_direct_expn_of(caller.span, "option_env").is_some()
-            {
-                lint(cx, expr.span);
-            }
-        }
     }
 }
diff --git a/clippy_lints/src/panic_unimplemented.rs b/clippy_lints/src/panic_unimplemented.rs
index 80ef761906e..4eefd0065f6 100644
--- a/clippy_lints/src/panic_unimplemented.rs
+++ b/clippy_lints/src/panic_unimplemented.rs
@@ -1,3 +1,4 @@
+use clippy_config::Conf;
 use clippy_utils::diagnostics::span_lint;
 use clippy_utils::is_in_test;
 use clippy_utils::macros::{is_panic, root_macro_call_first_node};
@@ -5,9 +6,16 @@ use rustc_hir::Expr;
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_session::impl_lint_pass;
 
-#[derive(Clone)]
 pub struct PanicUnimplemented {
-    pub allow_panic_in_tests: bool,
+    allow_panic_in_tests: bool,
+}
+
+impl PanicUnimplemented {
+    pub fn new(conf: &'static Conf) -> Self {
+        Self {
+            allow_panic_in_tests: conf.allow_panic_in_tests,
+        }
+    }
 }
 
 declare_clippy_lint! {
diff --git a/clippy_lints/src/pass_by_ref_or_value.rs b/clippy_lints/src/pass_by_ref_or_value.rs
index 128bfd49d9e..5ca244f0141 100644
--- a/clippy_lints/src/pass_by_ref_or_value.rs
+++ b/clippy_lints/src/pass_by_ref_or_value.rs
@@ -1,5 +1,6 @@
 use std::{cmp, iter};
 
+use clippy_config::Conf;
 use clippy_utils::diagnostics::span_lint_and_sugg;
 use clippy_utils::source::snippet;
 use clippy_utils::ty::{for_each_top_level_late_bound_region, is_copy};
@@ -14,7 +15,7 @@ use rustc_hir::{BindingMode, Body, FnDecl, Impl, ItemKind, MutTy, Mutability, No
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::ty::adjustment::{Adjust, PointerCoercion};
 use rustc_middle::ty::layout::LayoutOf;
-use rustc_middle::ty::{self, RegionKind};
+use rustc_middle::ty::{self, RegionKind, TyCtxt};
 use rustc_session::impl_lint_pass;
 use rustc_span::def_id::LocalDefId;
 use rustc_span::{sym, Span};
@@ -103,7 +104,6 @@ declare_clippy_lint! {
     "functions taking large arguments by value"
 }
 
-#[derive(Copy, Clone)]
 pub struct PassByRefOrValue {
     ref_min_size: u64,
     value_max_size: u64,
@@ -111,14 +111,9 @@ pub struct PassByRefOrValue {
 }
 
 impl<'tcx> PassByRefOrValue {
-    pub fn new(
-        ref_min_size: Option<u64>,
-        value_max_size: u64,
-        avoid_breaking_exported_api: bool,
-        pointer_width: u32,
-    ) -> Self {
-        let ref_min_size = ref_min_size.unwrap_or_else(|| {
-            let bit_width = u64::from(pointer_width);
+    pub fn new(tcx: TyCtxt<'_>, conf: &'static Conf) -> Self {
+        let ref_min_size = conf.trivial_copy_size_limit.unwrap_or_else(|| {
+            let bit_width = u64::from(tcx.sess.target.pointer_width);
             // Cap the calculated bit width at 32-bits to reduce
             // portability problems between 32 and 64-bit targets
             let bit_width = cmp::min(bit_width, 32);
@@ -130,8 +125,8 @@ impl<'tcx> PassByRefOrValue {
 
         Self {
             ref_min_size,
-            value_max_size,
-            avoid_breaking_exported_api,
+            value_max_size: conf.pass_by_value_size_limit,
+            avoid_breaking_exported_api: conf.avoid_breaking_exported_api,
         }
     }
 
diff --git a/clippy_lints/src/pathbuf_init_then_push.rs b/clippy_lints/src/pathbuf_init_then_push.rs
new file mode 100644
index 00000000000..0008f154ae3
--- /dev/null
+++ b/clippy_lints/src/pathbuf_init_then_push.rs
@@ -0,0 +1,193 @@
+use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::path_to_local_id;
+use clippy_utils::source::{snippet, snippet_opt};
+use clippy_utils::ty::is_type_diagnostic_item;
+use rustc_ast::{LitKind, StrStyle};
+use rustc_errors::Applicability;
+use rustc_hir::def::Res;
+use rustc_hir::{BindingMode, Block, Expr, ExprKind, HirId, LetStmt, PatKind, QPath, Stmt, StmtKind, TyKind};
+use rustc_lint::{LateContext, LateLintPass, LintContext};
+use rustc_middle::lint::in_external_macro;
+use rustc_session::impl_lint_pass;
+use rustc_span::{sym, Span, Symbol};
+
+declare_clippy_lint! {
+    /// ### What it does
+    /// Checks for calls to `push` immediately after creating a new `PathBuf`.
+    ///
+    /// ### Why is this bad?
+    /// Multiple `.join()` calls are usually easier to read than multiple `.push`
+    /// calls across multiple statements. It might also be possible to use
+    /// `PathBuf::from` instead.
+    ///
+    /// ### Known problems
+    /// `.join()` introduces an implicit `clone()`. `PathBuf::from` can alternativly be
+    /// used when the `PathBuf` is newly constructed. This will avoild the implicit clone.
+    ///
+    /// ### Example
+    /// ```rust
+    /// # use std::path::PathBuf;
+    /// let mut path_buf = PathBuf::new();
+    /// path_buf.push("foo");
+    /// ```
+    /// Use instead:
+    /// ```rust
+    /// # use std::path::PathBuf;
+    /// let path_buf = PathBuf::from("foo");
+    /// // or
+    /// let path_buf = PathBuf::new().join("foo");
+    /// ```
+    #[clippy::version = "1.81.0"]
+    pub PATHBUF_INIT_THEN_PUSH,
+    restriction,
+    "`push` immediately after `PathBuf` creation"
+}
+
+impl_lint_pass!(PathbufThenPush<'_> => [PATHBUF_INIT_THEN_PUSH]);
+
+#[derive(Default)]
+pub struct PathbufThenPush<'tcx> {
+    searcher: Option<PathbufPushSearcher<'tcx>>,
+}
+
+struct PathbufPushSearcher<'tcx> {
+    local_id: HirId,
+    lhs_is_let: bool,
+    let_ty_span: Option<Span>,
+    init_val: Expr<'tcx>,
+    arg: Option<Expr<'tcx>>,
+    name: Symbol,
+    err_span: Span,
+}
+
+impl<'tcx> PathbufPushSearcher<'tcx> {
+    /// Try to generate a suggestion with `PathBuf::from`.
+    /// Returns `None` if the suggestion would be invalid.
+    fn gen_pathbuf_from(&self, cx: &LateContext<'_>) -> Option<String> {
+        if let ExprKind::Call(iter_expr, []) = &self.init_val.kind
+            && let ExprKind::Path(QPath::TypeRelative(ty, segment)) = &iter_expr.kind
+            && let TyKind::Path(ty_path) = &ty.kind
+            && let QPath::Resolved(None, path) = ty_path
+            && let Res::Def(_, def_id) = &path.res
+            && cx.tcx.is_diagnostic_item(sym::PathBuf, *def_id)
+            && segment.ident.name == sym::new
+            && let Some(arg) = self.arg
+            && let ExprKind::Lit(x) = arg.kind
+            && let LitKind::Str(_, StrStyle::Cooked) = x.node
+            && let Some(s) = snippet_opt(cx, arg.span)
+        {
+            Some(format!(" = PathBuf::from({s});"))
+        } else {
+            None
+        }
+    }
+
+    fn gen_pathbuf_join(&self, cx: &LateContext<'_>) -> Option<String> {
+        let arg = self.arg?;
+        let arg_str = snippet_opt(cx, arg.span)?;
+        let init_val = snippet_opt(cx, self.init_val.span)?;
+        Some(format!(" = {init_val}.join({arg_str});"))
+    }
+
+    fn display_err(&self, cx: &LateContext<'_>) {
+        if clippy_utils::attrs::span_contains_cfg(cx, self.err_span) {
+            return;
+        }
+        let mut sugg = if self.lhs_is_let {
+            String::from("let mut ")
+        } else {
+            String::new()
+        };
+        sugg.push_str(self.name.as_str());
+        if let Some(span) = self.let_ty_span {
+            sugg.push_str(": ");
+            sugg.push_str(&snippet(cx, span, "_"));
+        }
+        match self.gen_pathbuf_from(cx) {
+            Some(value) => {
+                sugg.push_str(&value);
+            },
+            None => {
+                if let Some(value) = self.gen_pathbuf_join(cx) {
+                    sugg.push_str(&value);
+                } else {
+                    return;
+                }
+            },
+        }
+
+        span_lint_and_sugg(
+            cx,
+            PATHBUF_INIT_THEN_PUSH,
+            self.err_span,
+            "calls to `push` immediately after creation",
+            "consider using the `.join()`",
+            sugg,
+            Applicability::HasPlaceholders,
+        );
+    }
+}
+
+impl<'tcx> LateLintPass<'tcx> for PathbufThenPush<'tcx> {
+    fn check_block(&mut self, _: &LateContext<'tcx>, _: &'tcx Block<'tcx>) {
+        self.searcher = None;
+    }
+
+    fn check_local(&mut self, cx: &LateContext<'tcx>, local: &'tcx LetStmt<'tcx>) {
+        if let Some(init_expr) = local.init
+            && let PatKind::Binding(BindingMode::MUT, id, name, None) = local.pat.kind
+            && !in_external_macro(cx.sess(), local.span)
+            && let ty = cx.typeck_results().pat_ty(local.pat)
+            && is_type_diagnostic_item(cx, ty, sym::PathBuf)
+        {
+            self.searcher = Some(PathbufPushSearcher {
+                local_id: id,
+                lhs_is_let: true,
+                name: name.name,
+                let_ty_span: local.ty.map(|ty| ty.span),
+                err_span: local.span,
+                init_val: *init_expr,
+                arg: None,
+            });
+        }
+    }
+
+    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
+        if let ExprKind::Assign(left, right, _) = expr.kind
+            && let ExprKind::Path(QPath::Resolved(None, path)) = left.kind
+            && let [name] = &path.segments
+            && let Res::Local(id) = path.res
+            && !in_external_macro(cx.sess(), expr.span)
+            && let ty = cx.typeck_results().expr_ty(left)
+            && is_type_diagnostic_item(cx, ty, sym::PathBuf)
+        {
+            self.searcher = Some(PathbufPushSearcher {
+                local_id: id,
+                lhs_is_let: false,
+                let_ty_span: None,
+                name: name.ident.name,
+                err_span: expr.span,
+                init_val: *right,
+                arg: None,
+            });
+        }
+    }
+
+    fn check_stmt(&mut self, cx: &LateContext<'tcx>, stmt: &'tcx Stmt<'_>) {
+        if let Some(mut searcher) = self.searcher.take() {
+            if let StmtKind::Expr(expr) | StmtKind::Semi(expr) = stmt.kind
+                && let ExprKind::MethodCall(name, self_arg, [arg_expr], _) = expr.kind
+                && path_to_local_id(self_arg, searcher.local_id)
+                && name.ident.as_str() == "push"
+            {
+                searcher.err_span = searcher.err_span.to(stmt.span);
+                searcher.arg = Some(*arg_expr);
+                searcher.display_err(cx);
+            }
+        }
+    }
+
+    fn check_block_post(&mut self, _: &LateContext<'tcx>, _: &'tcx Block<'tcx>) {
+        self.searcher = None;
+    }
+}
diff --git a/clippy_lints/src/permissions_set_readonly_false.rs b/clippy_lints/src/permissions_set_readonly_false.rs
index 704acdc103e..dc142b6e157 100644
--- a/clippy_lints/src/permissions_set_readonly_false.rs
+++ b/clippy_lints/src/permissions_set_readonly_false.rs
@@ -31,10 +31,10 @@ declare_lint_pass!(PermissionsSetReadonlyFalse => [PERMISSIONS_SET_READONLY_FALS
 impl<'tcx> LateLintPass<'tcx> for PermissionsSetReadonlyFalse {
     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) {
         if let ExprKind::MethodCall(path, receiver, [arg], _) = &expr.kind
-            && is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(receiver), sym::FsPermissions)
-            && path.ident.name == sym!(set_readonly)
             && let ExprKind::Lit(lit) = &arg.kind
             && LitKind::Bool(false) == lit.node
+            && path.ident.name.as_str() == "set_readonly"
+            && is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(receiver), sym::FsPermissions)
         {
             span_lint_and_then(
                 cx,
diff --git a/clippy_lints/src/pub_underscore_fields.rs b/clippy_lints/src/pub_underscore_fields.rs
index d20d4a605a2..77b707567e4 100644
--- a/clippy_lints/src/pub_underscore_fields.rs
+++ b/clippy_lints/src/pub_underscore_fields.rs
@@ -1,4 +1,5 @@
 use clippy_config::types::PubUnderscoreFieldsBehaviour;
+use clippy_config::Conf;
 use clippy_utils::attrs::is_doc_hidden;
 use clippy_utils::diagnostics::span_lint_hir_and_then;
 use clippy_utils::is_path_lang_item;
@@ -42,10 +43,18 @@ declare_clippy_lint! {
 }
 
 pub struct PubUnderscoreFields {
-    pub behavior: PubUnderscoreFieldsBehaviour,
+    behavior: PubUnderscoreFieldsBehaviour,
 }
 impl_lint_pass!(PubUnderscoreFields => [PUB_UNDERSCORE_FIELDS]);
 
+impl PubUnderscoreFields {
+    pub fn new(conf: &'static Conf) -> Self {
+        Self {
+            behavior: conf.pub_underscore_fields_behavior,
+        }
+    }
+}
+
 impl<'tcx> LateLintPass<'tcx> for PubUnderscoreFields {
     fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) {
         // This lint only pertains to structs.
diff --git a/clippy_lints/src/question_mark.rs b/clippy_lints/src/question_mark.rs
index 7cf98ad9e09..ef6b4d3aeab 100644
--- a/clippy_lints/src/question_mark.rs
+++ b/clippy_lints/src/question_mark.rs
@@ -2,6 +2,7 @@ use crate::manual_let_else::MANUAL_LET_ELSE;
 use crate::question_mark_used::QUESTION_MARK_USED;
 use clippy_config::msrvs::Msrv;
 use clippy_config::types::MatchLintBehaviour;
+use clippy_config::Conf;
 use clippy_utils::diagnostics::span_lint_and_sugg;
 use clippy_utils::source::snippet_with_applicability;
 use clippy_utils::ty::{implements_trait, is_type_diagnostic_item};
@@ -62,11 +63,10 @@ pub struct QuestionMark {
 impl_lint_pass!(QuestionMark => [QUESTION_MARK, MANUAL_LET_ELSE]);
 
 impl QuestionMark {
-    #[must_use]
-    pub fn new(msrv: Msrv, matches_behaviour: MatchLintBehaviour) -> Self {
+    pub fn new(conf: &'static Conf) -> Self {
         Self {
-            msrv,
-            matches_behaviour,
+            msrv: conf.msrv.clone(),
+            matches_behaviour: conf.matches_for_let_else,
             try_block_depth_stack: Vec::new(),
         }
     }
diff --git a/clippy_lints/src/ranges.rs b/clippy_lints/src/ranges.rs
index 4fdaa9f00a1..829fb58bc65 100644
--- a/clippy_lints/src/ranges.rs
+++ b/clippy_lints/src/ranges.rs
@@ -1,4 +1,5 @@
 use clippy_config::msrvs::{self, Msrv};
+use clippy_config::Conf;
 use clippy_utils::consts::{constant, Constant};
 use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg, span_lint_and_then};
 use clippy_utils::source::{snippet, snippet_with_applicability, SpanRangeExt};
@@ -164,9 +165,10 @@ pub struct Ranges {
 }
 
 impl Ranges {
-    #[must_use]
-    pub fn new(msrv: Msrv) -> Self {
-        Self { msrv }
+    pub fn new(conf: &'static Conf) -> Self {
+        Self {
+            msrv: conf.msrv.clone(),
+        }
     }
 }
 
diff --git a/clippy_lints/src/raw_strings.rs b/clippy_lints/src/raw_strings.rs
index 3a004245459..3c19ee3522d 100644
--- a/clippy_lints/src/raw_strings.rs
+++ b/clippy_lints/src/raw_strings.rs
@@ -1,8 +1,6 @@
-use std::iter::once;
-use std::ops::ControlFlow;
-
+use clippy_config::Conf;
 use clippy_utils::diagnostics::span_lint_and_then;
-use clippy_utils::source::snippet;
+use clippy_utils::source::SpanRangeExt;
 use rustc_ast::ast::{Expr, ExprKind};
 use rustc_ast::token::LitKind;
 use rustc_errors::Applicability;
@@ -10,6 +8,8 @@ use rustc_lint::{EarlyContext, EarlyLintPass, LintContext};
 use rustc_middle::lint::in_external_macro;
 use rustc_session::impl_lint_pass;
 use rustc_span::{BytePos, Pos, Span};
+use std::iter::once;
+use std::ops::ControlFlow;
 
 declare_clippy_lint! {
     /// ### What it does
@@ -61,22 +61,27 @@ pub struct RawStrings {
     pub allow_one_hash_in_raw_strings: bool,
 }
 
+impl RawStrings {
+    pub fn new(conf: &'static Conf) -> Self {
+        Self {
+            allow_one_hash_in_raw_strings: conf.allow_one_hash_in_raw_strings,
+        }
+    }
+}
+
 impl EarlyLintPass for RawStrings {
     fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &Expr) {
-        if !in_external_macro(cx.sess(), expr.span)
-            && let ExprKind::Lit(lit) = expr.kind
-            && let LitKind::StrRaw(max) | LitKind::ByteStrRaw(max) | LitKind::CStrRaw(max) = lit.kind
+        if let ExprKind::Lit(lit) = expr.kind
+            && let (prefix, max) = match lit.kind {
+                LitKind::StrRaw(max) => ("r", max),
+                LitKind::ByteStrRaw(max) => ("br", max),
+                LitKind::CStrRaw(max) => ("cr", max),
+                _ => return,
+            }
+            && !in_external_macro(cx.sess(), expr.span)
+            && expr.span.check_source_text(cx, |src| src.starts_with(prefix))
         {
             let str = lit.symbol.as_str();
-            let prefix = match lit.kind {
-                LitKind::StrRaw(..) => "r",
-                LitKind::ByteStrRaw(..) => "br",
-                LitKind::CStrRaw(..) => "cr",
-                _ => unreachable!(),
-            };
-            if !snippet(cx, expr.span, prefix).trim().starts_with(prefix) {
-                return;
-            }
             let descr = lit.kind.descr();
 
             if !str.contains(['\\', '"']) {
@@ -86,7 +91,7 @@ impl EarlyLintPass for RawStrings {
                     expr.span,
                     "unnecessary raw string literal",
                     |diag| {
-                        let (start, end) = hash_spans(expr.span, prefix, 0, max);
+                        let (start, end) = hash_spans(expr.span, prefix.len(), 0, max);
 
                         // BytePos: skip over the `b` in `br`, we checked the prefix appears in the source text
                         let r_pos = expr.span.lo() + BytePos::from_usize(prefix.len() - 1);
@@ -148,7 +153,7 @@ impl EarlyLintPass for RawStrings {
                     expr.span,
                     "unnecessary hashes around raw string literal",
                     |diag| {
-                        let (start, end) = hash_spans(expr.span, prefix, req, max);
+                        let (start, end) = hash_spans(expr.span, prefix.len(), req, max);
 
                         let message = match max - req {
                             _ if req == 0 => format!("remove all the hashes around the {descr} literal"),
@@ -174,11 +179,11 @@ impl EarlyLintPass for RawStrings {
 /// r###".."###
 ///   ^^    ^^
 /// ```
-fn hash_spans(literal_span: Span, prefix: &str, req: u8, max: u8) -> (Span, Span) {
+fn hash_spans(literal_span: Span, prefix_len: usize, req: u8, max: u8) -> (Span, Span) {
     let literal_span = literal_span.data();
 
     // BytePos: we checked prefix appears literally in the source text
-    let hash_start = literal_span.lo + BytePos::from_usize(prefix.len());
+    let hash_start = literal_span.lo + BytePos::from_usize(prefix_len);
     let hash_end = literal_span.hi;
 
     // BytePos: req/max are counts of the ASCII character #
diff --git a/clippy_lints/src/redundant_closure_call.rs b/clippy_lints/src/redundant_closure_call.rs
index 47d3ed08b8e..bad9b979203 100644
--- a/clippy_lints/src/redundant_closure_call.rs
+++ b/clippy_lints/src/redundant_closure_call.rs
@@ -14,6 +14,7 @@ use rustc_middle::lint::in_external_macro;
 use rustc_middle::ty;
 use rustc_session::declare_lint_pass;
 use rustc_span::ExpnKind;
+use std::ops::ControlFlow;
 
 declare_clippy_lint! {
     /// ### What it does
@@ -42,24 +43,15 @@ declare_clippy_lint! {
 declare_lint_pass!(RedundantClosureCall => [REDUNDANT_CLOSURE_CALL]);
 
 // Used to find `return` statements or equivalents e.g., `?`
-struct ReturnVisitor {
-    found_return: bool,
-}
-
-impl ReturnVisitor {
-    #[must_use]
-    fn new() -> Self {
-        Self { found_return: false }
-    }
-}
+struct ReturnVisitor;
 
 impl<'tcx> Visitor<'tcx> for ReturnVisitor {
-    fn visit_expr(&mut self, ex: &'tcx hir::Expr<'tcx>) {
+    type Result = ControlFlow<()>;
+    fn visit_expr(&mut self, ex: &'tcx hir::Expr<'tcx>) -> ControlFlow<()> {
         if let ExprKind::Ret(_) | ExprKind::Match(.., hir::MatchSource::TryDesugar(_)) = ex.kind {
-            self.found_return = true;
-        } else {
-            hir_visit::walk_expr(self, ex);
+            return ControlFlow::Break(());
         }
+        hir_visit::walk_expr(self, ex)
     }
 }
 
@@ -101,9 +93,8 @@ fn find_innermost_closure<'tcx>(
     while let ExprKind::Closure(closure) = expr.kind
         && let body = cx.tcx.hir().body(closure.body)
         && {
-            let mut visitor = ReturnVisitor::new();
-            visitor.visit_expr(body.value);
-            !visitor.found_return
+            let mut visitor = ReturnVisitor;
+            !visitor.visit_expr(body.value).is_break()
         }
         && steps > 0
     {
diff --git a/clippy_lints/src/redundant_field_names.rs b/clippy_lints/src/redundant_field_names.rs
index 17b031d5f01..0e637538615 100644
--- a/clippy_lints/src/redundant_field_names.rs
+++ b/clippy_lints/src/redundant_field_names.rs
@@ -1,4 +1,5 @@
 use clippy_config::msrvs::{self, Msrv};
+use clippy_config::Conf;
 use clippy_utils::diagnostics::span_lint_and_sugg;
 use rustc_ast::ast::{Expr, ExprKind};
 use rustc_errors::Applicability;
@@ -40,9 +41,10 @@ pub struct RedundantFieldNames {
 }
 
 impl RedundantFieldNames {
-    #[must_use]
-    pub fn new(msrv: Msrv) -> Self {
-        Self { msrv }
+    pub fn new(conf: &'static Conf) -> Self {
+        Self {
+            msrv: conf.msrv.clone(),
+        }
     }
 }
 
diff --git a/clippy_lints/src/redundant_static_lifetimes.rs b/clippy_lints/src/redundant_static_lifetimes.rs
index 136e7db83bd..d6e741dd974 100644
--- a/clippy_lints/src/redundant_static_lifetimes.rs
+++ b/clippy_lints/src/redundant_static_lifetimes.rs
@@ -1,4 +1,5 @@
 use clippy_config::msrvs::{self, Msrv};
+use clippy_config::Conf;
 use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::source::snippet;
 use rustc_ast::ast::{ConstItem, Item, ItemKind, StaticItem, Ty, TyKind};
@@ -38,9 +39,10 @@ pub struct RedundantStaticLifetimes {
 }
 
 impl RedundantStaticLifetimes {
-    #[must_use]
-    pub fn new(msrv: Msrv) -> Self {
-        Self { msrv }
+    pub fn new(conf: &'static Conf) -> Self {
+        Self {
+            msrv: conf.msrv.clone(),
+        }
     }
 }
 
diff --git a/clippy_lints/src/regex.rs b/clippy_lints/src/regex.rs
index e925ec0271c..8cacb646f51 100644
--- a/clippy_lints/src/regex.rs
+++ b/clippy_lints/src/regex.rs
@@ -78,7 +78,7 @@ impl<'tcx> LateLintPass<'tcx> for Regex {
         // `def_path_def_ids` will resolve through re-exports but is relatively heavy, so we only perform
         // the operation once and store the results
         let mut resolve = |path, kind| {
-            for id in def_path_def_ids(cx, path) {
+            for id in def_path_def_ids(cx.tcx, path) {
                 self.definitions.insert(id, kind);
             }
         };
diff --git a/clippy_lints/src/semicolon_block.rs b/clippy_lints/src/semicolon_block.rs
index 0e77acdfd77..7615c21276d 100644
--- a/clippy_lints/src/semicolon_block.rs
+++ b/clippy_lints/src/semicolon_block.rs
@@ -1,3 +1,4 @@
+use clippy_config::Conf;
 use clippy_utils::diagnostics::{multispan_sugg_with_applicability, span_lint_and_then};
 use rustc_errors::Applicability;
 use rustc_hir::{Block, Expr, ExprKind, Stmt, StmtKind};
@@ -64,21 +65,20 @@ declare_clippy_lint! {
 }
 impl_lint_pass!(SemicolonBlock => [SEMICOLON_INSIDE_BLOCK, SEMICOLON_OUTSIDE_BLOCK]);
 
-#[derive(Copy, Clone)]
 pub struct SemicolonBlock {
     semicolon_inside_block_ignore_singleline: bool,
     semicolon_outside_block_ignore_multiline: bool,
 }
 
 impl SemicolonBlock {
-    pub fn new(semicolon_inside_block_ignore_singleline: bool, semicolon_outside_block_ignore_multiline: bool) -> Self {
+    pub fn new(conf: &'static Conf) -> Self {
         Self {
-            semicolon_inside_block_ignore_singleline,
-            semicolon_outside_block_ignore_multiline,
+            semicolon_inside_block_ignore_singleline: conf.semicolon_inside_block_ignore_singleline,
+            semicolon_outside_block_ignore_multiline: conf.semicolon_outside_block_ignore_multiline,
         }
     }
 
-    fn semicolon_inside_block(self, cx: &LateContext<'_>, block: &Block<'_>, tail: &Expr<'_>, semi_span: Span) {
+    fn semicolon_inside_block(&self, cx: &LateContext<'_>, block: &Block<'_>, tail: &Expr<'_>, semi_span: Span) {
         let insert_span = tail.span.source_callsite().shrink_to_hi();
         let remove_span = semi_span.with_lo(block.span.hi());
 
@@ -103,7 +103,7 @@ impl SemicolonBlock {
     }
 
     fn semicolon_outside_block(
-        self,
+        &self,
         cx: &LateContext<'_>,
         block: &Block<'_>,
         tail_stmt_expr: &Expr<'_>,
diff --git a/clippy_lints/src/serde_api.rs b/clippy_lints/src/serde_api.rs
index f1ec91d7aff..fcf1c4cc5c2 100644
--- a/clippy_lints/src/serde_api.rs
+++ b/clippy_lints/src/serde_api.rs
@@ -32,7 +32,7 @@ impl<'tcx> LateLintPass<'tcx> for SerdeApi {
         }) = item.kind
         {
             let did = trait_ref.path.res.def_id();
-            if let Some(visit_did) = get_trait_def_id(cx, &paths::SERDE_DE_VISITOR) {
+            if let Some(visit_did) = get_trait_def_id(cx.tcx, &paths::SERDE_DE_VISITOR) {
                 if did == visit_did {
                     let mut seen_str = None;
                     let mut seen_string = None;
diff --git a/clippy_lints/src/single_call_fn.rs b/clippy_lints/src/single_call_fn.rs
index 23bbeae0e31..abe13a97c0d 100644
--- a/clippy_lints/src/single_call_fn.rs
+++ b/clippy_lints/src/single_call_fn.rs
@@ -1,3 +1,4 @@
+use clippy_config::Conf;
 use clippy_utils::diagnostics::span_lint_hir_and_then;
 use clippy_utils::{is_from_proc_macro, is_in_test_function};
 use rustc_data_structures::fx::{FxIndexMap, IndexEntry};
@@ -66,13 +67,19 @@ pub enum CallState {
     Multiple,
 }
 
-#[derive(Clone)]
 pub struct SingleCallFn {
-    pub avoid_breaking_exported_api: bool,
-    pub def_id_to_usage: FxIndexMap<LocalDefId, CallState>,
+    avoid_breaking_exported_api: bool,
+    def_id_to_usage: FxIndexMap<LocalDefId, CallState>,
 }
 
 impl SingleCallFn {
+    pub fn new(conf: &'static Conf) -> Self {
+        Self {
+            avoid_breaking_exported_api: conf.avoid_breaking_exported_api,
+            def_id_to_usage: FxIndexMap::default(),
+        }
+    }
+
     fn is_function_allowed(
         &self,
         cx: &LateContext<'_>,
diff --git a/clippy_lints/src/single_range_in_vec_init.rs b/clippy_lints/src/single_range_in_vec_init.rs
index 0a9a3c6307a..e0558429638 100644
--- a/clippy_lints/src/single_range_in_vec_init.rs
+++ b/clippy_lints/src/single_range_in_vec_init.rs
@@ -99,7 +99,7 @@ impl LateLintPass<'_> for SingleRangeInVecInit {
             && let Some(start_snippet) = snippet_opt(cx, start.span)
             && let Some(end_snippet) = snippet_opt(cx, end.span)
         {
-            let should_emit_every_value = if let Some(step_def_id) = get_trait_def_id(cx, &["core", "iter", "Step"])
+            let should_emit_every_value = if let Some(step_def_id) = get_trait_def_id(cx.tcx, &["core", "iter", "Step"])
                 && implements_trait(cx, ty, step_def_id, &[])
             {
                 true
diff --git a/clippy_lints/src/string_patterns.rs b/clippy_lints/src/string_patterns.rs
index 7ba58942a17..7e211d64da1 100644
--- a/clippy_lints/src/string_patterns.rs
+++ b/clippy_lints/src/string_patterns.rs
@@ -1,6 +1,7 @@
 use std::ops::ControlFlow;
 
 use clippy_config::msrvs::{self, Msrv};
+use clippy_config::Conf;
 use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then};
 use clippy_utils::eager_or_lazy::switch_to_eager_eval;
 use clippy_utils::macros::matching_root_macro_call;
@@ -75,9 +76,10 @@ pub struct StringPatterns {
 }
 
 impl StringPatterns {
-    #[must_use]
-    pub fn new(msrv: Msrv) -> Self {
-        Self { msrv }
+    pub fn new(conf: &'static Conf) -> Self {
+        Self {
+            msrv: conf.msrv.clone(),
+        }
     }
 }
 
diff --git a/clippy_lints/src/trait_bounds.rs b/clippy_lints/src/trait_bounds.rs
index 07390d6f430..922a0006ee5 100644
--- a/clippy_lints/src/trait_bounds.rs
+++ b/clippy_lints/src/trait_bounds.rs
@@ -1,4 +1,5 @@
 use clippy_config::msrvs::{self, Msrv};
+use clippy_config::Conf;
 use clippy_utils::diagnostics::{span_lint_and_help, span_lint_and_sugg};
 use clippy_utils::source::{snippet, snippet_opt, snippet_with_applicability};
 use clippy_utils::{is_from_proc_macro, SpanlessEq, SpanlessHash};
@@ -86,16 +87,17 @@ declare_clippy_lint! {
     "check if the same trait bounds are specified more than once during a generic declaration"
 }
 
-#[derive(Clone)]
 pub struct TraitBounds {
     max_trait_bounds: u64,
     msrv: Msrv,
 }
 
 impl TraitBounds {
-    #[must_use]
-    pub fn new(max_trait_bounds: u64, msrv: Msrv) -> Self {
-        Self { max_trait_bounds, msrv }
+    pub fn new(conf: &'static Conf) -> Self {
+        Self {
+            max_trait_bounds: conf.max_trait_bounds,
+            msrv: conf.msrv.clone(),
+        }
     }
 }
 
diff --git a/clippy_lints/src/transmute/mod.rs b/clippy_lints/src/transmute/mod.rs
index aa329ec3366..9c6813a54b9 100644
--- a/clippy_lints/src/transmute/mod.rs
+++ b/clippy_lints/src/transmute/mod.rs
@@ -20,6 +20,7 @@ mod utils;
 mod wrong_transmute;
 
 use clippy_config::msrvs::Msrv;
+use clippy_config::Conf;
 use clippy_utils::in_constant;
 use rustc_hir::{Expr, ExprKind, QPath};
 use rustc_lint::{LateContext, LateLintPass};
@@ -577,9 +578,10 @@ impl_lint_pass!(Transmute => [
     MISSING_TRANSMUTE_ANNOTATIONS,
 ]);
 impl Transmute {
-    #[must_use]
-    pub fn new(msrv: Msrv) -> Self {
-        Self { msrv }
+    pub fn new(conf: &'static Conf) -> Self {
+        Self {
+            msrv: conf.msrv.clone(),
+        }
     }
 }
 impl<'tcx> LateLintPass<'tcx> for Transmute {
@@ -615,7 +617,7 @@ impl<'tcx> LateLintPass<'tcx> for Transmute {
                 | missing_transmute_annotations::check(cx, path, from_ty, to_ty, e.hir_id)
                 | transmute_int_to_char::check(cx, e, from_ty, to_ty, arg, const_context)
                 | transmute_ref_to_ref::check(cx, e, from_ty, to_ty, arg, const_context)
-                | transmute_ptr_to_ptr::check(cx, e, from_ty, to_ty, arg)
+                | transmute_ptr_to_ptr::check(cx, e, from_ty, to_ty, arg, &self.msrv)
                 | transmute_int_to_bool::check(cx, e, from_ty, to_ty, arg)
                 | transmute_int_to_float::check(cx, e, from_ty, to_ty, arg, const_context)
                 | transmute_int_to_non_zero::check(cx, e, from_ty, to_ty, arg)
diff --git a/clippy_lints/src/transmute/transmute_ptr_to_ptr.rs b/clippy_lints/src/transmute/transmute_ptr_to_ptr.rs
index 1476ea8e7a4..0772b284968 100644
--- a/clippy_lints/src/transmute/transmute_ptr_to_ptr.rs
+++ b/clippy_lints/src/transmute/transmute_ptr_to_ptr.rs
@@ -1,10 +1,11 @@
 use super::TRANSMUTE_PTR_TO_PTR;
+use clippy_config::msrvs::{self, Msrv};
 use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::sugg;
 use rustc_errors::Applicability;
 use rustc_hir::Expr;
 use rustc_lint::LateContext;
-use rustc_middle::ty::{self, Ty};
+use rustc_middle::ty::{self, Ty, TypeVisitableExt};
 
 /// Checks for `transmute_ptr_to_ptr` lint.
 /// Returns `true` if it's triggered, otherwise returns `false`.
@@ -14,9 +15,10 @@ pub(super) fn check<'tcx>(
     from_ty: Ty<'tcx>,
     to_ty: Ty<'tcx>,
     arg: &'tcx Expr<'_>,
+    msrv: &Msrv,
 ) -> bool {
-    match (&from_ty.kind(), &to_ty.kind()) {
-        (ty::RawPtr(_, _), ty::RawPtr(to_ty, to_mutbl)) => {
+    match (from_ty.kind(), to_ty.kind()) {
+        (ty::RawPtr(from_pointee_ty, from_mutbl), ty::RawPtr(to_pointee_ty, to_mutbl)) => {
             span_lint_and_then(
                 cx,
                 TRANSMUTE_PTR_TO_PTR,
@@ -24,8 +26,39 @@ pub(super) fn check<'tcx>(
                 "transmute from a pointer to a pointer",
                 |diag| {
                     if let Some(arg) = sugg::Sugg::hir_opt(cx, arg) {
-                        let sugg = arg.as_ty(Ty::new_ptr(cx.tcx, *to_ty, *to_mutbl));
-                        diag.span_suggestion(e.span, "try", sugg, Applicability::Unspecified);
+                        if from_mutbl == to_mutbl
+                            && to_pointee_ty.is_sized(cx.tcx, cx.param_env)
+                            && msrv.meets(msrvs::POINTER_CAST)
+                        {
+                            diag.span_suggestion_verbose(
+                                e.span,
+                                "use `pointer::cast` instead",
+                                format!("{}.cast::<{to_pointee_ty}>()", arg.maybe_par()),
+                                Applicability::MaybeIncorrect,
+                            );
+                        } else if from_pointee_ty == to_pointee_ty
+                            && let Some(method) = match (from_mutbl, to_mutbl) {
+                                (ty::Mutability::Not, ty::Mutability::Mut) => Some("cast_mut"),
+                                (ty::Mutability::Mut, ty::Mutability::Not) => Some("cast_const"),
+                                _ => None,
+                            }
+                            && !from_pointee_ty.has_erased_regions()
+                            && msrv.meets(msrvs::POINTER_CAST_CONSTNESS)
+                        {
+                            diag.span_suggestion_verbose(
+                                e.span,
+                                format!("use `pointer::{method}` instead"),
+                                format!("{}.{method}()", arg.maybe_par()),
+                                Applicability::MaybeIncorrect,
+                            );
+                        } else {
+                            diag.span_suggestion_verbose(
+                                e.span,
+                                "use an `as` cast instead",
+                                arg.as_ty(to_ty),
+                                Applicability::MaybeIncorrect,
+                            );
+                        }
                     }
                 },
             );
diff --git a/clippy_lints/src/tuple_array_conversions.rs b/clippy_lints/src/tuple_array_conversions.rs
index 564b065d0ba..1d0de932754 100644
--- a/clippy_lints/src/tuple_array_conversions.rs
+++ b/clippy_lints/src/tuple_array_conversions.rs
@@ -1,4 +1,5 @@
 use clippy_config::msrvs::{self, Msrv};
+use clippy_config::Conf;
 use clippy_utils::diagnostics::span_lint_and_help;
 use clippy_utils::visitors::for_each_local_use_after_expr;
 use clippy_utils::{is_from_proc_macro, path_to_local};
@@ -42,9 +43,15 @@ declare_clippy_lint! {
 }
 impl_lint_pass!(TupleArrayConversions => [TUPLE_ARRAY_CONVERSIONS]);
 
-#[derive(Clone)]
 pub struct TupleArrayConversions {
-    pub msrv: Msrv,
+    msrv: Msrv,
+}
+impl TupleArrayConversions {
+    pub fn new(conf: &'static Conf) -> Self {
+        Self {
+            msrv: conf.msrv.clone(),
+        }
+    }
 }
 
 impl LateLintPass<'_> for TupleArrayConversions {
diff --git a/clippy_lints/src/types/mod.rs b/clippy_lints/src/types/mod.rs
index 62ef65ca122..3a14927802b 100644
--- a/clippy_lints/src/types/mod.rs
+++ b/clippy_lints/src/types/mod.rs
@@ -9,6 +9,7 @@ mod type_complexity;
 mod utils;
 mod vec_box;
 
+use clippy_config::Conf;
 use rustc_hir as hir;
 use rustc_hir::intravisit::FnKind;
 use rustc_hir::{
@@ -446,11 +447,11 @@ impl<'tcx> LateLintPass<'tcx> for Types {
 }
 
 impl Types {
-    pub fn new(vec_box_size_threshold: u64, type_complexity_threshold: u64, avoid_breaking_exported_api: bool) -> Self {
+    pub fn new(conf: &'static Conf) -> Self {
         Self {
-            vec_box_size_threshold,
-            type_complexity_threshold,
-            avoid_breaking_exported_api,
+            vec_box_size_threshold: conf.vec_box_size_threshold,
+            type_complexity_threshold: conf.type_complexity_threshold,
+            avoid_breaking_exported_api: conf.avoid_breaking_exported_api,
         }
     }
 
diff --git a/clippy_lints/src/unconditional_recursion.rs b/clippy_lints/src/unconditional_recursion.rs
index 6ba98a92423..42100e1d755 100644
--- a/clippy_lints/src/unconditional_recursion.rs
+++ b/clippy_lints/src/unconditional_recursion.rs
@@ -16,6 +16,7 @@ use rustc_session::impl_lint_pass;
 use rustc_span::symbol::{kw, Ident};
 use rustc_span::{sym, Span};
 use rustc_trait_selection::error_reporting::traits::suggestions::ReturnsVisitor;
+use std::ops::ControlFlow;
 
 declare_clippy_lint! {
     /// ### What it does
@@ -276,7 +277,6 @@ struct CheckCalls<'a, 'tcx> {
     cx: &'a LateContext<'tcx>,
     map: Map<'tcx>,
     implemented_ty_id: DefId,
-    found_default_call: bool,
     method_span: Span,
 }
 
@@ -285,16 +285,14 @@ where
     'tcx: 'a,
 {
     type NestedFilter = nested_filter::OnlyBodies;
+    type Result = ControlFlow<()>;
 
     fn nested_visit_map(&mut self) -> Self::Map {
         self.map
     }
 
-    fn visit_expr(&mut self, expr: &'tcx Expr<'tcx>) {
-        if self.found_default_call {
-            return;
-        }
-        walk_expr(self, expr);
+    fn visit_expr(&mut self, expr: &'tcx Expr<'tcx>) -> ControlFlow<()> {
+        walk_expr(self, expr)?;
 
         if let ExprKind::Call(f, _) = expr.kind
             && let ExprKind::Path(qpath) = f.kind
@@ -303,9 +301,10 @@ where
             && let Some(trait_def_id) = self.cx.tcx.trait_of_item(method_def_id)
             && self.cx.tcx.is_diagnostic_item(sym::Default, trait_def_id)
         {
-            self.found_default_call = true;
             span_error(self.cx, self.method_span, expr);
+            return ControlFlow::Break(());
         }
+        ControlFlow::Continue(())
     }
 }
 
@@ -383,7 +382,6 @@ impl UnconditionalRecursion {
                 cx,
                 map: cx.tcx.hir(),
                 implemented_ty_id,
-                found_default_call: false,
                 method_span,
             };
             walk_body(&mut c, body);
diff --git a/clippy_lints/src/undocumented_unsafe_blocks.rs b/clippy_lints/src/undocumented_unsafe_blocks.rs
index 93a1089a970..3ab30bf5dba 100644
--- a/clippy_lints/src/undocumented_unsafe_blocks.rs
+++ b/clippy_lints/src/undocumented_unsafe_blocks.rs
@@ -1,5 +1,6 @@
 use std::ops::ControlFlow;
 
+use clippy_config::Conf;
 use clippy_utils::diagnostics::span_lint_and_help;
 use clippy_utils::is_lint_allowed;
 use clippy_utils::source::walk_span_to_context;
@@ -91,17 +92,16 @@ declare_clippy_lint! {
     "annotating safe code with a safety comment"
 }
 
-#[derive(Copy, Clone)]
 pub struct UndocumentedUnsafeBlocks {
     accept_comment_above_statement: bool,
     accept_comment_above_attributes: bool,
 }
 
 impl UndocumentedUnsafeBlocks {
-    pub fn new(accept_comment_above_statement: bool, accept_comment_above_attributes: bool) -> Self {
+    pub fn new(conf: &'static Conf) -> Self {
         Self {
-            accept_comment_above_statement,
-            accept_comment_above_attributes,
+            accept_comment_above_statement: conf.accept_comment_above_statement,
+            accept_comment_above_attributes: conf.accept_comment_above_attributes,
         }
     }
 }
diff --git a/clippy_lints/src/unnecessary_box_returns.rs b/clippy_lints/src/unnecessary_box_returns.rs
index bfcefb26153..3f130bf5a67 100644
--- a/clippy_lints/src/unnecessary_box_returns.rs
+++ b/clippy_lints/src/unnecessary_box_returns.rs
@@ -1,3 +1,4 @@
+use clippy_config::Conf;
 use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::ty::approx_ty_size;
 use rustc_errors::Applicability;
@@ -47,10 +48,10 @@ pub struct UnnecessaryBoxReturns {
 impl_lint_pass!(UnnecessaryBoxReturns => [UNNECESSARY_BOX_RETURNS]);
 
 impl UnnecessaryBoxReturns {
-    pub fn new(avoid_breaking_exported_api: bool, maximum_size: u64) -> Self {
+    pub fn new(conf: &'static Conf) -> Self {
         Self {
-            avoid_breaking_exported_api,
-            maximum_size,
+            avoid_breaking_exported_api: conf.avoid_breaking_exported_api,
+            maximum_size: conf.unnecessary_box_size,
         }
     }
 
diff --git a/clippy_lints/src/unnecessary_struct_initialization.rs b/clippy_lints/src/unnecessary_struct_initialization.rs
index 2da75334344..afdd3505cdd 100644
--- a/clippy_lints/src/unnecessary_struct_initialization.rs
+++ b/clippy_lints/src/unnecessary_struct_initialization.rs
@@ -2,14 +2,15 @@ use clippy_utils::diagnostics::span_lint_and_sugg;
 use clippy_utils::source::snippet;
 use clippy_utils::ty::is_copy;
 use clippy_utils::{get_parent_expr, path_to_local};
-use rustc_hir::{BindingMode, Expr, ExprKind, Node, PatKind, UnOp};
+use rustc_hir::{BindingMode, Expr, ExprField, ExprKind, Node, PatKind, Path, QPath, UnOp};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_session::declare_lint_pass;
 
 declare_clippy_lint! {
     /// ### What it does
-    /// Checks for initialization of a `struct` by copying a base without setting
-    /// any field.
+    /// Checks for initialization of an identical `struct` from another instance
+    /// of the type, either by copying a base without setting any field or by
+    /// moving all fields individually.
     ///
     /// ### Why is this bad?
     /// Readability suffers from unnecessary struct building.
@@ -29,9 +30,14 @@ declare_clippy_lint! {
     /// let b = a;
     /// ```
     ///
+    /// The struct literal ``S { ..a }`` in the assignment to ``b`` could be replaced
+    /// with just ``a``.
+    ///
     /// ### Known Problems
     /// Has false positives when the base is a place expression that cannot be
     /// moved out of, see [#10547](https://github.com/rust-lang/rust-clippy/issues/10547).
+    ///
+    /// Empty structs are ignored by the lint.
     #[clippy::version = "1.70.0"]
     pub UNNECESSARY_STRUCT_INITIALIZATION,
     nursery,
@@ -41,42 +47,111 @@ declare_lint_pass!(UnnecessaryStruct => [UNNECESSARY_STRUCT_INITIALIZATION]);
 
 impl LateLintPass<'_> for UnnecessaryStruct {
     fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) {
-        if let ExprKind::Struct(_, &[], Some(base)) = expr.kind {
-            if let Some(parent) = get_parent_expr(cx, expr)
-                && let parent_ty = cx.typeck_results().expr_ty_adjusted(parent)
-                && parent_ty.is_any_ptr()
-            {
-                if is_copy(cx, cx.typeck_results().expr_ty(expr)) && path_to_local(base).is_some() {
-                    // When the type implements `Copy`, a reference to the new struct works on the
-                    // copy. Using the original would borrow it.
-                    return;
-                }
-
-                if parent_ty.is_mutable_ptr() && !is_mutable(cx, base) {
-                    // The original can be used in a mutable reference context only if it is mutable.
-                    return;
-                }
-            }
+        let ExprKind::Struct(_, fields, base) = expr.kind else {
+            return;
+        };
 
-            // TODO: do not propose to replace *XX if XX is not Copy
-            if let ExprKind::Unary(UnOp::Deref, target) = base.kind
-                && matches!(target.kind, ExprKind::Path(..))
-                && !is_copy(cx, cx.typeck_results().expr_ty(expr))
-            {
-                // `*base` cannot be used instead of the struct in the general case if it is not Copy.
-                return;
-            }
+        if expr.span.from_expansion() {
+            // Prevent lint from hitting inside macro code
+            return;
+        }
+
+        let field_path = same_path_in_all_fields(cx, expr, fields);
+
+        let sugg = match (field_path, base) {
+            (Some(&path), None) => {
+                // all fields match, no base given
+                path.span
+            },
+            (Some(path), Some(base)) if base_is_suitable(cx, expr, base) && path_matches_base(path, base) => {
+                // all fields match, has base: ensure that the path of the base matches
+                base.span
+            },
+            (None, Some(base)) if fields.is_empty() && base_is_suitable(cx, expr, base) => {
+                // just the base, no explicit fields
+                base.span
+            },
+            _ => return,
+        };
+
+        span_lint_and_sugg(
+            cx,
+            UNNECESSARY_STRUCT_INITIALIZATION,
+            expr.span,
+            "unnecessary struct building",
+            "replace with",
+            snippet(cx, sugg, "..").into_owned(),
+            rustc_errors::Applicability::MachineApplicable,
+        );
+    }
+}
+
+fn base_is_suitable(cx: &LateContext<'_>, expr: &Expr<'_>, base: &Expr<'_>) -> bool {
+    if !check_references(cx, expr, base) {
+        return false;
+    }
+
+    // TODO: do not propose to replace *XX if XX is not Copy
+    if let ExprKind::Unary(UnOp::Deref, target) = base.kind
+        && matches!(target.kind, ExprKind::Path(..))
+        && !is_copy(cx, cx.typeck_results().expr_ty(expr))
+    {
+        // `*base` cannot be used instead of the struct in the general case if it is not Copy.
+        return false;
+    }
+    true
+}
+
+/// Check whether all fields of a struct assignment match.
+/// Returns a [Path] item that one can obtain a span from for the lint suggestion.
+///
+/// Conditions that must be satisfied to trigger this variant of the lint:
+///
+/// - source struct of the assignment must be of same type as the destination
+/// - names of destination struct fields must match the field names of the source
+///
+/// We don’t check here if all struct fields are assigned as the remainder may
+/// be filled in from a base struct.
+fn same_path_in_all_fields<'tcx>(
+    cx: &LateContext<'_>,
+    expr: &Expr<'_>,
+    fields: &[ExprField<'tcx>],
+) -> Option<&'tcx Path<'tcx>> {
+    let ty = cx.typeck_results().expr_ty(expr);
+
+    let mut found = None;
 
-            span_lint_and_sugg(
-                cx,
-                UNNECESSARY_STRUCT_INITIALIZATION,
-                expr.span,
-                "unnecessary struct building",
-                "replace with",
-                snippet(cx, base.span, "..").into_owned(),
-                rustc_errors::Applicability::MachineApplicable,
-            );
+    for f in fields {
+        // fields are assigned from expression
+        if let ExprKind::Field(src_expr, ident) = f.expr.kind
+            // expression type matches
+            && ty == cx.typeck_results().expr_ty(src_expr)
+            // field name matches
+            && f.ident == ident
+            // assigned from a path expression
+            && let ExprKind::Path(QPath::Resolved(None, src_path)) = src_expr.kind
+        {
+            let Some((_, p)) = found else {
+                // this is the first field assignment in the list
+                found = Some((src_expr, src_path));
+                continue;
+            };
+
+            if p.res == src_path.res {
+                // subsequent field assignment with same origin struct as before
+                continue;
+            }
         }
+        // source of field assignment doesn’t qualify
+        return None;
+    }
+
+    if let Some((src_expr, src_path)) = found
+        && check_references(cx, expr, src_expr)
+    {
+        Some(src_path)
+    } else {
+        None
     }
 }
 
@@ -89,3 +164,43 @@ fn is_mutable(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
         true
     }
 }
+
+fn check_references(cx: &LateContext<'_>, expr_a: &Expr<'_>, expr_b: &Expr<'_>) -> bool {
+    if let Some(parent) = get_parent_expr(cx, expr_a)
+        && let parent_ty = cx.typeck_results().expr_ty_adjusted(parent)
+        && parent_ty.is_any_ptr()
+    {
+        if is_copy(cx, cx.typeck_results().expr_ty(expr_a)) && path_to_local(expr_b).is_some() {
+            // When the type implements `Copy`, a reference to the new struct works on the
+            // copy. Using the original would borrow it.
+            return false;
+        }
+
+        if parent_ty.is_mutable_ptr() && !is_mutable(cx, expr_b) {
+            // The original can be used in a mutable reference context only if it is mutable.
+            return false;
+        }
+    }
+
+    true
+}
+
+/// When some fields are assigned from a base struct and others individually
+/// the lint applies only if the source of the field is the same as the base.
+/// This is enforced here by comparing the path of the base expression;
+/// needless to say the lint only applies if it (or whatever expression it is
+/// a reference of) actually has a path.
+fn path_matches_base(path: &Path<'_>, base: &Expr<'_>) -> bool {
+    let base_path = match base.kind {
+        ExprKind::Unary(UnOp::Deref, base_expr) => {
+            if let ExprKind::Path(QPath::Resolved(_, base_path)) = base_expr.kind {
+                base_path
+            } else {
+                return false;
+            }
+        },
+        ExprKind::Path(QPath::Resolved(_, base_path)) => base_path,
+        _ => return false,
+    };
+    path.res == base_path.res
+}
diff --git a/clippy_lints/src/unnecessary_wraps.rs b/clippy_lints/src/unnecessary_wraps.rs
index 5c7fbbab988..e4e7f7d06e7 100644
--- a/clippy_lints/src/unnecessary_wraps.rs
+++ b/clippy_lints/src/unnecessary_wraps.rs
@@ -1,3 +1,4 @@
+use clippy_config::Conf;
 use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::source::snippet;
 use clippy_utils::visitors::find_all_ret_expressions;
@@ -63,9 +64,9 @@ pub struct UnnecessaryWraps {
 impl_lint_pass!(UnnecessaryWraps => [UNNECESSARY_WRAPS]);
 
 impl UnnecessaryWraps {
-    pub fn new(avoid_breaking_exported_api: bool) -> Self {
+    pub fn new(conf: &'static Conf) -> Self {
         Self {
-            avoid_breaking_exported_api,
+            avoid_breaking_exported_api: conf.avoid_breaking_exported_api,
         }
     }
 }
diff --git a/clippy_lints/src/unnested_or_patterns.rs b/clippy_lints/src/unnested_or_patterns.rs
index 842046c941d..98f0be3135d 100644
--- a/clippy_lints/src/unnested_or_patterns.rs
+++ b/clippy_lints/src/unnested_or_patterns.rs
@@ -1,6 +1,7 @@
 #![allow(clippy::wildcard_imports, clippy::enum_glob_use)]
 
 use clippy_config::msrvs::{self, Msrv};
+use clippy_config::Conf;
 use clippy_utils::ast_utils::{eq_field_pat, eq_id, eq_maybe_qself, eq_pat, eq_path};
 use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::over;
@@ -51,9 +52,10 @@ pub struct UnnestedOrPatterns {
 }
 
 impl UnnestedOrPatterns {
-    #[must_use]
-    pub fn new(msrv: Msrv) -> Self {
-        Self { msrv }
+    pub fn new(conf: &'static Conf) -> Self {
+        Self {
+            msrv: conf.msrv.clone(),
+        }
     }
 }
 
diff --git a/clippy_lints/src/unused_peekable.rs b/clippy_lints/src/unused_peekable.rs
index e6f799335d7..86a811e17ca 100644
--- a/clippy_lints/src/unused_peekable.rs
+++ b/clippy_lints/src/unused_peekable.rs
@@ -8,6 +8,7 @@ use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::hir::nested_filter::OnlyBodies;
 use rustc_session::declare_lint_pass;
 use rustc_span::sym;
+use std::ops::ControlFlow;
 
 declare_clippy_lint! {
     /// ### What it does
@@ -70,15 +71,16 @@ impl<'tcx> LateLintPass<'tcx> for UnusedPeekable {
                     return;
                 }
 
-                for stmt in &block.stmts[idx..] {
-                    vis.visit_stmt(stmt);
-                }
+                let mut found_peek_call = block.stmts[idx..].iter().any(|stmt| vis.visit_stmt(stmt).is_break());
 
-                if let Some(expr) = block.expr {
-                    vis.visit_expr(expr);
+                if !found_peek_call
+                    && let Some(expr) = block.expr
+                    && vis.visit_expr(expr).is_break()
+                {
+                    found_peek_call = true;
                 }
 
-                if !vis.found_peek_call {
+                if !found_peek_call {
                     span_lint_hir_and_then(
                         cx,
                         UNUSED_PEEKABLE,
@@ -98,31 +100,23 @@ impl<'tcx> LateLintPass<'tcx> for UnusedPeekable {
 struct PeekableVisitor<'a, 'tcx> {
     cx: &'a LateContext<'tcx>,
     expected_hir_id: HirId,
-    found_peek_call: bool,
 }
 
 impl<'a, 'tcx> PeekableVisitor<'a, 'tcx> {
     fn new(cx: &'a LateContext<'tcx>, expected_hir_id: HirId) -> Self {
-        Self {
-            cx,
-            expected_hir_id,
-            found_peek_call: false,
-        }
+        Self { cx, expected_hir_id }
     }
 }
 
 impl<'tcx> Visitor<'tcx> for PeekableVisitor<'_, 'tcx> {
     type NestedFilter = OnlyBodies;
+    type Result = ControlFlow<()>;
 
     fn nested_visit_map(&mut self) -> Self::Map {
         self.cx.tcx.hir()
     }
 
-    fn visit_expr(&mut self, ex: &'tcx Expr<'tcx>) {
-        if self.found_peek_call {
-            return;
-        }
-
+    fn visit_expr(&mut self, ex: &'tcx Expr<'tcx>) -> ControlFlow<()> {
         if path_to_local_id(ex, self.expected_hir_id) {
             for (_, node) in self.cx.tcx.hir().parent_iter(ex.hir_id) {
                 match node {
@@ -137,14 +131,14 @@ impl<'tcx> Visitor<'tcx> for PeekableVisitor<'_, 'tcx> {
                                     && func_did == into_iter_did
                                 {
                                     // Probably a for loop desugar, stop searching
-                                    return;
+                                    return ControlFlow::Continue(());
                                 }
 
                                 if args.iter().any(|arg| arg_is_mut_peekable(self.cx, arg)) {
-                                    self.found_peek_call = true;
+                                    return ControlFlow::Break(());
                                 }
 
-                                return;
+                                return ControlFlow::Continue(());
                             },
                             // Catch anything taking a Peekable mutably
                             ExprKind::MethodCall(
@@ -162,16 +156,14 @@ impl<'tcx> Visitor<'tcx> for PeekableVisitor<'_, 'tcx> {
                                 if matches!(method_name, "peek" | "peek_mut" | "next_if" | "next_if_eq")
                                     && arg_is_mut_peekable(self.cx, self_arg)
                                 {
-                                    self.found_peek_call = true;
-                                    return;
+                                    return ControlFlow::Break(());
                                 }
 
                                 // foo.some_method() excluding Iterator methods
                                 if remaining_args.iter().any(|arg| arg_is_mut_peekable(self.cx, arg))
                                     && !is_trait_method(self.cx, expr, sym::Iterator)
                                 {
-                                    self.found_peek_call = true;
-                                    return;
+                                    return ControlFlow::Break(());
                                 }
 
                                 // foo.by_ref(), keep checking for `peek`
@@ -179,41 +171,42 @@ impl<'tcx> Visitor<'tcx> for PeekableVisitor<'_, 'tcx> {
                                     continue;
                                 }
 
-                                return;
+                                return ControlFlow::Continue(());
                             },
                             ExprKind::AddrOf(_, Mutability::Mut, _) | ExprKind::Unary(..) | ExprKind::DropTemps(_) => {
                             },
-                            ExprKind::AddrOf(_, Mutability::Not, _) => return,
+                            ExprKind::AddrOf(_, Mutability::Not, _) => return ControlFlow::Continue(()),
                             _ => {
-                                self.found_peek_call = true;
-                                return;
+                                return ControlFlow::Break(());
                             },
                         }
                     },
                     Node::LetStmt(LetStmt { init: Some(init), .. }) => {
                         if arg_is_mut_peekable(self.cx, init) {
-                            self.found_peek_call = true;
+                            return ControlFlow::Break(());
                         }
 
-                        return;
+                        return ControlFlow::Continue(());
                     },
                     Node::Stmt(stmt) => {
                         match stmt.kind {
-                            StmtKind::Let(_) | StmtKind::Item(_) => self.found_peek_call = true,
+                            StmtKind::Let(_) | StmtKind::Item(_) => {
+                                return ControlFlow::Break(());
+                            },
                             StmtKind::Expr(_) | StmtKind::Semi(_) => {},
                         }
 
-                        return;
+                        return ControlFlow::Continue(());
                     },
                     Node::Block(_) | Node::ExprField(_) => {},
                     _ => {
-                        return;
+                        return ControlFlow::Continue(());
                     },
                 }
             }
         }
 
-        walk_expr(self, ex);
+        walk_expr(self, ex)
     }
 }
 
diff --git a/clippy_lints/src/unused_self.rs b/clippy_lints/src/unused_self.rs
index 3e6102f5982..781f51aa9b0 100644
--- a/clippy_lints/src/unused_self.rs
+++ b/clippy_lints/src/unused_self.rs
@@ -1,3 +1,4 @@
+use clippy_config::Conf;
 use clippy_utils::diagnostics::span_lint_and_help;
 use clippy_utils::macros::root_macro_call_first_node;
 use clippy_utils::visitors::is_local_used;
@@ -43,9 +44,9 @@ pub struct UnusedSelf {
 impl_lint_pass!(UnusedSelf => [UNUSED_SELF]);
 
 impl UnusedSelf {
-    pub fn new(avoid_breaking_exported_api: bool) -> Self {
+    pub fn new(conf: &'static Conf) -> Self {
         Self {
-            avoid_breaking_exported_api,
+            avoid_breaking_exported_api: conf.avoid_breaking_exported_api,
         }
     }
 }
diff --git a/clippy_lints/src/upper_case_acronyms.rs b/clippy_lints/src/upper_case_acronyms.rs
index 72392f8e1f7..8de062a8fc1 100644
--- a/clippy_lints/src/upper_case_acronyms.rs
+++ b/clippy_lints/src/upper_case_acronyms.rs
@@ -1,3 +1,4 @@
+use clippy_config::Conf;
 use clippy_utils::diagnostics::span_lint_hir_and_then;
 use core::mem::replace;
 use rustc_errors::Applicability;
@@ -39,17 +40,16 @@ declare_clippy_lint! {
     "capitalized acronyms are against the naming convention"
 }
 
-#[derive(Default)]
 pub struct UpperCaseAcronyms {
     avoid_breaking_exported_api: bool,
     upper_case_acronyms_aggressive: bool,
 }
 
 impl UpperCaseAcronyms {
-    pub fn new(avoid_breaking_exported_api: bool, aggressive: bool) -> Self {
+    pub fn new(conf: &'static Conf) -> Self {
         Self {
-            avoid_breaking_exported_api,
-            upper_case_acronyms_aggressive: aggressive,
+            avoid_breaking_exported_api: conf.avoid_breaking_exported_api,
+            upper_case_acronyms_aggressive: conf.upper_case_acronyms_aggressive,
         }
     }
 }
diff --git a/clippy_lints/src/use_self.rs b/clippy_lints/src/use_self.rs
index 0bab917607d..93785b45c27 100644
--- a/clippy_lints/src/use_self.rs
+++ b/clippy_lints/src/use_self.rs
@@ -1,4 +1,5 @@
 use clippy_config::msrvs::{self, Msrv};
+use clippy_config::Conf;
 use clippy_utils::diagnostics::span_lint_and_sugg;
 use clippy_utils::is_from_proc_macro;
 use clippy_utils::ty::same_type_and_consts;
@@ -60,10 +61,9 @@ pub struct UseSelf {
 }
 
 impl UseSelf {
-    #[must_use]
-    pub fn new(msrv: Msrv) -> Self {
+    pub fn new(conf: &'static Conf) -> Self {
         Self {
-            msrv,
+            msrv: conf.msrv.clone(),
             stack: Vec::new(),
         }
     }
diff --git a/clippy_lints/src/utils/internal_lints/interning_defined_symbol.rs b/clippy_lints/src/utils/internal_lints/interning_defined_symbol.rs
index 07879e81fc2..b017a6bf665 100644
--- a/clippy_lints/src/utils/internal_lints/interning_defined_symbol.rs
+++ b/clippy_lints/src/utils/internal_lints/interning_defined_symbol.rs
@@ -74,7 +74,7 @@ impl<'tcx> LateLintPass<'tcx> for InterningDefinedSymbol {
         }
 
         for &module in &[&paths::KW_MODULE, &paths::SYM_MODULE] {
-            for def_id in def_path_def_ids(cx, module) {
+            for def_id in def_path_def_ids(cx.tcx, module) {
                 for item in cx.tcx.module_children(def_id) {
                     if let Res::Def(DefKind::Const, item_def_id) = item.res
                         && let ty = cx.tcx.type_of(item_def_id).instantiate_identity()
diff --git a/clippy_lints/src/utils/internal_lints/invalid_paths.rs b/clippy_lints/src/utils/internal_lints/invalid_paths.rs
index 0beb0bb8ed4..980437259c3 100644
--- a/clippy_lints/src/utils/internal_lints/invalid_paths.rs
+++ b/clippy_lints/src/utils/internal_lints/invalid_paths.rs
@@ -55,7 +55,7 @@ impl<'tcx> LateLintPass<'tcx> for InvalidPaths {
 // This is not a complete resolver for paths. It works on all the paths currently used in the paths
 // module.  That's all it does and all it needs to do.
 pub fn check_path(cx: &LateContext<'_>, path: &[&str]) -> bool {
-    if !def_path_res(cx, path).is_empty() {
+    if !def_path_res(cx.tcx, path).is_empty() {
         return true;
     }
 
diff --git a/clippy_lints/src/utils/internal_lints/unnecessary_def_path.rs b/clippy_lints/src/utils/internal_lints/unnecessary_def_path.rs
index 8cf42832761..41183700f09 100644
--- a/clippy_lints/src/utils/internal_lints/unnecessary_def_path.rs
+++ b/clippy_lints/src/utils/internal_lints/unnecessary_def_path.rs
@@ -108,7 +108,7 @@ impl UnnecessaryDefPath {
             // Extract the path to the matched type
             && let Some(segments) = path_to_matched_type(cx, item_arg)
             && let segments = segments.iter().map(|sym| &**sym).collect::<Vec<_>>()
-            && let Some(def_id) = def_path_def_ids(cx, &segments[..]).next()
+            && let Some(def_id) = def_path_def_ids(cx.tcx, &segments[..]).next()
         {
             // Check if the target item is a diagnostic item or LangItem.
             #[rustfmt::skip]
@@ -206,7 +206,7 @@ impl UnnecessaryDefPath {
     fn check_array(&mut self, cx: &LateContext<'_>, elements: &[Expr<'_>], span: Span) {
         let Some(path) = path_from_array(elements) else { return };
 
-        for def_id in def_path_def_ids(cx, &path.iter().map(AsRef::as_ref).collect::<Vec<_>>()) {
+        for def_id in def_path_def_ids(cx.tcx, &path.iter().map(AsRef::as_ref).collect::<Vec<_>>()) {
             self.array_def_ids.insert((def_id, span));
         }
     }
diff --git a/clippy_lints/src/vec.rs b/clippy_lints/src/vec.rs
index 9edf7579d48..a831234906b 100644
--- a/clippy_lints/src/vec.rs
+++ b/clippy_lints/src/vec.rs
@@ -2,6 +2,7 @@ use std::collections::BTreeMap;
 use std::ops::ControlFlow;
 
 use clippy_config::msrvs::{self, Msrv};
+use clippy_config::Conf;
 use clippy_utils::consts::{constant, Constant};
 use clippy_utils::diagnostics::span_lint_hir_and_then;
 use clippy_utils::source::snippet_opt;
@@ -17,12 +18,21 @@ use rustc_session::impl_lint_pass;
 use rustc_span::{sym, DesugaringKind, Span};
 
 #[expect(clippy::module_name_repetitions)]
-#[derive(Clone)]
 pub struct UselessVec {
-    pub too_large_for_stack: u64,
-    pub msrv: Msrv,
-    pub span_to_lint_map: BTreeMap<Span, Option<(HirId, SuggestedType, String, Applicability)>>,
-    pub allow_in_test: bool,
+    too_large_for_stack: u64,
+    msrv: Msrv,
+    span_to_lint_map: BTreeMap<Span, Option<(HirId, SuggestedType, String, Applicability)>>,
+    allow_in_test: bool,
+}
+impl UselessVec {
+    pub fn new(conf: &'static Conf) -> Self {
+        Self {
+            too_large_for_stack: conf.too_large_for_stack,
+            msrv: conf.msrv.clone(),
+            span_to_lint_map: BTreeMap::new(),
+            allow_in_test: conf.allow_useless_vec_in_tests,
+        }
+    }
 }
 
 declare_clippy_lint! {
diff --git a/clippy_lints/src/wildcard_imports.rs b/clippy_lints/src/wildcard_imports.rs
index a0a60ca8875..c4d64ee4609 100644
--- a/clippy_lints/src/wildcard_imports.rs
+++ b/clippy_lints/src/wildcard_imports.rs
@@ -1,3 +1,4 @@
+use clippy_config::Conf;
 use clippy_utils::diagnostics::span_lint_and_sugg;
 use clippy_utils::is_in_test;
 use clippy_utils::source::{snippet, snippet_with_applicability};
@@ -97,17 +98,16 @@ declare_clippy_lint! {
     "lint `use _::*` statements"
 }
 
-#[derive(Default)]
 pub struct WildcardImports {
     warn_on_all: bool,
-    allowed_segments: FxHashSet<String>,
+    allowed_segments: &'static FxHashSet<String>,
 }
 
 impl WildcardImports {
-    pub fn new(warn_on_all: bool, allowed_wildcard_imports: FxHashSet<String>) -> Self {
+    pub fn new(conf: &'static Conf) -> Self {
         Self {
-            warn_on_all,
-            allowed_segments: allowed_wildcard_imports,
+            warn_on_all: conf.warn_on_all_wildcard_imports,
+            allowed_segments: &conf.allowed_wildcard_imports,
         }
     }
 }
@@ -181,7 +181,7 @@ impl WildcardImports {
     fn check_exceptions(&self, cx: &LateContext<'_>, item: &Item<'_>, segments: &[PathSegment<'_>]) -> bool {
         item.span.from_expansion()
             || is_prelude_import(segments)
-            || is_allowed_via_config(segments, &self.allowed_segments)
+            || is_allowed_via_config(segments, self.allowed_segments)
             || (is_super_only_import(segments) && is_in_test(cx.tcx, item.hir_id()))
     }
 }
diff --git a/clippy_lints/src/write.rs b/clippy_lints/src/write.rs
index 96e53b7ef0b..54e7e92f0c4 100644
--- a/clippy_lints/src/write.rs
+++ b/clippy_lints/src/write.rs
@@ -1,3 +1,4 @@
+use clippy_config::Conf;
 use clippy_utils::diagnostics::{span_lint, span_lint_and_then};
 use clippy_utils::is_in_test;
 use clippy_utils::macros::{format_arg_removal_span, root_macro_call_first_node, FormatArgsStorage, MacroCall};
@@ -237,7 +238,6 @@ declare_clippy_lint! {
     "writing a literal with a format string"
 }
 
-#[derive(Default)]
 pub struct Write {
     format_args: FormatArgsStorage,
     in_debug_impl: bool,
@@ -245,11 +245,11 @@ pub struct Write {
 }
 
 impl Write {
-    pub fn new(format_args: FormatArgsStorage, allow_print_in_tests: bool) -> Self {
+    pub fn new(conf: &'static Conf, format_args: FormatArgsStorage) -> Self {
         Self {
             format_args,
-            allow_print_in_tests,
-            ..Default::default()
+            allow_print_in_tests: conf.allow_print_in_tests,
+            in_debug_impl: false,
         }
     }
 }
diff --git a/clippy_lints/src/zero_repeat_side_effects.rs b/clippy_lints/src/zero_repeat_side_effects.rs
index ad041e55bda..fdc1d06e67a 100644
--- a/clippy_lints/src/zero_repeat_side_effects.rs
+++ b/clippy_lints/src/zero_repeat_side_effects.rs
@@ -3,10 +3,11 @@ use clippy_utils::higher::VecArgs;
 use clippy_utils::source::snippet;
 use clippy_utils::visitors::for_each_expr_without_closures;
 use rustc_ast::LitKind;
+use rustc_data_structures::packed::Pu128;
 use rustc_errors::Applicability;
-use rustc_hir::{ExprKind, Node};
+use rustc_hir::{ArrayLen, ConstArgKind, ExprKind, Node};
 use rustc_lint::{LateContext, LateLintPass};
-use rustc_middle::ty::{self, ConstKind, Ty};
+use rustc_middle::ty::Ty;
 use rustc_session::declare_lint_pass;
 use rustc_span::Span;
 
@@ -45,18 +46,27 @@ declare_clippy_lint! {
 declare_lint_pass!(ZeroRepeatSideEffects => [ZERO_REPEAT_SIDE_EFFECTS]);
 
 impl LateLintPass<'_> for ZeroRepeatSideEffects {
-    fn check_expr(&mut self, cx: &LateContext<'_>, expr: &'_ rustc_hir::Expr<'_>) {
+    fn check_expr(&mut self, cx: &LateContext<'_>, expr: &rustc_hir::Expr<'_>) {
+        let hir_map = cx.tcx.hir();
         if let Some(args) = VecArgs::hir(cx, expr)
             && let VecArgs::Repeat(inner_expr, len) = args
             && let ExprKind::Lit(l) = len.kind
-            && let LitKind::Int(i, _) = l.node
-            && i.0 == 0
+            && let LitKind::Int(Pu128(0), _) = l.node
         {
             inner_check(cx, expr, inner_expr, true);
-        } else if let ExprKind::Repeat(inner_expr, _) = expr.kind
-            && let ty::Array(_, cst) = cx.typeck_results().expr_ty(expr).kind()
-            && let ConstKind::Value(_, ty::ValTree::Leaf(element_count)) = cst.kind()
-            && element_count.to_target_usize(cx.tcx) == 0
+        }
+        // Lint only if the length is a literal zero, and not a path to any constants.
+        // NOTE(@y21): When reading `[f(); LEN]`, I intuitively expect that the function is called and it
+        // doesn't seem as confusing as `[f(); 0]`. It would also have false positives when eg.
+        // the const item depends on `#[cfg]s` and has different values in different compilation
+        // sessions).
+        else if let ExprKind::Repeat(inner_expr, length) = expr.kind
+            && let ArrayLen::Body(const_arg) = length
+            && let ConstArgKind::Anon(anon_const) = const_arg.kind
+            && let length_expr = hir_map.body(anon_const.body).value
+            && !length_expr.span.from_expansion()
+            && let ExprKind::Lit(literal) = length_expr.kind
+            && let LitKind::Int(Pu128(0), _) = literal.node
         {
             inner_check(cx, expr, inner_expr, false);
         }