about summary refs log tree commit diff
path: root/clippy_lints/src
diff options
context:
space:
mode:
Diffstat (limited to 'clippy_lints/src')
-rw-r--r--clippy_lints/src/arbitrary_source_item_ordering.rs531
-rw-r--r--clippy_lints/src/attrs/mod.rs2
-rw-r--r--clippy_lints/src/attrs/useless_attribute.rs5
-rw-r--r--clippy_lints/src/await_holding_invalid.rs2
-rw-r--r--clippy_lints/src/booleans.rs15
-rw-r--r--clippy_lints/src/borrow_deref_ref.rs4
-rw-r--r--clippy_lints/src/casts/cast_ptr_alignment.rs2
-rw-r--r--clippy_lints/src/casts/unnecessary_cast.rs3
-rw-r--r--clippy_lints/src/checked_conversions.rs4
-rw-r--r--clippy_lints/src/cognitive_complexity.rs2
-rw-r--r--clippy_lints/src/copies.rs16
-rw-r--r--clippy_lints/src/copy_iterator.rs2
-rw-r--r--clippy_lints/src/ctfe.rs1
-rw-r--r--clippy_lints/src/declare_clippy_lint.rs49
-rw-r--r--clippy_lints/src/declared_lints.rs6
-rw-r--r--clippy_lints/src/derivable_impls.rs2
-rw-r--r--clippy_lints/src/derive.rs40
-rw-r--r--clippy_lints/src/disallowed_macros.rs23
-rw-r--r--clippy_lints/src/disallowed_script_idents.rs2
-rw-r--r--clippy_lints/src/doc/mod.rs8
-rw-r--r--clippy_lints/src/empty_drop.rs2
-rw-r--r--clippy_lints/src/eta_reduction.rs18
-rw-r--r--clippy_lints/src/explicit_write.rs2
-rw-r--r--clippy_lints/src/from_over_into.rs29
-rw-r--r--clippy_lints/src/from_raw_with_void_ptr.rs2
-rw-r--r--clippy_lints/src/functions/mod.rs2
-rw-r--r--clippy_lints/src/functions/ref_option.rs6
-rw-r--r--clippy_lints/src/implicit_hasher.rs4
-rw-r--r--clippy_lints/src/infinite_iter.rs6
-rw-r--r--clippy_lints/src/iter_without_into_iter.rs4
-rw-r--r--clippy_lints/src/large_const_arrays.rs4
-rw-r--r--clippy_lints/src/large_include_file.rs63
-rw-r--r--clippy_lints/src/len_zero.rs2
-rw-r--r--clippy_lints/src/lib.rs12
-rw-r--r--clippy_lints/src/loops/explicit_iter_loop.rs6
-rw-r--r--clippy_lints/src/loops/infinite_loop.rs59
-rw-r--r--clippy_lints/src/loops/while_immutable_condition.rs15
-rw-r--r--clippy_lints/src/loops/while_let_on_iterator.rs60
-rw-r--r--clippy_lints/src/manual_async_fn.rs23
-rw-r--r--clippy_lints/src/manual_bits.rs5
-rw-r--r--clippy_lints/src/manual_hash_one.rs4
-rw-r--r--clippy_lints/src/manual_is_ascii_check.rs2
-rw-r--r--clippy_lints/src/matches/match_like_matches.rs2
-rw-r--r--clippy_lints/src/matches/match_str_case_mismatch.rs30
-rw-r--r--clippy_lints/src/matches/redundant_guards.rs12
-rw-r--r--clippy_lints/src/matches/redundant_pattern_match.rs15
-rw-r--r--clippy_lints/src/matches/single_match.rs5
-rw-r--r--clippy_lints/src/methods/filter_map.rs8
-rw-r--r--clippy_lints/src/methods/is_empty.rs13
-rw-r--r--clippy_lints/src/methods/iter_out_of_bounds.rs5
-rw-r--r--clippy_lints/src/methods/map_all_any_identity.rs43
-rw-r--r--clippy_lints/src/methods/map_with_unused_argument_over_ranges.rs134
-rw-r--r--clippy_lints/src/methods/mod.rs134
-rw-r--r--clippy_lints/src/methods/needless_as_bytes.rs28
-rw-r--r--clippy_lints/src/methods/needless_collect.rs2
-rw-r--r--clippy_lints/src/methods/read_line_without_trim.rs4
-rw-r--r--clippy_lints/src/methods/unnecessary_filter_map.rs33
-rw-r--r--clippy_lints/src/minmax.rs4
-rw-r--r--clippy_lints/src/missing_doc.rs25
-rw-r--r--clippy_lints/src/missing_fields_in_debug.rs2
-rw-r--r--clippy_lints/src/needless_continue.rs5
-rw-r--r--clippy_lints/src/needless_late_init.rs4
-rw-r--r--clippy_lints/src/needless_maybe_sized.rs2
-rw-r--r--clippy_lints/src/needless_pass_by_ref_mut.rs2
-rw-r--r--clippy_lints/src/no_effect.rs8
-rw-r--r--clippy_lints/src/no_mangle_with_rust_abi.rs13
-rw-r--r--clippy_lints/src/non_octal_unix_permissions.rs4
-rw-r--r--clippy_lints/src/operators/float_cmp.rs2
-rw-r--r--clippy_lints/src/partialeq_ne_impl.rs2
-rw-r--r--clippy_lints/src/ptr_offset_with_cast.rs2
-rw-r--r--clippy_lints/src/question_mark.rs6
-rw-r--r--clippy_lints/src/ref_option_ref.rs2
-rw-r--r--clippy_lints/src/returns.rs2
-rw-r--r--clippy_lints/src/semicolon_block.rs27
-rw-r--r--clippy_lints/src/serde_api.rs2
-rw-r--r--clippy_lints/src/single_component_path_imports.rs2
-rw-r--r--clippy_lints/src/slow_vector_initialization.rs6
-rw-r--r--clippy_lints/src/strings.rs6
-rw-r--r--clippy_lints/src/suspicious_operation_groupings.rs28
-rw-r--r--clippy_lints/src/swap.rs2
-rw-r--r--clippy_lints/src/trait_bounds.rs10
-rw-r--r--clippy_lints/src/transmute/eager_transmute.rs4
-rw-r--r--clippy_lints/src/undocumented_unsafe_blocks.rs2
-rw-r--r--clippy_lints/src/unit_types/let_unit_value.rs2
-rw-r--r--clippy_lints/src/unit_types/unit_arg.rs2
-rw-r--r--clippy_lints/src/unused_io_amount.rs28
-rw-r--r--clippy_lints/src/utils/attr_collector.rs40
-rw-r--r--clippy_lints/src/utils/author.rs2
-rw-r--r--clippy_lints/src/utils/internal_lints.rs1
-rw-r--r--clippy_lints/src/utils/internal_lints/collapsible_calls.rs2
-rw-r--r--clippy_lints/src/utils/internal_lints/lint_without_lint_pass.rs14
-rw-r--r--clippy_lints/src/utils/internal_lints/msrv_attr_impl.rs2
-rw-r--r--clippy_lints/src/utils/internal_lints/slow_symbol_comparisons.rs69
-rw-r--r--clippy_lints/src/utils/mod.rs2
94 files changed, 1511 insertions, 344 deletions
diff --git a/clippy_lints/src/arbitrary_source_item_ordering.rs b/clippy_lints/src/arbitrary_source_item_ordering.rs
new file mode 100644
index 00000000000..8719f61a890
--- /dev/null
+++ b/clippy_lints/src/arbitrary_source_item_ordering.rs
@@ -0,0 +1,531 @@
+use clippy_config::Conf;
+use clippy_config::types::{
+    SourceItemOrderingCategory, SourceItemOrderingModuleItemGroupings, SourceItemOrderingModuleItemKind,
+    SourceItemOrderingTraitAssocItemKind, SourceItemOrderingTraitAssocItemKinds,
+};
+use clippy_utils::diagnostics::span_lint_and_note;
+use rustc_hir::{
+    AssocItemKind, FieldDef, HirId, ImplItemRef, IsAuto, Item, ItemKind, Mod, QPath, TraitItemRef, TyKind, UseKind,
+    Variant, VariantData,
+};
+use rustc_lint::{LateContext, LateLintPass, LintContext};
+use rustc_middle::lint::in_external_macro;
+use rustc_session::impl_lint_pass;
+
+declare_clippy_lint! {
+    /// ### What it does
+    ///
+    /// Confirms that items are sorted in source files as per configuration.
+    ///
+    /// ### Why restrict this?
+    ///
+    /// Keeping a consistent ordering throughout the codebase helps with working
+    /// as a team, and possibly improves maintainability of the codebase. The
+    /// idea is that by defining a consistent and enforceable rule for how
+    /// source files are structured, less time will be wasted during reviews on
+    /// a topic that is (under most circumstances) not relevant to the logic
+    /// implemented in the code. Sometimes this will be referred to as
+    /// "bikeshedding".
+    ///
+    /// ### Default Ordering and Configuration
+    ///
+    /// As there is no generally applicable rule, and each project may have
+    /// different requirements, the lint can be configured with high
+    /// granularity. The configuration is split into two stages:
+    ///
+    /// 1. Which item kinds that should have an internal order enforced.
+    /// 2. Individual ordering rules per item kind.
+    ///
+    /// The item kinds that can be linted are:
+    /// - Module (with customized groupings, alphabetical within)
+    /// - Trait (with customized order of associated items, alphabetical within)
+    /// - Enum, Impl, Struct (purely alphabetical)
+    ///
+    /// #### Module Item Order
+    ///
+    /// Due to the large variation of items within modules, the ordering can be
+    /// configured on a very granular level. Item kinds can be grouped together
+    /// arbitrarily, items within groups will be ordered alphabetically. The
+    /// following table shows the default groupings:
+    ///
+    /// | Group              | Item Kinds           |
+    /// |--------------------|----------------------|
+    /// | `modules`          | "mod", "foreign_mod" |
+    /// | `use`              | "use"                |
+    /// | `macros`           | "macro"              |
+    /// | `global_asm`       | "global_asm"         |
+    /// | `UPPER_SNAKE_CASE` | "static", "const"    |
+    /// | `PascalCase`       | "ty_alias", "opaque_ty", "enum", "struct", "union", "trait", "trait_alias", "impl" |
+    /// | `lower_snake_case` | "fn"                 |
+    ///
+    /// All item kinds must be accounted for to create an enforceable linting
+    /// rule set.
+    ///
+    /// ### Known Problems
+    ///
+    /// #### Performance Impact
+    ///
+    /// Keep in mind, that ordering source code alphabetically can lead to
+    /// reduced performance in cases where the most commonly used enum variant
+    /// isn't the first entry anymore, and similar optimizations that can reduce
+    /// branch misses, cache locality and such. Either don't use this lint if
+    /// that's relevant, or disable the lint in modules or items specifically
+    /// where it matters. Other solutions can be to use profile guided
+    /// optimization (PGO), post-link optimization (e.g. using BOLT for LLVM),
+    /// or other advanced optimization methods. A good starting point to dig
+    /// into optimization is [cargo-pgo][cargo-pgo].
+    ///
+    /// #### Lints on a Contains basis
+    ///
+    /// The lint can be disabled only on a "contains" basis, but not per element
+    /// within a "container", e.g. the lint works per-module, per-struct,
+    /// per-enum, etc. but not for "don't order this particular enum variant".
+    ///
+    /// #### Module documentation
+    ///
+    /// Module level rustdoc comments are not part of the resulting syntax tree
+    /// and as such cannot be linted from within `check_mod`. Instead, the
+    /// `rustdoc::missing_documentation` lint may be used.
+    ///
+    /// #### Module Tests
+    ///
+    /// This lint does not implement detection of module tests (or other feature
+    /// dependent elements for that matter). To lint the location of mod tests,
+    /// the lint `items_after_test_module` can be used instead.
+    ///
+    /// ### Example
+    ///
+    /// ```no_run
+    /// trait TraitUnordered {
+    ///     const A: bool;
+    ///     const C: bool;
+    ///     const B: bool;
+    ///
+    ///     type SomeType;
+    ///
+    ///     fn a();
+    ///     fn c();
+    ///     fn b();
+    /// }
+    /// ```
+    ///
+    /// Use instead:
+    /// ```no_run
+    /// trait TraitOrdered {
+    ///     const A: bool;
+    ///     const B: bool;
+    ///     const C: bool;
+    ///
+    ///     type SomeType;
+    ///
+    ///     fn a();
+    ///     fn b();
+    ///     fn c();
+    /// }
+    /// ```
+    ///
+    /// [cargo-pgo]: https://github.com/Kobzol/cargo-pgo/blob/main/README.md
+    ///
+    #[clippy::version = "1.82.0"]
+    pub ARBITRARY_SOURCE_ITEM_ORDERING,
+    restriction,
+    "arbitrary source item ordering"
+}
+
+impl_lint_pass!(ArbitrarySourceItemOrdering => [ARBITRARY_SOURCE_ITEM_ORDERING]);
+
+#[derive(Debug)]
+#[allow(clippy::struct_excessive_bools)] // Bools are cached feature flags.
+pub struct ArbitrarySourceItemOrdering {
+    assoc_types_order: SourceItemOrderingTraitAssocItemKinds,
+    enable_ordering_for_enum: bool,
+    enable_ordering_for_impl: bool,
+    enable_ordering_for_module: bool,
+    enable_ordering_for_struct: bool,
+    enable_ordering_for_trait: bool,
+    module_item_order_groupings: SourceItemOrderingModuleItemGroupings,
+}
+
+impl ArbitrarySourceItemOrdering {
+    pub fn new(conf: &'static Conf) -> Self {
+        #[allow(clippy::enum_glob_use)] // Very local glob use for legibility.
+        use SourceItemOrderingCategory::*;
+        Self {
+            assoc_types_order: conf.trait_assoc_item_kinds_order.clone(),
+            enable_ordering_for_enum: conf.source_item_ordering.contains(&Enum),
+            enable_ordering_for_impl: conf.source_item_ordering.contains(&Impl),
+            enable_ordering_for_module: conf.source_item_ordering.contains(&Module),
+            enable_ordering_for_struct: conf.source_item_ordering.contains(&Struct),
+            enable_ordering_for_trait: conf.source_item_ordering.contains(&Trait),
+            module_item_order_groupings: conf.module_item_order_groupings.clone(),
+        }
+    }
+
+    /// Produces a linting warning for incorrectly ordered impl items.
+    fn lint_impl_item<T: LintContext>(&self, cx: &T, item: &ImplItemRef, before_item: &ImplItemRef) {
+        span_lint_and_note(
+            cx,
+            ARBITRARY_SOURCE_ITEM_ORDERING,
+            item.span,
+            format!(
+                "incorrect ordering of impl items (defined order: {:?})",
+                self.assoc_types_order
+            ),
+            Some(before_item.span),
+            format!("should be placed before `{}`", before_item.ident.as_str(),),
+        );
+    }
+
+    /// Produces a linting warning for incorrectly ordered item members.
+    fn lint_member_name<T: LintContext>(
+        cx: &T,
+        ident: &rustc_span::symbol::Ident,
+        before_ident: &rustc_span::symbol::Ident,
+    ) {
+        span_lint_and_note(
+            cx,
+            ARBITRARY_SOURCE_ITEM_ORDERING,
+            ident.span,
+            "incorrect ordering of items (must be alphabetically ordered)",
+            Some(before_ident.span),
+            format!("should be placed before `{}`", before_ident.as_str(),),
+        );
+    }
+
+    fn lint_member_item<T: LintContext>(cx: &T, item: &Item<'_>, before_item: &Item<'_>) {
+        let span = if item.ident.as_str().is_empty() {
+            &item.span
+        } else {
+            &item.ident.span
+        };
+
+        let (before_span, note) = if before_item.ident.as_str().is_empty() {
+            (
+                &before_item.span,
+                "should be placed before the following item".to_owned(),
+            )
+        } else {
+            (
+                &before_item.ident.span,
+                format!("should be placed before `{}`", before_item.ident.as_str(),),
+            )
+        };
+
+        // This catches false positives where generated code gets linted.
+        if span == before_span {
+            return;
+        }
+
+        span_lint_and_note(
+            cx,
+            ARBITRARY_SOURCE_ITEM_ORDERING,
+            *span,
+            "incorrect ordering of items (must be alphabetically ordered)",
+            Some(*before_span),
+            note,
+        );
+    }
+
+    /// Produces a linting warning for incorrectly ordered trait items.
+    fn lint_trait_item<T: LintContext>(&self, cx: &T, item: &TraitItemRef, before_item: &TraitItemRef) {
+        span_lint_and_note(
+            cx,
+            ARBITRARY_SOURCE_ITEM_ORDERING,
+            item.span,
+            format!(
+                "incorrect ordering of trait items (defined order: {:?})",
+                self.assoc_types_order
+            ),
+            Some(before_item.span),
+            format!("should be placed before `{}`", before_item.ident.as_str(),),
+        );
+    }
+}
+
+impl<'tcx> LateLintPass<'tcx> for ArbitrarySourceItemOrdering {
+    fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'tcx>) {
+        match &item.kind {
+            ItemKind::Enum(enum_def, _generics) if self.enable_ordering_for_enum => {
+                let mut cur_v: Option<&Variant<'_>> = None;
+                for variant in enum_def.variants {
+                    if in_external_macro(cx.sess(), variant.span) {
+                        continue;
+                    }
+
+                    if let Some(cur_v) = cur_v {
+                        if cur_v.ident.name.as_str() > variant.ident.name.as_str() && cur_v.span != variant.span {
+                            Self::lint_member_name(cx, &variant.ident, &cur_v.ident);
+                        }
+                    }
+                    cur_v = Some(variant);
+                }
+            },
+            ItemKind::Struct(VariantData::Struct { fields, .. }, _generics) if self.enable_ordering_for_struct => {
+                let mut cur_f: Option<&FieldDef<'_>> = None;
+                for field in *fields {
+                    if in_external_macro(cx.sess(), field.span) {
+                        continue;
+                    }
+
+                    if let Some(cur_f) = cur_f {
+                        if cur_f.ident.name.as_str() > field.ident.name.as_str() && cur_f.span != field.span {
+                            Self::lint_member_name(cx, &field.ident, &cur_f.ident);
+                        }
+                    }
+                    cur_f = Some(field);
+                }
+            },
+            ItemKind::Trait(is_auto, _safety, _generics, _generic_bounds, item_ref)
+                if self.enable_ordering_for_trait && *is_auto == IsAuto::No =>
+            {
+                let mut cur_t: Option<&TraitItemRef> = None;
+
+                for item in *item_ref {
+                    if in_external_macro(cx.sess(), item.span) {
+                        continue;
+                    }
+
+                    if let Some(cur_t) = cur_t {
+                        let cur_t_kind = convert_assoc_item_kind(cur_t.kind);
+                        let cur_t_kind_index = self.assoc_types_order.index_of(&cur_t_kind);
+                        let item_kind = convert_assoc_item_kind(item.kind);
+                        let item_kind_index = self.assoc_types_order.index_of(&item_kind);
+
+                        if cur_t_kind == item_kind && cur_t.ident.name.as_str() > item.ident.name.as_str() {
+                            Self::lint_member_name(cx, &item.ident, &cur_t.ident);
+                        } else if cur_t_kind_index > item_kind_index {
+                            self.lint_trait_item(cx, item, cur_t);
+                        }
+                    }
+                    cur_t = Some(item);
+                }
+            },
+            ItemKind::Impl(trait_impl) if self.enable_ordering_for_impl => {
+                let mut cur_t: Option<&ImplItemRef> = None;
+
+                for item in trait_impl.items {
+                    if in_external_macro(cx.sess(), item.span) {
+                        continue;
+                    }
+
+                    if let Some(cur_t) = cur_t {
+                        let cur_t_kind = convert_assoc_item_kind(cur_t.kind);
+                        let cur_t_kind_index = self.assoc_types_order.index_of(&cur_t_kind);
+                        let item_kind = convert_assoc_item_kind(item.kind);
+                        let item_kind_index = self.assoc_types_order.index_of(&item_kind);
+
+                        if cur_t_kind == item_kind && cur_t.ident.name.as_str() > item.ident.name.as_str() {
+                            Self::lint_member_name(cx, &item.ident, &cur_t.ident);
+                        } else if cur_t_kind_index > item_kind_index {
+                            self.lint_impl_item(cx, item, cur_t);
+                        }
+                    }
+                    cur_t = Some(item);
+                }
+            },
+            _ => {}, // Catch-all for `ItemKinds` that don't have fields.
+        }
+    }
+
+    fn check_mod(&mut self, cx: &LateContext<'tcx>, module: &'tcx Mod<'tcx>, _: HirId) {
+        struct CurItem<'a> {
+            item: &'a Item<'a>,
+            order: usize,
+            name: String,
+        }
+        let mut cur_t: Option<CurItem<'_>> = None;
+
+        if !self.enable_ordering_for_module {
+            return;
+        }
+
+        let items = module.item_ids.iter().map(|&id| cx.tcx.hir().item(id));
+
+        // Iterates over the items within a module.
+        //
+        // As of 2023-05-09, the Rust compiler will hold the entries in the same
+        // order as they appear in the source code, which is convenient for us,
+        // as no sorting by source map/line of code has to be applied.
+        //
+        for item in items {
+            if in_external_macro(cx.sess(), item.span) {
+                continue;
+            }
+
+            // The following exceptions (skipping with `continue;`) may not be
+            // complete, edge cases have not been explored further than what
+            // appears in the existing code base.
+            if item.ident.name == rustc_span::symbol::kw::Empty {
+                if let ItemKind::Impl(_) = item.kind {
+                    // Sorting trait impls for unnamed types makes no sense.
+                    if get_item_name(item).is_empty() {
+                        continue;
+                    }
+                } else if let ItemKind::ForeignMod { .. } = item.kind {
+                    continue;
+                } else if let ItemKind::GlobalAsm(_) = item.kind {
+                    continue;
+                } else if let ItemKind::Use(path, use_kind) = item.kind {
+                    if path.segments.is_empty() {
+                        // Use statements that contain braces get caught here.
+                        // They will still be linted internally.
+                        continue;
+                    } else if path.segments.len() >= 2
+                        && (path.segments[0].ident.name == rustc_span::sym::std
+                            || path.segments[0].ident.name == rustc_span::sym::core)
+                        && path.segments[1].ident.name == rustc_span::sym::prelude
+                    {
+                        // Filters the autogenerated prelude use statement.
+                        // e.g. `use std::prelude::rustc_2021`
+                    } else if use_kind == UseKind::Glob {
+                        // Filters glob kinds of uses.
+                        // e.g. `use std::sync::*`
+                    } else {
+                        // This can be used for debugging.
+                        // println!("Unknown autogenerated use statement: {:?}", item);
+                    }
+                    continue;
+                }
+            }
+
+            if item.ident.name.as_str().starts_with('_') {
+                // Filters out unnamed macro-like impls for various derives,
+                // e.g. serde::Serialize or num_derive::FromPrimitive.
+                continue;
+            }
+
+            if item.ident.name == rustc_span::sym::std && item.span.is_dummy() {
+                if let ItemKind::ExternCrate(None) = item.kind {
+                    // Filters the auto-included Rust standard library.
+                    continue;
+                }
+                println!("Unknown item: {item:?}");
+            }
+
+            let item_kind = convert_module_item_kind(&item.kind);
+            let module_level_order = self
+                .module_item_order_groupings
+                .module_level_order_of(&item_kind)
+                .unwrap_or_default();
+
+            if let Some(cur_t) = cur_t.as_ref() {
+                use std::cmp::Ordering; // Better legibility.
+                match module_level_order.cmp(&cur_t.order) {
+                    Ordering::Less => {
+                        Self::lint_member_item(cx, item, cur_t.item);
+                    },
+                    Ordering::Equal if item_kind == SourceItemOrderingModuleItemKind::Use => {
+                        // Skip ordering use statements, as these should be ordered by rustfmt.
+                    },
+                    Ordering::Equal if cur_t.name > get_item_name(item) => {
+                        Self::lint_member_item(cx, item, cur_t.item);
+                    },
+                    Ordering::Equal | Ordering::Greater => {
+                        // Nothing to do in this case, they're already in the right order.
+                    },
+                }
+            }
+
+            // Makes a note of the current item for comparison with the next.
+            cur_t = Some(CurItem {
+                order: module_level_order,
+                item,
+                name: get_item_name(item),
+            });
+        }
+    }
+}
+
+/// Converts a [`rustc_hir::AssocItemKind`] to a
+/// [`SourceItemOrderingTraitAssocItemKind`].
+///
+/// This is implemented here because `rustc_hir` is not a dependency of
+/// `clippy_config`.
+fn convert_assoc_item_kind(value: AssocItemKind) -> SourceItemOrderingTraitAssocItemKind {
+    #[allow(clippy::enum_glob_use)] // Very local glob use for legibility.
+    use SourceItemOrderingTraitAssocItemKind::*;
+    match value {
+        AssocItemKind::Const { .. } => Const,
+        AssocItemKind::Type { .. } => Type,
+        AssocItemKind::Fn { .. } => Fn,
+    }
+}
+
+/// Converts a [`rustc_hir::ItemKind`] to a
+/// [`SourceItemOrderingModuleItemKind`].
+///
+/// This is implemented here because `rustc_hir` is not a dependency of
+/// `clippy_config`.
+fn convert_module_item_kind(value: &ItemKind<'_>) -> SourceItemOrderingModuleItemKind {
+    #[allow(clippy::enum_glob_use)] // Very local glob use for legibility.
+    use SourceItemOrderingModuleItemKind::*;
+    match value {
+        ItemKind::ExternCrate(..) => ExternCrate,
+        ItemKind::Use(..) => Use,
+        ItemKind::Static(..) => Static,
+        ItemKind::Const(..) => Const,
+        ItemKind::Fn(..) => Fn,
+        ItemKind::Macro(..) => Macro,
+        ItemKind::Mod(..) => Mod,
+        ItemKind::ForeignMod { .. } => ForeignMod,
+        ItemKind::GlobalAsm(..) => GlobalAsm,
+        ItemKind::TyAlias(..) => TyAlias,
+        ItemKind::Enum(..) => Enum,
+        ItemKind::Struct(..) => Struct,
+        ItemKind::Union(..) => Union,
+        ItemKind::Trait(..) => Trait,
+        ItemKind::TraitAlias(..) => TraitAlias,
+        ItemKind::Impl(..) => Impl,
+    }
+}
+
+/// Gets the item name for sorting purposes, which in the general case is
+/// `item.ident.name`.
+///
+/// For trait impls, the name used for sorting will be the written path of
+/// `item.self_ty` plus the written path of `item.of_trait`, joined with
+/// exclamation marks. Exclamation marks are used because they are the first
+/// printable ASCII character.
+///
+/// Trait impls generated using a derive-macro will have their path rewritten,
+/// such that for example `Default` is `$crate::default::Default`, and
+/// `std::clone::Clone` is `$crate::clone::Clone`. This behaviour is described
+/// further in the [Rust Reference, Paths Chapter][rust_ref].
+///
+/// [rust_ref]: https://doc.rust-lang.org/reference/paths.html#crate-1
+fn get_item_name(item: &Item<'_>) -> String {
+    match item.kind {
+        ItemKind::Impl(im) => {
+            if let TyKind::Path(path) = im.self_ty.kind {
+                match path {
+                    QPath::Resolved(_, path) => {
+                        let segs = path.segments.iter();
+                        let mut segs: Vec<String> = segs.map(|s| s.ident.name.as_str().to_owned()).collect();
+
+                        if let Some(of_trait) = im.of_trait {
+                            let mut trait_segs: Vec<String> = of_trait
+                                .path
+                                .segments
+                                .iter()
+                                .map(|s| s.ident.name.as_str().to_owned())
+                                .collect();
+                            segs.append(&mut trait_segs);
+                        }
+
+                        segs.push(String::new());
+                        segs.join("!!")
+                    },
+                    QPath::TypeRelative(_, _path_seg) => {
+                        // This case doesn't exist in the clippy tests codebase.
+                        String::new()
+                    },
+                    QPath::LangItem(_, _) => String::new(),
+                }
+            } else {
+                // Impls for anything that isn't a named type can be skipped.
+                String::new()
+            }
+        },
+        _ => item.ident.name.as_str().to_owned(),
+    }
+}
diff --git a/clippy_lints/src/attrs/mod.rs b/clippy_lints/src/attrs/mod.rs
index 684756ce87f..c29c9f08cf7 100644
--- a/clippy_lints/src/attrs/mod.rs
+++ b/clippy_lints/src/attrs/mod.rs
@@ -14,7 +14,7 @@ mod utils;
 
 use clippy_config::Conf;
 use clippy_config::msrvs::{self, Msrv};
-use rustc_ast::{Attribute, MetaItemInner, MetaItemKind, self as ast};
+use rustc_ast::{self as ast, Attribute, MetaItemInner, MetaItemKind};
 use rustc_hir::{ImplItem, Item, TraitItem};
 use rustc_lint::{EarlyContext, EarlyLintPass, LateContext, LateLintPass};
 use rustc_session::impl_lint_pass;
diff --git a/clippy_lints/src/attrs/useless_attribute.rs b/clippy_lints/src/attrs/useless_attribute.rs
index 92b9f9cba52..dc5a6857089 100644
--- a/clippy_lints/src/attrs/useless_attribute.rs
+++ b/clippy_lints/src/attrs/useless_attribute.rs
@@ -1,10 +1,9 @@
-use super::utils::{extract_clippy_lint, is_lint_level, is_word};
 use super::USELESS_ATTRIBUTE;
+use super::utils::{extract_clippy_lint, is_lint_level, is_word};
 use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::source::{SpanRangeExt, first_line_of_span};
-use rustc_ast::MetaItemInner;
+use rustc_ast::{Attribute, Item, ItemKind, MetaItemInner};
 use rustc_errors::Applicability;
-use rustc_ast::{Item, ItemKind, Attribute};
 use rustc_lint::{EarlyContext, LintContext};
 use rustc_middle::lint::in_external_macro;
 use rustc_span::sym;
diff --git a/clippy_lints/src/await_holding_invalid.rs b/clippy_lints/src/await_holding_invalid.rs
index 9952d0af99e..6948cf560a5 100644
--- a/clippy_lints/src/await_holding_invalid.rs
+++ b/clippy_lints/src/await_holding_invalid.rs
@@ -15,7 +15,7 @@ declare_clippy_lint! {
     /// `MutexGuard`.
     ///
     /// ### Why is this bad?
-    /// The Mutex types found in [`std::sync`][https://doc.rust-lang.org/stable/std/sync/] and
+    /// The Mutex types found in [`std::sync`](https://doc.rust-lang.org/stable/std/sync/) and
     /// [`parking_lot`](https://docs.rs/parking_lot/latest/parking_lot/) are
     /// not designed to operate in an async context across await points.
     ///
diff --git a/clippy_lints/src/booleans.rs b/clippy_lints/src/booleans.rs
index 26888f7e3a0..26a20bc99a0 100644
--- a/clippy_lints/src/booleans.rs
+++ b/clippy_lints/src/booleans.rs
@@ -203,6 +203,21 @@ fn check_simplify_not(cx: &LateContext<'_>, msrv: &Msrv, expr: &Expr<'_>) {
         && let Some(suggestion) = simplify_not(cx, msrv, inner)
         && cx.tcx.lint_level_at_node(NONMINIMAL_BOOL, expr.hir_id).0 != Level::Allow
     {
+        use clippy_utils::sugg::{Sugg, has_enclosing_paren};
+        let maybe_par = if let Some(sug) = Sugg::hir_opt(cx, inner) {
+            match sug {
+                Sugg::BinOp(..) => true,
+                Sugg::MaybeParen(sug) if !has_enclosing_paren(&sug) => true,
+                _ => false,
+            }
+        } else {
+            false
+        };
+        let suggestion = if maybe_par {
+            format!("({suggestion})")
+        } else {
+            suggestion
+        };
         span_lint_and_sugg(
             cx,
             NONMINIMAL_BOOL,
diff --git a/clippy_lints/src/borrow_deref_ref.rs b/clippy_lints/src/borrow_deref_ref.rs
index cba8224b84c..f2551a05b1a 100644
--- a/clippy_lints/src/borrow_deref_ref.rs
+++ b/clippy_lints/src/borrow_deref_ref.rs
@@ -4,7 +4,7 @@ use clippy_utils::source::SpanRangeExt;
 use clippy_utils::ty::implements_trait;
 use clippy_utils::{get_parent_expr, is_from_proc_macro, is_lint_allowed};
 use rustc_errors::Applicability;
-use rustc_hir::{ExprKind, UnOp};
+use rustc_hir::{BorrowKind, ExprKind, UnOp};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::mir::Mutability;
 use rustc_middle::ty;
@@ -49,7 +49,7 @@ 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 let ExprKind::AddrOf(_, Mutability::Not, addrof_target) = e.kind
+        if let ExprKind::AddrOf(BorrowKind::Ref, Mutability::Not, addrof_target) = e.kind
             && let ExprKind::Unary(UnOp::Deref, deref_target) = addrof_target.kind
             && !matches!(deref_target.kind, ExprKind::Unary(UnOp::Deref, ..))
             && !e.span.from_expansion()
diff --git a/clippy_lints/src/casts/cast_ptr_alignment.rs b/clippy_lints/src/casts/cast_ptr_alignment.rs
index b11b967f8bc..205357afd84 100644
--- a/clippy_lints/src/casts/cast_ptr_alignment.rs
+++ b/clippy_lints/src/casts/cast_ptr_alignment.rs
@@ -20,7 +20,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>) {
         );
         lint_cast_ptr_alignment(cx, expr, cast_from, cast_to);
     } else if let ExprKind::MethodCall(method_path, self_arg, [], _) = &expr.kind {
-        if method_path.ident.name == sym!(cast)
+        if method_path.ident.name.as_str() == "cast"
             && let Some(generic_args) = method_path.args
             && let [GenericArg::Type(cast_to)] = generic_args.args
             // There probably is no obvious reason to do this, just to be consistent with `as` cases.
diff --git a/clippy_lints/src/casts/unnecessary_cast.rs b/clippy_lints/src/casts/unnecessary_cast.rs
index 811d33c8bde..abd80abffe6 100644
--- a/clippy_lints/src/casts/unnecessary_cast.rs
+++ b/clippy_lints/src/casts/unnecessary_cast.rs
@@ -268,8 +268,7 @@ fn is_cast_from_ty_alias<'tcx>(cx: &LateContext<'tcx>, expr: impl Visitable<'tcx
                 if !snippet
                     .split("->")
                     .skip(1)
-                    .map(|s| snippet_eq_ty(s, cast_from) || s.split("where").any(|ty| snippet_eq_ty(ty, cast_from)))
-                    .any(|a| a)
+                    .any(|s| snippet_eq_ty(s, cast_from) || s.split("where").any(|ty| snippet_eq_ty(ty, cast_from)))
                 {
                     return ControlFlow::Break(());
                 }
diff --git a/clippy_lints/src/checked_conversions.rs b/clippy_lints/src/checked_conversions.rs
index 2e7f91a842e..f76e399517c 100644
--- a/clippy_lints/src/checked_conversions.rs
+++ b/clippy_lints/src/checked_conversions.rs
@@ -232,7 +232,7 @@ fn get_types_from_cast<'a>(
     // or `to_type::MAX as from_type`
     let call_from_cast: Option<(&Expr<'_>, &str)> = if let ExprKind::Cast(limit, from_type) = &expr.kind
         // to_type::max_value(), from_type
-        && let TyKind::Path(ref from_type_path) = &from_type.kind
+        && let TyKind::Path(from_type_path) = &from_type.kind
         && let Some(from_sym) = int_ty_to_sym(from_type_path)
     {
         Some((limit, from_sym))
@@ -245,7 +245,7 @@ fn get_types_from_cast<'a>(
         if let ExprKind::Call(from_func, [limit]) = &expr.kind
             // `from_type::from, to_type::max_value()`
             // `from_type::from`
-            && let ExprKind::Path(ref path) = &from_func.kind
+            && let ExprKind::Path(path) = &from_func.kind
             && let Some(from_sym) = get_implementing_type(path, INTS, "from")
         {
             Some((limit, from_sym))
diff --git a/clippy_lints/src/cognitive_complexity.rs b/clippy_lints/src/cognitive_complexity.rs
index 477435236a5..383fae7992b 100644
--- a/clippy_lints/src/cognitive_complexity.rs
+++ b/clippy_lints/src/cognitive_complexity.rs
@@ -30,7 +30,7 @@ declare_clippy_lint! {
     #[clippy::version = "1.35.0"]
     pub COGNITIVE_COMPLEXITY,
     nursery,
-    "functions that should be split up into multiple functions"
+    "functions that should be split up into multiple functions",
     @eval_always = true
 }
 
diff --git a/clippy_lints/src/copies.rs b/clippy_lints/src/copies.rs
index d90a22bb62a..c4afdc757d8 100644
--- a/clippy_lints/src/copies.rs
+++ b/clippy_lints/src/copies.rs
@@ -540,24 +540,22 @@ fn check_for_warn_of_moved_symbol(cx: &LateContext<'_>, symbols: &[(HirId, Symbo
             .iter()
             .filter(|&&(_, name)| !name.as_str().starts_with('_'))
             .any(|&(_, name)| {
-                let mut walker = ContainsName {
-                    name,
-                    result: false,
-                    cx,
-                };
+                let mut walker = ContainsName { name, cx };
 
                 // Scan block
-                block
+                let mut res = block
                     .stmts
                     .iter()
                     .filter(|stmt| !ignore_span.overlaps(stmt.span))
-                    .for_each(|stmt| intravisit::walk_stmt(&mut walker, stmt));
+                    .try_for_each(|stmt| intravisit::walk_stmt(&mut walker, stmt));
 
                 if let Some(expr) = block.expr {
-                    intravisit::walk_expr(&mut walker, expr);
+                    if res.is_continue() {
+                        res = intravisit::walk_expr(&mut walker, expr);
+                    }
                 }
 
-                walker.result
+                res.is_break()
             })
     })
 }
diff --git a/clippy_lints/src/copy_iterator.rs b/clippy_lints/src/copy_iterator.rs
index 50fd76a3a47..4ecf3e41611 100644
--- a/clippy_lints/src/copy_iterator.rs
+++ b/clippy_lints/src/copy_iterator.rs
@@ -37,7 +37,7 @@ declare_lint_pass!(CopyIterator => [COPY_ITERATOR]);
 impl<'tcx> LateLintPass<'tcx> for CopyIterator {
     fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) {
         if let ItemKind::Impl(Impl {
-            of_trait: Some(ref trait_ref),
+            of_trait: Some(trait_ref),
             ..
         }) = item.kind
             && let ty = cx.tcx.type_of(item.owner_id).instantiate_identity()
diff --git a/clippy_lints/src/ctfe.rs b/clippy_lints/src/ctfe.rs
index 181514e8372..589b99518a0 100644
--- a/clippy_lints/src/ctfe.rs
+++ b/clippy_lints/src/ctfe.rs
@@ -5,7 +5,6 @@ use rustc_lint::{LateContext, LateLintPass};
 use rustc_session::declare_lint_pass;
 use rustc_span::Span;
 
-
 declare_lint_pass! {
     /// Ensures that Constant-time Function Evaluation is being done (specifically, MIR lint passes).
     /// As Clippy deactivates codegen, this lint ensures that CTFE (used in hard errors) is still ran.
diff --git a/clippy_lints/src/declare_clippy_lint.rs b/clippy_lints/src/declare_clippy_lint.rs
index a785a9d377c..4d908af4084 100644
--- a/clippy_lints/src/declare_clippy_lint.rs
+++ b/clippy_lints/src/declare_clippy_lint.rs
@@ -4,7 +4,7 @@ macro_rules! declare_clippy_lint {
     (@
         $(#[doc = $lit:literal])*
         pub $lint_name:ident,
-        $category:ident,
+        $level:ident,
         $lintcategory:expr,
         $desc:literal,
         $version_expr:expr,
@@ -15,7 +15,7 @@ macro_rules! declare_clippy_lint {
             $(#[doc = $lit])*
             #[clippy::version = $version_lit]
             pub clippy::$lint_name,
-            $category,
+            $level,
             $desc,
             report_in_external_macro:true
             $(, @eval_always = $eval_always)?
@@ -35,12 +35,13 @@ macro_rules! declare_clippy_lint {
         pub $lint_name:ident,
         restriction,
         $desc:literal
-        $(@eval_always = $eval_always: literal)?
+        $(, @eval_always = $eval_always: literal)?
     ) => {
         declare_clippy_lint! {@
             $(#[doc = $lit])*
             pub $lint_name, Allow, crate::LintCategory::Restriction, $desc,
-            Some($version), $version $(, $eval_always)?
+            Some($version), $version
+            $(, $eval_always)?
         }
     };
     (
@@ -49,12 +50,13 @@ macro_rules! declare_clippy_lint {
         pub $lint_name:ident,
         style,
         $desc:literal
-        $(@eval_always = $eval_always: literal)?
+        $(, @eval_always = $eval_always: literal)?
     ) => {
         declare_clippy_lint! {@
             $(#[doc = $lit])*
             pub $lint_name, Warn, crate::LintCategory::Style, $desc,
-            Some($version), $version $(, $eval_always)?
+            Some($version), $version
+            $(, $eval_always)?
         }
     };
     (
@@ -63,12 +65,13 @@ macro_rules! declare_clippy_lint {
         pub $lint_name:ident,
         correctness,
         $desc:literal
-        $(@eval_always = $eval_always: literal)?
+        $(, @eval_always = $eval_always: literal)?
     ) => {
         declare_clippy_lint! {@
             $(#[doc = $lit])*
             pub $lint_name, Deny, crate::LintCategory::Correctness, $desc,
-            Some($version), $version $(, $eval_always)?
+            Some($version), $version
+            $(, $eval_always)?
 
         }
     };
@@ -78,12 +81,13 @@ macro_rules! declare_clippy_lint {
         pub $lint_name:ident,
         perf,
         $desc:literal
-        $(@eval_always = $eval_always: literal)?
+        $(, @eval_always = $eval_always: literal)?
     ) => {
         declare_clippy_lint! {@
             $(#[doc = $lit])*
             pub $lint_name, Warn, crate::LintCategory::Perf, $desc,
-            Some($version), $version $(, $eval_always)?
+            Some($version), $version
+            $(, $eval_always)?
         }
     };
     (
@@ -92,12 +96,13 @@ macro_rules! declare_clippy_lint {
         pub $lint_name:ident,
         complexity,
         $desc:literal
-        $(@eval_always = $eval_always: literal)?
+        $(, @eval_always = $eval_always: literal)?
     ) => {
         declare_clippy_lint! {@
             $(#[doc = $lit])*
             pub $lint_name, Warn, crate::LintCategory::Complexity, $desc,
-            Some($version), $version $(, $eval_always)?
+            Some($version), $version
+            $(, $eval_always)?
         }
     };
     (
@@ -106,12 +111,13 @@ macro_rules! declare_clippy_lint {
         pub $lint_name:ident,
         suspicious,
         $desc:literal
-        $(@eval_always = $eval_always: literal)?
+        $(, @eval_always = $eval_always: literal)?
     ) => {
         declare_clippy_lint! {@
             $(#[doc = $lit])*
             pub $lint_name, Warn, crate::LintCategory::Suspicious, $desc,
-            Some($version), $version $(, $eval_always)?
+            Some($version), $version
+            $(, $eval_always)?
         }
     };
     (
@@ -120,12 +126,13 @@ macro_rules! declare_clippy_lint {
         pub $lint_name:ident,
         nursery,
         $desc:literal
-        $(@eval_always = $eval_always: literal)?
+        $(, @eval_always = $eval_always: literal)?
     ) => {
         declare_clippy_lint! {@
             $(#[doc = $lit])*
             pub $lint_name, Allow, crate::LintCategory::Nursery, $desc,
-            Some($version), $version $(, $eval_always)?
+            Some($version), $version
+            $(, $eval_always)?
         }
     };
     (
@@ -134,12 +141,13 @@ macro_rules! declare_clippy_lint {
         pub $lint_name:ident,
         pedantic,
         $desc:literal
-        $(@eval_always = $eval_always: literal)?
+        $(, @eval_always = $eval_always: literal)?
     ) => {
         declare_clippy_lint! {@
             $(#[doc = $lit])*
             pub $lint_name, Allow, crate::LintCategory::Pedantic, $desc,
-            Some($version), $version $(, $eval_always)?
+            Some($version), $version
+            $(, $eval_always)?
         }
     };
     (
@@ -148,12 +156,13 @@ macro_rules! declare_clippy_lint {
         pub $lint_name:ident,
         cargo,
         $desc:literal
-        $(@eval_always = $eval_always: literal)?
+        $(, @eval_always = $eval_always: literal)?
     ) => {
         declare_clippy_lint! {@
             $(#[doc = $lit])*
             pub $lint_name, Allow, crate::LintCategory::Cargo, $desc,
-            Some($version), $version $(, $eval_always)?
+            Some($version), $version
+            $(, $eval_always)?
         }
     };
 
diff --git a/clippy_lints/src/declared_lints.rs b/clippy_lints/src/declared_lints.rs
index 3c4e75df8ab..edb52851e0c 100644
--- a/clippy_lints/src/declared_lints.rs
+++ b/clippy_lints/src/declared_lints.rs
@@ -28,12 +28,15 @@ pub static LINTS: &[&crate::LintInfo] = &[
     #[cfg(feature = "internal")]
     crate::utils::internal_lints::produce_ice::PRODUCE_ICE_INFO,
     #[cfg(feature = "internal")]
+    crate::utils::internal_lints::slow_symbol_comparisons::SLOW_SYMBOL_COMPARISONS_INFO,
+    #[cfg(feature = "internal")]
     crate::utils::internal_lints::unnecessary_def_path::UNNECESSARY_DEF_PATH_INFO,
     #[cfg(feature = "internal")]
     crate::utils::internal_lints::unsorted_clippy_utils_paths::UNSORTED_CLIPPY_UTILS_PATHS_INFO,
     crate::absolute_paths::ABSOLUTE_PATHS_INFO,
     crate::almost_complete_range::ALMOST_COMPLETE_RANGE_INFO,
     crate::approx_const::APPROX_CONSTANT_INFO,
+    crate::arbitrary_source_item_ordering::ARBITRARY_SOURCE_ITEM_ORDERING_INFO,
     crate::arc_with_non_send_sync::ARC_WITH_NON_SEND_SYNC_INFO,
     crate::as_conversions::AS_CONVERSIONS_INFO,
     crate::asm_syntax::INLINE_ASM_X86_ATT_SYNTAX_INFO,
@@ -414,14 +417,17 @@ pub static LINTS: &[&crate::LintInfo] = &[
     crate::methods::MANUAL_SPLIT_ONCE_INFO,
     crate::methods::MANUAL_STR_REPEAT_INFO,
     crate::methods::MANUAL_TRY_FOLD_INFO,
+    crate::methods::MAP_ALL_ANY_IDENTITY_INFO,
     crate::methods::MAP_CLONE_INFO,
     crate::methods::MAP_COLLECT_RESULT_UNIT_INFO,
     crate::methods::MAP_ERR_IGNORE_INFO,
     crate::methods::MAP_FLATTEN_INFO,
     crate::methods::MAP_IDENTITY_INFO,
     crate::methods::MAP_UNWRAP_OR_INFO,
+    crate::methods::MAP_WITH_UNUSED_ARGUMENT_OVER_RANGES_INFO,
     crate::methods::MUT_MUTEX_LOCK_INFO,
     crate::methods::NAIVE_BYTECOUNT_INFO,
+    crate::methods::NEEDLESS_AS_BYTES_INFO,
     crate::methods::NEEDLESS_CHARACTER_ITERATION_INFO,
     crate::methods::NEEDLESS_COLLECT_INFO,
     crate::methods::NEEDLESS_OPTION_AS_DEREF_INFO,
diff --git a/clippy_lints/src/derivable_impls.rs b/clippy_lints/src/derivable_impls.rs
index 2920bbb4c81..2b6bfafe695 100644
--- a/clippy_lints/src/derivable_impls.rs
+++ b/clippy_lints/src/derivable_impls.rs
@@ -187,7 +187,7 @@ fn check_enum<'tcx>(cx: &LateContext<'tcx>, item: &'tcx Item<'_>, func_expr: &Ex
 impl<'tcx> LateLintPass<'tcx> for DerivableImpls {
     fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) {
         if let ItemKind::Impl(Impl {
-            of_trait: Some(ref trait_ref),
+            of_trait: Some(trait_ref),
             items: [child],
             self_ty,
             ..
diff --git a/clippy_lints/src/derive.rs b/clippy_lints/src/derive.rs
index e8e21edd494..e569c4dc786 100644
--- a/clippy_lints/src/derive.rs
+++ b/clippy_lints/src/derive.rs
@@ -1,3 +1,5 @@
+use std::ops::ControlFlow;
+
 use clippy_utils::diagnostics::{span_lint_and_note, span_lint_and_then, span_lint_hir_and_then};
 use clippy_utils::ty::{implements_trait, implements_trait_with_env, is_copy};
 use clippy_utils::{has_non_exhaustive_attr, is_lint_allowed, match_def_path, paths};
@@ -202,7 +204,7 @@ declare_lint_pass!(Derive => [
 impl<'tcx> LateLintPass<'tcx> for Derive {
     fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) {
         if let ItemKind::Impl(Impl {
-            of_trait: Some(ref trait_ref),
+            of_trait: Some(trait_ref),
             ..
         }) = item.kind
         {
@@ -371,9 +373,8 @@ fn check_unsafe_derive_deserialize<'tcx>(
     ty: Ty<'tcx>,
 ) {
     fn has_unsafe<'tcx>(cx: &LateContext<'tcx>, item: &'tcx Item<'_>) -> bool {
-        let mut visitor = UnsafeVisitor { cx, has_unsafe: false };
-        walk_item(&mut visitor, item);
-        visitor.has_unsafe
+        let mut visitor = UnsafeVisitor { cx };
+        walk_item(&mut visitor, item).is_break()
     }
 
     if let Some(trait_def_id) = trait_ref.trait_def_id()
@@ -406,38 +407,37 @@ fn check_unsafe_derive_deserialize<'tcx>(
 
 struct UnsafeVisitor<'a, 'tcx> {
     cx: &'a LateContext<'tcx>,
-    has_unsafe: bool,
 }
 
 impl<'tcx> Visitor<'tcx> for UnsafeVisitor<'_, 'tcx> {
+    type Result = ControlFlow<()>;
     type NestedFilter = nested_filter::All;
 
-    fn visit_fn(&mut self, kind: FnKind<'tcx>, decl: &'tcx FnDecl<'_>, body_id: BodyId, _: Span, id: LocalDefId) {
-        if self.has_unsafe {
-            return;
-        }
-
+    fn visit_fn(
+        &mut self,
+        kind: FnKind<'tcx>,
+        decl: &'tcx FnDecl<'_>,
+        body_id: BodyId,
+        _: Span,
+        id: LocalDefId,
+    ) -> Self::Result {
         if let Some(header) = kind.header()
             && header.safety == Safety::Unsafe
         {
-            self.has_unsafe = true;
+            ControlFlow::Break(())
+        } else {
+            walk_fn(self, kind, decl, body_id, id)
         }
-
-        walk_fn(self, kind, decl, body_id, id);
     }
 
-    fn visit_expr(&mut self, expr: &'tcx Expr<'_>) {
-        if self.has_unsafe {
-            return;
-        }
-
+    fn visit_expr(&mut self, expr: &'tcx Expr<'_>) -> Self::Result {
         if let ExprKind::Block(block, _) = expr.kind {
             if block.rules == BlockCheckMode::UnsafeBlock(UnsafeSource::UserProvided) {
-                self.has_unsafe = true;
+                return ControlFlow::Break(());
             }
         }
 
-        walk_expr(self, expr);
+        walk_expr(self, expr)
     }
 
     fn nested_visit_map(&mut self) -> Self::Map {
diff --git a/clippy_lints/src/disallowed_macros.rs b/clippy_lints/src/disallowed_macros.rs
index b51d343132b..bdd49bf8aa7 100644
--- a/clippy_lints/src/disallowed_macros.rs
+++ b/clippy_lints/src/disallowed_macros.rs
@@ -2,7 +2,6 @@ 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;
 use rustc_data_structures::fx::FxHashSet;
 use rustc_errors::Diag;
 use rustc_hir::def_id::DefIdMap;
@@ -14,6 +13,8 @@ use rustc_middle::ty::TyCtxt;
 use rustc_session::impl_lint_pass;
 use rustc_span::{ExpnId, MacroKind, Span};
 
+use crate::utils::attr_collector::AttrStorage;
+
 declare_clippy_lint! {
     /// ### What it does
     /// Denies the configured macros in clippy.toml
@@ -64,14 +65,19 @@ pub struct DisallowedMacros {
     // Track the most recently seen node that can have a `derive` attribute.
     // Needed to use the correct lint level.
     derive_src: Option<OwnerId>,
+
+    // When a macro is disallowed in an early pass, it's stored
+    // and emitted during the late pass. This happens for attributes.
+    earlies: AttrStorage,
 }
 
 impl DisallowedMacros {
-    pub fn new(tcx: TyCtxt<'_>, conf: &'static Conf) -> Self {
+    pub fn new(tcx: TyCtxt<'_>, conf: &'static Conf, earlies: AttrStorage) -> Self {
         Self {
             disallowed: create_disallowed_map(tcx, &conf.disallowed_macros),
             seen: FxHashSet::default(),
             derive_src: None,
+            earlies,
         }
     }
 
@@ -114,6 +120,15 @@ impl DisallowedMacros {
 impl_lint_pass!(DisallowedMacros => [DISALLOWED_MACROS]);
 
 impl LateLintPass<'_> for DisallowedMacros {
+    fn check_crate(&mut self, cx: &LateContext<'_>) {
+        // once we check a crate in the late pass we can emit the early pass lints
+        if let Some(attr_spans) = self.earlies.clone().0.get() {
+            for span in attr_spans {
+                self.check(cx, *span, None);
+            }
+        }
+    }
+
     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
@@ -164,8 +179,4 @@ impl LateLintPass<'_> for DisallowedMacros {
     fn check_path(&mut self, cx: &LateContext<'_>, path: &Path<'_>, _: HirId) {
         self.check(cx, path.span, None);
     }
-
-    fn check_attribute(&mut self, cx: &LateContext<'_>, attr: &Attribute) {
-        self.check(cx, attr.span, self.derive_src);
-    }
 }
diff --git a/clippy_lints/src/disallowed_script_idents.rs b/clippy_lints/src/disallowed_script_idents.rs
index f79264e6b04..53c24a3faf1 100644
--- a/clippy_lints/src/disallowed_script_idents.rs
+++ b/clippy_lints/src/disallowed_script_idents.rs
@@ -80,7 +80,7 @@ impl EarlyLintPass for DisallowedScriptIdents {
         let mut symbols: Vec<_> = symbols.iter().collect();
         symbols.sort_unstable_by_key(|k| k.1);
 
-        for (symbol, &span) in &symbols {
+        for &(symbol, &span) in &symbols {
             // Note: `symbol.as_str()` is an expensive operation, thus should not be called
             // more than once for a single symbol.
             let symbol_str = symbol.as_str();
diff --git a/clippy_lints/src/doc/mod.rs b/clippy_lints/src/doc/mod.rs
index 89c6a4e08dc..df7c37a192a 100644
--- a/clippy_lints/src/doc/mod.rs
+++ b/clippy_lints/src/doc/mod.rs
@@ -427,11 +427,11 @@ declare_clippy_lint! {
 
 declare_clippy_lint! {
     /// ### What it does
-    /// Checks if the first line in the documentation of items listed in module page is too long.
+    /// Checks if the first paragraph in the documentation of items listed in the module page is too long.
     ///
     /// ### Why is this bad?
-    /// Documentation will show the first paragraph of the doscstring in the summary page of a
-    /// module, so having a nice, short summary in the first paragraph is part of writing good docs.
+    /// Documentation will show the first paragraph of the docstring in the summary page of a
+    /// module. Having a nice, short summary in the first paragraph is part of writing good docs.
     ///
     /// ### Example
     /// ```no_run
@@ -453,7 +453,7 @@ declare_clippy_lint! {
     #[clippy::version = "1.82.0"]
     pub TOO_LONG_FIRST_DOC_PARAGRAPH,
     nursery,
-    "ensure that the first line of a documentation paragraph isn't too long"
+    "ensure the first documentation paragraph is short"
 }
 
 declare_clippy_lint! {
diff --git a/clippy_lints/src/empty_drop.rs b/clippy_lints/src/empty_drop.rs
index b66dd2108fc..10a84b1b2ff 100644
--- a/clippy_lints/src/empty_drop.rs
+++ b/clippy_lints/src/empty_drop.rs
@@ -36,7 +36,7 @@ declare_lint_pass!(EmptyDrop => [EMPTY_DROP]);
 impl LateLintPass<'_> for EmptyDrop {
     fn check_item(&mut self, cx: &LateContext<'_>, item: &Item<'_>) {
         if let ItemKind::Impl(Impl {
-            of_trait: Some(ref trait_ref),
+            of_trait: Some(trait_ref),
             items: [child],
             ..
         }) = item.kind
diff --git a/clippy_lints/src/eta_reduction.rs b/clippy_lints/src/eta_reduction.rs
index 6ca599ed361..de10b7bf533 100644
--- a/clippy_lints/src/eta_reduction.rs
+++ b/clippy_lints/src/eta_reduction.rs
@@ -9,8 +9,7 @@ use rustc_hir::{BindingMode, Expr, ExprKind, FnRetTy, Param, PatKind, QPath, Saf
 use rustc_infer::infer::TyCtxtInferExt;
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::ty::{
-    self, Binder, ClosureKind, FnSig, GenericArg, GenericArgKind, List, Region, Ty, TypeVisitableExt,
-    TypeckResults,
+    self, Binder, ClosureKind, FnSig, GenericArg, GenericArgKind, List, Region, Ty, TypeVisitableExt, TypeckResults,
 };
 use rustc_session::declare_lint_pass;
 use rustc_span::symbol::sym;
@@ -204,11 +203,16 @@ fn check_clousure<'tcx>(cx: &LateContext<'tcx>, outer_receiver: Option<&Expr<'tc
                             // 'cuz currently nothing changes after deleting this check.
                             local_used_in(cx, l, args) || local_used_after_expr(cx, l, expr)
                         }) {
-                            match cx.tcx.infer_ctxt().build(cx.typing_mode()).err_ctxt().type_implements_fn_trait(
-                                cx.param_env,
-                                Binder::bind_with_vars(callee_ty_adjusted, List::empty()),
-                                ty::PredicatePolarity::Positive,
-                            ) {
+                            match cx
+                                .tcx
+                                .infer_ctxt()
+                                .build(cx.typing_mode())
+                                .err_ctxt()
+                                .type_implements_fn_trait(
+                                    cx.param_env,
+                                    Binder::bind_with_vars(callee_ty_adjusted, List::empty()),
+                                    ty::PredicatePolarity::Positive,
+                                ) {
                                 // Mutable closure is used after current expr; we cannot consume it.
                                 Ok((ClosureKind::FnMut, _)) => snippet = format!("&mut {snippet}"),
                                 Ok((ClosureKind::Fn, _)) if !callee_ty_raw.is_ref() => {
diff --git a/clippy_lints/src/explicit_write.rs b/clippy_lints/src/explicit_write.rs
index 4e4434ec7d1..0550c22761a 100644
--- a/clippy_lints/src/explicit_write.rs
+++ b/clippy_lints/src/explicit_write.rs
@@ -58,7 +58,7 @@ impl<'tcx> LateLintPass<'tcx> for ExplicitWrite {
             // match call to write_fmt
             && let ExprKind::MethodCall(write_fun, write_recv, [write_arg], _) = *look_in_block(cx, &write_call.kind)
             && let ExprKind::Call(write_recv_path, []) = write_recv.kind
-            && write_fun.ident.name == sym!(write_fmt)
+            && write_fun.ident.name.as_str() == "write_fmt"
             && let Some(def_id) = path_def_id(cx, write_recv_path)
         {
             // match calls to std::io::stdout() / std::io::stderr ()
diff --git a/clippy_lints/src/from_over_into.rs b/clippy_lints/src/from_over_into.rs
index d5a2e06863d..14da0b515a5 100644
--- a/clippy_lints/src/from_over_into.rs
+++ b/clippy_lints/src/from_over_into.rs
@@ -1,3 +1,5 @@
+use std::ops::ControlFlow;
+
 use clippy_config::Conf;
 use clippy_config::msrvs::{self, Msrv};
 use clippy_utils::diagnostics::span_lint_and_then;
@@ -115,25 +117,26 @@ impl<'tcx> LateLintPass<'tcx> for FromOverInto {
 }
 
 /// Finds the occurrences of `Self` and `self`
+///
+/// Returns `ControlFlow::break` if any of the `self`/`Self` usages were from an expansion, or the
+/// body contained a binding already named `val`.
 struct SelfFinder<'a, 'tcx> {
     cx: &'a LateContext<'tcx>,
     /// Occurrences of `Self`
     upper: Vec<Span>,
     /// Occurrences of `self`
     lower: Vec<Span>,
-    /// If any of the `self`/`Self` usages were from an expansion, or the body contained a binding
-    /// already named `val`
-    invalid: bool,
 }
 
 impl<'tcx> Visitor<'tcx> for SelfFinder<'_, 'tcx> {
+    type Result = ControlFlow<()>;
     type NestedFilter = OnlyBodies;
 
     fn nested_visit_map(&mut self) -> Self::Map {
         self.cx.tcx.hir()
     }
 
-    fn visit_path(&mut self, path: &Path<'tcx>, _id: HirId) {
+    fn visit_path(&mut self, path: &Path<'tcx>, _id: HirId) -> Self::Result {
         for segment in path.segments {
             match segment.ident.name {
                 kw::SelfLower => self.lower.push(segment.ident.span),
@@ -141,17 +144,19 @@ impl<'tcx> Visitor<'tcx> for SelfFinder<'_, 'tcx> {
                 _ => continue,
             }
 
-            self.invalid |= segment.ident.span.from_expansion();
+            if segment.ident.span.from_expansion() {
+                return ControlFlow::Break(());
+            }
         }
 
-        if !self.invalid {
-            walk_path(self, path);
-        }
+        walk_path(self, path)
     }
 
-    fn visit_name(&mut self, name: Symbol) {
+    fn visit_name(&mut self, name: Symbol) -> Self::Result {
         if name == sym::val {
-            self.invalid = true;
+            ControlFlow::Break(())
+        } else {
+            ControlFlow::Continue(())
         }
     }
 }
@@ -209,11 +214,9 @@ fn convert_to_from(
         cx,
         upper: Vec::new(),
         lower: Vec::new(),
-        invalid: false,
     };
-    finder.visit_expr(body.value);
 
-    if finder.invalid {
+    if finder.visit_expr(body.value).is_break() {
         return None;
     }
 
diff --git a/clippy_lints/src/from_raw_with_void_ptr.rs b/clippy_lints/src/from_raw_with_void_ptr.rs
index d62d008d480..c8828c93615 100644
--- a/clippy_lints/src/from_raw_with_void_ptr.rs
+++ b/clippy_lints/src/from_raw_with_void_ptr.rs
@@ -41,7 +41,7 @@ impl LateLintPass<'_> for FromRawWithVoidPtr {
     fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) {
         if let ExprKind::Call(box_from_raw, [arg]) = expr.kind
             && let ExprKind::Path(QPath::TypeRelative(ty, seg)) = box_from_raw.kind
-            && seg.ident.name == sym!(from_raw)
+            && seg.ident.name.as_str() == "from_raw"
             && let Some(type_str) = path_def_id(cx, ty).and_then(|id| def_id_matches_type(cx, id))
             && let arg_kind = cx.typeck_results().expr_ty(arg).kind()
             && let ty::RawPtr(ty, _) = arg_kind
diff --git a/clippy_lints/src/functions/mod.rs b/clippy_lints/src/functions/mod.rs
index 91d73c2a9c9..be3d0f7ad63 100644
--- a/clippy_lints/src/functions/mod.rs
+++ b/clippy_lints/src/functions/mod.rs
@@ -441,7 +441,7 @@ declare_clippy_lint! {
     /// fn bar(&self) -> Option<&String> { None }
     /// # }
     /// ```
-    #[clippy::version = "1.82.0"]
+    #[clippy::version = "1.83.0"]
     pub REF_OPTION,
     pedantic,
     "function signature uses `&Option<T>` instead of `Option<&T>`"
diff --git a/clippy_lints/src/functions/ref_option.rs b/clippy_lints/src/functions/ref_option.rs
index 373ecd74cb3..aba0fbcb9fe 100644
--- a/clippy_lints/src/functions/ref_option.rs
+++ b/clippy_lints/src/functions/ref_option.rs
@@ -15,9 +15,9 @@ use rustc_span::{Span, sym};
 fn check_ty<'a>(cx: &LateContext<'a>, param: &rustc_hir::Ty<'a>, param_ty: Ty<'a>, fixes: &mut Vec<(Span, String)>) {
     if let ty::Ref(_, opt_ty, Mutability::Not) = param_ty.kind()
         && is_type_diagnostic_item(cx, *opt_ty, sym::Option)
-        && let ty::Adt(_, opt_gen) = opt_ty.kind()
-        && let [gen] = opt_gen.as_slice()
-        && let GenericArgKind::Type(gen_ty) = gen.unpack()
+        && let ty::Adt(_, opt_gen_args) = opt_ty.kind()
+        && let [gen_arg] = opt_gen_args.as_slice()
+        && let GenericArgKind::Type(gen_ty) = gen_arg.unpack()
         && !gen_ty.is_ref()
         // Need to gen the original spans, so first parsing mid, and hir parsing afterward
         && let hir::TyKind::Ref(lifetime, hir::MutTy { ty, .. }) = param.kind
diff --git a/clippy_lints/src/implicit_hasher.rs b/clippy_lints/src/implicit_hasher.rs
index 4c5375730b8..c370f206c8f 100644
--- a/clippy_lints/src/implicit_hasher.rs
+++ b/clippy_lints/src/implicit_hasher.rs
@@ -340,7 +340,7 @@ impl<'tcx> Visitor<'tcx> for ImplicitHasherConstructorVisitor<'_, '_, 'tcx> {
             if self.cx.tcx.is_diagnostic_item(sym::HashMap, ty_did) {
                 if method.ident.name == sym::new {
                     self.suggestions.insert(e.span, "HashMap::default()".to_string());
-                } else if method.ident.name == sym!(with_capacity) {
+                } else if method.ident.name.as_str() == "with_capacity" {
                     self.suggestions.insert(
                         e.span,
                         format!(
@@ -352,7 +352,7 @@ impl<'tcx> Visitor<'tcx> for ImplicitHasherConstructorVisitor<'_, '_, 'tcx> {
             } else if self.cx.tcx.is_diagnostic_item(sym::HashSet, ty_did) {
                 if method.ident.name == sym::new {
                     self.suggestions.insert(e.span, "HashSet::default()".to_string());
-                } else if method.ident.name == sym!(with_capacity) {
+                } else if method.ident.name.as_str() == "with_capacity" {
                     self.suggestions.insert(
                         e.span,
                         format!(
diff --git a/clippy_lints/src/infinite_iter.rs b/clippy_lints/src/infinite_iter.rs
index 71c317552ee..48874d6064b 100644
--- a/clippy_lints/src/infinite_iter.rs
+++ b/clippy_lints/src/infinite_iter.rs
@@ -157,7 +157,7 @@ fn is_infinite(cx: &LateContext<'_>, expr: &Expr<'_>) -> Finiteness {
                     .and(cap);
                 }
             }
-            if method.ident.name == sym!(flat_map) && args.len() == 1 {
+            if method.ident.name.as_str() == "flat_map" && args.len() == 1 {
                 if let ExprKind::Closure(&Closure { body, .. }) = args[0].kind {
                     let body = cx.tcx.hir().body(body);
                     return is_infinite(cx, body.value);
@@ -224,7 +224,7 @@ fn complete_infinite_iter(cx: &LateContext<'_>, expr: &Expr<'_>) -> Finiteness {
                     return MaybeInfinite.and(is_infinite(cx, receiver));
                 }
             }
-            if method.ident.name == sym!(last) && args.is_empty() {
+            if method.ident.name.as_str() == "last" && args.is_empty() {
                 let not_double_ended = cx
                     .tcx
                     .get_diagnostic_item(sym::DoubleEndedIterator)
@@ -234,7 +234,7 @@ fn complete_infinite_iter(cx: &LateContext<'_>, expr: &Expr<'_>) -> Finiteness {
                 if not_double_ended {
                     return is_infinite(cx, receiver);
                 }
-            } else if method.ident.name == sym!(collect) {
+            } else if method.ident.name.as_str() == "collect" {
                 let ty = cx.typeck_results().expr_ty(expr);
                 if matches!(
                     get_type_diagnostic_name(cx, ty),
diff --git a/clippy_lints/src/iter_without_into_iter.rs b/clippy_lints/src/iter_without_into_iter.rs
index 1e6404190d3..314d0dfa26c 100644
--- a/clippy_lints/src/iter_without_into_iter.rs
+++ b/clippy_lints/src/iter_without_into_iter.rs
@@ -142,7 +142,7 @@ impl LateLintPass<'_> for IterWithoutIntoIter {
                 ty.peel_refs().is_slice() || get_adt_inherent_method(cx, ty, expected_method_name).is_some()
             })
             && let Some(iter_assoc_span) = imp.items.iter().find_map(|item| {
-                if item.ident.name == sym!(IntoIter) {
+                if item.ident.name.as_str() == "IntoIter" {
                     Some(cx.tcx.hir().impl_item(item.id).expect_type().span)
                 } else {
                     None
@@ -247,8 +247,8 @@ impl {self_ty_without_ref} {{
                     let sugg = format!(
                         "
 impl IntoIterator for {self_ty_snippet} {{
-    type IntoIter = {ret_ty};
     type Item = {iter_ty};
+    type IntoIter = {ret_ty};
     fn into_iter(self) -> Self::IntoIter {{
         self.iter()
     }}
diff --git a/clippy_lints/src/large_const_arrays.rs b/clippy_lints/src/large_const_arrays.rs
index 5d2b521b250..aa8b4d88d2f 100644
--- a/clippy_lints/src/large_const_arrays.rs
+++ b/clippy_lints/src/large_const_arrays.rs
@@ -4,7 +4,7 @@ use rustc_errors::Applicability;
 use rustc_hir::{Item, ItemKind};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::ty::layout::LayoutOf;
-use rustc_middle::ty::{self, ConstKind};
+use rustc_middle::ty::{self, ParamEnv};
 use rustc_session::impl_lint_pass;
 use rustc_span::{BytePos, Pos, Span};
 
@@ -56,7 +56,7 @@ impl<'tcx> LateLintPass<'tcx> for LargeConstArrays {
             && !item.span.from_expansion()
             && let ty = cx.tcx.type_of(item.owner_id).instantiate_identity()
             && let ty::Array(element_type, cst) = ty.kind()
-            && let ConstKind::Value(_, ty::ValTree::Leaf(element_count)) = cst.kind()
+            && let Ok((_, ty::ValTree::Leaf(element_count))) = cst.eval_valtree(cx.tcx, ParamEnv::empty(), item.span)
             && let element_count = element_count.to_target_usize(cx.tcx)
             && let Ok(element_size) = cx.layout_of(*element_type).map(|l| l.size.bytes())
             && u128::from(self.maximum_allowed_size) < u128::from(element_count) * u128::from(element_size)
diff --git a/clippy_lints/src/large_include_file.rs b/clippy_lints/src/large_include_file.rs
index f2f841dcec3..ab3d19f89c3 100644
--- a/clippy_lints/src/large_include_file.rs
+++ b/clippy_lints/src/large_include_file.rs
@@ -1,11 +1,12 @@
 use clippy_config::Conf;
 use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::macros::root_macro_call_first_node;
-use rustc_ast::LitKind;
+use clippy_utils::source::snippet_opt;
+use rustc_ast::{AttrArgs, AttrArgsEq, AttrKind, Attribute, LitKind};
 use rustc_hir::{Expr, ExprKind};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_session::impl_lint_pass;
-use rustc_span::sym;
+use rustc_span::{Span, sym};
 
 declare_clippy_lint! {
     /// ### What it does
@@ -51,6 +52,24 @@ impl LargeIncludeFile {
 
 impl_lint_pass!(LargeIncludeFile => [LARGE_INCLUDE_FILE]);
 
+impl LargeIncludeFile {
+    fn emit_lint(&self, cx: &LateContext<'_>, span: Span) {
+        #[expect(clippy::collapsible_span_lint_calls, reason = "rust-clippy#7797")]
+        span_lint_and_then(
+            cx,
+            LARGE_INCLUDE_FILE,
+            span,
+            "attempted to include a large file",
+            |diag| {
+                diag.note(format!(
+                    "the configuration allows a maximum size of {} bytes",
+                    self.max_file_size
+                ));
+            },
+        );
+    }
+}
+
 impl LateLintPass<'_> for LargeIncludeFile {
     fn check_expr(&mut self, cx: &LateContext<'_>, expr: &'_ Expr<'_>) {
         if let ExprKind::Lit(lit) = &expr.kind
@@ -66,19 +85,33 @@ impl LateLintPass<'_> for LargeIncludeFile {
             && (cx.tcx.is_diagnostic_item(sym::include_bytes_macro, macro_call.def_id)
                 || cx.tcx.is_diagnostic_item(sym::include_str_macro, macro_call.def_id))
         {
-            #[expect(clippy::collapsible_span_lint_calls, reason = "rust-clippy#7797")]
-            span_lint_and_then(
-                cx,
-                LARGE_INCLUDE_FILE,
-                expr.span.source_callsite(),
-                "attempted to include a large file",
-                |diag| {
-                    diag.note(format!(
-                        "the configuration allows a maximum size of {} bytes",
-                        self.max_file_size
-                    ));
-                },
-            );
+            self.emit_lint(cx, expr.span.source_callsite());
+        }
+    }
+
+    fn check_attribute(&mut self, cx: &LateContext<'_>, attr: &Attribute) {
+        if !attr.span.from_expansion()
+            // Currently, rustc limits the usage of macro at the top-level of attributes,
+            // so we don't need to recurse into each level.
+            && let AttrKind::Normal(ref normal) = attr.kind
+            && let AttrArgs::Eq(_, AttrArgsEq::Hir(ref meta)) = normal.item.args
+            && !attr.span.contains(meta.span)
+            // Since the `include_str` is already expanded at this point, we can only take the
+            // whole attribute snippet and then modify for our suggestion.
+            && let Some(snippet) = snippet_opt(cx, attr.span)
+            // We cannot remove this because a `#[doc = include_str!("...")]` attribute can
+            // occupy several lines.
+            && let Some(start) = snippet.find('[')
+            && let Some(end) = snippet.rfind(']')
+            && let snippet = &snippet[start + 1..end]
+            // We check that the expansion actually comes from `include_str!` and not just from
+            // another macro.
+            && let Some(sub_snippet) = snippet.trim().strip_prefix("doc")
+            && let Some(sub_snippet) = sub_snippet.trim().strip_prefix("=")
+            && let sub_snippet = sub_snippet.trim()
+            && (sub_snippet.starts_with("include_str!") || sub_snippet.starts_with("include_bytes!"))
+        {
+            self.emit_lint(cx, attr.span);
         }
     }
 }
diff --git a/clippy_lints/src/len_zero.rs b/clippy_lints/src/len_zero.rs
index 47c65ee6d0b..b7887ef76a5 100644
--- a/clippy_lints/src/len_zero.rs
+++ b/clippy_lints/src/len_zero.rs
@@ -629,7 +629,7 @@ fn has_is_empty(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
                 .filter_by_name_unhygienic(is_empty)
                 .any(|item| is_is_empty(cx, item))
         }),
-        ty::Alias(ty::Projection, ref proj) => has_is_empty_impl(cx, proj.def_id),
+        ty::Alias(ty::Projection, proj) => has_is_empty_impl(cx, proj.def_id),
         ty::Adt(id, _) => has_is_empty_impl(cx, id.did()),
         ty::Array(..) | ty::Slice(..) | ty::Str => true,
         _ => false,
diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs
index 3fd07ced0e4..c9064df25ac 100644
--- a/clippy_lints/src/lib.rs
+++ b/clippy_lints/src/lib.rs
@@ -73,6 +73,7 @@ pub mod deprecated_lints;
 mod absolute_paths;
 mod almost_complete_range;
 mod approx_const;
+mod arbitrary_source_item_ordering;
 mod arc_with_non_send_sync;
 mod as_conversions;
 mod asm_syntax;
@@ -400,6 +401,7 @@ use clippy_config::{Conf, get_configuration_metadata, sanitize_explanation};
 use clippy_utils::macros::FormatArgsStorage;
 use rustc_data_structures::fx::FxHashSet;
 use rustc_lint::{Lint, LintId};
+use utils::attr_collector::{AttrCollector, AttrStorage};
 
 /// Register all pre expansion lints
 ///
@@ -464,6 +466,7 @@ pub(crate) enum LintCategory {
     #[cfg(feature = "internal")]
     Internal,
 }
+
 #[allow(clippy::enum_glob_use)]
 use LintCategory::*;
 
@@ -585,6 +588,10 @@ pub fn register_lints(store: &mut rustc_lint::LintStore, conf: &'static Conf) {
         ))
     });
 
+    let attr_storage = AttrStorage::default();
+    let attrs = attr_storage.clone();
+    store.register_early_pass(move || Box::new(AttrCollector::new(attrs.clone())));
+
     // all the internal lints
     #[cfg(feature = "internal")]
     {
@@ -606,6 +613,7 @@ pub fn register_lints(store: &mut rustc_lint::LintStore, conf: &'static Conf) {
         store.register_late_pass(|_| {
             Box::new(utils::internal_lints::almost_standard_lint_formulation::AlmostStandardFormulation::new())
         });
+        store.register_late_pass(|_| Box::new(utils::internal_lints::slow_symbol_comparisons::SlowSymbolComparisons));
     }
 
     store.register_late_pass(|_| Box::new(ctfe::ClippyCtfe));
@@ -795,7 +803,8 @@ pub fn register_lints(store: &mut rustc_lint::LintStore, conf: &'static Conf) {
     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 |tcx| Box::new(disallowed_macros::DisallowedMacros::new(tcx, conf)));
+    let attrs = attr_storage.clone();
+    store.register_late_pass(move |tcx| Box::new(disallowed_macros::DisallowedMacros::new(tcx, conf, attrs.clone())));
     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));
@@ -953,5 +962,6 @@ pub fn register_lints(store: &mut rustc_lint::LintStore, conf: &'static Conf) {
     store.register_late_pass(move |_| Box::new(unused_trait_names::UnusedTraitNames::new(conf)));
     store.register_late_pass(|_| Box::new(manual_ignore_case_cmp::ManualIgnoreCaseCmp));
     store.register_late_pass(|_| Box::new(unnecessary_literal_bound::UnnecessaryLiteralBound));
+    store.register_late_pass(move |_| Box::new(arbitrary_source_item_ordering::ArbitrarySourceItemOrdering::new(conf)));
     // add lints here, do not remove this comment, it's used in `new_lint`
 }
diff --git a/clippy_lints/src/loops/explicit_iter_loop.rs b/clippy_lints/src/loops/explicit_iter_loop.rs
index 119e410b91c..ee561ea85ed 100644
--- a/clippy_lints/src/loops/explicit_iter_loop.rs
+++ b/clippy_lints/src/loops/explicit_iter_loop.rs
@@ -29,11 +29,7 @@ pub(super) fn check(
             if !msrv.meets(msrvs::ARRAY_INTO_ITERATOR) {
                 return;
             }
-        } else if count
-            .try_to_target_usize(cx.tcx)
-            .map_or(true, |x| x > 32)
-            && !msrv.meets(msrvs::ARRAY_IMPL_ANY_LEN)
-        {
+        } else if count.try_to_target_usize(cx.tcx).map_or(true, |x| x > 32) && !msrv.meets(msrvs::ARRAY_IMPL_ANY_LEN) {
             return;
         }
     }
diff --git a/clippy_lints/src/loops/infinite_loop.rs b/clippy_lints/src/loops/infinite_loop.rs
index e25c03db534..9f543b79bac 100644
--- a/clippy_lints/src/loops/infinite_loop.rs
+++ b/clippy_lints/src/loops/infinite_loop.rs
@@ -1,12 +1,13 @@
 use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::{fn_def_id, is_from_proc_macro, is_lint_allowed};
 use hir::intravisit::{Visitor, walk_expr};
-use hir::{Expr, ExprKind, FnRetTy, FnSig, Node};
+use hir::{Expr, ExprKind, FnRetTy, FnSig, Node, TyKind};
 use rustc_ast::Label;
 use rustc_errors::Applicability;
 use rustc_hir as hir;
 use rustc_lint::{LateContext, LintContext};
 use rustc_middle::lint::in_external_macro;
+use rustc_span::sym;
 
 use super::INFINITE_LOOP;
 
@@ -25,13 +26,7 @@ pub(super) fn check<'tcx>(
         return;
     };
     // Or, its parent function is already returning `Never`
-    if matches!(
-        parent_fn_ret,
-        FnRetTy::Return(hir::Ty {
-            kind: hir::TyKind::Never,
-            ..
-        })
-    ) {
+    if is_never_return(parent_fn_ret) {
         return;
     }
 
@@ -69,6 +64,16 @@ pub(super) fn check<'tcx>(
 fn get_parent_fn_ret_ty<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'_>) -> Option<FnRetTy<'tcx>> {
     for (_, parent_node) in cx.tcx.hir().parent_iter(expr.hir_id) {
         match parent_node {
+            // Skip `Coroutine` closures, these are the body of `async fn`, not async closures.
+            // This is because we still need to backtrack one parent node to get the `OpaqueDef` ty.
+            Node::Expr(Expr {
+                kind:
+                    ExprKind::Closure(hir::Closure {
+                        kind: hir::ClosureKind::Coroutine(_),
+                        ..
+                    }),
+                ..
+            }) => (),
             Node::Item(hir::Item {
                 kind: hir::ItemKind::Fn(FnSig { decl, .. }, _, _),
                 ..
@@ -143,3 +148,41 @@ impl<'hir> Visitor<'hir> for LoopVisitor<'hir, '_> {
         }
     }
 }
+
+/// Return `true` if the given [`FnRetTy`] is never (!).
+///
+/// Note: This function also take care of return type of async fn,
+/// as the actual type is behind an [`OpaqueDef`](TyKind::OpaqueDef).
+fn is_never_return(ret_ty: FnRetTy<'_>) -> bool {
+    let FnRetTy::Return(hir_ty) = ret_ty else { return false };
+
+    match hir_ty.kind {
+        TyKind::Never => true,
+        TyKind::OpaqueDef(hir::OpaqueTy {
+            origin: hir::OpaqueTyOrigin::AsyncFn { .. },
+            bounds,
+            ..
+        }) => {
+            if let Some(trait_ref) = bounds.iter().find_map(|b| b.trait_ref())
+                && let Some(segment) = trait_ref
+                    .path
+                    .segments
+                    .iter()
+                    .find(|seg| seg.ident.name == sym::future_trait)
+                && let Some(args) = segment.args
+                && let Some(cst_kind) = args
+                    .constraints
+                    .iter()
+                    .find_map(|cst| (cst.ident.name == sym::Output).then_some(cst.kind))
+                && let hir::AssocItemConstraintKind::Equality {
+                    term: hir::Term::Ty(ty),
+                } = cst_kind
+            {
+                matches!(ty.kind, TyKind::Never)
+            } else {
+                false
+            }
+        },
+        _ => false,
+    }
+}
diff --git a/clippy_lints/src/loops/while_immutable_condition.rs b/clippy_lints/src/loops/while_immutable_condition.rs
index 1a1cde3c5bd..7da4fa76e2c 100644
--- a/clippy_lints/src/loops/while_immutable_condition.rs
+++ b/clippy_lints/src/loops/while_immutable_condition.rs
@@ -19,10 +19,8 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, cond: &'tcx Expr<'_>, expr: &'
         cx,
         ids: HirIdSet::default(),
         def_ids: DefIdMap::default(),
-        skip: false,
     };
-    var_visitor.visit_expr(cond);
-    if var_visitor.skip {
+    if var_visitor.visit_expr(cond).is_break() {
         return;
     }
     let used_in_condition = &var_visitor.ids;
@@ -81,7 +79,6 @@ struct VarCollectorVisitor<'a, 'tcx> {
     cx: &'a LateContext<'tcx>,
     ids: HirIdSet,
     def_ids: DefIdMap<bool>,
-    skip: bool,
 }
 
 impl<'tcx> VarCollectorVisitor<'_, 'tcx> {
@@ -104,11 +101,15 @@ impl<'tcx> VarCollectorVisitor<'_, 'tcx> {
 }
 
 impl<'tcx> Visitor<'tcx> for VarCollectorVisitor<'_, 'tcx> {
-    fn visit_expr(&mut self, ex: &'tcx Expr<'_>) {
+    type Result = ControlFlow<()>;
+    fn visit_expr(&mut self, ex: &'tcx Expr<'_>) -> Self::Result {
         match ex.kind {
-            ExprKind::Path(_) => self.insert_def_id(ex),
+            ExprKind::Path(_) => {
+                self.insert_def_id(ex);
+                ControlFlow::Continue(())
+            },
             // If there is any function/method call… we just stop analysis
-            ExprKind::Call(..) | ExprKind::MethodCall(..) => self.skip = true,
+            ExprKind::Call(..) | ExprKind::MethodCall(..) => ControlFlow::Break(()),
 
             _ => walk_expr(self, ex),
         }
diff --git a/clippy_lints/src/loops/while_let_on_iterator.rs b/clippy_lints/src/loops/while_let_on_iterator.rs
index 74467522619..b7e37c1a876 100644
--- a/clippy_lints/src/loops/while_let_on_iterator.rs
+++ b/clippy_lints/src/loops/while_let_on_iterator.rs
@@ -1,3 +1,5 @@
+use std::ops::ControlFlow;
+
 use super::WHILE_LET_ON_ITERATOR;
 use clippy_utils::diagnostics::span_lint_and_sugg;
 use clippy_utils::source::snippet_with_applicability;
@@ -204,35 +206,32 @@ fn uses_iter<'tcx>(cx: &LateContext<'tcx>, iter_expr: &IterExpr, container: &'tc
     struct V<'a, 'b, 'tcx> {
         cx: &'a LateContext<'tcx>,
         iter_expr: &'b IterExpr,
-        uses_iter: bool,
     }
     impl<'tcx> Visitor<'tcx> for V<'_, '_, 'tcx> {
-        fn visit_expr(&mut self, e: &'tcx Expr<'_>) {
-            if self.uses_iter {
-                // return
-            } else if is_expr_same_child_or_parent_field(self.cx, e, &self.iter_expr.fields, self.iter_expr.path) {
-                self.uses_iter = true;
+        type Result = ControlFlow<()>;
+        fn visit_expr(&mut self, e: &'tcx Expr<'_>) -> Self::Result {
+            if is_expr_same_child_or_parent_field(self.cx, e, &self.iter_expr.fields, self.iter_expr.path) {
+                ControlFlow::Break(())
             } else if let (e, true) = skip_fields_and_path(e) {
                 if let Some(e) = e {
-                    self.visit_expr(e);
+                    self.visit_expr(e)
+                } else {
+                    ControlFlow::Continue(())
                 }
             } else if let ExprKind::Closure(&Closure { body: id, .. }) = e.kind {
                 if is_res_used(self.cx, self.iter_expr.path, id) {
-                    self.uses_iter = true;
+                    ControlFlow::Break(())
+                } else {
+                    ControlFlow::Continue(())
                 }
             } else {
-                walk_expr(self, e);
+                walk_expr(self, e)
             }
         }
     }
 
-    let mut v = V {
-        cx,
-        iter_expr,
-        uses_iter: false,
-    };
-    v.visit_expr(container);
-    v.uses_iter
+    let mut v = V { cx, iter_expr };
+    v.visit_expr(container).is_break()
 }
 
 #[expect(clippy::too_many_lines)]
@@ -242,34 +241,38 @@ fn needs_mutable_borrow(cx: &LateContext<'_>, iter_expr: &IterExpr, loop_expr: &
         iter_expr: &'b IterExpr,
         loop_id: HirId,
         after_loop: bool,
-        used_iter: bool,
     }
     impl<'tcx> Visitor<'tcx> for AfterLoopVisitor<'_, '_, 'tcx> {
         type NestedFilter = OnlyBodies;
+        type Result = ControlFlow<()>;
         fn nested_visit_map(&mut self) -> Self::Map {
             self.cx.tcx.hir()
         }
 
-        fn visit_expr(&mut self, e: &'tcx Expr<'_>) {
-            if self.used_iter {
-                return;
-            }
+        fn visit_expr(&mut self, e: &'tcx Expr<'_>) -> Self::Result {
             if self.after_loop {
                 if is_expr_same_child_or_parent_field(self.cx, e, &self.iter_expr.fields, self.iter_expr.path) {
-                    self.used_iter = true;
+                    ControlFlow::Break(())
                 } else if let (e, true) = skip_fields_and_path(e) {
                     if let Some(e) = e {
-                        self.visit_expr(e);
+                        self.visit_expr(e)
+                    } else {
+                        ControlFlow::Continue(())
                     }
                 } else if let ExprKind::Closure(&Closure { body: id, .. }) = e.kind {
-                    self.used_iter = is_res_used(self.cx, self.iter_expr.path, id);
+                    if is_res_used(self.cx, self.iter_expr.path, id) {
+                        ControlFlow::Break(())
+                    } else {
+                        ControlFlow::Continue(())
+                    }
                 } else {
-                    walk_expr(self, e);
+                    walk_expr(self, e)
                 }
             } else if self.loop_id == e.hir_id {
                 self.after_loop = true;
+                ControlFlow::Continue(())
             } else {
-                walk_expr(self, e);
+                walk_expr(self, e)
             }
         }
     }
@@ -347,9 +350,8 @@ fn needs_mutable_borrow(cx: &LateContext<'_>, iter_expr: &IterExpr, loop_expr: &
             iter_expr,
             loop_id: loop_expr.hir_id,
             after_loop: false,
-            used_iter: false,
         };
-        v.visit_expr(cx.tcx.hir().body(cx.enclosing_body.unwrap()).value);
-        v.used_iter
+        v.visit_expr(cx.tcx.hir().body(cx.enclosing_body.unwrap()).value)
+            .is_break()
     }
 }
diff --git a/clippy_lints/src/manual_async_fn.rs b/clippy_lints/src/manual_async_fn.rs
index c904137da1a..3c77db84a40 100644
--- a/clippy_lints/src/manual_async_fn.rs
+++ b/clippy_lints/src/manual_async_fn.rs
@@ -106,13 +106,12 @@ impl<'tcx> LateLintPass<'tcx> for ManualAsyncFn {
 
 fn future_trait_ref<'tcx>(cx: &LateContext<'tcx>, opaque: &'tcx OpaqueTy<'tcx>) -> Option<&'tcx TraitRef<'tcx>> {
     if let Some(trait_ref) = opaque.bounds.iter().find_map(|bound| {
-            if let GenericBound::Trait(poly) = bound {
-                Some(&poly.trait_ref)
-            } else {
-                None
-            }
-        })
-        && trait_ref.trait_def_id() == cx.tcx.lang_items().future_trait()
+        if let GenericBound::Trait(poly) = bound {
+            Some(&poly.trait_ref)
+        } else {
+            None
+        }
+    }) && trait_ref.trait_def_id() == cx.tcx.lang_items().future_trait()
     {
         return Some(trait_ref);
     }
@@ -156,16 +155,18 @@ fn captures_all_lifetimes(cx: &LateContext<'_>, fn_def_id: LocalDefId, opaque_de
         .tcx
         .opaque_captured_lifetimes(opaque_def_id)
         .iter()
-        .filter(|&(lifetime, _)| match *lifetime {
-            ResolvedArg::EarlyBound(_) | ResolvedArg::LateBound(ty::INNERMOST, _, _) => true,
-            _ => false,
+        .filter(|&(lifetime, _)| {
+            matches!(
+                *lifetime,
+                ResolvedArg::EarlyBound(_) | ResolvedArg::LateBound(ty::INNERMOST, _, _)
+            )
         })
         .count();
     num_captured_lifetimes == num_early_lifetimes + num_late_lifetimes
 }
 
 fn desugared_async_block<'tcx>(cx: &LateContext<'tcx>, block: &'tcx Block<'tcx>) -> Option<&'tcx Body<'tcx>> {
-    if let Some(Expr {
+    if let Some(&Expr {
         kind: ExprKind::Closure(&Closure { kind, body, .. }),
         ..
     }) = block.expr
diff --git a/clippy_lints/src/manual_bits.rs b/clippy_lints/src/manual_bits.rs
index 1bd8813e348..fd71167f814 100644
--- a/clippy_lints/src/manual_bits.rs
+++ b/clippy_lints/src/manual_bits.rs
@@ -7,8 +7,7 @@ use rustc_ast::ast::LitKind;
 use rustc_data_structures::packed::Pu128;
 use rustc_errors::Applicability;
 use rustc_hir::{BinOpKind, Expr, ExprKind, GenericArg, QPath};
-use rustc_lint::{LateContext, LateLintPass, LintContext};
-use rustc_middle::lint::in_external_macro;
+use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::ty::{self, Ty};
 use rustc_session::impl_lint_pass;
 use rustc_span::sym;
@@ -53,7 +52,7 @@ impl<'tcx> LateLintPass<'tcx> for ManualBits {
     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
         if let ExprKind::Binary(bin_op, left_expr, right_expr) = expr.kind
             && let BinOpKind::Mul = &bin_op.node
-            && !in_external_macro(cx.sess(), expr.span)
+            && !expr.span.from_expansion()
             && self.msrv.meets(msrvs::MANUAL_BITS)
             && let ctxt = expr.span.ctxt()
             && left_expr.span.ctxt() == ctxt
diff --git a/clippy_lints/src/manual_hash_one.rs b/clippy_lints/src/manual_hash_one.rs
index c62bd65bea6..7a9c9963742 100644
--- a/clippy_lints/src/manual_hash_one.rs
+++ b/clippy_lints/src/manual_hash_one.rs
@@ -68,7 +68,7 @@ impl LateLintPass<'_> for ManualHashOne {
             && let Some(init) = local.init
             && !init.span.from_expansion()
             && let ExprKind::MethodCall(seg, build_hasher, [], _) = init.kind
-            && seg.ident.name == sym!(build_hasher)
+            && seg.ident.name.as_str() == "build_hasher"
 
             && let Node::Stmt(local_stmt) = cx.tcx.parent_hir_node(local.hir_id)
             && let Node::Block(block) = cx.tcx.parent_hir_node(local_stmt.hir_id)
@@ -96,7 +96,7 @@ impl LateLintPass<'_> for ManualHashOne {
             && let Node::Expr(finish_expr) = cx.tcx.parent_hir_node(path_expr.hir_id)
             && !finish_expr.span.from_expansion()
             && let ExprKind::MethodCall(seg, _, [], _) = finish_expr.kind
-            && seg.ident.name == sym!(finish)
+            && seg.ident.name.as_str() == "finish"
 
             && self.msrv.meets(msrvs::BUILD_HASHER_HASH_ONE)
         {
diff --git a/clippy_lints/src/manual_is_ascii_check.rs b/clippy_lints/src/manual_is_ascii_check.rs
index 24207705743..dec8c5d85de 100644
--- a/clippy_lints/src/manual_is_ascii_check.rs
+++ b/clippy_lints/src/manual_is_ascii_check.rs
@@ -105,7 +105,7 @@ impl<'tcx> LateLintPass<'tcx> for ManualIsAsciiCheck {
                 check_is_ascii(cx, macro_call.span, recv, &range, None);
             }
         } else if let ExprKind::MethodCall(path, receiver, [arg], ..) = expr.kind
-            && path.ident.name == sym!(contains)
+            && path.ident.name.as_str() == "contains"
             && let Some(higher::Range {
                 start: Some(start),
                 end: Some(end),
diff --git a/clippy_lints/src/matches/match_like_matches.rs b/clippy_lints/src/matches/match_like_matches.rs
index 64cb7a06ce9..6d62b530ae7 100644
--- a/clippy_lints/src/matches/match_like_matches.rs
+++ b/clippy_lints/src/matches/match_like_matches.rs
@@ -148,7 +148,7 @@ fn find_bool_lit(ex: &ExprKind<'_>) -> Option<bool> {
         }) => Some(*b),
         ExprKind::Block(
             rustc_hir::Block {
-                stmts: &[],
+                stmts: [],
                 expr: Some(exp),
                 ..
             },
diff --git a/clippy_lints/src/matches/match_str_case_mismatch.rs b/clippy_lints/src/matches/match_str_case_mismatch.rs
index 463aa602bc8..1267fc9d0a5 100644
--- a/clippy_lints/src/matches/match_str_case_mismatch.rs
+++ b/clippy_lints/src/matches/match_str_case_mismatch.rs
@@ -1,3 +1,5 @@
+use std::ops::ControlFlow;
+
 use clippy_utils::diagnostics::span_lint_and_sugg;
 use clippy_utils::ty::is_type_lang_item;
 use rustc_ast::ast::LitKind;
@@ -23,11 +25,8 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, scrutinee: &'tcx Expr<'_>, arm
     if let ty::Ref(_, ty, _) = cx.typeck_results().expr_ty(scrutinee).kind()
         && let ty::Str = ty.kind()
     {
-        let mut visitor = MatchExprVisitor { cx, case_method: None };
-
-        visitor.visit_expr(scrutinee);
-
-        if let Some(case_method) = visitor.case_method {
+        let mut visitor = MatchExprVisitor { cx };
+        if let ControlFlow::Break(case_method) = visitor.visit_expr(scrutinee) {
             if let Some((bad_case_span, bad_case_sym)) = verify_case(&case_method, arms) {
                 lint(cx, &case_method, bad_case_span, bad_case_sym.as_str());
             }
@@ -37,30 +36,33 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, scrutinee: &'tcx Expr<'_>, arm
 
 struct MatchExprVisitor<'a, 'tcx> {
     cx: &'a LateContext<'tcx>,
-    case_method: Option<CaseMethod>,
 }
 
 impl<'tcx> Visitor<'tcx> for MatchExprVisitor<'_, 'tcx> {
-    fn visit_expr(&mut self, ex: &'tcx Expr<'_>) {
-        match ex.kind {
-            ExprKind::MethodCall(segment, receiver, [], _) if self.case_altered(segment.ident.as_str(), receiver) => {},
-            _ => walk_expr(self, ex),
+    type Result = ControlFlow<CaseMethod>;
+    fn visit_expr(&mut self, ex: &'tcx Expr<'_>) -> Self::Result {
+        if let ExprKind::MethodCall(segment, receiver, [], _) = ex.kind {
+            let result = self.case_altered(segment.ident.as_str(), receiver);
+            if result.is_break() {
+                return result;
+            }
         }
+
+        walk_expr(self, ex)
     }
 }
 
 impl MatchExprVisitor<'_, '_> {
-    fn case_altered(&mut self, segment_ident: &str, receiver: &Expr<'_>) -> bool {
+    fn case_altered(&mut self, segment_ident: &str, receiver: &Expr<'_>) -> ControlFlow<CaseMethod> {
         if let Some(case_method) = get_case_method(segment_ident) {
             let ty = self.cx.typeck_results().expr_ty(receiver).peel_refs();
 
             if is_type_lang_item(self.cx, ty, LangItem::String) || ty.kind() == &ty::Str {
-                self.case_method = Some(case_method);
-                return true;
+                return ControlFlow::Break(case_method);
             }
         }
 
-        false
+        ControlFlow::Continue(())
     }
 }
 
diff --git a/clippy_lints/src/matches/redundant_guards.rs b/clippy_lints/src/matches/redundant_guards.rs
index 42d9efe4ff6..9e54475033c 100644
--- a/clippy_lints/src/matches/redundant_guards.rs
+++ b/clippy_lints/src/matches/redundant_guards.rs
@@ -10,7 +10,7 @@ use rustc_hir::def::{DefKind, Res};
 use rustc_hir::{Arm, BinOpKind, Expr, ExprKind, MatchSource, Node, PatKind, UnOp};
 use rustc_lint::LateContext;
 use rustc_span::symbol::Ident;
-use rustc_span::{Span, Symbol, sym};
+use rustc_span::{Span, sym};
 use std::borrow::Cow;
 use std::ops::ControlFlow;
 
@@ -95,7 +95,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, arms: &'tcx [Arm<'tcx>], msrv:
         } else if let ExprKind::MethodCall(path, recv, args, ..) = guard.kind
             && let Some(binding) = get_pat_binding(cx, recv, outer_arm)
         {
-            check_method_calls(cx, outer_arm, path.ident.name, recv, args, guard, &binding);
+            check_method_calls(cx, outer_arm, path.ident.name.as_str(), recv, args, guard, &binding);
         }
     }
 }
@@ -103,7 +103,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, arms: &'tcx [Arm<'tcx>], msrv:
 fn check_method_calls<'tcx>(
     cx: &LateContext<'tcx>,
     arm: &Arm<'tcx>,
-    method: Symbol,
+    method: &str,
     recv: &Expr<'_>,
     args: &[Expr<'_>],
     if_expr: &Expr<'_>,
@@ -112,7 +112,7 @@ fn check_method_calls<'tcx>(
     let ty = cx.typeck_results().expr_ty(recv).peel_refs();
     let slice_like = ty.is_slice() || ty.is_array();
 
-    let sugg = if method == sym!(is_empty) {
+    let sugg = if method == "is_empty" {
         // `s if s.is_empty()` becomes ""
         // `arr if arr.is_empty()` becomes []
 
@@ -137,9 +137,9 @@ fn check_method_calls<'tcx>(
 
         if needles.is_empty() {
             sugg.insert_str(1, "..");
-        } else if method == sym!(starts_with) {
+        } else if method == "starts_with" {
             sugg.insert_str(sugg.len() - 1, ", ..");
-        } else if method == sym!(ends_with) {
+        } else if method == "ends_with" {
             sugg.insert_str(1, ".., ");
         } else {
             return;
diff --git a/clippy_lints/src/matches/redundant_pattern_match.rs b/clippy_lints/src/matches/redundant_pattern_match.rs
index 9ca75fb2615..ca45ed6ea59 100644
--- a/clippy_lints/src/matches/redundant_pattern_match.rs
+++ b/clippy_lints/src/matches/redundant_pattern_match.rs
@@ -319,10 +319,9 @@ fn found_good_method<'tcx>(
     node: (&PatKind<'_>, &PatKind<'_>),
 ) -> Option<(&'static str, Option<&'tcx Expr<'tcx>>)> {
     match node {
-        (
-            PatKind::TupleStruct(ref path_left, patterns_left, _),
-            PatKind::TupleStruct(ref path_right, patterns_right, _),
-        ) if patterns_left.len() == 1 && patterns_right.len() == 1 => {
+        (PatKind::TupleStruct(path_left, patterns_left, _), PatKind::TupleStruct(path_right, patterns_right, _))
+            if patterns_left.len() == 1 && patterns_right.len() == 1 =>
+        {
             if let (PatKind::Wild, PatKind::Wild) = (&patterns_left[0].kind, &patterns_right[0].kind) {
                 find_good_method_for_match(
                     cx,
@@ -350,8 +349,8 @@ fn found_good_method<'tcx>(
                 None
             }
         },
-        (PatKind::TupleStruct(ref path_left, patterns, _), PatKind::Path(ref path_right))
-        | (PatKind::Path(ref path_left), PatKind::TupleStruct(ref path_right, patterns, _))
+        (PatKind::TupleStruct(path_left, patterns, _), PatKind::Path(path_right))
+        | (PatKind::Path(path_left), PatKind::TupleStruct(path_right, patterns, _))
             if patterns.len() == 1 =>
         {
             if let PatKind::Wild = patterns[0].kind {
@@ -381,14 +380,14 @@ fn found_good_method<'tcx>(
                 None
             }
         },
-        (PatKind::TupleStruct(ref path_left, patterns, _), PatKind::Wild) if patterns.len() == 1 => {
+        (PatKind::TupleStruct(path_left, patterns, _), PatKind::Wild) if patterns.len() == 1 => {
             if let PatKind::Wild = patterns[0].kind {
                 get_good_method(cx, arms, path_left)
             } else {
                 None
             }
         },
-        (PatKind::Path(ref path_left), PatKind::Wild) => get_good_method(cx, arms, path_left),
+        (PatKind::Path(path_left), PatKind::Wild) => get_good_method(cx, arms, path_left),
         _ => None,
     }
 }
diff --git a/clippy_lints/src/matches/single_match.rs b/clippy_lints/src/matches/single_match.rs
index 047d070a131..2aea25b5f12 100644
--- a/clippy_lints/src/matches/single_match.rs
+++ b/clippy_lints/src/matches/single_match.rs
@@ -247,7 +247,10 @@ impl<'a> PatState<'a> {
         let states = match self {
             Self::Wild => return None,
             Self::Other => {
-                *self = Self::StdEnum(cx.arena.alloc_from_iter((0..adt.variants().len()).map(|_| Self::Other)));
+                *self = Self::StdEnum(
+                    cx.arena
+                        .alloc_from_iter(std::iter::repeat_with(|| Self::Other).take(adt.variants().len())),
+                );
                 let Self::StdEnum(x) = self else {
                     unreachable!();
                 };
diff --git a/clippy_lints/src/methods/filter_map.rs b/clippy_lints/src/methods/filter_map.rs
index 06482a743dd..c1653b65e98 100644
--- a/clippy_lints/src/methods/filter_map.rs
+++ b/clippy_lints/src/methods/filter_map.rs
@@ -21,8 +21,8 @@ fn is_method(cx: &LateContext<'_>, expr: &Expr<'_>, method_name: Symbol) -> bool
         ExprKind::Path(QPath::TypeRelative(_, mname)) => mname.ident.name == method_name,
         ExprKind::Path(QPath::Resolved(_, segments)) => segments.segments.last().unwrap().ident.name == method_name,
         ExprKind::MethodCall(segment, _, _, _) => segment.ident.name == method_name,
-        ExprKind::Closure(&Closure { body, .. }) => {
-            let body = cx.tcx.hir().body(body);
+        ExprKind::Closure(Closure { body, .. }) => {
+            let body = cx.tcx.hir().body(*body);
             let closure_expr = peel_blocks(body.value);
             match closure_expr.kind {
                 ExprKind::MethodCall(PathSegment { ident, .. }, receiver, ..) => {
@@ -234,12 +234,12 @@ impl<'tcx> OffendingFilterExpr<'tcx> {
             // the latter only calls `effect` once
             let side_effect_expr_span = receiver.can_have_side_effects().then_some(receiver.span);
 
-            if cx.tcx.is_diagnostic_item(sym::Option, recv_ty.did()) && path.ident.name == sym!(is_some) {
+            if cx.tcx.is_diagnostic_item(sym::Option, recv_ty.did()) && path.ident.name.as_str() == "is_some" {
                 Some(Self::IsSome {
                     receiver,
                     side_effect_expr_span,
                 })
-            } else if cx.tcx.is_diagnostic_item(sym::Result, recv_ty.did()) && path.ident.name == sym!(is_ok) {
+            } else if cx.tcx.is_diagnostic_item(sym::Result, recv_ty.did()) && path.ident.name.as_str() == "is_ok" {
                 Some(Self::IsOk {
                     receiver,
                     side_effect_expr_span,
diff --git a/clippy_lints/src/methods/is_empty.rs b/clippy_lints/src/methods/is_empty.rs
index cc82f6cfd63..a0c21faaa4c 100644
--- a/clippy_lints/src/methods/is_empty.rs
+++ b/clippy_lints/src/methods/is_empty.rs
@@ -1,6 +1,7 @@
 use clippy_utils::consts::ConstEvalCtxt;
 use clippy_utils::diagnostics::span_lint;
-use clippy_utils::{find_binding_init, path_to_local};
+use clippy_utils::macros::{is_assert_macro, root_macro_call};
+use clippy_utils::{find_binding_init, get_parent_expr, is_inside_always_const_context, path_to_local};
 use rustc_hir::{Expr, HirId};
 use rustc_lint::{LateContext, LintContext};
 use rustc_middle::lint::in_external_macro;
@@ -14,6 +15,16 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &'_ Expr<'_>, receiver: &Expr<'_
     if in_external_macro(cx.sess(), expr.span) || !receiver.span.eq_ctxt(expr.span) {
         return;
     }
+    if let Some(parent) = get_parent_expr(cx, expr) {
+        if let Some(parent) = get_parent_expr(cx, parent) {
+            if is_inside_always_const_context(cx.tcx, expr.hir_id)
+                && let Some(macro_call) = root_macro_call(parent.span)
+                && is_assert_macro(cx, macro_call.def_id)
+            {
+                return;
+            }
+        }
+    }
     let init_expr = expr_or_init(cx, receiver);
     if !receiver.span.eq_ctxt(init_expr.span) {
         return;
diff --git a/clippy_lints/src/methods/iter_out_of_bounds.rs b/clippy_lints/src/methods/iter_out_of_bounds.rs
index 9d462bd1845..9a62b719a8f 100644
--- a/clippy_lints/src/methods/iter_out_of_bounds.rs
+++ b/clippy_lints/src/methods/iter_out_of_bounds.rs
@@ -29,10 +29,7 @@ fn get_iterator_length<'tcx>(cx: &LateContext<'tcx>, iter: &'tcx Expr<'tcx>) ->
     if cx.tcx.is_diagnostic_item(sym::ArrayIntoIter, did) {
         // For array::IntoIter<T, const N: usize>, the length is the second generic
         // parameter.
-        substs
-            .const_at(1)
-            .try_to_target_usize(cx.tcx)
-            .map(u128::from)
+        substs.const_at(1).try_to_target_usize(cx.tcx).map(u128::from)
     } else if cx.tcx.is_diagnostic_item(sym::SliceIter, did)
         && let ExprKind::MethodCall(_, recv, ..) = iter.kind
     {
diff --git a/clippy_lints/src/methods/map_all_any_identity.rs b/clippy_lints/src/methods/map_all_any_identity.rs
new file mode 100644
index 00000000000..ac11baa2d54
--- /dev/null
+++ b/clippy_lints/src/methods/map_all_any_identity.rs
@@ -0,0 +1,43 @@
+use clippy_utils::diagnostics::span_lint_and_then;
+use clippy_utils::source::SpanRangeExt;
+use clippy_utils::{is_expr_identity_function, is_trait_method};
+use rustc_errors::Applicability;
+use rustc_hir::Expr;
+use rustc_lint::LateContext;
+use rustc_span::{Span, sym};
+
+use super::MAP_ALL_ANY_IDENTITY;
+
+#[allow(clippy::too_many_arguments)]
+pub(super) fn check(
+    cx: &LateContext<'_>,
+    expr: &Expr<'_>,
+    recv: &Expr<'_>,
+    map_call_span: Span,
+    map_arg: &Expr<'_>,
+    any_call_span: Span,
+    any_arg: &Expr<'_>,
+    method: &str,
+) {
+    if is_trait_method(cx, expr, sym::Iterator)
+        && is_trait_method(cx, recv, sym::Iterator)
+        && is_expr_identity_function(cx, any_arg)
+        && let map_any_call_span = map_call_span.with_hi(any_call_span.hi())
+        && let Some(map_arg) = map_arg.span.get_source_text(cx)
+    {
+        span_lint_and_then(
+            cx,
+            MAP_ALL_ANY_IDENTITY,
+            map_any_call_span,
+            format!("usage of `.map(...).{method}(identity)`"),
+            |diag| {
+                diag.span_suggestion_verbose(
+                    map_any_call_span,
+                    format!("use `.{method}(...)` instead"),
+                    format!("{method}({map_arg})"),
+                    Applicability::MachineApplicable,
+                );
+            },
+        );
+    }
+}
diff --git a/clippy_lints/src/methods/map_with_unused_argument_over_ranges.rs b/clippy_lints/src/methods/map_with_unused_argument_over_ranges.rs
new file mode 100644
index 00000000000..fc656fd78ba
--- /dev/null
+++ b/clippy_lints/src/methods/map_with_unused_argument_over_ranges.rs
@@ -0,0 +1,134 @@
+use crate::methods::MAP_WITH_UNUSED_ARGUMENT_OVER_RANGES;
+use clippy_config::msrvs::{self, Msrv};
+use clippy_utils::diagnostics::span_lint_and_then;
+use clippy_utils::source::snippet_with_applicability;
+use clippy_utils::sugg::Sugg;
+use clippy_utils::{eager_or_lazy, higher, usage};
+use rustc_ast::LitKind;
+use rustc_ast::ast::RangeLimits;
+use rustc_data_structures::packed::Pu128;
+use rustc_errors::Applicability;
+use rustc_hir::{Body, Closure, Expr, ExprKind};
+use rustc_lint::LateContext;
+use rustc_span::Span;
+
+fn extract_count_with_applicability(
+    cx: &LateContext<'_>,
+    range: higher::Range<'_>,
+    applicability: &mut Applicability,
+) -> Option<String> {
+    let start = range.start?;
+    let end = range.end?;
+    // TODO: This doens't handle if either the start or end are negative literals, or if the start is
+    // not a literal. In the first case, we need to be careful about how we handle computing the
+    // count to avoid overflows. In the second, we may need to add parenthesis to make the
+    // suggestion correct.
+    if let ExprKind::Lit(lit) = start.kind
+        && let LitKind::Int(Pu128(lower_bound), _) = lit.node
+    {
+        if let ExprKind::Lit(lit) = end.kind
+            && let LitKind::Int(Pu128(upper_bound), _) = lit.node
+        {
+            // Here we can explicitly calculate the number of iterations
+            let count = if upper_bound >= lower_bound {
+                match range.limits {
+                    RangeLimits::HalfOpen => upper_bound - lower_bound,
+                    RangeLimits::Closed => (upper_bound - lower_bound).checked_add(1)?,
+                }
+            } else {
+                0
+            };
+            return Some(format!("{count}"));
+        }
+        let end_snippet = Sugg::hir_with_applicability(cx, end, "...", applicability)
+            .maybe_par()
+            .into_string();
+        if lower_bound == 0 {
+            if range.limits == RangeLimits::Closed {
+                return Some(format!("{end_snippet} + 1"));
+            }
+            return Some(end_snippet);
+        }
+        if range.limits == RangeLimits::Closed {
+            return Some(format!("{end_snippet} - {}", lower_bound - 1));
+        }
+        return Some(format!("{end_snippet} - {lower_bound}"));
+    }
+    None
+}
+
+pub(super) fn check(
+    cx: &LateContext<'_>,
+    ex: &Expr<'_>,
+    receiver: &Expr<'_>,
+    arg: &Expr<'_>,
+    msrv: &Msrv,
+    method_call_span: Span,
+) {
+    let mut applicability = Applicability::MaybeIncorrect;
+    if let Some(range) = higher::Range::hir(receiver)
+        && let ExprKind::Closure(Closure { body, .. }) = arg.kind
+        && let body_hir = cx.tcx.hir().body(*body)
+        && let Body {
+            params: [param],
+            value: body_expr,
+        } = body_hir
+        && !usage::BindingUsageFinder::are_params_used(cx, body_hir)
+        && let Some(count) = extract_count_with_applicability(cx, range, &mut applicability)
+    {
+        let method_to_use_name;
+        let new_span;
+        let use_take;
+
+        if eager_or_lazy::switch_to_eager_eval(cx, body_expr) {
+            if msrv.meets(msrvs::REPEAT_N) {
+                method_to_use_name = "repeat_n";
+                let body_snippet = snippet_with_applicability(cx, body_expr.span, "..", &mut applicability);
+                new_span = (arg.span, format!("{body_snippet}, {count}"));
+                use_take = false;
+            } else {
+                method_to_use_name = "repeat";
+                let body_snippet = snippet_with_applicability(cx, body_expr.span, "..", &mut applicability);
+                new_span = (arg.span, body_snippet.to_string());
+                use_take = true;
+            }
+        } else if msrv.meets(msrvs::REPEAT_WITH) {
+            method_to_use_name = "repeat_with";
+            new_span = (param.span, String::new());
+            use_take = true;
+        } else {
+            return;
+        }
+
+        // We need to provide nonempty parts to diag.multipart_suggestion so we
+        // collate all our parts here and then remove those that are empty.
+        let mut parts = vec![
+            (
+                receiver.span.to(method_call_span),
+                format!("std::iter::{method_to_use_name}"),
+            ),
+            new_span,
+        ];
+        if use_take {
+            parts.push((ex.span.shrink_to_hi(), format!(".take({count})")));
+        }
+
+        span_lint_and_then(
+            cx,
+            MAP_WITH_UNUSED_ARGUMENT_OVER_RANGES,
+            ex.span,
+            "map of a closure that does not depend on its parameter over a range",
+            |diag| {
+                diag.multipart_suggestion(
+                    if use_take {
+                        format!("remove the explicit range and use `{method_to_use_name}` and `take`")
+                    } else {
+                        format!("remove the explicit range and use `{method_to_use_name}`")
+                    },
+                    parts,
+                    applicability,
+                );
+            },
+        );
+    }
+}
diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs
index 2a391870d70..b1809796355 100644
--- a/clippy_lints/src/methods/mod.rs
+++ b/clippy_lints/src/methods/mod.rs
@@ -60,13 +60,16 @@ mod manual_ok_or;
 mod manual_saturating_arithmetic;
 mod manual_str_repeat;
 mod manual_try_fold;
+mod map_all_any_identity;
 mod map_clone;
 mod map_collect_result_unit;
 mod map_err_ignore;
 mod map_flatten;
 mod map_identity;
 mod map_unwrap_or;
+mod map_with_unused_argument_over_ranges;
 mod mut_mutex_lock;
+mod needless_as_bytes;
 mod needless_character_iteration;
 mod needless_collect;
 mod needless_option_as_deref;
@@ -4166,6 +4169,90 @@ declare_clippy_lint! {
     "calling `.first().is_some()` or `.first().is_none()` instead of `.is_empty()`"
 }
 
+declare_clippy_lint! {
+   /// ### What it does
+   /// It detects useless calls to `str::as_bytes()` before calling `len()` or `is_empty()`.
+   ///
+   /// ### Why is this bad?
+   /// The `len()` and `is_empty()` methods are also directly available on strings, and they
+   /// return identical results. In particular, `len()` on a string returns the number of
+   /// bytes.
+   ///
+   /// ### Example
+   /// ```
+   /// let len = "some string".as_bytes().len();
+   /// let b = "some string".as_bytes().is_empty();
+   /// ```
+   /// Use instead:
+   /// ```
+   /// let len = "some string".len();
+   /// let b = "some string".is_empty();
+   /// ```
+   #[clippy::version = "1.84.0"]
+   pub NEEDLESS_AS_BYTES,
+   complexity,
+   "detect useless calls to `as_bytes()`"
+}
+
+declare_clippy_lint! {
+    /// ### What it does
+    /// Checks for usage of `.map(…)`, followed by `.all(identity)` or `.any(identity)`.
+    ///
+    /// ### Why is this bad?
+    /// The `.all(…)` or `.any(…)` methods can be called directly in place of `.map(…)`.
+    ///
+    /// ### Example
+    /// ```
+    /// # let mut v = [""];
+    /// let e1 = v.iter().map(|s| s.is_empty()).all(|a| a);
+    /// let e2 = v.iter().map(|s| s.is_empty()).any(std::convert::identity);
+    /// ```
+    /// Use instead:
+    /// ```
+    /// # let mut v = [""];
+    /// let e1 = v.iter().all(|s| s.is_empty());
+    /// let e2 = v.iter().any(|s| s.is_empty());
+    /// ```
+    #[clippy::version = "1.84.0"]
+    pub MAP_ALL_ANY_IDENTITY,
+    complexity,
+    "combine `.map(_)` followed by `.all(identity)`/`.any(identity)` into a single call"
+}
+
+declare_clippy_lint! {
+    /// ### What it does
+    ///
+    /// Checks for `Iterator::map` over ranges without using the parameter which
+    /// could be more clearly expressed using `std::iter::repeat(...).take(...)`
+    /// or `std::iter::repeat_n`.
+    ///
+    /// ### Why is this bad?
+    ///
+    /// It expresses the intent more clearly to `take` the correct number of times
+    /// from a generating function than to apply a closure to each number in a
+    /// range only to discard them.
+    ///
+    /// ### Example
+    ///
+    /// ```no_run
+    /// let random_numbers : Vec<_> = (0..10).map(|_| { 3 + 1 }).collect();
+    /// ```
+    /// Use instead:
+    /// ```no_run
+    /// let f : Vec<_> = std::iter::repeat( 3 + 1 ).take(10).collect();
+    /// ```
+    ///
+    /// ### Known Issues
+    ///
+    /// This lint may suggest replacing a `Map<Range>` with a `Take<RepeatWith>`.
+    /// The former implements some traits that the latter does not, such as
+    /// `DoubleEndedIterator`.
+    #[clippy::version = "1.84.0"]
+    pub MAP_WITH_UNUSED_ARGUMENT_OVER_RANGES,
+    restriction,
+    "map of a trivial closure (not dependent on parameter) over a range"
+}
+
 pub struct Methods {
     avoid_breaking_exported_api: bool,
     msrv: Msrv,
@@ -4327,6 +4414,9 @@ impl_lint_pass!(Methods => [
     NEEDLESS_CHARACTER_ITERATION,
     MANUAL_INSPECT,
     UNNECESSARY_MIN_OR_MAX,
+    NEEDLESS_AS_BYTES,
+    MAP_ALL_ANY_IDENTITY,
+    MAP_WITH_UNUSED_ARGUMENT_OVER_RANGES,
 ]);
 
 /// Extracts a method call name, args, and `Span` of the method name.
@@ -4534,15 +4624,21 @@ impl Methods {
                 ("all", [arg]) => {
                     unused_enumerate_index::check(cx, expr, recv, arg);
                     needless_character_iteration::check(cx, expr, recv, arg, true);
-                    if let Some(("cloned", recv2, [], _, _)) = method_call(recv) {
-                        iter_overeager_cloned::check(
-                            cx,
-                            expr,
-                            recv,
-                            recv2,
-                            iter_overeager_cloned::Op::NeedlessMove(arg),
-                            false,
-                        );
+                    match method_call(recv) {
+                        Some(("cloned", recv2, [], _, _)) => {
+                            iter_overeager_cloned::check(
+                                cx,
+                                expr,
+                                recv,
+                                recv2,
+                                iter_overeager_cloned::Op::NeedlessMove(arg),
+                                false,
+                            );
+                        },
+                        Some(("map", _, [map_arg], _, map_call_span)) => {
+                            map_all_any_identity::check(cx, expr, recv, map_call_span, map_arg, call_span, arg, "all");
+                        },
+                        _ => {},
                     }
                 },
                 ("and_then", [arg]) => {
@@ -4571,6 +4667,9 @@ impl Methods {
                         {
                             string_lit_chars_any::check(cx, expr, recv, param, peel_blocks(body.value), &self.msrv);
                         },
+                        Some(("map", _, [map_arg], _, map_call_span)) => {
+                            map_all_any_identity::check(cx, expr, recv, map_call_span, map_arg, call_span, arg, "any");
+                        },
                         _ => {},
                     }
                 },
@@ -4764,8 +4863,14 @@ impl Methods {
                     unit_hash::check(cx, expr, recv, arg);
                 },
                 ("is_empty", []) => {
-                    if let Some(("as_str", recv, [], as_str_span, _)) = method_call(recv) {
-                        redundant_as_str::check(cx, expr, recv, as_str_span, span);
+                    match method_call(recv) {
+                        Some(("as_bytes", prev_recv, [], _, _)) => {
+                            needless_as_bytes::check(cx, "is_empty", recv, prev_recv, expr.span);
+                        },
+                        Some(("as_str", recv, [], as_str_span, _)) => {
+                            redundant_as_str::check(cx, expr, recv, as_str_span, span);
+                        },
+                        _ => {},
                     }
                     is_empty::check(cx, expr, recv);
                 },
@@ -4795,6 +4900,11 @@ impl Methods {
                         );
                     }
                 },
+                ("len", []) => {
+                    if let Some(("as_bytes", prev_recv, [], _, _)) = method_call(recv) {
+                        needless_as_bytes::check(cx, "len", recv, prev_recv, expr.span);
+                    }
+                },
                 ("lock", []) => {
                     mut_mutex_lock::check(cx, expr, recv, span);
                 },
@@ -4802,6 +4912,7 @@ impl Methods {
                     if name == "map" {
                         unused_enumerate_index::check(cx, expr, recv, m_arg);
                         map_clone::check(cx, expr, recv, m_arg, &self.msrv);
+                        map_with_unused_argument_over_ranges::check(cx, expr, recv, m_arg, &self.msrv, span);
                         match method_call(recv) {
                             Some((map_name @ ("iter" | "into_iter"), recv2, _, _, _)) => {
                                 iter_kv_map::check(cx, map_name, expr, recv2, m_arg, &self.msrv);
@@ -5182,7 +5293,6 @@ impl ShouldImplTraitCase {
 }
 
 #[rustfmt::skip]
-#[expect(clippy::large_const_arrays, reason = "`Span` is not sync, so this can't be static")]
 const TRAIT_METHODS: [ShouldImplTraitCase; 30] = [
     ShouldImplTraitCase::new("std::ops::Add", "add",  2,  FN_HEADER,  SelfKind::Value,  OutType::Any, true),
     ShouldImplTraitCase::new("std::convert::AsMut", "as_mut",  1,  FN_HEADER,  SelfKind::RefMut,  OutType::Ref, true),
diff --git a/clippy_lints/src/methods/needless_as_bytes.rs b/clippy_lints/src/methods/needless_as_bytes.rs
new file mode 100644
index 00000000000..75e9f317230
--- /dev/null
+++ b/clippy_lints/src/methods/needless_as_bytes.rs
@@ -0,0 +1,28 @@
+use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::sugg::Sugg;
+use clippy_utils::ty::is_type_lang_item;
+use rustc_errors::Applicability;
+use rustc_hir::{Expr, LangItem};
+use rustc_lint::LateContext;
+use rustc_span::Span;
+
+use super::NEEDLESS_AS_BYTES;
+
+pub fn check(cx: &LateContext<'_>, method: &str, recv: &Expr<'_>, prev_recv: &Expr<'_>, span: Span) {
+    if cx.typeck_results().expr_ty_adjusted(recv).peel_refs().is_slice()
+        && let ty1 = cx.typeck_results().expr_ty_adjusted(prev_recv).peel_refs()
+        && (is_type_lang_item(cx, ty1, LangItem::String) || ty1.is_str())
+    {
+        let mut app = Applicability::MachineApplicable;
+        let sugg = Sugg::hir_with_context(cx, prev_recv, span.ctxt(), "..", &mut app);
+        span_lint_and_sugg(
+            cx,
+            NEEDLESS_AS_BYTES,
+            span,
+            "needless call to `as_bytes()`",
+            format!("`{method}()` can be called directly on strings"),
+            format!("{sugg}.{method}()"),
+            app,
+        );
+    }
+}
diff --git a/clippy_lints/src/methods/needless_collect.rs b/clippy_lints/src/methods/needless_collect.rs
index 96a31812ca4..055107068ae 100644
--- a/clippy_lints/src/methods/needless_collect.rs
+++ b/clippy_lints/src/methods/needless_collect.rs
@@ -322,7 +322,7 @@ impl<'tcx> Visitor<'tcx> for IterFunctionVisitor<'_, 'tcx> {
         // Check function calls on our collection
         if let ExprKind::MethodCall(method_name, recv, args, _) = &expr.kind {
             if args.is_empty()
-                && method_name.ident.name == sym!(collect)
+                && method_name.ident.name.as_str() == "collect"
                 && is_trait_method(self.cx, expr, sym::Iterator)
             {
                 self.current_mutably_captured_ids = get_captured_ids(self.cx, self.cx.typeck_results().expr_ty(recv));
diff --git a/clippy_lints/src/methods/read_line_without_trim.rs b/clippy_lints/src/methods/read_line_without_trim.rs
index 65e545ed03a..db2b9d4d92f 100644
--- a/clippy_lints/src/methods/read_line_without_trim.rs
+++ b/clippy_lints/src/methods/read_line_without_trim.rs
@@ -44,7 +44,7 @@ pub fn check(cx: &LateContext<'_>, call: &Expr<'_>, recv: &Expr<'_>, arg: &Expr<
             if let Some(parent) = get_parent_expr(cx, expr) {
                 let data = if let ExprKind::MethodCall(segment, recv, args, span) = parent.kind {
                     if args.is_empty()
-                        && segment.ident.name == sym!(parse)
+                        && segment.ident.name.as_str() == "parse"
                         && let parse_result_ty = cx.typeck_results().expr_ty(parent)
                         && is_type_diagnostic_item(cx, parse_result_ty, sym::Result)
                         && let ty::Adt(_, substs) = parse_result_ty.kind()
@@ -58,7 +58,7 @@ pub fn check(cx: &LateContext<'_>, call: &Expr<'_>, recv: &Expr<'_>, arg: &Expr<
                             "calling `.parse()` on a string without trimming the trailing newline character",
                             "checking",
                         ))
-                    } else if segment.ident.name == sym!(ends_with)
+                    } else if segment.ident.name.as_str() == "ends_with"
                         && recv.span == expr.span
                         && let [arg] = args
                         && expr_is_string_literal_without_trailing_newline(arg)
diff --git a/clippy_lints/src/methods/unnecessary_filter_map.rs b/clippy_lints/src/methods/unnecessary_filter_map.rs
index ca46da81fa0..bab439015c5 100644
--- a/clippy_lints/src/methods/unnecessary_filter_map.rs
+++ b/clippy_lints/src/methods/unnecessary_filter_map.rs
@@ -1,13 +1,15 @@
 use super::utils::clone_or_copy_needed;
-use clippy_utils::diagnostics::span_lint;
+use clippy_utils::diagnostics::span_lint_and_sugg;
 use clippy_utils::ty::is_copy;
 use clippy_utils::usage::mutated_variables;
 use clippy_utils::visitors::{Descend, for_each_expr_without_closures};
-use clippy_utils::{is_res_lang_ctor, is_trait_method, path_res, path_to_local_id};
+use clippy_utils::{MaybePath, is_res_lang_ctor, is_trait_method, path_res, path_to_local_id};
 use core::ops::ControlFlow;
+use rustc_errors::Applicability;
 use rustc_hir as hir;
 use rustc_hir::LangItem::{OptionNone, OptionSome};
 use rustc_lint::LateContext;
+use rustc_middle::query::Key;
 use rustc_middle::ty;
 use rustc_span::sym;
 
@@ -36,9 +38,25 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'tcx>, a
                 ControlFlow::Continue(Descend::Yes)
             }
         });
-
         let in_ty = cx.typeck_results().node_type(body.params[0].hir_id);
         let sugg = if !found_filtering {
+            // Check if the closure is .filter_map(|x| Some(x))
+            if name == "filter_map"
+                && let hir::ExprKind::Call(expr, args) = body.value.kind
+                && is_res_lang_ctor(cx, path_res(cx, expr), OptionSome)
+                && arg_id.ty_def_id() == args[0].hir_id().ty_def_id()
+                && let hir::ExprKind::Path(_) = args[0].kind
+            {
+                span_lint_and_sugg(
+                    cx,
+                    UNNECESSARY_FILTER_MAP,
+                    expr.span,
+                    format!("{name} is unnecessary"),
+                    "try removing the filter_map",
+                    String::new(),
+                    Applicability::MaybeIncorrect,
+                );
+            }
             if name == "filter_map" { "map" } else { "map(..).next()" }
         } else if !found_mapping && !mutates_arg && (!clone_or_copy_needed || is_copy(cx, in_ty)) {
             match cx.typeck_results().expr_ty(body.value).kind() {
@@ -52,7 +70,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'tcx>, a
         } else {
             return;
         };
-        span_lint(
+        span_lint_and_sugg(
             cx,
             if name == "filter_map" {
                 UNNECESSARY_FILTER_MAP
@@ -60,7 +78,10 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'tcx>, a
                 UNNECESSARY_FIND_MAP
             },
             expr.span,
-            format!("this `.{name}` can be written more simply using `.{sugg}`"),
+            format!("this `.{name}` can be written more simply"),
+            "try instead",
+            sugg.to_string(),
+            Applicability::MaybeIncorrect,
         );
     }
 }
@@ -78,7 +99,7 @@ fn check_expression<'tcx>(cx: &LateContext<'tcx>, arg_id: hir::HirId, expr: &'tc
             (true, true)
         },
         hir::ExprKind::MethodCall(segment, recv, [arg], _) => {
-            if segment.ident.name == sym!(then_some)
+            if segment.ident.name.as_str() == "then_some"
                 && cx.typeck_results().expr_ty(recv).is_bool()
                 && path_to_local_id(arg, arg_id)
             {
diff --git a/clippy_lints/src/minmax.rs b/clippy_lints/src/minmax.rs
index e95864c6db8..ed89b3b3438 100644
--- a/clippy_lints/src/minmax.rs
+++ b/clippy_lints/src/minmax.rs
@@ -79,9 +79,9 @@ fn min_max<'a, 'tcx>(cx: &LateContext<'tcx>, expr: &'a Expr<'a>) -> Option<(MinM
         },
         ExprKind::MethodCall(path, receiver, args @ [_], _) => {
             if cx.typeck_results().expr_ty(receiver).is_floating_point() || is_trait_method(cx, expr, sym::Ord) {
-                if path.ident.name == sym!(max) {
+                if path.ident.name.as_str() == "max" {
                     fetch_const(cx, Some(receiver), args, MinMax::Max)
-                } else if path.ident.name == sym!(min) {
+                } else if path.ident.name.as_str() == "min" {
                     fetch_const(cx, Some(receiver), args, MinMax::Min)
                 } else {
                     None
diff --git a/clippy_lints/src/missing_doc.rs b/clippy_lints/src/missing_doc.rs
index ce508d85d63..1300c7d1062 100644
--- a/clippy_lints/src/missing_doc.rs
+++ b/clippy_lints/src/missing_doc.rs
@@ -12,11 +12,13 @@ use clippy_utils::is_from_proc_macro;
 use clippy_utils::source::SpanRangeExt;
 use rustc_ast::ast::{self, MetaItem, MetaItemKind};
 use rustc_hir as hir;
+use rustc_hir::def::DefKind;
 use rustc_hir::def_id::LocalDefId;
 use rustc_lint::{LateContext, LateLintPass, LintContext};
 use rustc_middle::ty::Visibility;
 use rustc_session::impl_lint_pass;
 use rustc_span::def_id::CRATE_DEF_ID;
+use rustc_span::symbol::kw;
 use rustc_span::{Span, sym};
 
 declare_clippy_lint! {
@@ -110,6 +112,21 @@ impl MissingDoc {
             return;
         }
 
+        if let Some(parent_def_id) = cx.tcx.opt_parent(def_id.to_def_id())
+            && let DefKind::AnonConst
+            | DefKind::AssocConst
+            | DefKind::AssocFn
+            | DefKind::Closure
+            | DefKind::Const
+            | DefKind::Fn
+            | DefKind::InlineConst
+            | DefKind::Static { .. }
+            | DefKind::SyntheticCoroutineBody = cx.tcx.def_kind(parent_def_id)
+        {
+            // Nested item has no generated documentation, so it doesn't need to be documented.
+            return;
+        }
+
         let has_doc = attrs
             .iter()
             .any(|a| a.doc_str().is_some() || Self::has_include(a.meta()))
@@ -184,8 +201,12 @@ impl<'tcx> LateLintPass<'tcx> for MissingDoc {
                     }
                 }
             },
-            hir::ItemKind::Const(..)
-            | hir::ItemKind::Enum(..)
+            hir::ItemKind::Const(..) => {
+                if it.ident.name == kw::Underscore {
+                    note_prev_span_then_ret!(self.prev_span, it.span);
+                }
+            },
+            hir::ItemKind::Enum(..)
             | hir::ItemKind::Macro(..)
             | hir::ItemKind::Mod(..)
             | hir::ItemKind::Static(..)
diff --git a/clippy_lints/src/missing_fields_in_debug.rs b/clippy_lints/src/missing_fields_in_debug.rs
index fc01b6753f1..f28b431ab99 100644
--- a/clippy_lints/src/missing_fields_in_debug.rs
+++ b/clippy_lints/src/missing_fields_in_debug.rs
@@ -116,7 +116,7 @@ fn should_lint<'tcx>(
 
             if path.ident.name == sym::debug_struct && is_type_diagnostic_item(cx, recv_ty, sym::Formatter) {
                 has_debug_struct = true;
-            } else if path.ident.name == sym!(finish_non_exhaustive)
+            } else if path.ident.name.as_str() == "finish_non_exhaustive"
                 && is_type_diagnostic_item(cx, recv_ty, sym::DebugStruct)
             {
                 has_finish_non_exhaustive = true;
diff --git a/clippy_lints/src/needless_continue.rs b/clippy_lints/src/needless_continue.rs
index ce97370d4d9..c4836772933 100644
--- a/clippy_lints/src/needless_continue.rs
+++ b/clippy_lints/src/needless_continue.rs
@@ -330,10 +330,11 @@ fn suggestion_snippet_for_continue_inside_else(cx: &EarlyContext<'_>, data: &Lin
 }
 
 fn check_and_warn(cx: &EarlyContext<'_>, expr: &ast::Expr) {
-    if let ast::ExprKind::Loop(loop_block, ..) = &expr.kind
+    if let ast::ExprKind::Loop(loop_block, loop_label, ..) = &expr.kind
         && let Some(last_stmt) = loop_block.stmts.last()
         && let ast::StmtKind::Expr(inner_expr) | ast::StmtKind::Semi(inner_expr) = &last_stmt.kind
-        && let ast::ExprKind::Continue(_) = inner_expr.kind
+        && let ast::ExprKind::Continue(continue_label) = inner_expr.kind
+        && compare_labels(loop_label.as_ref(), continue_label.as_ref())
     {
         span_lint_and_help(
             cx,
diff --git a/clippy_lints/src/needless_late_init.rs b/clippy_lints/src/needless_late_init.rs
index 46cdb82130f..a67addea948 100644
--- a/clippy_lints/src/needless_late_init.rs
+++ b/clippy_lints/src/needless_late_init.rs
@@ -347,7 +347,7 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessLateInit {
         if let LetStmt {
             init: None,
             pat:
-                &Pat {
+                Pat {
                     kind: PatKind::Binding(BindingMode::NONE, binding_id, _, None),
                     ..
                 },
@@ -357,7 +357,7 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessLateInit {
             && let Some((_, Node::Stmt(local_stmt))) = parents.next()
             && let Some((_, Node::Block(block))) = parents.next()
         {
-            check(cx, local, local_stmt, block, binding_id);
+            check(cx, local, local_stmt, block, *binding_id);
         }
     }
 }
diff --git a/clippy_lints/src/needless_maybe_sized.rs b/clippy_lints/src/needless_maybe_sized.rs
index 9a1c397b5b2..852a0ce8c6d 100644
--- a/clippy_lints/src/needless_maybe_sized.rs
+++ b/clippy_lints/src/needless_maybe_sized.rs
@@ -1,7 +1,7 @@
 use clippy_utils::diagnostics::span_lint_and_then;
 use rustc_errors::Applicability;
 use rustc_hir::def_id::{DefId, DefIdMap};
-use rustc_hir::{GenericBound, Generics, PolyTraitRef, TraitBoundModifiers, BoundPolarity, WherePredicate};
+use rustc_hir::{BoundPolarity, GenericBound, Generics, PolyTraitRef, TraitBoundModifiers, WherePredicate};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::ty::{ClauseKind, PredicatePolarity};
 use rustc_session::declare_lint_pass;
diff --git a/clippy_lints/src/needless_pass_by_ref_mut.rs b/clippy_lints/src/needless_pass_by_ref_mut.rs
index f8c815d9729..b7dc269061c 100644
--- a/clippy_lints/src/needless_pass_by_ref_mut.rs
+++ b/clippy_lints/src/needless_pass_by_ref_mut.rs
@@ -183,7 +183,7 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessPassByRefMut<'tcx> {
             .iter()
             .zip(fn_sig.inputs())
             .zip(body.params)
-            .filter(|((&input, &ty), arg)| !should_skip(cx, input, ty, arg))
+            .filter(|&((&input, &ty), arg)| !should_skip(cx, input, ty, arg))
             .peekable();
         if it.peek().is_none() {
             return;
diff --git a/clippy_lints/src/no_effect.rs b/clippy_lints/src/no_effect.rs
index 2e5195d459f..74536028b5d 100644
--- a/clippy_lints/src/no_effect.rs
+++ b/clippy_lints/src/no_effect.rs
@@ -159,8 +159,12 @@ impl NoEffect {
 
                                 // Remove `impl Future<Output = T>` to get `T`
                                 if cx.tcx.ty_is_opaque_future(ret_ty)
-                                    && let Some(true_ret_ty) =
-                                        cx.tcx.infer_ctxt().build(cx.typing_mode()).err_ctxt().get_impl_future_output_ty(ret_ty)
+                                    && let Some(true_ret_ty) = cx
+                                        .tcx
+                                        .infer_ctxt()
+                                        .build(cx.typing_mode())
+                                        .err_ctxt()
+                                        .get_impl_future_output_ty(ret_ty)
                                 {
                                     ret_ty = true_ret_ty;
                                 }
diff --git a/clippy_lints/src/no_mangle_with_rust_abi.rs b/clippy_lints/src/no_mangle_with_rust_abi.rs
index 8d5a523fd8f..64587e08ddc 100644
--- a/clippy_lints/src/no_mangle_with_rust_abi.rs
+++ b/clippy_lints/src/no_mangle_with_rust_abi.rs
@@ -1,5 +1,5 @@
 use clippy_utils::diagnostics::span_lint_and_then;
-use clippy_utils::source::snippet_with_applicability;
+use clippy_utils::source::{snippet, snippet_with_applicability};
 use rustc_errors::Applicability;
 use rustc_hir::{Item, ItemKind};
 use rustc_lint::{LateContext, LateLintPass};
@@ -18,13 +18,13 @@ declare_clippy_lint! {
     /// Rust ABI can break this at any point.
     ///
     /// ### Example
-    /// ```no_run
+    /// ```rust,ignore
     ///  #[no_mangle]
     ///  fn example(arg_one: u32, arg_two: usize) {}
     /// ```
     ///
     /// Use instead:
-    /// ```no_run
+    /// ```rust,ignore
     ///  #[no_mangle]
     ///  extern "C" fn example(arg_one: u32, arg_two: usize) {}
     /// ```
@@ -40,24 +40,25 @@ impl<'tcx> LateLintPass<'tcx> for NoMangleWithRustAbi {
         if let ItemKind::Fn(fn_sig, _, _) = &item.kind {
             let attrs = cx.tcx.hir().attrs(item.hir_id());
             let mut app = Applicability::MaybeIncorrect;
-            let snippet = snippet_with_applicability(cx, fn_sig.span, "..", &mut app);
+            let fn_snippet = snippet_with_applicability(cx, fn_sig.span.with_hi(item.ident.span.lo()), "..", &mut app);
             for attr in attrs {
                 if let Some(ident) = attr.ident()
                     && ident.name == rustc_span::sym::no_mangle
                     && fn_sig.header.abi == Abi::Rust
-                    && let Some((fn_attrs, _)) = snippet.split_once("fn")
+                    && let Some((fn_attrs, _)) = fn_snippet.rsplit_once("fn")
                     && !fn_attrs.contains("extern")
                 {
                     let sugg_span = fn_sig
                         .span
                         .with_lo(fn_sig.span.lo() + BytePos::from_usize(fn_attrs.len()))
                         .shrink_to_lo();
+                    let attr_snippet = snippet(cx, attr.span, "..");
 
                     span_lint_and_then(
                         cx,
                         NO_MANGLE_WITH_RUST_ABI,
                         fn_sig.span,
-                        "`#[no_mangle]` set on a function with the default (`Rust`) ABI",
+                        format!("`{attr_snippet}` set on a function with the default (`Rust`) ABI"),
                         |diag| {
                             diag.span_suggestion(sugg_span, "set an ABI", "extern \"C\" ", app)
                                 .span_suggestion(sugg_span, "or explicitly set the default", "extern \"Rust\" ", app);
diff --git a/clippy_lints/src/non_octal_unix_permissions.rs b/clippy_lints/src/non_octal_unix_permissions.rs
index 3f156aa5510..0caa19cd844 100644
--- a/clippy_lints/src/non_octal_unix_permissions.rs
+++ b/clippy_lints/src/non_octal_unix_permissions.rs
@@ -43,12 +43,12 @@ impl<'tcx> LateLintPass<'tcx> for NonOctalUnixPermissions {
         match &expr.kind {
             ExprKind::MethodCall(path, func, [param], _) => {
                 if let Some(adt) = cx.typeck_results().expr_ty(func).peel_refs().ty_adt_def()
-                    && ((path.ident.name == sym!(mode)
+                    && ((path.ident.name.as_str() == "mode"
                         && matches!(
                             cx.tcx.get_diagnostic_name(adt.did()),
                             Some(sym::FsOpenOptions | sym::DirBuilder)
                         ))
-                        || (path.ident.name == sym!(set_mode)
+                        || (path.ident.name.as_str() == "set_mode"
                             && cx.tcx.is_diagnostic_item(sym::FsPermissions, adt.did())))
                     && let ExprKind::Lit(_) = param.kind
                     && param.span.eq_ctxt(expr.span)
diff --git a/clippy_lints/src/operators/float_cmp.rs b/clippy_lints/src/operators/float_cmp.rs
index 8e394944c21..ab5f91c1d67 100644
--- a/clippy_lints/src/operators/float_cmp.rs
+++ b/clippy_lints/src/operators/float_cmp.rs
@@ -107,7 +107,7 @@ fn is_signum(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
     }
 
     if let ExprKind::MethodCall(method_name, self_arg, [], _) = expr.kind
-        && sym!(signum) == method_name.ident.name
+        && method_name.ident.name.as_str() == "signum"
     // Check that the receiver of the signum() is a float (expressions[0] is the receiver of
     // the method call)
     {
diff --git a/clippy_lints/src/partialeq_ne_impl.rs b/clippy_lints/src/partialeq_ne_impl.rs
index 18e6aad9c9a..794bef7b321 100644
--- a/clippy_lints/src/partialeq_ne_impl.rs
+++ b/clippy_lints/src/partialeq_ne_impl.rs
@@ -34,7 +34,7 @@ declare_lint_pass!(PartialEqNeImpl => [PARTIALEQ_NE_IMPL]);
 impl<'tcx> LateLintPass<'tcx> for PartialEqNeImpl {
     fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) {
         if let ItemKind::Impl(Impl {
-            of_trait: Some(ref trait_ref),
+            of_trait: Some(trait_ref),
             items: impl_items,
             ..
         }) = item.kind
diff --git a/clippy_lints/src/ptr_offset_with_cast.rs b/clippy_lints/src/ptr_offset_with_cast.rs
index 56d07aeae17..808a7e005c6 100644
--- a/clippy_lints/src/ptr_offset_with_cast.rs
+++ b/clippy_lints/src/ptr_offset_with_cast.rs
@@ -96,7 +96,7 @@ fn expr_as_ptr_offset_call<'tcx>(
             if path_segment.ident.name == sym::offset {
                 return Some((arg_0, arg_1, Method::Offset));
             }
-            if path_segment.ident.name == sym!(wrapping_offset) {
+            if path_segment.ident.name.as_str() == "wrapping_offset" {
                 return Some((arg_0, arg_1, Method::WrappingOffset));
             }
         }
diff --git a/clippy_lints/src/question_mark.rs b/clippy_lints/src/question_mark.rs
index 9344cb41993..cb374fcf20e 100644
--- a/clippy_lints/src/question_mark.rs
+++ b/clippy_lints/src/question_mark.rs
@@ -93,7 +93,7 @@ enum IfBlockType<'hir> {
 
 fn find_let_else_ret_expression<'hir>(block: &'hir Block<'hir>) -> Option<&'hir Expr<'hir>> {
     if let Block {
-        stmts: &[],
+        stmts: [],
         expr: Some(els),
         ..
     } = block
@@ -163,8 +163,8 @@ fn is_early_return(smbl: Symbol, cx: &LateContext<'_>, if_block: &IfBlockType<'_
             is_type_diagnostic_item(cx, caller_ty, smbl)
                 && expr_return_none_or_err(smbl, cx, if_then, caller, None)
                 && match smbl {
-                    sym::Option => call_sym == sym!(is_none),
-                    sym::Result => call_sym == sym!(is_err),
+                    sym::Option => call_sym.as_str() == "is_none",
+                    sym::Result => call_sym.as_str() == "is_err",
                     _ => false,
                 }
         },
diff --git a/clippy_lints/src/ref_option_ref.rs b/clippy_lints/src/ref_option_ref.rs
index 19ce08bde10..7d59bf24d93 100644
--- a/clippy_lints/src/ref_option_ref.rs
+++ b/clippy_lints/src/ref_option_ref.rs
@@ -39,7 +39,7 @@ impl<'tcx> LateLintPass<'tcx> for RefOptionRef {
     fn check_ty(&mut self, cx: &LateContext<'tcx>, ty: &'tcx Ty<'tcx>) {
         if let TyKind::Ref(_, ref mut_ty) = ty.kind
             && mut_ty.mutbl == Mutability::Not
-            && let TyKind::Path(ref qpath) = &mut_ty.ty.kind
+            && let TyKind::Path(qpath) = &mut_ty.ty.kind
             && let last = last_path_segment(qpath)
             && let Some(def_id) = last.res.opt_def_id()
             && cx.tcx.is_diagnostic_item(sym::Option, def_id)
diff --git a/clippy_lints/src/returns.rs b/clippy_lints/src/returns.rs
index 110dea8fb8e..1e0f6dff1ab 100644
--- a/clippy_lints/src/returns.rs
+++ b/clippy_lints/src/returns.rs
@@ -347,7 +347,7 @@ fn check_final_expr<'tcx>(
     let peeled_drop_expr = expr.peel_drop_temps();
     match &peeled_drop_expr.kind {
         // simple return is always "bad"
-        ExprKind::Ret(ref inner) => {
+        ExprKind::Ret(inner) => {
             // check if expr return nothing
             let ret_span = if inner.is_none() && replacement == RetReplacement::Empty {
                 extend_span_to_previous_non_ws(cx, peeled_drop_expr.span)
diff --git a/clippy_lints/src/semicolon_block.rs b/clippy_lints/src/semicolon_block.rs
index 09f1c112352..d85f4a8fa01 100644
--- a/clippy_lints/src/semicolon_block.rs
+++ b/clippy_lints/src/semicolon_block.rs
@@ -101,17 +101,21 @@ impl SemicolonBlock {
         );
     }
 
-    fn semicolon_outside_block(
-        &self,
-        cx: &LateContext<'_>,
-        block: &Block<'_>,
-        tail_stmt_expr: &Expr<'_>,
-        semi_span: Span,
-    ) {
+    fn semicolon_outside_block(&self, cx: &LateContext<'_>, block: &Block<'_>, tail_stmt_expr: &Expr<'_>) {
         let insert_span = block.span.with_lo(block.span.hi());
-        // account for macro calls
-        let semi_span = cx.sess().source_map().stmt_span(semi_span, block.span);
-        let remove_span = semi_span.with_lo(tail_stmt_expr.span.source_callsite().hi());
+
+        // For macro call semicolon statements (`mac!();`), the statement's span does not actually
+        // include the semicolon itself, so use `mac_call_stmt_semi_span`, which finds the semicolon
+        // based on a source snippet.
+        // (Does not use `stmt_span` as that requires `.from_expansion()` to return true,
+        // which is not the case for e.g. `line!();` and `asm!();`)
+        let Some(remove_span) = cx
+            .sess()
+            .source_map()
+            .mac_call_stmt_semi_span(tail_stmt_expr.span.source_callsite())
+        else {
+            return;
+        };
 
         if self.semicolon_outside_block_ignore_multiline && get_line(cx, remove_span) != get_line(cx, insert_span) {
             return;
@@ -150,13 +154,12 @@ impl LateLintPass<'_> for SemicolonBlock {
                 };
                 let &Stmt {
                     kind: StmtKind::Semi(expr),
-                    span,
                     ..
                 } = stmt
                 else {
                     return;
                 };
-                self.semicolon_outside_block(cx, block, expr, span);
+                self.semicolon_outside_block(cx, block, expr);
             },
             StmtKind::Semi(Expr {
                 kind: ExprKind::Block(block @ Block { expr: Some(tail), .. }, _),
diff --git a/clippy_lints/src/serde_api.rs b/clippy_lints/src/serde_api.rs
index fcf1c4cc5c2..6a0dfde2d9c 100644
--- a/clippy_lints/src/serde_api.rs
+++ b/clippy_lints/src/serde_api.rs
@@ -26,7 +26,7 @@ declare_lint_pass!(SerdeApi => [SERDE_API_MISUSE]);
 impl<'tcx> LateLintPass<'tcx> for SerdeApi {
     fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) {
         if let ItemKind::Impl(Impl {
-            of_trait: Some(ref trait_ref),
+            of_trait: Some(trait_ref),
             items,
             ..
         }) = item.kind
diff --git a/clippy_lints/src/single_component_path_imports.rs b/clippy_lints/src/single_component_path_imports.rs
index 9fdee8543a8..fa082453504 100644
--- a/clippy_lints/src/single_component_path_imports.rs
+++ b/clippy_lints/src/single_component_path_imports.rs
@@ -174,7 +174,7 @@ impl SingleComponentPathImports {
         }
 
         match &item.kind {
-            ItemKind::Mod(_, ModKind::Loaded(ref items, ..)) => {
+            ItemKind::Mod(_, ModKind::Loaded(items, ..)) => {
                 self.check_mod(items);
             },
             ItemKind::MacroDef(MacroDef { macro_rules: true, .. }) => {
diff --git a/clippy_lints/src/slow_vector_initialization.rs b/clippy_lints/src/slow_vector_initialization.rs
index ec6e45256d1..8c8f11569c8 100644
--- a/clippy_lints/src/slow_vector_initialization.rs
+++ b/clippy_lints/src/slow_vector_initialization.rs
@@ -235,7 +235,7 @@ impl<'tcx> VectorInitializationVisitor<'_, 'tcx> {
         if self.initialization_found
             && let ExprKind::MethodCall(path, self_arg, [extend_arg], _) = expr.kind
             && path_to_local_id(self_arg, self.vec_alloc.local_id)
-            && path.ident.name == sym!(extend)
+            && path.ident.name.as_str() == "extend"
             && self.is_repeat_take(extend_arg)
         {
             self.slow_expression = Some(InitializationType::Extend(expr));
@@ -247,7 +247,7 @@ impl<'tcx> VectorInitializationVisitor<'_, 'tcx> {
         if self.initialization_found
             && let ExprKind::MethodCall(path, self_arg, [len_arg, fill_arg], _) = expr.kind
             && path_to_local_id(self_arg, self.vec_alloc.local_id)
-            && path.ident.name == sym!(resize)
+            && path.ident.name.as_str() == "resize"
             // Check that is filled with 0
             && is_integer_literal(fill_arg, 0)
         {
@@ -269,7 +269,7 @@ impl<'tcx> VectorInitializationVisitor<'_, 'tcx> {
     /// Returns `true` if give expression is `repeat(0).take(...)`
     fn is_repeat_take(&mut self, expr: &'tcx Expr<'tcx>) -> bool {
         if let ExprKind::MethodCall(take_path, recv, [len_arg], _) = expr.kind
-            && take_path.ident.name == sym!(take)
+            && take_path.ident.name.as_str() == "take"
             // Check that take is applied to `repeat(0)`
             && self.is_repeat_zero(recv)
         {
diff --git a/clippy_lints/src/strings.rs b/clippy_lints/src/strings.rs
index bf49bb60162..e09c0706006 100644
--- a/clippy_lints/src/strings.rs
+++ b/clippy_lints/src/strings.rs
@@ -286,7 +286,7 @@ impl<'tcx> LateLintPass<'tcx> for StringLitAsBytes {
 
         if !in_external_macro(cx.sess(), e.span)
             && let ExprKind::MethodCall(path, receiver, ..) = &e.kind
-            && path.ident.name == sym!(as_bytes)
+            && path.ident.name.as_str() == "as_bytes"
             && let ExprKind::Lit(lit) = &receiver.kind
             && let LitKind::Str(lit_content, _) = &lit.node
         {
@@ -332,7 +332,7 @@ impl<'tcx> LateLintPass<'tcx> for StringLitAsBytes {
         }
 
         if let ExprKind::MethodCall(path, recv, [], _) = &e.kind
-            && path.ident.name == sym!(into_bytes)
+            && path.ident.name.as_str() == "into_bytes"
             && let ExprKind::MethodCall(path, recv, [], _) = &recv.kind
             && matches!(path.ident.name.as_str(), "to_owned" | "to_string")
             && let ExprKind::Lit(lit) = &recv.kind
@@ -493,7 +493,7 @@ impl<'tcx> LateLintPass<'tcx> for TrimSplitWhitespace {
     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &Expr<'_>) {
         let tyckres = cx.typeck_results();
         if let ExprKind::MethodCall(path, split_recv, [], split_ws_span) = expr.kind
-            && path.ident.name == sym!(split_whitespace)
+            && path.ident.name.as_str() == "split_whitespace"
             && let Some(split_ws_def_id) = tyckres.type_dependent_def_id(expr.hir_id)
             && cx.tcx.is_diagnostic_item(sym::str_split_whitespace, split_ws_def_id)
             && let ExprKind::MethodCall(path, _trim_recv, [], trim_span) = split_recv.kind
diff --git a/clippy_lints/src/suspicious_operation_groupings.rs b/clippy_lints/src/suspicious_operation_groupings.rs
index be32dc0aab0..0d809c17989 100644
--- a/clippy_lints/src/suspicious_operation_groupings.rs
+++ b/clippy_lints/src/suspicious_operation_groupings.rs
@@ -334,7 +334,7 @@ fn strip_non_ident_wrappers(expr: &Expr) -> &Expr {
     let mut output = expr;
     loop {
         output = match &output.kind {
-            ExprKind::Paren(ref inner) | ExprKind::Unary(_, ref inner) => inner,
+            ExprKind::Paren(inner) | ExprKind::Unary(_, inner) => inner,
             _ => {
                 return output;
             },
@@ -348,13 +348,13 @@ fn extract_related_binops(kind: &ExprKind) -> Option<Vec<BinaryOp<'_>>> {
 
 fn if_statement_binops(kind: &ExprKind) -> Option<Vec<BinaryOp<'_>>> {
     match kind {
-        ExprKind::If(ref condition, _, _) => chained_binops(&condition.kind),
-        ExprKind::Paren(ref e) => if_statement_binops(&e.kind),
-        ExprKind::Block(ref block, _) => {
+        ExprKind::If(condition, _, _) => chained_binops(&condition.kind),
+        ExprKind::Paren(e) => if_statement_binops(&e.kind),
+        ExprKind::Block(block, _) => {
             let mut output = None;
             for stmt in &block.stmts {
-                match stmt.kind {
-                    StmtKind::Expr(ref e) | StmtKind::Semi(ref e) => {
+                match &stmt.kind {
+                    StmtKind::Expr(e) | StmtKind::Semi(e) => {
                         output = append_opt_vecs(output, if_statement_binops(&e.kind));
                     },
                     _ => {},
@@ -383,7 +383,7 @@ fn append_opt_vecs<A>(target_opt: Option<Vec<A>>, source_opt: Option<Vec<A>>) ->
 fn chained_binops(kind: &ExprKind) -> Option<Vec<BinaryOp<'_>>> {
     match kind {
         ExprKind::Binary(_, left_outer, right_outer) => chained_binops_helper(left_outer, right_outer),
-        ExprKind::Paren(ref e) | ExprKind::Unary(_, ref e) => chained_binops(&e.kind),
+        ExprKind::Paren(e) | ExprKind::Unary(_, e) => chained_binops(&e.kind),
         _ => None,
     }
 }
@@ -391,16 +391,14 @@ fn chained_binops(kind: &ExprKind) -> Option<Vec<BinaryOp<'_>>> {
 fn chained_binops_helper<'expr>(left_outer: &'expr Expr, right_outer: &'expr Expr) -> Option<Vec<BinaryOp<'expr>>> {
     match (&left_outer.kind, &right_outer.kind) {
         (
-            ExprKind::Paren(ref left_e) | ExprKind::Unary(_, ref left_e),
-            ExprKind::Paren(ref right_e) | ExprKind::Unary(_, ref right_e),
+            ExprKind::Paren(left_e) | ExprKind::Unary(_, left_e),
+            ExprKind::Paren(right_e) | ExprKind::Unary(_, right_e),
         ) => chained_binops_helper(left_e, right_e),
-        (ExprKind::Paren(ref left_e) | ExprKind::Unary(_, ref left_e), _) => chained_binops_helper(left_e, right_outer),
-        (_, ExprKind::Paren(ref right_e) | ExprKind::Unary(_, ref right_e)) => {
-            chained_binops_helper(left_outer, right_e)
-        },
+        (ExprKind::Paren(left_e) | ExprKind::Unary(_, left_e), _) => chained_binops_helper(left_e, right_outer),
+        (_, ExprKind::Paren(right_e) | ExprKind::Unary(_, right_e)) => chained_binops_helper(left_outer, right_e),
         (
-            ExprKind::Binary(Spanned { node: left_op, .. }, ref left_left, ref left_right),
-            ExprKind::Binary(Spanned { node: right_op, .. }, ref right_left, ref right_right),
+            ExprKind::Binary(Spanned { node: left_op, .. }, left_left, left_right),
+            ExprKind::Binary(Spanned { node: right_op, .. }, right_left, right_right),
         ) => match (
             chained_binops_helper(left_left, left_right),
             chained_binops_helper(right_left, right_right),
diff --git a/clippy_lints/src/swap.rs b/clippy_lints/src/swap.rs
index 6cba560393d..23362506cca 100644
--- a/clippy_lints/src/swap.rs
+++ b/clippy_lints/src/swap.rs
@@ -392,7 +392,7 @@ impl<'tcx> IndexBinding<'_, 'tcx> {
         for stmt in self.block.stmts {
             match stmt.kind {
                 StmtKind::Expr(expr) | StmtKind::Semi(expr) => v.visit_expr(expr),
-                StmtKind::Let(LetStmt { ref init, .. }) => {
+                StmtKind::Let(LetStmt { init, .. }) => {
                     if let Some(init) = init.as_ref() {
                         v.visit_expr(init);
                     }
diff --git a/clippy_lints/src/trait_bounds.rs b/clippy_lints/src/trait_bounds.rs
index 3da4bf67558..07bf4319ff0 100644
--- a/clippy_lints/src/trait_bounds.rs
+++ b/clippy_lints/src/trait_bounds.rs
@@ -10,8 +10,8 @@ use rustc_data_structures::unhash::UnhashMap;
 use rustc_errors::Applicability;
 use rustc_hir::def::Res;
 use rustc_hir::{
-    GenericBound, Generics, Item, ItemKind, LangItem, Node, Path, PathSegment, PredicateOrigin, QPath,
-    TraitBoundModifiers, TraitItem, TraitRef, Ty, TyKind, WherePredicate, BoundPolarity,
+    BoundPolarity, GenericBound, Generics, Item, ItemKind, LangItem, Node, Path, PathSegment, PredicateOrigin, QPath,
+    TraitBoundModifiers, TraitItem, TraitRef, Ty, TyKind, WherePredicate,
 };
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_session::impl_lint_pass;
@@ -124,7 +124,7 @@ impl<'tcx> LateLintPass<'tcx> for TraitBounds {
         let mut self_bounds_map = FxHashMap::default();
 
         for predicate in item.generics.predicates {
-            if let WherePredicate::BoundPredicate(ref bound_predicate) = predicate
+            if let WherePredicate::BoundPredicate(bound_predicate) = predicate
                 && bound_predicate.origin != PredicateOrigin::ImplTrait
                 && !bound_predicate.span.from_expansion()
                 && let TyKind::Path(QPath::Resolved(_, Path { segments, .. })) = bound_predicate.bounded_ty.kind
@@ -268,7 +268,7 @@ impl TraitBounds {
         let mut map: UnhashMap<SpanlessTy<'_, '_>, Vec<&GenericBound<'_>>> = UnhashMap::default();
         let mut applicability = Applicability::MaybeIncorrect;
         for bound in generics.predicates {
-            if let WherePredicate::BoundPredicate(ref p) = bound
+            if let WherePredicate::BoundPredicate(p) = bound
                 && p.origin != PredicateOrigin::ImplTrait
                 && p.bounds.len() as u64 <= self.max_trait_bounds
                 && !p.span.from_expansion()
@@ -379,7 +379,7 @@ struct ComparableTraitRef<'a, 'tcx> {
 
 impl PartialEq for ComparableTraitRef<'_, '_> {
     fn eq(&self, other: &Self) -> bool {
-        SpanlessEq::new(self.cx).eq_modifiers(self.modifiers, other.modifiers)
+        SpanlessEq::eq_modifiers(self.modifiers, other.modifiers)
             && SpanlessEq::new(self.cx)
                 .paths_by_resolution()
                 .eq_path(self.trait_ref.path, other.trait_ref.path)
diff --git a/clippy_lints/src/transmute/eager_transmute.rs b/clippy_lints/src/transmute/eager_transmute.rs
index 1dfc9f7091e..ca9daf2d2a0 100644
--- a/clippy_lints/src/transmute/eager_transmute.rs
+++ b/clippy_lints/src/transmute/eager_transmute.rs
@@ -43,7 +43,7 @@ fn binops_with_local(cx: &LateContext<'_>, local_expr: &Expr<'_>, expr: &Expr<'_
             binops_with_local(cx, local_expr, lhs) || binops_with_local(cx, local_expr, rhs)
         },
         ExprKind::MethodCall(path, receiver, [arg], _)
-            if path.ident.name == sym!(contains)
+            if path.ident.name.as_str() == "contains"
                 // ... `contains` called on some kind of range
                 && let Some(receiver_adt) = cx.typeck_results().expr_ty(receiver).peel_refs().ty_adt_def()
                 && let lang_items = cx.tcx.lang_items()
@@ -81,7 +81,7 @@ pub(super) fn check<'tcx>(
     if let Some(then_some_call) = peel_parent_unsafe_blocks(cx, expr)
         && let ExprKind::MethodCall(path, receiver, [arg], _) = then_some_call.kind
         && cx.typeck_results().expr_ty(receiver).is_bool()
-        && path.ident.name == sym!(then_some)
+        && path.ident.name.as_str() == "then_some"
         && is_local_with_projections(transmutable)
         && binops_with_local(cx, transmutable, receiver)
         && is_normalizable(cx, cx.param_env, from_ty)
diff --git a/clippy_lints/src/undocumented_unsafe_blocks.rs b/clippy_lints/src/undocumented_unsafe_blocks.rs
index 44eb0a6c593..0bba611116b 100644
--- a/clippy_lints/src/undocumented_unsafe_blocks.rs
+++ b/clippy_lints/src/undocumented_unsafe_blocks.rs
@@ -295,7 +295,7 @@ fn expr_has_unnecessary_safety_comment<'tcx>(
     if cx.tcx.hir().parent_iter(expr.hir_id).any(|(_, ref node)| {
         matches!(
             node,
-            Node::Block(&Block {
+            Node::Block(Block {
                 rules: BlockCheckMode::UnsafeBlock(UnsafeSource::UserProvided),
                 ..
             }),
diff --git a/clippy_lints/src/unit_types/let_unit_value.rs b/clippy_lints/src/unit_types/let_unit_value.rs
index bf2d75ea1a9..1a1284ce9c4 100644
--- a/clippy_lints/src/unit_types/let_unit_value.rs
+++ b/clippy_lints/src/unit_types/let_unit_value.rs
@@ -194,7 +194,7 @@ fn needs_inferred_result_ty(
     let (id, receiver, args) = match e.kind {
         ExprKind::Call(
             Expr {
-                kind: ExprKind::Path(ref path),
+                kind: ExprKind::Path(path),
                 hir_id,
                 ..
             },
diff --git a/clippy_lints/src/unit_types/unit_arg.rs b/clippy_lints/src/unit_types/unit_arg.rs
index e7d26fa238e..0f4bd286145 100644
--- a/clippy_lints/src/unit_types/unit_arg.rs
+++ b/clippy_lints/src/unit_types/unit_arg.rs
@@ -149,7 +149,7 @@ fn is_empty_block(expr: &Expr<'_>) -> bool {
         expr.kind,
         ExprKind::Block(
             Block {
-                stmts: &[],
+                stmts: [],
                 expr: None,
                 ..
             },
diff --git a/clippy_lints/src/unused_io_amount.rs b/clippy_lints/src/unused_io_amount.rs
index cf406b817da..7c9455bf8ab 100644
--- a/clippy_lints/src/unused_io_amount.rs
+++ b/clippy_lints/src/unused_io_amount.rs
@@ -1,6 +1,6 @@
 use clippy_utils::diagnostics::span_lint_hir_and_then;
 use clippy_utils::macros::{is_panic, root_macro_call_first_node};
-use clippy_utils::{is_res_lang_ctor, is_trait_method, match_trait_method, paths, peel_blocks};
+use clippy_utils::{is_res_lang_ctor, is_trait_method, match_def_path, match_trait_method, paths, peel_blocks};
 use hir::{ExprKind, HirId, PatKind};
 use rustc_hir as hir;
 use rustc_lint::{LateContext, LateLintPass};
@@ -83,6 +83,28 @@ impl<'tcx> LateLintPass<'tcx> for UnusedIoAmount {
     /// to consider the arms, and we want to avoid breaking the logic for situations where things
     /// get desugared to match.
     fn check_block(&mut self, cx: &LateContext<'tcx>, block: &'tcx hir::Block<'tcx>) {
+        let fn_def_id = block.hir_id.owner.to_def_id();
+        if let Some(impl_id) = cx.tcx.impl_of_method(fn_def_id)
+            && let Some(trait_id) = cx.tcx.trait_id_of_impl(impl_id)
+        {
+            // We don't want to lint inside io::Read or io::Write implementations, as the author has more
+            // information about their trait implementation than our lint, see https://github.com/rust-lang/rust-clippy/issues/4836
+            if cx.tcx.is_diagnostic_item(sym::IoRead, trait_id) || cx.tcx.is_diagnostic_item(sym::IoWrite, trait_id) {
+                return;
+            }
+
+            let async_paths: [&[&str]; 4] = [
+                &paths::TOKIO_IO_ASYNCREADEXT,
+                &paths::TOKIO_IO_ASYNCWRITEEXT,
+                &paths::FUTURES_IO_ASYNCREADEXT,
+                &paths::FUTURES_IO_ASYNCWRITEEXT,
+            ];
+
+            if async_paths.into_iter().any(|path| match_def_path(cx, trait_id, path)) {
+                return;
+            }
+        }
+
         for stmt in block.stmts {
             if let hir::StmtKind::Semi(exp) = stmt.kind {
                 check_expr(cx, exp);
@@ -222,7 +244,7 @@ fn unpack_call_chain<'a>(mut expr: &'a hir::Expr<'a>) -> &'a hir::Expr<'a> {
 }
 
 fn unpack_try<'a>(mut expr: &'a hir::Expr<'a>) -> &'a hir::Expr<'a> {
-    while let ExprKind::Call(func, [ref arg_0]) = expr.kind
+    while let ExprKind::Call(func, [arg_0]) = expr.kind
         && matches!(
             func.kind,
             ExprKind::Path(hir::QPath::LangItem(hir::LangItem::TryTraitBranch, ..))
@@ -244,7 +266,7 @@ fn unpack_match<'a>(mut expr: &'a hir::Expr<'a>) -> &'a hir::Expr<'a> {
 /// waited on.  Otherwise return None.
 fn unpack_await<'a>(expr: &'a hir::Expr<'a>) -> &'a hir::Expr<'a> {
     if let ExprKind::Match(expr, _, hir::MatchSource::AwaitDesugar) = expr.kind {
-        if let ExprKind::Call(func, [ref arg_0]) = expr.kind {
+        if let ExprKind::Call(func, [arg_0]) = expr.kind {
             if matches!(
                 func.kind,
                 ExprKind::Path(hir::QPath::LangItem(hir::LangItem::IntoFutureIntoFuture, ..))
diff --git a/clippy_lints/src/utils/attr_collector.rs b/clippy_lints/src/utils/attr_collector.rs
new file mode 100644
index 00000000000..1522553bbf5
--- /dev/null
+++ b/clippy_lints/src/utils/attr_collector.rs
@@ -0,0 +1,40 @@
+use std::mem;
+use std::sync::OnceLock;
+
+use rustc_ast::{Attribute, Crate};
+use rustc_data_structures::sync::Lrc;
+use rustc_lint::{EarlyContext, EarlyLintPass};
+use rustc_session::impl_lint_pass;
+use rustc_span::Span;
+
+#[derive(Clone, Default)]
+pub struct AttrStorage(pub Lrc<OnceLock<Vec<Span>>>);
+
+pub struct AttrCollector {
+    storage: AttrStorage,
+    attrs: Vec<Span>,
+}
+
+impl AttrCollector {
+    pub fn new(storage: AttrStorage) -> Self {
+        Self {
+            storage,
+            attrs: Vec::new(),
+        }
+    }
+}
+
+impl_lint_pass!(AttrCollector => []);
+
+impl EarlyLintPass for AttrCollector {
+    fn check_attribute(&mut self, _cx: &EarlyContext<'_>, attr: &Attribute) {
+        self.attrs.push(attr.span);
+    }
+
+    fn check_crate_post(&mut self, _: &EarlyContext<'_>, _: &Crate) {
+        self.storage
+            .0
+            .set(mem::take(&mut self.attrs))
+            .expect("should only be called once");
+    }
+}
diff --git a/clippy_lints/src/utils/author.rs b/clippy_lints/src/utils/author.rs
index 31f9d84f5e4..1bf24083665 100644
--- a/clippy_lints/src/utils/author.rs
+++ b/clippy_lints/src/utils/author.rs
@@ -396,7 +396,7 @@ impl<'a, 'tcx> PrintVisitor<'a, 'tcx> {
                 self.pat(field!(let_expr.pat));
                 // Does what ExprKind::Cast does, only adds a clause for the type
                 // if it's a path
-                if let Some(TyKind::Path(ref qpath)) = let_expr.value.ty.as_ref().map(|ty| &ty.kind) {
+                if let Some(TyKind::Path(qpath)) = let_expr.value.ty.as_ref().map(|ty| &ty.kind) {
                     bind!(self, qpath);
                     chain!(self, "let TyKind::Path(ref {qpath}) = {let_expr}.ty.kind");
                     self.qpath(qpath);
diff --git a/clippy_lints/src/utils/internal_lints.rs b/clippy_lints/src/utils/internal_lints.rs
index f662c7651f6..deb983b6971 100644
--- a/clippy_lints/src/utils/internal_lints.rs
+++ b/clippy_lints/src/utils/internal_lints.rs
@@ -6,5 +6,6 @@ pub mod lint_without_lint_pass;
 pub mod msrv_attr_impl;
 pub mod outer_expn_data_pass;
 pub mod produce_ice;
+pub mod slow_symbol_comparisons;
 pub mod unnecessary_def_path;
 pub mod unsorted_clippy_utils_paths;
diff --git a/clippy_lints/src/utils/internal_lints/collapsible_calls.rs b/clippy_lints/src/utils/internal_lints/collapsible_calls.rs
index a3f9abe4f96..eaeb754a23f 100644
--- a/clippy_lints/src/utils/internal_lints/collapsible_calls.rs
+++ b/clippy_lints/src/utils/internal_lints/collapsible_calls.rs
@@ -79,7 +79,7 @@ impl<'tcx> LateLintPass<'tcx> for CollapsibleCalls {
 
         if let ExprKind::Call(func, [call_cx, call_lint, call_sp, call_msg, call_f]) = expr.kind
             && is_expr_path_def_path(cx, func, &["clippy_utils", "diagnostics", "span_lint_and_then"])
-            && let ExprKind::Closure(&Closure { body, .. }) = &call_f.kind
+            && let ExprKind::Closure(&Closure { body, .. }) = call_f.kind
             && let body = cx.tcx.hir().body(body)
             && let only_expr = peel_blocks_with_stmt(body.value)
             && let ExprKind::MethodCall(ps, recv, span_call_args, _) = &only_expr.kind
diff --git a/clippy_lints/src/utils/internal_lints/lint_without_lint_pass.rs b/clippy_lints/src/utils/internal_lints/lint_without_lint_pass.rs
index 51235de9f29..af38e066559 100644
--- a/clippy_lints/src/utils/internal_lints/lint_without_lint_pass.rs
+++ b/clippy_lints/src/utils/internal_lints/lint_without_lint_pass.rs
@@ -21,7 +21,7 @@ declare_clippy_lint! {
     ///
     /// ### Why is this bad?
     /// The compiler only knows lints via a `LintPass`. Without
-    /// putting a lint to a `LintPass::get_lints()`'s return, the compiler will not
+    /// putting a lint to a `LintPass::lint_vec()`'s return, the compiler will not
     /// know the name of the lint.
     ///
     /// ### Known problems
@@ -123,7 +123,7 @@ impl<'tcx> LateLintPass<'tcx> for LintWithoutLintPass {
                     .expect("lints must have a description field");
 
                 if let ExprKind::Lit(Spanned {
-                    node: LitKind::Str(ref sym, _),
+                    node: LitKind::Str(sym, _),
                     ..
                 }) = field.expr.kind
                 {
@@ -159,8 +159,8 @@ impl<'tcx> LateLintPass<'tcx> for LintWithoutLintPass {
                 let body = cx.tcx.hir().body_owned_by(
                     impl_item_refs
                         .iter()
-                        .find(|iiref| iiref.ident.as_str() == "get_lints")
-                        .expect("LintPass needs to implement get_lints")
+                        .find(|iiref| iiref.ident.as_str() == "lint_vec")
+                        .expect("LintPass needs to implement lint_vec")
                         .id
                         .owner_id
                         .def_id,
@@ -218,9 +218,7 @@ pub(super) fn is_lint_ref_type(cx: &LateContext<'_>, ty: &hir::Ty<'_>) -> bool {
 
 fn check_invalid_clippy_version_attribute(cx: &LateContext<'_>, item: &'_ Item<'_>) {
     if let Some(value) = extract_clippy_version_value(cx, item) {
-        // The `sym!` macro doesn't work as it only expects a single token.
-        // It's better to keep it this way and have a direct `Symbol::intern` call here.
-        if value == Symbol::intern("pre 1.29.0") {
+        if value.as_str() == "pre 1.29.0" {
             return;
         }
 
@@ -251,7 +249,7 @@ fn check_invalid_clippy_version_attribute(cx: &LateContext<'_>, item: &'_ Item<'
 pub(super) fn extract_clippy_version_value(cx: &LateContext<'_>, item: &'_ Item<'_>) -> Option<Symbol> {
     let attrs = cx.tcx.hir().attrs(item.hir_id());
     attrs.iter().find_map(|attr| {
-        if let ast::AttrKind::Normal(ref attr_kind) = &attr.kind
+        if let ast::AttrKind::Normal(attr_kind) = &attr.kind
             // Identify attribute
             && let [tool_name, attr_name] = &attr_kind.item.path.segments[..]
             && tool_name.ident.name == sym::clippy
diff --git a/clippy_lints/src/utils/internal_lints/msrv_attr_impl.rs b/clippy_lints/src/utils/internal_lints/msrv_attr_impl.rs
index 63fcbd61528..68692246153 100644
--- a/clippy_lints/src/utils/internal_lints/msrv_attr_impl.rs
+++ b/clippy_lints/src/utils/internal_lints/msrv_attr_impl.rs
@@ -42,7 +42,7 @@ impl LateLintPass<'_> for MsrvAttrImpl {
                     .filter(|t| matches!(t.unpack(), GenericArgKind::Type(_)))
                     .any(|t| match_type(cx, t.expect_ty(), &paths::MSRV))
             })
-            && !items.iter().any(|item| item.ident.name == sym!(check_attributes))
+            && !items.iter().any(|item| item.ident.name.as_str() == "check_attributes")
         {
             let context = if is_late_pass { "LateContext" } else { "EarlyContext" };
             let lint_pass = if is_late_pass { "LateLintPass" } else { "EarlyLintPass" };
diff --git a/clippy_lints/src/utils/internal_lints/slow_symbol_comparisons.rs b/clippy_lints/src/utils/internal_lints/slow_symbol_comparisons.rs
new file mode 100644
index 00000000000..3742be0e103
--- /dev/null
+++ b/clippy_lints/src/utils/internal_lints/slow_symbol_comparisons.rs
@@ -0,0 +1,69 @@
+use clippy_utils::consts::{ConstEvalCtxt, Constant};
+use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::source::snippet_with_applicability;
+use clippy_utils::ty::match_type;
+use clippy_utils::{match_function_call, paths};
+use rustc_errors::Applicability;
+use rustc_hir::{BinOpKind, Expr, ExprKind};
+use rustc_lint::{LateContext, LateLintPass};
+use rustc_session::declare_lint_pass;
+use rustc_span::Span;
+
+declare_clippy_lint! {
+    /// ### What it does
+    ///
+    /// Detects symbol comparision using `Symbol::intern`.
+    ///
+    /// ### Why is this bad?
+    ///
+    /// Comparision via `Symbol::as_str()` is faster if the interned symbols are not reused.
+    ///
+    /// ### Example
+    ///
+    /// None, see suggestion.
+    pub SLOW_SYMBOL_COMPARISONS,
+    internal,
+    "detects slow comparisions of symbol"
+}
+
+declare_lint_pass!(SlowSymbolComparisons => [SLOW_SYMBOL_COMPARISONS]);
+
+fn check_slow_comparison<'tcx>(
+    cx: &LateContext<'tcx>,
+    op1: &'tcx Expr<'tcx>,
+    op2: &'tcx Expr<'tcx>,
+) -> Option<(Span, String)> {
+    if match_type(cx, cx.typeck_results().expr_ty(op1), &paths::SYMBOL)
+        && let Some([symbol_name_expr]) = match_function_call(cx, op2, &paths::SYMBOL_INTERN)
+        && let Some(Constant::Str(symbol_name)) = ConstEvalCtxt::new(cx).eval_simple(symbol_name_expr)
+    {
+        Some((op1.span, symbol_name))
+    } else {
+        None
+    }
+}
+
+impl<'tcx> LateLintPass<'tcx> for SlowSymbolComparisons {
+    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &Expr<'tcx>) {
+        if let ExprKind::Binary(op, left, right) = expr.kind
+            && (op.node == BinOpKind::Eq || op.node == BinOpKind::Ne)
+            && let Some((symbol_span, symbol_name)) =
+                check_slow_comparison(cx, left, right).or_else(|| check_slow_comparison(cx, right, left))
+        {
+            let mut applicability = Applicability::MachineApplicable;
+            span_lint_and_sugg(
+                cx,
+                SLOW_SYMBOL_COMPARISONS,
+                expr.span,
+                "comparing `Symbol` via `Symbol::intern`",
+                "use `Symbol::as_str` and check the string instead",
+                format!(
+                    "{}.as_str() {} \"{symbol_name}\"",
+                    snippet_with_applicability(cx, symbol_span, "symbol", &mut applicability),
+                    op.node.as_str()
+                ),
+                applicability,
+            );
+        };
+    }
+}
diff --git a/clippy_lints/src/utils/mod.rs b/clippy_lints/src/utils/mod.rs
index 13e9ead9a57..4476cd1005e 100644
--- a/clippy_lints/src/utils/mod.rs
+++ b/clippy_lints/src/utils/mod.rs
@@ -1,5 +1,7 @@
+pub mod attr_collector;
 pub mod author;
 pub mod dump_hir;
 pub mod format_args_collector;
+
 #[cfg(feature = "internal")]
 pub mod internal_lints;