about summary refs log tree commit diff
diff options
context:
space:
mode:
authorPhilipp Krones <hello@philkrones.com>2025-05-01 10:22:55 +0200
committerPhilipp Krones <hello@philkrones.com>2025-05-01 10:22:55 +0200
commitc9992d6c54e2221b05655f22056f2e097913d5fc (patch)
tree3b532599de30119ceabe824d549120b1110f3bd7
parent6e23095adf9209614a45f7f75fea36dad7b92afb (diff)
parent03a5b6b976ac121f4233775c49a4bce026065b47 (diff)
downloadrust-c9992d6c54e2221b05655f22056f2e097913d5fc.tar.gz
rust-c9992d6c54e2221b05655f22056f2e097913d5fc.zip
Merge commit '03a5b6b976ac121f4233775c49a4bce026065b47' into clippy-subtree-update
-rw-r--r--src/tools/clippy/clippy_lints/src/assigning_clones.rs11
-rw-r--r--src/tools/clippy/clippy_lints/src/attrs/blanket_clippy_restriction_lints.rs8
-rw-r--r--src/tools/clippy/clippy_lints/src/attrs/deprecated_cfg_attr.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/attrs/deprecated_semver.rs3
-rw-r--r--src/tools/clippy/clippy_lints/src/casts/cast_abs_to_unsigned.rs3
-rw-r--r--src/tools/clippy/clippy_lints/src/casts/cast_possible_truncation.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/casts/cast_ptr_alignment.rs5
-rw-r--r--src/tools/clippy/clippy_lints/src/casts/unnecessary_cast.rs55
-rw-r--r--src/tools/clippy/clippy_lints/src/crate_in_macro_def.rs5
-rw-r--r--src/tools/clippy/clippy_lints/src/equatable_if_let.rs34
-rw-r--r--src/tools/clippy/clippy_lints/src/floating_point_arithmetic.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/from_raw_with_void_ptr.rs5
-rw-r--r--src/tools/clippy/clippy_lints/src/from_str_radix_10.rs5
-rw-r--r--src/tools/clippy/clippy_lints/src/implicit_hasher.rs21
-rw-r--r--src/tools/clippy/clippy_lints/src/infinite_iter.rs9
-rw-r--r--src/tools/clippy/clippy_lints/src/iter_without_into_iter.rs5
-rw-r--r--src/tools/clippy/clippy_lints/src/len_zero.rs8
-rw-r--r--src/tools/clippy/clippy_lints/src/lib.rs1
-rw-r--r--src/tools/clippy/clippy_lints/src/loops/same_item_push.rs5
-rw-r--r--src/tools/clippy/clippy_lints/src/manual_div_ceil.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/manual_hash_one.rs7
-rw-r--r--src/tools/clippy/clippy_lints/src/manual_is_ascii_check.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/manual_option_as_slice.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/double_ended_iterator_last.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/filter_map.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/mod.rs5
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/needless_character_iteration.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/needless_collect.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/read_line_without_trim.rs7
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/return_and_then.rs11
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/str_split.rs3
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/unnecessary_filter_map.rs5
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/unnecessary_to_owned.rs12
-rw-r--r--src/tools/clippy/clippy_lints/src/minmax.rs13
-rw-r--r--src/tools/clippy/clippy_lints/src/missing_fields_in_debug.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/mixed_read_write_in_expression.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/needless_for_each.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/needless_question_mark.rs70
-rw-r--r--src/tools/clippy/clippy_lints/src/non_octal_unix_permissions.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/non_zero_suggestions.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/operators/float_cmp.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/permissions_set_readonly_false.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/ptr.rs22
-rw-r--r--src/tools/clippy/clippy_lints/src/ptr_offset_with_cast.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/question_mark.rs15
-rw-r--r--src/tools/clippy/clippy_lints/src/question_mark_used.rs18
-rw-r--r--src/tools/clippy/clippy_lints/src/slow_vector_initialization.rs9
-rw-r--r--src/tools/clippy/clippy_lints/src/strings.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/to_digit_is_some.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/transmute/eager_transmute.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/types/vec_box.rs105
-rw-r--r--src/tools/clippy/clippy_lints/src/uninit_vec.rs8
-rw-r--r--src/tools/clippy/clippy_lints/src/unused_self.rs11
-rw-r--r--src/tools/clippy/clippy_lints/src/unused_unit.rs155
-rw-r--r--src/tools/clippy/clippy_lints/src/unwrap.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/write.rs12
-rw-r--r--src/tools/clippy/clippy_lints/src/zombie_processes.rs5
-rw-r--r--src/tools/clippy/clippy_lints_internal/src/lib.rs8
-rw-r--r--src/tools/clippy/clippy_lints_internal/src/symbols.rs (renamed from src/tools/clippy/clippy_lints_internal/src/interning_literals.rs)99
-rw-r--r--src/tools/clippy/clippy_utils/README.md2
-rw-r--r--src/tools/clippy/clippy_utils/src/higher.rs6
-rw-r--r--src/tools/clippy/clippy_utils/src/hir_utils.rs4
-rw-r--r--src/tools/clippy/clippy_utils/src/lib.rs9
-rw-r--r--src/tools/clippy/clippy_utils/src/sym.rs44
-rw-r--r--src/tools/clippy/rust-toolchain.toml2
-rw-r--r--src/tools/clippy/tests/ui-internal/symbol_as_str.fixed21
-rw-r--r--src/tools/clippy/tests/ui-internal/symbol_as_str.rs21
-rw-r--r--src/tools/clippy/tests/ui-internal/symbol_as_str.stderr76
-rw-r--r--src/tools/clippy/tests/ui-internal/symbol_as_str_unfixable.rs15
-rw-r--r--src/tools/clippy/tests/ui-internal/symbol_as_str_unfixable.stderr40
-rw-r--r--src/tools/clippy/tests/ui/blocks_in_conditions.fixed1
-rw-r--r--src/tools/clippy/tests/ui/blocks_in_conditions.rs1
-rw-r--r--src/tools/clippy/tests/ui/blocks_in_conditions.stderr6
-rw-r--r--src/tools/clippy/tests/ui/equatable_if_let.fixed36
-rw-r--r--src/tools/clippy/tests/ui/equatable_if_let.rs36
-rw-r--r--src/tools/clippy/tests/ui/equatable_if_let.stderr20
-rw-r--r--src/tools/clippy/tests/ui/manual_div_ceil.fixed23
-rw-r--r--src/tools/clippy/tests/ui/manual_div_ceil.rs23
-rw-r--r--src/tools/clippy/tests/ui/manual_div_ceil.stderr62
-rw-r--r--src/tools/clippy/tests/ui/needless_if.fixed4
-rw-r--r--src/tools/clippy/tests/ui/needless_if.rs4
-rw-r--r--src/tools/clippy/tests/ui/needless_if.stderr8
-rw-r--r--src/tools/clippy/tests/ui/needless_late_init.fixed4
-rw-r--r--src/tools/clippy/tests/ui/needless_late_init.rs4
-rw-r--r--src/tools/clippy/tests/ui/needless_late_init.stderr2
-rw-r--r--src/tools/clippy/tests/ui/needless_question_mark.stderr148
-rw-r--r--src/tools/clippy/tests/ui/ptr_eq.fixed28
-rw-r--r--src/tools/clippy/tests/ui/ptr_eq.rs18
-rw-r--r--src/tools/clippy/tests/ui/ptr_eq.stderr38
-rw-r--r--src/tools/clippy/tests/ui/ptr_eq_no_std.fixed20
-rw-r--r--src/tools/clippy/tests/ui/ptr_eq_no_std.rs12
-rw-r--r--src/tools/clippy/tests/ui/ptr_eq_no_std.stderr26
-rw-r--r--src/tools/clippy/tests/ui/question_mark.fixed5
-rw-r--r--src/tools/clippy/tests/ui/question_mark.rs5
-rw-r--r--src/tools/clippy/tests/ui/question_mark.stderr20
-rw-r--r--src/tools/clippy/tests/ui/question_mark_used.stderr2
-rw-r--r--src/tools/clippy/tests/ui/return_and_then.stderr14
-rw-r--r--src/tools/clippy/tests/ui/unnecessary_cast.fixed16
-rw-r--r--src/tools/clippy/tests/ui/unnecessary_cast.rs14
-rw-r--r--src/tools/clippy/tests/ui/unnecessary_cast.stderr22
-rw-r--r--src/tools/clippy/tests/ui/unused_unit.edition2021.fixed146
-rw-r--r--src/tools/clippy/tests/ui/unused_unit.edition2021.stderr128
-rw-r--r--src/tools/clippy/tests/ui/unused_unit.edition2024.fixed146
-rw-r--r--src/tools/clippy/tests/ui/unused_unit.edition2024.stderr122
-rw-r--r--src/tools/clippy/tests/ui/unused_unit.fixed21
-rw-r--r--src/tools/clippy/tests/ui/unused_unit.rs26
-rw-r--r--src/tools/clippy/tests/ui/unused_unit.stderr32
-rw-r--r--src/tools/clippy/tests/ui/zombie_processes.rs22
-rwxr-xr-xsrc/tools/clippy/util/etc/pre-commit.sh1
109 files changed, 1819 insertions, 582 deletions
diff --git a/src/tools/clippy/clippy_lints/src/assigning_clones.rs b/src/tools/clippy/clippy_lints/src/assigning_clones.rs
index 9acff676d4f..8b8b42bbf72 100644
--- a/src/tools/clippy/clippy_lints/src/assigning_clones.rs
+++ b/src/tools/clippy/clippy_lints/src/assigning_clones.rs
@@ -3,14 +3,13 @@ use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::mir::{PossibleBorrowerMap, enclosing_mir};
 use clippy_utils::msrvs::{self, Msrv};
 use clippy_utils::sugg::Sugg;
-use clippy_utils::{is_diag_trait_item, is_in_test, last_path_segment, local_is_initialized, path_to_local};
+use clippy_utils::{is_diag_trait_item, is_in_test, last_path_segment, local_is_initialized, path_to_local, sym};
 use rustc_errors::Applicability;
 use rustc_hir::{self as hir, Expr, ExprKind};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::mir;
 use rustc_middle::ty::{self, Instance, Mutability};
 use rustc_session::impl_lint_pass;
-use rustc_span::symbol::sym;
 use rustc_span::{Span, SyntaxContext};
 
 declare_clippy_lint! {
@@ -86,9 +85,9 @@ impl<'tcx> LateLintPass<'tcx> for AssigningClones {
             && ctxt.is_root()
             && let which_trait = match fn_name {
                 sym::clone if is_diag_trait_item(cx, fn_id, sym::Clone) => CloneTrait::Clone,
-                _ if fn_name.as_str() == "to_owned"
-                    && is_diag_trait_item(cx, fn_id, sym::ToOwned)
-                    && self.msrv.meets(cx, msrvs::CLONE_INTO) =>
+                sym::to_owned
+                    if is_diag_trait_item(cx, fn_id, sym::ToOwned)
+                        && self.msrv.meets(cx, msrvs::CLONE_INTO) =>
                 {
                     CloneTrait::ToOwned
                 },
@@ -112,7 +111,7 @@ impl<'tcx> LateLintPass<'tcx> for AssigningClones {
             && resolved_assoc_items.in_definition_order().any(|assoc|
                 match which_trait {
                     CloneTrait::Clone => assoc.name() == sym::clone_from,
-                    CloneTrait::ToOwned => assoc.name().as_str() == "clone_into",
+                    CloneTrait::ToOwned => assoc.name() == sym::clone_into,
                 }
             )
             && !clone_source_borrows_from_dest(cx, lhs, rhs.span)
diff --git a/src/tools/clippy/clippy_lints/src/attrs/blanket_clippy_restriction_lints.rs b/src/tools/clippy/clippy_lints/src/attrs/blanket_clippy_restriction_lints.rs
index 457692ed5dc..4d64eec25d2 100644
--- a/src/tools/clippy/clippy_lints/src/attrs/blanket_clippy_restriction_lints.rs
+++ b/src/tools/clippy/clippy_lints/src/attrs/blanket_clippy_restriction_lints.rs
@@ -1,17 +1,15 @@
 use super::BLANKET_CLIPPY_RESTRICTION_LINTS;
 use super::utils::extract_clippy_lint;
 use clippy_utils::diagnostics::{span_lint_and_help, span_lint_and_then};
+use clippy_utils::sym;
 use rustc_ast::MetaItemInner;
 use rustc_lint::{EarlyContext, Level, LintContext};
+use rustc_span::DUMMY_SP;
 use rustc_span::symbol::Symbol;
-use rustc_span::{DUMMY_SP, sym};
 
 pub(super) fn check(cx: &EarlyContext<'_>, name: Symbol, items: &[MetaItemInner]) {
     for lint in items {
-        if let Some(lint_name) = extract_clippy_lint(lint)
-            && lint_name.as_str() == "restriction"
-            && name != sym::allow
-        {
+        if name != sym::allow && extract_clippy_lint(lint) == Some(sym::restriction) {
             span_lint_and_help(
                 cx,
                 BLANKET_CLIPPY_RESTRICTION_LINTS,
diff --git a/src/tools/clippy/clippy_lints/src/attrs/deprecated_cfg_attr.rs b/src/tools/clippy/clippy_lints/src/attrs/deprecated_cfg_attr.rs
index 7fab97d3ea1..0edb50be8c7 100644
--- a/src/tools/clippy/clippy_lints/src/attrs/deprecated_cfg_attr.rs
+++ b/src/tools/clippy/clippy_lints/src/attrs/deprecated_cfg_attr.rs
@@ -73,7 +73,7 @@ fn check_deprecated_cfg_recursively(cx: &EarlyContext<'_>, attr: &rustc_ast::Met
 }
 
 fn check_cargo_clippy_attr(cx: &EarlyContext<'_>, item: &rustc_ast::MetaItem) {
-    if item.has_name(sym::feature) && item.value_str().is_some_and(|v| v.as_str() == "cargo-clippy") {
+    if item.has_name(sym::feature) && item.value_str() == Some(sym::cargo_clippy) {
         span_lint_and_sugg(
             cx,
             DEPRECATED_CLIPPY_CFG_ATTR,
diff --git a/src/tools/clippy/clippy_lints/src/attrs/deprecated_semver.rs b/src/tools/clippy/clippy_lints/src/attrs/deprecated_semver.rs
index 50943b36809..bd6459d6f9d 100644
--- a/src/tools/clippy/clippy_lints/src/attrs/deprecated_semver.rs
+++ b/src/tools/clippy/clippy_lints/src/attrs/deprecated_semver.rs
@@ -1,5 +1,6 @@
 use super::DEPRECATED_SEMVER;
 use clippy_utils::diagnostics::span_lint;
+use clippy_utils::sym;
 use rustc_ast::{LitKind, MetaItemLit};
 use rustc_lint::EarlyContext;
 use rustc_span::Span;
@@ -7,7 +8,7 @@ use semver::Version;
 
 pub(super) fn check(cx: &EarlyContext<'_>, span: Span, lit: &MetaItemLit) {
     if let LitKind::Str(is, _) = lit.kind
-        && (is.as_str() == "TBD" || Version::parse(is.as_str()).is_ok())
+        && (is == sym::TBD || Version::parse(is.as_str()).is_ok())
     {
         return;
     }
diff --git a/src/tools/clippy/clippy_lints/src/casts/cast_abs_to_unsigned.rs b/src/tools/clippy/clippy_lints/src/casts/cast_abs_to_unsigned.rs
index 164d3540253..ba31a51f738 100644
--- a/src/tools/clippy/clippy_lints/src/casts/cast_abs_to_unsigned.rs
+++ b/src/tools/clippy/clippy_lints/src/casts/cast_abs_to_unsigned.rs
@@ -1,6 +1,7 @@
 use clippy_utils::diagnostics::span_lint_and_sugg;
 use clippy_utils::msrvs::{self, Msrv};
 use clippy_utils::sugg::Sugg;
+use clippy_utils::sym;
 use rustc_errors::Applicability;
 use rustc_hir::{Expr, ExprKind};
 use rustc_lint::LateContext;
@@ -19,7 +20,7 @@ pub(super) fn check(
     if let ty::Int(from) = cast_from.kind()
         && let ty::Uint(to) = cast_to.kind()
         && let ExprKind::MethodCall(method_path, receiver, [], _) = cast_expr.kind
-        && method_path.ident.name.as_str() == "abs"
+        && method_path.ident.name == sym::abs
         && msrv.meets(cx, msrvs::UNSIGNED_ABS)
     {
         let span = if from.bit_width() == to.bit_width() {
diff --git a/src/tools/clippy/clippy_lints/src/casts/cast_possible_truncation.rs b/src/tools/clippy/clippy_lints/src/casts/cast_possible_truncation.rs
index 8742f5f1a0e..e92879b853d 100644
--- a/src/tools/clippy/clippy_lints/src/casts/cast_possible_truncation.rs
+++ b/src/tools/clippy/clippy_lints/src/casts/cast_possible_truncation.rs
@@ -1,9 +1,9 @@
 use clippy_utils::consts::{ConstEvalCtxt, Constant};
 use clippy_utils::diagnostics::{span_lint, span_lint_and_then};
-use clippy_utils::expr_or_init;
 use clippy_utils::source::snippet;
 use clippy_utils::sugg::Sugg;
 use clippy_utils::ty::{get_discriminant_value, is_isize_or_usize};
+use clippy_utils::{expr_or_init, sym};
 use rustc_abi::IntegerType;
 use rustc_errors::{Applicability, Diag};
 use rustc_hir::def::{DefKind, Res};
@@ -73,7 +73,7 @@ fn apply_reductions(cx: &LateContext<'_>, nbits: u64, expr: &Expr<'_>, signed: b
             nbits
         },
         ExprKind::MethodCall(method, _value, [], _) => {
-            if method.ident.name.as_str() == "signum" {
+            if method.ident.name == sym::signum {
                 0 // do not lint if cast comes from a `signum` function
             } else {
                 nbits
diff --git a/src/tools/clippy/clippy_lints/src/casts/cast_ptr_alignment.rs b/src/tools/clippy/clippy_lints/src/casts/cast_ptr_alignment.rs
index 3fca0f89707..01020f3eee2 100644
--- a/src/tools/clippy/clippy_lints/src/casts/cast_ptr_alignment.rs
+++ b/src/tools/clippy/clippy_lints/src/casts/cast_ptr_alignment.rs
@@ -1,11 +1,10 @@
 use clippy_utils::diagnostics::span_lint;
 use clippy_utils::ty::is_c_void;
-use clippy_utils::{get_parent_expr, is_hir_ty_cfg_dependant};
+use clippy_utils::{get_parent_expr, is_hir_ty_cfg_dependant, sym};
 use rustc_hir::{Expr, ExprKind, GenericArg};
 use rustc_lint::LateContext;
 use rustc_middle::ty::layout::LayoutOf;
 use rustc_middle::ty::{self, Ty};
-use rustc_span::sym;
 
 use super::CAST_PTR_ALIGNMENT;
 
@@ -20,7 +19,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
-        && method_path.ident.name.as_str() == "cast"
+        && method_path.ident.name == sym::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/src/tools/clippy/clippy_lints/src/casts/unnecessary_cast.rs b/src/tools/clippy/clippy_lints/src/casts/unnecessary_cast.rs
index ae994e94a32..8e8c55cf383 100644
--- a/src/tools/clippy/clippy_lints/src/casts/unnecessary_cast.rs
+++ b/src/tools/clippy/clippy_lints/src/casts/unnecessary_cast.rs
@@ -8,7 +8,9 @@ use rustc_errors::Applicability;
 use rustc_hir::def::{DefKind, Res};
 use rustc_hir::{Expr, ExprKind, Lit, Node, Path, QPath, TyKind, UnOp};
 use rustc_lint::{LateContext, LintContext};
+use rustc_middle::ty::adjustment::Adjust;
 use rustc_middle::ty::{self, FloatTy, InferTy, Ty};
+use rustc_span::{Symbol, sym};
 use std::ops::ControlFlow;
 
 use super::UNNECESSARY_CAST;
@@ -142,6 +144,33 @@ pub(super) fn check<'tcx>(
     }
 
     if cast_from.kind() == cast_to.kind() && !expr.span.in_external_macro(cx.sess().source_map()) {
+        enum MaybeParenOrBlock {
+            Paren,
+            Block,
+            Nothing,
+        }
+
+        fn is_borrow_expr(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
+            matches!(expr.kind, ExprKind::AddrOf(..))
+                || cx
+                    .typeck_results()
+                    .expr_adjustments(expr)
+                    .first()
+                    .is_some_and(|adj| matches!(adj.kind, Adjust::Borrow(_)))
+        }
+
+        fn is_in_allowed_macro(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
+            const ALLOWED_MACROS: &[Symbol] = &[
+                sym::format_args_macro,
+                sym::assert_eq_macro,
+                sym::debug_assert_eq_macro,
+                sym::assert_ne_macro,
+                sym::debug_assert_ne_macro,
+            ];
+            matches!(expr.span.ctxt().outer_expn_data().macro_def_id, Some(def_id) if 
+                cx.tcx.get_diagnostic_name(def_id).is_some_and(|sym| ALLOWED_MACROS.contains(&sym)))
+        }
+
         if let Some(id) = path_to_local(cast_expr)
             && !cx.tcx.hir_span(id).eq_ctxt(cast_expr.span)
         {
@@ -150,15 +179,15 @@ pub(super) fn check<'tcx>(
             return false;
         }
 
-        // If the whole cast expression is a unary expression (`(*x as T)`) or an addressof
-        // expression (`(&x as T)`), then not surrounding the suggestion into a block risks us
-        // changing the precedence of operators if the cast expression is followed by an operation
-        // with higher precedence than the unary operator (`(*x as T).foo()` would become
-        // `*x.foo()`, which changes what the `*` applies on).
-        // The same is true if the expression encompassing the cast expression is a unary
-        // expression or an addressof expression.
-        let needs_block = matches!(cast_expr.kind, ExprKind::Unary(..) | ExprKind::AddrOf(..))
-            || get_parent_expr(cx, expr).is_some_and(|e| matches!(e.kind, ExprKind::Unary(..) | ExprKind::AddrOf(..)));
+        // Changing `&(x as i32)` to `&x` would change the meaning of the code because the previous creates
+        // a reference to the temporary while the latter creates a reference to the original value.
+        let surrounding = match cx.tcx.parent_hir_node(expr.hir_id) {
+            Node::Expr(parent) if is_borrow_expr(cx, parent) && !is_in_allowed_macro(cx, parent) => {
+                MaybeParenOrBlock::Block
+            },
+            Node::Expr(parent) if cast_expr.precedence() < parent.precedence() => MaybeParenOrBlock::Paren,
+            _ => MaybeParenOrBlock::Nothing,
+        };
 
         span_lint_and_sugg(
             cx,
@@ -166,10 +195,10 @@ pub(super) fn check<'tcx>(
             expr.span,
             format!("casting to the same type is unnecessary (`{cast_from}` -> `{cast_to}`)"),
             "try",
-            if needs_block {
-                format!("{{ {cast_str} }}")
-            } else {
-                cast_str
+            match surrounding {
+                MaybeParenOrBlock::Paren => format!("({cast_str})"),
+                MaybeParenOrBlock::Block => format!("{{ {cast_str} }}"),
+                MaybeParenOrBlock::Nothing => cast_str,
             },
             Applicability::MachineApplicable,
         );
diff --git a/src/tools/clippy/clippy_lints/src/crate_in_macro_def.rs b/src/tools/clippy/clippy_lints/src/crate_in_macro_def.rs
index c2aac7ca090..19f62e8bf79 100644
--- a/src/tools/clippy/clippy_lints/src/crate_in_macro_def.rs
+++ b/src/tools/clippy/clippy_lints/src/crate_in_macro_def.rs
@@ -5,8 +5,8 @@ use rustc_ast::tokenstream::{TokenStream, TokenTree};
 use rustc_errors::Applicability;
 use rustc_lint::{EarlyContext, EarlyLintPass};
 use rustc_session::declare_lint_pass;
-use rustc_span::Span;
 use rustc_span::symbol::sym;
+use rustc_span::{Span, kw};
 
 declare_clippy_lint! {
     /// ### What it does
@@ -105,12 +105,11 @@ fn contains_unhygienic_crate_reference(tts: &TokenStream) -> Option<Span> {
 fn is_crate_keyword(tt: &TokenTree) -> Option<Span> {
     if let TokenTree::Token(
         Token {
-            kind: TokenKind::Ident(symbol, _),
+            kind: TokenKind::Ident(kw::Crate, _),
             span,
         },
         _,
     ) = tt
-        && symbol.as_str() == "crate"
     {
         Some(*span)
     } else {
diff --git a/src/tools/clippy/clippy_lints/src/equatable_if_let.rs b/src/tools/clippy/clippy_lints/src/equatable_if_let.rs
index 3afb687040f..72f5eaf8a4b 100644
--- a/src/tools/clippy/clippy_lints/src/equatable_if_let.rs
+++ b/src/tools/clippy/clippy_lints/src/equatable_if_let.rs
@@ -68,6 +68,38 @@ fn is_structural_partial_eq<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>, other: T
     }
 }
 
+/// Check if the pattern has any type mismatch that would prevent it from being used in an equality
+/// check. This can happen if the expr has a reference type and the corresponding pattern is a
+/// literal.
+fn contains_type_mismatch(cx: &LateContext<'_>, pat: &Pat<'_>) -> bool {
+    let mut result = false;
+    pat.walk(|p| {
+        if result {
+            return false;
+        }
+
+        if p.span.in_external_macro(cx.sess().source_map()) {
+            return true;
+        }
+
+        let adjust_pat = match p.kind {
+            PatKind::Or([p, ..]) => p,
+            _ => p,
+        };
+
+        if let Some(adjustments) = cx.typeck_results().pat_adjustments().get(adjust_pat.hir_id)
+            && adjustments.first().is_some_and(|first| first.source.is_ref())
+        {
+            result = true;
+            return false;
+        }
+
+        true
+    });
+
+    result
+}
+
 impl<'tcx> LateLintPass<'tcx> for PatternEquality {
     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) {
         if let ExprKind::Let(let_expr) = expr.kind
@@ -78,7 +110,7 @@ impl<'tcx> LateLintPass<'tcx> for PatternEquality {
             let pat_ty = cx.typeck_results().pat_ty(let_expr.pat);
             let mut applicability = Applicability::MachineApplicable;
 
-            if is_structural_partial_eq(cx, exp_ty, pat_ty) {
+            if is_structural_partial_eq(cx, exp_ty, pat_ty) && !contains_type_mismatch(cx, let_expr.pat) {
                 let pat_str = match let_expr.pat.kind {
                     PatKind::Struct(..) => format!(
                         "({})",
diff --git a/src/tools/clippy/clippy_lints/src/floating_point_arithmetic.rs b/src/tools/clippy/clippy_lints/src/floating_point_arithmetic.rs
index d5f0659f842..553a00ed868 100644
--- a/src/tools/clippy/clippy_lints/src/floating_point_arithmetic.rs
+++ b/src/tools/clippy/clippy_lints/src/floating_point_arithmetic.rs
@@ -3,7 +3,7 @@ use clippy_utils::consts::{ConstEvalCtxt, Constant};
 use clippy_utils::diagnostics::span_lint_and_sugg;
 use clippy_utils::{
     eq_expr_value, get_parent_expr, higher, is_in_const_context, is_inherent_method_call, is_no_std_crate,
-    numeric_literal, peel_blocks, sugg,
+    numeric_literal, peel_blocks, sugg, sym,
 };
 use rustc_errors::Applicability;
 use rustc_hir::{BinOpKind, Expr, ExprKind, PathSegment, UnOp};
@@ -435,7 +435,7 @@ fn check_expm1(cx: &LateContext<'_>, expr: &Expr<'_>) {
         rhs,
     ) = expr.kind
         && let ExprKind::MethodCall(path, self_arg, [], _) = &lhs.kind
-        && path.ident.name.as_str() == "exp"
+        && path.ident.name == sym::exp
         && cx.typeck_results().expr_ty(lhs).is_floating_point()
         && let Some(value) = ConstEvalCtxt::new(cx).eval(rhs)
         && (F32(1.0) == value || F64(1.0) == value)
diff --git a/src/tools/clippy/clippy_lints/src/from_raw_with_void_ptr.rs b/src/tools/clippy/clippy_lints/src/from_raw_with_void_ptr.rs
index c8828c93615..5e2e2c9dbf7 100644
--- a/src/tools/clippy/clippy_lints/src/from_raw_with_void_ptr.rs
+++ b/src/tools/clippy/clippy_lints/src/from_raw_with_void_ptr.rs
@@ -1,12 +1,11 @@
 use clippy_utils::diagnostics::span_lint_and_help;
-use clippy_utils::path_def_id;
 use clippy_utils::ty::is_c_void;
+use clippy_utils::{path_def_id, sym};
 use rustc_hir::def_id::DefId;
 use rustc_hir::{Expr, ExprKind, QPath};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::ty;
 use rustc_session::declare_lint_pass;
-use rustc_span::sym;
 
 declare_clippy_lint! {
     /// ### What it does
@@ -41,7 +40,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.as_str() == "from_raw"
+            && seg.ident.name == sym::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/src/tools/clippy/clippy_lints/src/from_str_radix_10.rs b/src/tools/clippy/clippy_lints/src/from_str_radix_10.rs
index 25b087e8484..b816963cc82 100644
--- a/src/tools/clippy/clippy_lints/src/from_str_radix_10.rs
+++ b/src/tools/clippy/clippy_lints/src/from_str_radix_10.rs
@@ -1,13 +1,12 @@
 use clippy_utils::diagnostics::span_lint_and_sugg;
 use clippy_utils::sugg::Sugg;
 use clippy_utils::ty::{is_type_diagnostic_item, is_type_lang_item};
-use clippy_utils::{is_in_const_context, is_integer_literal};
+use clippy_utils::{is_in_const_context, is_integer_literal, sym};
 use rustc_errors::Applicability;
 use rustc_hir::{Expr, ExprKind, LangItem, PrimTy, QPath, TyKind, def};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::ty::Ty;
 use rustc_session::declare_lint_pass;
-use rustc_span::symbol::sym;
 
 declare_clippy_lint! {
     /// ### What it does
@@ -53,7 +52,7 @@ impl<'tcx> LateLintPass<'tcx> for FromStrRadix10 {
 
             // check if the second part of the path indeed calls the associated
             // function `from_str_radix`
-            && pathseg.ident.name.as_str() == "from_str_radix"
+            && pathseg.ident.name == sym::from_str_radix
 
             // check if the first part of the path is some integer primitive
             && let TyKind::Path(ty_qpath) = &ty.kind
diff --git a/src/tools/clippy/clippy_lints/src/implicit_hasher.rs b/src/tools/clippy/clippy_lints/src/implicit_hasher.rs
index d2545e57652..4c17834c3ad 100644
--- a/src/tools/clippy/clippy_lints/src/implicit_hasher.rs
+++ b/src/tools/clippy/clippy_lints/src/implicit_hasher.rs
@@ -10,10 +10,10 @@ use rustc_middle::hir::nested_filter;
 use rustc_middle::ty::{Ty, TypeckResults};
 use rustc_session::declare_lint_pass;
 use rustc_span::Span;
-use rustc_span::symbol::sym;
 
 use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::source::{IntoSpan, SpanRangeExt, snippet};
+use clippy_utils::sym;
 use clippy_utils::ty::is_type_diagnostic_item;
 
 declare_clippy_lint! {
@@ -326,6 +326,7 @@ impl<'tcx> Visitor<'tcx> for ImplicitHasherConstructorVisitor<'_, '_, 'tcx> {
     fn visit_expr(&mut self, e: &'tcx Expr<'_>) {
         if let ExprKind::Call(fun, args) = e.kind
             && let ExprKind::Path(QPath::TypeRelative(ty, method)) = fun.kind
+            && matches!(method.ident.name, sym::new | sym::with_capacity)
             && let TyKind::Path(QPath::Resolved(None, ty_path)) = ty.kind
             && let Some(ty_did) = ty_path.res.opt_def_id()
         {
@@ -333,10 +334,11 @@ impl<'tcx> Visitor<'tcx> for ImplicitHasherConstructorVisitor<'_, '_, 'tcx> {
                 return;
             }
 
-            if self.cx.tcx.is_diagnostic_item(sym::HashMap, ty_did) {
-                if method.ident.name == sym::new {
+            match (self.cx.tcx.get_diagnostic_name(ty_did), method.ident.name) {
+                (Some(sym::HashMap), sym::new) => {
                     self.suggestions.insert(e.span, "HashMap::default()".to_string());
-                } else if method.ident.name.as_str() == "with_capacity" {
+                },
+                (Some(sym::HashMap), sym::with_capacity) => {
                     self.suggestions.insert(
                         e.span,
                         format!(
@@ -344,11 +346,11 @@ impl<'tcx> Visitor<'tcx> for ImplicitHasherConstructorVisitor<'_, '_, 'tcx> {
                             snippet(self.cx, args[0].span, "capacity"),
                         ),
                     );
-                }
-            } else if self.cx.tcx.is_diagnostic_item(sym::HashSet, ty_did) {
-                if method.ident.name == sym::new {
+                },
+                (Some(sym::HashSet), sym::new) => {
                     self.suggestions.insert(e.span, "HashSet::default()".to_string());
-                } else if method.ident.name.as_str() == "with_capacity" {
+                },
+                (Some(sym::HashSet), sym::with_capacity) => {
                     self.suggestions.insert(
                         e.span,
                         format!(
@@ -356,7 +358,8 @@ impl<'tcx> Visitor<'tcx> for ImplicitHasherConstructorVisitor<'_, '_, 'tcx> {
                             snippet(self.cx, args[0].span, "capacity"),
                         ),
                     );
-                }
+                },
+                _ => {},
             }
         }
 
diff --git a/src/tools/clippy/clippy_lints/src/infinite_iter.rs b/src/tools/clippy/clippy_lints/src/infinite_iter.rs
index 427a1f82555..c4e10837bf1 100644
--- a/src/tools/clippy/clippy_lints/src/infinite_iter.rs
+++ b/src/tools/clippy/clippy_lints/src/infinite_iter.rs
@@ -1,10 +1,9 @@
 use clippy_utils::diagnostics::span_lint;
-use clippy_utils::higher;
 use clippy_utils::ty::{get_type_diagnostic_name, implements_trait};
+use clippy_utils::{higher, sym};
 use rustc_hir::{BorrowKind, Closure, Expr, ExprKind};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_session::declare_lint_pass;
-use rustc_span::symbol::sym;
 
 declare_clippy_lint! {
     /// ### What it does
@@ -156,7 +155,7 @@ fn is_infinite(cx: &LateContext<'_>, expr: &Expr<'_>) -> Finiteness {
                     .and(cap);
                 }
             }
-            if method.ident.name.as_str() == "flat_map"
+            if method.ident.name == sym::flat_map
                 && args.len() == 1
                 && let ExprKind::Closure(&Closure { body, .. }) = args[0].kind
             {
@@ -224,7 +223,7 @@ fn complete_infinite_iter(cx: &LateContext<'_>, expr: &Expr<'_>) -> Finiteness {
                     return MaybeInfinite.and(is_infinite(cx, receiver));
                 }
             }
-            if method.ident.name.as_str() == "last" && args.is_empty() {
+            if method.ident.name == sym::last && args.is_empty() {
                 let not_double_ended = cx
                     .tcx
                     .get_diagnostic_item(sym::DoubleEndedIterator)
@@ -232,7 +231,7 @@ fn complete_infinite_iter(cx: &LateContext<'_>, expr: &Expr<'_>) -> Finiteness {
                 if not_double_ended {
                     return is_infinite(cx, receiver);
                 }
-            } else if method.ident.name.as_str() == "collect" {
+            } else if method.ident.name == sym::collect {
                 let ty = cx.typeck_results().expr_ty(expr);
                 if matches!(
                     get_type_diagnostic_name(cx, ty),
diff --git a/src/tools/clippy/clippy_lints/src/iter_without_into_iter.rs b/src/tools/clippy/clippy_lints/src/iter_without_into_iter.rs
index 173232c511a..900b20aa9cf 100644
--- a/src/tools/clippy/clippy_lints/src/iter_without_into_iter.rs
+++ b/src/tools/clippy/clippy_lints/src/iter_without_into_iter.rs
@@ -1,14 +1,13 @@
 use clippy_utils::diagnostics::span_lint_and_then;
-use clippy_utils::get_parent_as_impl;
 use clippy_utils::source::snippet;
 use clippy_utils::ty::{deref_chain, get_adt_inherent_method, implements_trait, make_normalized_projection};
+use clippy_utils::{get_parent_as_impl, sym};
 use rustc_ast::Mutability;
 use rustc_errors::Applicability;
 use rustc_hir::{FnRetTy, ImplItemKind, ImplicitSelfKind, ItemKind, TyKind};
 use rustc_lint::{LateContext, LateLintPass, LintContext};
 use rustc_middle::ty::{self, Ty};
 use rustc_session::declare_lint_pass;
-use rustc_span::sym;
 
 declare_clippy_lint! {
     /// ### What it does
@@ -141,7 +140,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.as_str() == "IntoIter" {
+                if item.ident.name == sym::IntoIter {
                     Some(cx.tcx.hir_impl_item(item.id).expect_type().span)
                 } else {
                     None
diff --git a/src/tools/clippy/clippy_lints/src/len_zero.rs b/src/tools/clippy/clippy_lints/src/len_zero.rs
index 8c71d34c95f..aded31971ce 100644
--- a/src/tools/clippy/clippy_lints/src/len_zero.rs
+++ b/src/tools/clippy/clippy_lints/src/len_zero.rs
@@ -2,7 +2,9 @@ use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg, span_lint_and_the
 use clippy_utils::source::{SpanRangeExt, snippet_with_context};
 use clippy_utils::sugg::{Sugg, has_enclosing_paren};
 use clippy_utils::ty::implements_trait;
-use clippy_utils::{fulfill_or_allowed, get_item_name, get_parent_as_impl, is_trait_method, peel_ref_operators, sym};
+use clippy_utils::{
+    fulfill_or_allowed, get_parent_as_impl, is_trait_method, parent_item_name, peel_ref_operators, sym,
+};
 use rustc_ast::ast::LitKind;
 use rustc_errors::Applicability;
 use rustc_hir::def::Res;
@@ -533,9 +535,7 @@ fn check_cmp(cx: &LateContext<'_>, span: Span, method: &Expr<'_>, lit: &Expr<'_>
 
     if let (&ExprKind::MethodCall(method_path, receiver, [], _), ExprKind::Lit(lit)) = (&method.kind, &lit.kind) {
         // check if we are in an is_empty() method
-        if let Some(name) = get_item_name(cx, method)
-            && name.as_str() == "is_empty"
-        {
+        if parent_item_name(cx, method) == Some(sym::is_empty) {
             return;
         }
 
diff --git a/src/tools/clippy/clippy_lints/src/lib.rs b/src/tools/clippy/clippy_lints/src/lib.rs
index 5fa8f6f4bf3..bc7fc60827a 100644
--- a/src/tools/clippy/clippy_lints/src/lib.rs
+++ b/src/tools/clippy/clippy_lints/src/lib.rs
@@ -729,6 +729,7 @@ pub fn register_lints(store: &mut rustc_lint::LintStore, conf: &'static Conf) {
     store.register_early_pass(|| Box::new(misc_early::MiscEarlyLints));
     store.register_late_pass(|_| Box::new(redundant_closure_call::RedundantClosureCall));
     store.register_early_pass(|| Box::new(unused_unit::UnusedUnit));
+    store.register_late_pass(|_| Box::new(unused_unit::UnusedUnit));
     store.register_late_pass(|_| Box::new(returns::Return));
     store.register_late_pass(move |tcx| Box::new(collapsible_if::CollapsibleIf::new(tcx, conf)));
     store.register_late_pass(|_| Box::new(items_after_statements::ItemsAfterStatements));
diff --git a/src/tools/clippy/clippy_lints/src/loops/same_item_push.rs b/src/tools/clippy/clippy_lints/src/loops/same_item_push.rs
index 661b4b590d8..388034c39f5 100644
--- a/src/tools/clippy/clippy_lints/src/loops/same_item_push.rs
+++ b/src/tools/clippy/clippy_lints/src/loops/same_item_push.rs
@@ -3,7 +3,7 @@ use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::msrvs::Msrv;
 use clippy_utils::source::snippet_with_context;
 use clippy_utils::ty::{implements_trait, is_type_diagnostic_item};
-use clippy_utils::{msrvs, path_to_local, std_or_core};
+use clippy_utils::{msrvs, path_to_local, std_or_core, sym};
 use rustc_data_structures::fx::FxHashSet;
 use rustc_errors::Applicability;
 use rustc_hir::def::{DefKind, Res};
@@ -11,7 +11,6 @@ use rustc_hir::intravisit::{Visitor, walk_expr};
 use rustc_hir::{BindingMode, Block, Expr, ExprKind, HirId, Mutability, Node, Pat, PatKind, Stmt, StmtKind};
 use rustc_lint::LateContext;
 use rustc_span::SyntaxContext;
-use rustc_span::symbol::sym;
 
 /// Detects for loop pushing the same item into a Vec
 pub(super) fn check<'tcx>(
@@ -187,8 +186,8 @@ fn get_vec_push<'tcx>(
             // Extract method being called and figure out the parameters for the method call
             && let ExprKind::MethodCall(path, self_expr, [pushed_item], _) = &semi_stmt.kind
             // Check that the method being called is push() on a Vec
+            && path.ident.name == sym::push
             && is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(self_expr), sym::Vec)
-            && path.ident.name.as_str() == "push"
     {
         return Some((self_expr, pushed_item, semi_stmt.span.ctxt()));
     }
diff --git a/src/tools/clippy/clippy_lints/src/manual_div_ceil.rs b/src/tools/clippy/clippy_lints/src/manual_div_ceil.rs
index 444ecd5d2bb..ed0cce754b9 100644
--- a/src/tools/clippy/clippy_lints/src/manual_div_ceil.rs
+++ b/src/tools/clippy/clippy_lints/src/manual_div_ceil.rs
@@ -1,7 +1,7 @@
 use clippy_config::Conf;
 use clippy_utils::diagnostics::span_lint_and_sugg;
 use clippy_utils::msrvs::{self, Msrv};
-use clippy_utils::source::snippet_with_applicability;
+use clippy_utils::source::snippet_with_context;
 use clippy_utils::sugg::{Sugg, has_enclosing_paren};
 use clippy_utils::{SpanlessEq, sym};
 use rustc_ast::{BinOpKind, LitIntType, LitKind, UnOp};
@@ -199,9 +199,9 @@ fn build_suggestion(
     } else {
         format!("{dividend_sugg_str}{type_suffix}")
     };
-    let divisor_snippet = snippet_with_applicability(cx, rhs.span.source_callsite(), "..", applicability);
+    let divisor_snippet = snippet_with_context(cx, rhs.span, expr.span.ctxt(), "..", applicability);
 
-    let sugg = format!("{suggestion_before_div_ceil}.div_ceil({divisor_snippet})");
+    let sugg = format!("{suggestion_before_div_ceil}.div_ceil({})", divisor_snippet.0);
 
     span_lint_and_sugg(
         cx,
diff --git a/src/tools/clippy/clippy_lints/src/manual_hash_one.rs b/src/tools/clippy/clippy_lints/src/manual_hash_one.rs
index f71264a93ca..b3ee45cc020 100644
--- a/src/tools/clippy/clippy_lints/src/manual_hash_one.rs
+++ b/src/tools/clippy/clippy_lints/src/manual_hash_one.rs
@@ -3,12 +3,11 @@ use clippy_utils::diagnostics::span_lint_hir_and_then;
 use clippy_utils::msrvs::{self, Msrv};
 use clippy_utils::source::SpanRangeExt;
 use clippy_utils::visitors::{is_local_used, local_used_once};
-use clippy_utils::{is_trait_method, path_to_local_id};
+use clippy_utils::{is_trait_method, path_to_local_id, sym};
 use rustc_errors::Applicability;
 use rustc_hir::{BindingMode, ExprKind, LetStmt, Node, PatKind, StmtKind};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_session::impl_lint_pass;
-use rustc_span::sym;
 
 declare_clippy_lint! {
     /// ### What it does
@@ -66,7 +65,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.as_str() == "build_hasher"
+            && seg.ident.name == sym::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)
@@ -94,7 +93,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.as_str() == "finish"
+            && seg.ident.name == sym::finish
 
             && self.msrv.meets(cx, msrvs::BUILD_HASHER_HASH_ONE)
         {
diff --git a/src/tools/clippy/clippy_lints/src/manual_is_ascii_check.rs b/src/tools/clippy/clippy_lints/src/manual_is_ascii_check.rs
index 8ab49bd2ea8..ac8c88f0205 100644
--- a/src/tools/clippy/clippy_lints/src/manual_is_ascii_check.rs
+++ b/src/tools/clippy/clippy_lints/src/manual_is_ascii_check.rs
@@ -3,7 +3,7 @@ use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::macros::matching_root_macro_call;
 use clippy_utils::msrvs::{self, Msrv};
 use clippy_utils::sugg::Sugg;
-use clippy_utils::{higher, is_in_const_context, path_to_local, peel_ref_operators};
+use clippy_utils::{higher, is_in_const_context, path_to_local, peel_ref_operators, sym};
 use rustc_ast::LitKind::{Byte, Char};
 use rustc_ast::ast::RangeLimits;
 use rustc_errors::Applicability;
@@ -11,7 +11,7 @@ use rustc_hir::{Expr, ExprKind, Lit, Node, Param, PatExpr, PatExprKind, PatKind,
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::ty::{self, Ty};
 use rustc_session::impl_lint_pass;
-use rustc_span::{Span, sym};
+use rustc_span::Span;
 
 declare_clippy_lint! {
     /// ### What it does
@@ -103,7 +103,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.as_str() == "contains"
+            && path.ident.name == sym::contains
             && let Some(higher::Range {
                 start: Some(start),
                 end: Some(end),
diff --git a/src/tools/clippy/clippy_lints/src/manual_option_as_slice.rs b/src/tools/clippy/clippy_lints/src/manual_option_as_slice.rs
index e4ad3953b67..b365dbf088f 100644
--- a/src/tools/clippy/clippy_lints/src/manual_option_as_slice.rs
+++ b/src/tools/clippy/clippy_lints/src/manual_option_as_slice.rs
@@ -1,14 +1,14 @@
 use clippy_config::Conf;
 use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg};
 use clippy_utils::msrvs::Msrv;
-use clippy_utils::{is_none_arm, msrvs, peel_hir_expr_refs};
+use clippy_utils::{is_none_arm, msrvs, peel_hir_expr_refs, sym};
 use rustc_errors::Applicability;
 use rustc_hir::def::{DefKind, Res};
 use rustc_hir::{Arm, Expr, ExprKind, LangItem, Pat, PatKind, QPath, is_range_literal};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::ty;
 use rustc_session::impl_lint_pass;
-use rustc_span::{Span, Symbol, sym};
+use rustc_span::{Span, Symbol};
 
 declare_clippy_lint! {
     /// ### What it does
@@ -76,7 +76,7 @@ impl LateLintPass<'_> for ManualOptionAsSlice {
                 }
             },
             ExprKind::MethodCall(seg, callee, [], _) => {
-                if seg.ident.name.as_str() == "unwrap_or_default" {
+                if seg.ident.name == sym::unwrap_or_default {
                     check_map(cx, callee, span, self.msrv);
                 }
             },
diff --git a/src/tools/clippy/clippy_lints/src/methods/double_ended_iterator_last.rs b/src/tools/clippy/clippy_lints/src/methods/double_ended_iterator_last.rs
index e666f31217c..6d841853fbe 100644
--- a/src/tools/clippy/clippy_lints/src/methods/double_ended_iterator_last.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/double_ended_iterator_last.rs
@@ -1,11 +1,11 @@
 use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::ty::{has_non_owning_mutable_access, implements_trait};
-use clippy_utils::{is_mutable, is_trait_method, path_to_local};
+use clippy_utils::{is_mutable, is_trait_method, path_to_local, sym};
 use rustc_errors::Applicability;
 use rustc_hir::{Expr, Node, PatKind};
 use rustc_lint::LateContext;
 use rustc_middle::ty::Instance;
-use rustc_span::{Span, sym};
+use rustc_span::Span;
 
 use super::DOUBLE_ENDED_ITERATOR_LAST;
 
@@ -24,7 +24,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &'_ Expr<'_>, self_expr: &'_ Exp
         && let Ok(Some(fn_def)) = Instance::try_resolve(cx.tcx, cx.typing_env(), id, args)
         // find the provided definition of Iterator::last
         && let Some(item) = cx.tcx.get_diagnostic_item(sym::Iterator)
-        && let Some(last_def) = cx.tcx.provided_trait_methods(item).find(|m| m.name().as_str() == "last")
+        && let Some(last_def) = cx.tcx.provided_trait_methods(item).find(|m| m.name() == sym::last)
         // if the resolved method is the same as the provided definition
         && fn_def.def_id() == last_def.def_id
         && let self_ty = cx.typeck_results().expr_ty(self_expr)
diff --git a/src/tools/clippy/clippy_lints/src/methods/filter_map.rs b/src/tools/clippy/clippy_lints/src/methods/filter_map.rs
index da123f13d46..4dd54cf1974 100644
--- a/src/tools/clippy/clippy_lints/src/methods/filter_map.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/filter_map.rs
@@ -233,12 +233,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.as_str() == "is_some" {
+            if cx.tcx.is_diagnostic_item(sym::Option, recv_ty.did()) && path.ident.name == sym::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.as_str() == "is_ok" {
+            } else if cx.tcx.is_diagnostic_item(sym::Result, recv_ty.did()) && path.ident.name == sym::is_ok {
                 Some(Self::IsOk {
                     receiver,
                     side_effect_expr_span,
diff --git a/src/tools/clippy/clippy_lints/src/methods/mod.rs b/src/tools/clippy/clippy_lints/src/methods/mod.rs
index ad374dee516..10f4637d08f 100644
--- a/src/tools/clippy/clippy_lints/src/methods/mod.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/mod.rs
@@ -4370,11 +4370,10 @@ declare_clippy_lint! {
 
 declare_clippy_lint! {
     /// ### What it does
-    ///
-    /// Detect functions that end with `Option::and_then` or `Result::and_then`, and suggest using a question mark (`?`) instead.
+    /// Detect functions that end with `Option::and_then` or `Result::and_then`, and suggest using
+    /// the `?` operator instead.
     ///
     /// ### Why is this bad?
-    ///
     /// The `and_then` method is used to chain a computation that returns an `Option` or a `Result`.
     /// This can be replaced with the `?` operator, which is more concise and idiomatic.
     ///
diff --git a/src/tools/clippy/clippy_lints/src/methods/needless_character_iteration.rs b/src/tools/clippy/clippy_lints/src/methods/needless_character_iteration.rs
index 743aacf0588..f528f7f065c 100644
--- a/src/tools/clippy/clippy_lints/src/methods/needless_character_iteration.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/needless_character_iteration.rs
@@ -9,7 +9,7 @@ use super::utils::get_last_chain_binding_hir_id;
 use clippy_utils::diagnostics::span_lint_and_sugg;
 use clippy_utils::paths::CHAR_IS_ASCII;
 use clippy_utils::source::SpanRangeExt;
-use clippy_utils::{match_def_path, path_to_local_id, peel_blocks};
+use clippy_utils::{match_def_path, path_to_local_id, peel_blocks, sym};
 
 fn peels_expr_ref<'a, 'tcx>(mut expr: &'a Expr<'tcx>) -> &'a Expr<'tcx> {
     while let ExprKind::AddrOf(_, _, e) = expr.kind {
@@ -32,7 +32,7 @@ fn handle_expr(
             // If we have `!is_ascii`, then only `.any()` should warn. And if the condition is
             // `is_ascii`, then only `.all()` should warn.
             if revert != is_all
-                && method.ident.name.as_str() == "is_ascii"
+                && method.ident.name == sym::is_ascii
                 && path_to_local_id(receiver, first_param)
                 && let char_arg_ty = cx.typeck_results().expr_ty_adjusted(receiver).peel_refs()
                 && *char_arg_ty.kind() == ty::Char
@@ -102,7 +102,7 @@ pub(super) fn check(cx: &LateContext<'_>, call_expr: &Expr<'_>, recv: &Expr<'_>,
         && let body = cx.tcx.hir_body(body)
         && let Some(first_param) = body.params.first()
         && let ExprKind::MethodCall(method, mut recv, [], _) = recv.kind
-        && method.ident.name.as_str() == "chars"
+        && method.ident.name == sym::chars
         && let str_ty = cx.typeck_results().expr_ty_adjusted(recv).peel_refs()
         && *str_ty.kind() == ty::Str
     {
diff --git a/src/tools/clippy/clippy_lints/src/methods/needless_collect.rs b/src/tools/clippy/clippy_lints/src/methods/needless_collect.rs
index 6efaba525e3..cd22583b8a2 100644
--- a/src/tools/clippy/clippy_lints/src/methods/needless_collect.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/needless_collect.rs
@@ -9,7 +9,7 @@ use clippy_utils::ty::{
 };
 use clippy_utils::{
     CaptureKind, can_move_expr_to_closure, fn_def_id, get_enclosing_block, higher, is_trait_method, path_to_local,
-    path_to_local_id,
+    path_to_local_id, sym,
 };
 use rustc_data_structures::fx::FxHashMap;
 use rustc_errors::{Applicability, MultiSpan};
@@ -20,8 +20,8 @@ use rustc_hir::{
 use rustc_lint::LateContext;
 use rustc_middle::hir::nested_filter;
 use rustc_middle::ty::{self, AssocTag, ClauseKind, EarlyBinder, GenericArg, GenericArgKind, Ty};
+use rustc_span::Span;
 use rustc_span::symbol::Ident;
-use rustc_span::{Span, sym};
 
 const NEEDLESS_COLLECT_MSG: &str = "avoid using `collect()` when not needed";
 
@@ -339,7 +339,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.as_str() == "collect"
+                && method_name.ident.name == sym::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/src/tools/clippy/clippy_lints/src/methods/read_line_without_trim.rs b/src/tools/clippy/clippy_lints/src/methods/read_line_without_trim.rs
index fe999a3b5f8..407f2e80aff 100644
--- a/src/tools/clippy/clippy_lints/src/methods/read_line_without_trim.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/read_line_without_trim.rs
@@ -1,17 +1,16 @@
 use std::ops::ControlFlow;
 
 use clippy_utils::diagnostics::span_lint_and_then;
-use clippy_utils::get_parent_expr;
 use clippy_utils::source::snippet;
 use clippy_utils::ty::is_type_diagnostic_item;
 use clippy_utils::visitors::for_each_local_use_after_expr;
+use clippy_utils::{get_parent_expr, sym};
 use rustc_ast::LitKind;
 use rustc_errors::Applicability;
 use rustc_hir::def::Res;
 use rustc_hir::{BinOpKind, Expr, ExprKind, QPath};
 use rustc_lint::LateContext;
 use rustc_middle::ty::{self, Ty};
-use rustc_span::sym;
 
 use super::READ_LINE_WITHOUT_TRIM;
 
@@ -44,7 +43,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.as_str() == "parse"
+                        && segment.ident.name == sym::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 +57,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.as_str() == "ends_with"
+                    } else if segment.ident.name == sym::ends_with
                         && recv.span == expr.span
                         && let [arg] = args
                         && expr_is_string_literal_without_trailing_newline(arg)
diff --git a/src/tools/clippy/clippy_lints/src/methods/return_and_then.rs b/src/tools/clippy/clippy_lints/src/methods/return_and_then.rs
index e8861935d42..91643b0dfef 100644
--- a/src/tools/clippy/clippy_lints/src/methods/return_and_then.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/return_and_then.rs
@@ -55,7 +55,6 @@ pub(super) fn check<'tcx>(
         None => &body_snip,
     };
 
-    let msg = "use the question mark operator instead of an `and_then` call";
     let sugg = format!(
         "let {} = {}?;\n{}",
         arg_snip,
@@ -63,5 +62,13 @@ pub(super) fn check<'tcx>(
         reindent_multiline(inner, false, indent_of(cx, expr.span))
     );
 
-    span_lint_and_sugg(cx, RETURN_AND_THEN, expr.span, msg, "try", sugg, applicability);
+    span_lint_and_sugg(
+        cx,
+        RETURN_AND_THEN,
+        expr.span,
+        "use the `?` operator instead of an `and_then` call",
+        "try",
+        sugg,
+        applicability,
+    );
 }
diff --git a/src/tools/clippy/clippy_lints/src/methods/str_split.rs b/src/tools/clippy/clippy_lints/src/methods/str_split.rs
index 3586e11f56a..fb4ac7b3613 100644
--- a/src/tools/clippy/clippy_lints/src/methods/str_split.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/str_split.rs
@@ -1,5 +1,6 @@
 use clippy_utils::diagnostics::span_lint_and_sugg;
 use clippy_utils::source::snippet_with_context;
+use clippy_utils::sym;
 use clippy_utils::visitors::is_const_evaluatable;
 use rustc_ast::ast::LitKind;
 use rustc_errors::Applicability;
@@ -19,7 +20,7 @@ pub(super) fn check<'a>(cx: &LateContext<'a>, expr: &'_ Expr<'_>, split_recv: &'
         && !is_const_evaluatable(cx, trim_recv)
         && let ExprKind::Lit(split_lit) = split_arg.kind
         && (matches!(split_lit.node, LitKind::Char('\n'))
-            || matches!(split_lit.node, LitKind::Str(sym, _) if (sym.as_str() == "\n" || sym.as_str() == "\r\n")))
+            || matches!(split_lit.node, LitKind::Str(sym::LF | sym::CRLF, _)))
     {
         let mut app = Applicability::MaybeIncorrect;
         span_lint_and_sugg(
diff --git a/src/tools/clippy/clippy_lints/src/methods/unnecessary_filter_map.rs b/src/tools/clippy/clippy_lints/src/methods/unnecessary_filter_map.rs
index f920f306bc1..79ed352193f 100644
--- a/src/tools/clippy/clippy_lints/src/methods/unnecessary_filter_map.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/unnecessary_filter_map.rs
@@ -3,13 +3,12 @@ use clippy_utils::diagnostics::span_lint;
 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::{is_res_lang_ctor, is_trait_method, path_res, path_to_local_id, sym};
 use core::ops::ControlFlow;
 use rustc_hir as hir;
 use rustc_hir::LangItem::{OptionNone, OptionSome};
 use rustc_lint::LateContext;
 use rustc_middle::ty;
-use rustc_span::sym;
 
 use super::{UNNECESSARY_FILTER_MAP, UNNECESSARY_FIND_MAP};
 
@@ -95,7 +94,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.as_str() == "then_some"
+            if segment.ident.name == sym::then_some
                 && cx.typeck_results().expr_ty(recv).is_bool()
                 && path_to_local_id(arg, arg_id)
             {
diff --git a/src/tools/clippy/clippy_lints/src/methods/unnecessary_to_owned.rs b/src/tools/clippy/clippy_lints/src/methods/unnecessary_to_owned.rs
index 206b0a8ae3c..87bb8d46a1d 100644
--- a/src/tools/clippy/clippy_lints/src/methods/unnecessary_to_owned.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/unnecessary_to_owned.rs
@@ -7,7 +7,7 @@ use clippy_utils::ty::{get_iterator_item_ty, implements_trait, is_copy, is_type_
 use clippy_utils::visitors::find_all_ret_expressions;
 use clippy_utils::{
     fn_def_id, get_parent_expr, is_diag_item_method, is_diag_trait_item, is_expr_temporary_value, peel_middle_ty_refs,
-    return_ty,
+    return_ty, sym,
 };
 use rustc_errors::Applicability;
 use rustc_hir::def::{DefKind, Res};
@@ -20,7 +20,7 @@ use rustc_middle::ty::adjustment::{Adjust, Adjustment, OverloadedDeref};
 use rustc_middle::ty::{
     self, ClauseKind, GenericArg, GenericArgKind, GenericArgsRef, ParamTy, ProjectionPredicate, TraitPredicate, Ty,
 };
-use rustc_span::{Symbol, sym};
+use rustc_span::Symbol;
 use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt as _;
 use rustc_trait_selection::traits::{Obligation, ObligationCause};
 
@@ -312,8 +312,7 @@ fn check_string_from_utf8<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>,
 /// call of a `to_owned`-like function is unnecessary.
 fn check_split_call_arg(cx: &LateContext<'_>, expr: &Expr<'_>, method_name: Symbol, receiver: &Expr<'_>) -> bool {
     if let Some(parent) = get_parent_expr(cx, expr)
-        && let Some((fn_name, argument_expr)) = get_fn_name_and_arg(cx, parent)
-        && fn_name.as_str() == "split"
+        && let Some((sym::split, argument_expr)) = get_fn_name_and_arg(cx, parent)
         && let Some(receiver_snippet) = receiver.span.get_source_text(cx)
         && let Some(arg_snippet) = argument_expr.span.get_source_text(cx)
     {
@@ -614,8 +613,7 @@ fn has_lifetime(ty: Ty<'_>) -> bool {
 
 /// Returns true if the named method is `Iterator::cloned` or `Iterator::copied`.
 fn is_cloned_or_copied(cx: &LateContext<'_>, method_name: Symbol, method_def_id: DefId) -> bool {
-    (method_name.as_str() == "cloned" || method_name.as_str() == "copied")
-        && is_diag_trait_item(cx, method_def_id, sym::Iterator)
+    matches!(method_name, sym::cloned | sym::copied) && is_diag_trait_item(cx, method_def_id, sym::Iterator)
 }
 
 /// Returns true if the named method can be used to convert the receiver to its "owned"
@@ -628,7 +626,7 @@ fn is_to_owned_like<'a>(cx: &LateContext<'a>, call_expr: &Expr<'a>, method_name:
 
 /// Returns true if the named method is `Cow::into_owned`.
 fn is_cow_into_owned(cx: &LateContext<'_>, method_name: Symbol, method_def_id: DefId) -> bool {
-    method_name.as_str() == "into_owned" && is_diag_item_method(cx, method_def_id, sym::Cow)
+    method_name == sym::into_owned && is_diag_item_method(cx, method_def_id, sym::Cow)
 }
 
 /// Returns true if the named method is `ToString::to_string` and it's called on a type that
diff --git a/src/tools/clippy/clippy_lints/src/minmax.rs b/src/tools/clippy/clippy_lints/src/minmax.rs
index ed89b3b3438..64eafc0ebcc 100644
--- a/src/tools/clippy/clippy_lints/src/minmax.rs
+++ b/src/tools/clippy/clippy_lints/src/minmax.rs
@@ -1,10 +1,9 @@
 use clippy_utils::consts::{ConstEvalCtxt, Constant};
 use clippy_utils::diagnostics::span_lint;
-use clippy_utils::is_trait_method;
+use clippy_utils::{is_trait_method, sym};
 use rustc_hir::{Expr, ExprKind};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_session::declare_lint_pass;
-use rustc_span::sym;
 use std::cmp::Ordering::{Equal, Greater, Less};
 
 declare_clippy_lint! {
@@ -79,12 +78,10 @@ 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.as_str() == "max" {
-                    fetch_const(cx, Some(receiver), args, MinMax::Max)
-                } else if path.ident.name.as_str() == "min" {
-                    fetch_const(cx, Some(receiver), args, MinMax::Min)
-                } else {
-                    None
+                match path.ident.name {
+                    sym::max => fetch_const(cx, Some(receiver), args, MinMax::Max),
+                    sym::min => fetch_const(cx, Some(receiver), args, MinMax::Min),
+                    _ => None,
                 }
             } else {
                 None
diff --git a/src/tools/clippy/clippy_lints/src/missing_fields_in_debug.rs b/src/tools/clippy/clippy_lints/src/missing_fields_in_debug.rs
index 1932d2d5f97..be7dd74fd62 100644
--- a/src/tools/clippy/clippy_lints/src/missing_fields_in_debug.rs
+++ b/src/tools/clippy/clippy_lints/src/missing_fields_in_debug.rs
@@ -1,9 +1,9 @@
 use std::ops::ControlFlow;
 
 use clippy_utils::diagnostics::span_lint_and_then;
-use clippy_utils::is_path_lang_item;
 use clippy_utils::ty::is_type_diagnostic_item;
 use clippy_utils::visitors::{Visitable, for_each_expr};
+use clippy_utils::{is_path_lang_item, sym};
 use rustc_ast::LitKind;
 use rustc_data_structures::fx::FxHashSet;
 use rustc_hir::def::{DefKind, Res};
@@ -13,7 +13,7 @@ use rustc_hir::{
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::ty::{Ty, TypeckResults};
 use rustc_session::declare_lint_pass;
-use rustc_span::{Span, Symbol, sym};
+use rustc_span::{Span, Symbol};
 
 declare_clippy_lint! {
     /// ### What it does
@@ -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.as_str() == "finish_non_exhaustive"
+            } else if path.ident.name == sym::finish_non_exhaustive
                 && is_type_diagnostic_item(cx, recv_ty, sym::DebugStruct)
             {
                 has_finish_non_exhaustive = true;
diff --git a/src/tools/clippy/clippy_lints/src/mixed_read_write_in_expression.rs b/src/tools/clippy/clippy_lints/src/mixed_read_write_in_expression.rs
index 0e085585962..d9f4fb271fb 100644
--- a/src/tools/clippy/clippy_lints/src/mixed_read_write_in_expression.rs
+++ b/src/tools/clippy/clippy_lints/src/mixed_read_write_in_expression.rs
@@ -1,6 +1,6 @@
 use clippy_utils::diagnostics::{span_lint, span_lint_and_then};
 use clippy_utils::macros::root_macro_call_first_node;
-use clippy_utils::{get_parent_expr, path_to_local, path_to_local_id};
+use clippy_utils::{get_parent_expr, path_to_local, path_to_local_id, sym};
 use rustc_hir::intravisit::{Visitor, walk_expr};
 use rustc_hir::{BinOpKind, Block, Expr, ExprKind, HirId, LetStmt, Node, Stmt, StmtKind};
 use rustc_lint::{LateContext, LateLintPass};
@@ -136,7 +136,7 @@ impl<'tcx> DivergenceVisitor<'_, 'tcx> {
 
     fn report_diverging_sub_expr(&mut self, e: &Expr<'_>) {
         if let Some(macro_call) = root_macro_call_first_node(self.cx, e)
-            && self.cx.tcx.item_name(macro_call.def_id).as_str() == "todo"
+            && self.cx.tcx.is_diagnostic_item(sym::todo_macro, macro_call.def_id)
         {
             return;
         }
diff --git a/src/tools/clippy/clippy_lints/src/needless_for_each.rs b/src/tools/clippy/clippy_lints/src/needless_for_each.rs
index 90b27f5dbac..7dd96f1f037 100644
--- a/src/tools/clippy/clippy_lints/src/needless_for_each.rs
+++ b/src/tools/clippy/clippy_lints/src/needless_for_each.rs
@@ -3,12 +3,12 @@ use rustc_hir::intravisit::{Visitor, walk_expr};
 use rustc_hir::{Block, BlockCheckMode, Closure, Expr, ExprKind, Stmt, StmtKind};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_session::declare_lint_pass;
-use rustc_span::{Span, sym};
+use rustc_span::Span;
 
 use clippy_utils::diagnostics::span_lint_and_then;
-use clippy_utils::is_trait_method;
 use clippy_utils::source::snippet_with_applicability;
 use clippy_utils::ty::has_iter_method;
+use clippy_utils::{is_trait_method, sym};
 
 declare_clippy_lint! {
     /// ### What it does
@@ -64,7 +64,7 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessForEach {
                 iter_recv.kind,
                 ExprKind::Array(..) | ExprKind::Call(..) | ExprKind::Path(..)
             )
-            && method_name.ident.name.as_str() == "for_each"
+            && method_name.ident.name == sym::for_each
             && is_trait_method(cx, expr, sym::Iterator)
             // Checks the type of the `iter` method receiver is NOT a user defined type.
             && has_iter_method(cx, cx.typeck_results().expr_ty(iter_recv)).is_some()
diff --git a/src/tools/clippy/clippy_lints/src/needless_question_mark.rs b/src/tools/clippy/clippy_lints/src/needless_question_mark.rs
index 72b0a80260e..2a2160c3be2 100644
--- a/src/tools/clippy/clippy_lints/src/needless_question_mark.rs
+++ b/src/tools/clippy/clippy_lints/src/needless_question_mark.rs
@@ -1,6 +1,5 @@
-use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::diagnostics::span_lint_hir_and_then;
 use clippy_utils::path_res;
-use clippy_utils::source::snippet;
 use rustc_errors::Applicability;
 use rustc_hir::def::{DefKind, Res};
 use rustc_hir::{Block, Body, Expr, ExprKind, LangItem, MatchSource, QPath};
@@ -9,52 +8,38 @@ use rustc_session::declare_lint_pass;
 
 declare_clippy_lint! {
     /// ### What it does
-    /// Suggests alternatives for useless applications of `?` in terminating expressions
+    /// Suggests replacing `Ok(x?)` or `Some(x?)` with `x` in return positions where the `?` operator
+    /// is not needed to convert the type of `x`.
     ///
     /// ### Why is this bad?
     /// There's no reason to use `?` to short-circuit when execution of the body will end there anyway.
     ///
     /// ### Example
     /// ```no_run
-    /// struct TO {
-    ///     magic: Option<usize>,
+    /// # use std::num::ParseIntError;
+    /// fn f(s: &str) -> Option<usize> {
+    ///     Some(s.find('x')?)
     /// }
     ///
-    /// fn f(to: TO) -> Option<usize> {
-    ///     Some(to.magic?)
+    /// fn g(s: &str) -> Result<usize, ParseIntError> {
+    ///     Ok(s.parse()?)
     /// }
-    ///
-    /// struct TR {
-    ///     magic: Result<usize, bool>,
-    /// }
-    ///
-    /// fn g(tr: Result<TR, bool>) -> Result<usize, bool> {
-    ///     tr.and_then(|t| Ok(t.magic?))
-    /// }
-    ///
     /// ```
     /// Use instead:
     /// ```no_run
-    /// struct TO {
-    ///     magic: Option<usize>,
+    /// # use std::num::ParseIntError;
+    /// fn f(s: &str) -> Option<usize> {
+    ///     s.find('x')
     /// }
     ///
-    /// fn f(to: TO) -> Option<usize> {
-    ///     to.magic
-    /// }
-    ///
-    /// struct TR {
-    ///     magic: Result<usize, bool>,
-    /// }
-    ///
-    /// fn g(tr: Result<TR, bool>) -> Result<usize, bool> {
-    ///     tr.and_then(|t| t.magic)
+    /// fn g(s: &str) -> Result<usize, ParseIntError> {
+    ///     s.parse()
     /// }
     /// ```
     #[clippy::version = "1.51.0"]
     pub NEEDLESS_QUESTION_MARK,
     complexity,
-    "Suggest `value.inner_option` instead of `Some(value.inner_option?)`. The same goes for `Result<T, E>`."
+    "using `Ok(x?)` or `Some(x?)` where `x` would be equivalent"
 }
 
 declare_lint_pass!(NeedlessQuestionMark => [NEEDLESS_QUESTION_MARK]);
@@ -111,10 +96,10 @@ fn check(cx: &LateContext<'_>, expr: &Expr<'_>) {
     if let ExprKind::Call(path, [arg]) = expr.kind
         && let Res::Def(DefKind::Ctor(..), ctor_id) = path_res(cx, path)
         && let Some(variant_id) = cx.tcx.opt_parent(ctor_id)
-        && let sugg_remove = if cx.tcx.lang_items().option_some_variant() == Some(variant_id) {
-            "Some()"
+        && let variant = if cx.tcx.lang_items().option_some_variant() == Some(variant_id) {
+            "Some"
         } else if cx.tcx.lang_items().result_ok_variant() == Some(variant_id) {
-            "Ok()"
+            "Ok"
         } else {
             return;
         }
@@ -126,14 +111,25 @@ fn check(cx: &LateContext<'_>, expr: &Expr<'_>) {
         && let inner_ty = cx.typeck_results().expr_ty(inner_expr)
         && expr_ty == inner_ty
     {
-        span_lint_and_sugg(
+        span_lint_hir_and_then(
             cx,
             NEEDLESS_QUESTION_MARK,
+            expr.hir_id,
             expr.span,
-            "question mark operator is useless here",
-            format!("try removing question mark and `{sugg_remove}`"),
-            format!("{}", snippet(cx, inner_expr.span, r#""...""#)),
-            Applicability::MachineApplicable,
+            format!("enclosing `{variant}` and `?` operator are unneeded"),
+            |diag| {
+                diag.multipart_suggestion(
+                    format!("remove the enclosing `{variant}` and `?` operator"),
+                    vec![
+                        (expr.span.until(inner_expr.span), String::new()),
+                        (
+                            inner_expr.span.shrink_to_hi().to(expr.span.shrink_to_hi()),
+                            String::new(),
+                        ),
+                    ],
+                    Applicability::MachineApplicable,
+                );
+            },
         );
     }
 }
diff --git a/src/tools/clippy/clippy_lints/src/non_octal_unix_permissions.rs b/src/tools/clippy/clippy_lints/src/non_octal_unix_permissions.rs
index 852c3885f56..23a1622f30f 100644
--- a/src/tools/clippy/clippy_lints/src/non_octal_unix_permissions.rs
+++ b/src/tools/clippy/clippy_lints/src/non_octal_unix_permissions.rs
@@ -1,10 +1,10 @@
 use clippy_utils::diagnostics::span_lint_and_sugg;
 use clippy_utils::source::{SpanRangeExt, snippet_with_applicability};
+use clippy_utils::sym;
 use rustc_errors::Applicability;
 use rustc_hir::{Expr, ExprKind};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_session::declare_lint_pass;
-use rustc_span::sym;
 
 declare_clippy_lint! {
     /// ### What it does
@@ -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.as_str() == "mode"
+                    && ((path.ident.name == sym::mode
                         && matches!(
                             cx.tcx.get_diagnostic_name(adt.did()),
                             Some(sym::FsOpenOptions | sym::DirBuilder)
                         ))
-                        || (path.ident.name.as_str() == "set_mode"
+                        || (path.ident.name == sym::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/src/tools/clippy/clippy_lints/src/non_zero_suggestions.rs b/src/tools/clippy/clippy_lints/src/non_zero_suggestions.rs
index 635f5678e2a..1b8ab1bdedf 100644
--- a/src/tools/clippy/clippy_lints/src/non_zero_suggestions.rs
+++ b/src/tools/clippy/clippy_lints/src/non_zero_suggestions.rs
@@ -1,12 +1,12 @@
 use clippy_utils::diagnostics::span_lint_and_sugg;
 use clippy_utils::source::snippet;
+use clippy_utils::sym;
 use rustc_ast::ast::BinOpKind;
 use rustc_errors::Applicability;
 use rustc_hir::{Expr, ExprKind};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::ty::{self, Ty};
 use rustc_session::declare_lint_pass;
-use rustc_span::symbol::sym;
 
 declare_clippy_lint! {
     /// ### What it does
@@ -72,7 +72,7 @@ fn check_non_zero_conversion(cx: &LateContext<'_>, expr: &Expr<'_>, applicabilit
         && let ExprKind::Path(qpath) = &func.kind
         && let Some(def_id) = cx.qpath_res(qpath, func.hir_id).opt_def_id()
         && let ExprKind::MethodCall(rcv_path, receiver, [], _) = &arg.kind
-        && rcv_path.ident.name.as_str() == "get"
+        && rcv_path.ident.name == sym::get
     {
         let fn_name = cx.tcx.item_name(def_id);
         let target_ty = cx.typeck_results().expr_ty(expr);
diff --git a/src/tools/clippy/clippy_lints/src/operators/float_cmp.rs b/src/tools/clippy/clippy_lints/src/operators/float_cmp.rs
index 01dc6a27c33..ded161c8576 100644
--- a/src/tools/clippy/clippy_lints/src/operators/float_cmp.rs
+++ b/src/tools/clippy/clippy_lints/src/operators/float_cmp.rs
@@ -1,7 +1,7 @@
 use clippy_utils::consts::{ConstEvalCtxt, Constant};
 use clippy_utils::diagnostics::span_lint_and_then;
-use clippy_utils::get_item_name;
 use clippy_utils::sugg::Sugg;
+use clippy_utils::{parent_item_name, sym};
 use rustc_errors::Applicability;
 use rustc_hir::{BinOpKind, Expr, ExprKind, UnOp};
 use rustc_lint::LateContext;
@@ -34,7 +34,7 @@ pub(crate) fn check<'tcx>(
             return;
         }
 
-        if let Some(name) = get_item_name(cx, expr) {
+        if let Some(name) = parent_item_name(cx, expr) {
             let name = name.as_str();
             if name == "eq" || name == "ne" || name == "is_nan" || name.starts_with("eq_") || name.ends_with("_eq") {
                 return;
@@ -106,7 +106,7 @@ fn is_signum(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
     }
 
     if let ExprKind::MethodCall(method_name, self_arg, [], _) = expr.kind
-        && method_name.ident.name.as_str() == "signum"
+        && method_name.ident.name == sym::signum
     // Check that the receiver of the signum() is a float (expressions[0] is the receiver of
     // the method call)
     {
diff --git a/src/tools/clippy/clippy_lints/src/permissions_set_readonly_false.rs b/src/tools/clippy/clippy_lints/src/permissions_set_readonly_false.rs
index dc142b6e157..da56a785007 100644
--- a/src/tools/clippy/clippy_lints/src/permissions_set_readonly_false.rs
+++ b/src/tools/clippy/clippy_lints/src/permissions_set_readonly_false.rs
@@ -1,10 +1,10 @@
 use clippy_utils::diagnostics::span_lint_and_then;
+use clippy_utils::sym;
 use clippy_utils::ty::is_type_diagnostic_item;
 use rustc_ast::ast::LitKind;
 use rustc_hir::{Expr, ExprKind};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_session::declare_lint_pass;
-use rustc_span::sym;
 
 declare_clippy_lint! {
     /// ### What it does
@@ -33,7 +33,7 @@ impl<'tcx> LateLintPass<'tcx> for PermissionsSetReadonlyFalse {
         if let ExprKind::MethodCall(path, receiver, [arg], _) = &expr.kind
             && let ExprKind::Lit(lit) = &arg.kind
             && LitKind::Bool(false) == lit.node
-            && path.ident.name.as_str() == "set_readonly"
+            && path.ident.name == sym::set_readonly
             && is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(receiver), sym::FsPermissions)
         {
             span_lint_and_then(
diff --git a/src/tools/clippy/clippy_lints/src/ptr.rs b/src/tools/clippy/clippy_lints/src/ptr.rs
index 491961408ad..9149406642d 100644
--- a/src/tools/clippy/clippy_lints/src/ptr.rs
+++ b/src/tools/clippy/clippy_lints/src/ptr.rs
@@ -743,9 +743,9 @@ fn check_ptr_eq<'tcx>(
     }
 
     // Remove one level of usize conversion if any
-    let (left, right) = match (expr_as_cast_to_usize(cx, left), expr_as_cast_to_usize(cx, right)) {
-        (Some(lhs), Some(rhs)) => (lhs, rhs),
-        _ => (left, right),
+    let (left, right, usize_peeled) = match (expr_as_cast_to_usize(cx, left), expr_as_cast_to_usize(cx, right)) {
+        (Some(lhs), Some(rhs)) => (lhs, rhs, true),
+        _ => (left, right, false),
     };
 
     // This lint concerns raw pointers
@@ -754,7 +754,12 @@ fn check_ptr_eq<'tcx>(
         return;
     }
 
-    let (left_var, right_var) = (peel_raw_casts(cx, left, left_ty), peel_raw_casts(cx, right, right_ty));
+    let ((left_var, left_casts_peeled), (right_var, right_casts_peeled)) =
+        (peel_raw_casts(cx, left, left_ty), peel_raw_casts(cx, right, right_ty));
+
+    if !(usize_peeled || left_casts_peeled || right_casts_peeled) {
+        return;
+    }
 
     let mut app = Applicability::MachineApplicable;
     let left_snip = Sugg::hir_with_context(cx, left_var, expr.span.ctxt(), "_", &mut app);
@@ -787,8 +792,9 @@ fn expr_as_cast_to_usize<'tcx>(cx: &LateContext<'tcx>, cast_expr: &'tcx Expr<'_>
     }
 }
 
-// Peel raw casts if the remaining expression can be coerced to it
-fn peel_raw_casts<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>, expr_ty: Ty<'tcx>) -> &'tcx Expr<'tcx> {
+// Peel raw casts if the remaining expression can be coerced to it, and whether casts have been
+// peeled or not.
+fn peel_raw_casts<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>, expr_ty: Ty<'tcx>) -> (&'tcx Expr<'tcx>, bool) {
     if !expr.span.from_expansion()
         && let ExprKind::Cast(inner, _) = expr.kind
         && let ty::RawPtr(target_ty, _) = expr_ty.kind()
@@ -796,8 +802,8 @@ fn peel_raw_casts<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>, expr_ty:
         && let ty::RawPtr(inner_target_ty, _) | ty::Ref(_, inner_target_ty, _) = inner_ty.kind()
         && target_ty == inner_target_ty
     {
-        peel_raw_casts(cx, inner, inner_ty)
+        (peel_raw_casts(cx, inner, inner_ty).0, true)
     } else {
-        expr
+        (expr, false)
     }
 }
diff --git a/src/tools/clippy/clippy_lints/src/ptr_offset_with_cast.rs b/src/tools/clippy/clippy_lints/src/ptr_offset_with_cast.rs
index 7f74a2fff9f..d8d813f9846 100644
--- a/src/tools/clippy/clippy_lints/src/ptr_offset_with_cast.rs
+++ b/src/tools/clippy/clippy_lints/src/ptr_offset_with_cast.rs
@@ -1,10 +1,10 @@
 use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg};
 use clippy_utils::source::SpanRangeExt;
+use clippy_utils::sym;
 use rustc_errors::Applicability;
 use rustc_hir::{Expr, ExprKind};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_session::declare_lint_pass;
-use rustc_span::sym;
 use std::fmt;
 
 declare_clippy_lint! {
@@ -97,7 +97,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.as_str() == "wrapping_offset" {
+        if path_segment.ident.name == sym::wrapping_offset {
             return Some((arg_0, arg_1, Method::WrappingOffset));
         }
     }
diff --git a/src/tools/clippy/clippy_lints/src/question_mark.rs b/src/tools/clippy/clippy_lints/src/question_mark.rs
index d318897443d..c02e5e0621c 100644
--- a/src/tools/clippy/clippy_lints/src/question_mark.rs
+++ b/src/tools/clippy/clippy_lints/src/question_mark.rs
@@ -10,7 +10,7 @@ use clippy_utils::ty::{implements_trait, is_type_diagnostic_item};
 use clippy_utils::{
     eq_expr_value, higher, is_else_clause, is_in_const_context, is_lint_allowed, is_path_lang_item, is_res_lang_ctor,
     pat_and_expr_can_be_question_mark, path_res, path_to_local, path_to_local_id, peel_blocks, peel_blocks_with_stmt,
-    span_contains_cfg, span_contains_comment,
+    span_contains_cfg, span_contains_comment, sym,
 };
 use rustc_errors::Applicability;
 use rustc_hir::LangItem::{self, OptionNone, OptionSome, ResultErr, ResultOk};
@@ -22,15 +22,14 @@ use rustc_hir::{
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::ty::{self, Ty};
 use rustc_session::impl_lint_pass;
-use rustc_span::sym;
 use rustc_span::symbol::Symbol;
 
 declare_clippy_lint! {
     /// ### What it does
-    /// Checks for expressions that could be replaced by the question mark operator.
+    /// Checks for expressions that could be replaced by the `?` operator.
     ///
     /// ### Why is this bad?
-    /// Question mark usage is more idiomatic.
+    /// Using the `?` operator is shorter and more idiomatic.
     ///
     /// ### Example
     /// ```ignore
@@ -47,7 +46,7 @@ declare_clippy_lint! {
     #[clippy::version = "pre 1.29.0"]
     pub QUESTION_MARK,
     style,
-    "checks for expressions that could be replaced by the question mark operator"
+    "checks for expressions that could be replaced by the `?` operator"
 }
 
 pub struct QuestionMark {
@@ -207,8 +206,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.as_str() == "is_none",
-                    sym::Result => call_sym.as_str() == "is_err",
+                    sym::Option => call_sym == sym::is_none,
+                    sym::Result => call_sym == sym::is_err,
                     _ => false,
                 }
         },
@@ -280,7 +279,7 @@ fn expr_return_none_or_err(
 /// }
 /// ```
 ///
-/// If it matches, it will suggest to use the question mark operator instead
+/// If it matches, it will suggest to use the `?` operator instead
 fn check_is_none_or_err_and_early_return<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'tcx>) {
     if let Some(higher::If { cond, then, r#else }) = higher::If::hir(expr)
         && !is_else_clause(cx.tcx, expr)
diff --git a/src/tools/clippy/clippy_lints/src/question_mark_used.rs b/src/tools/clippy/clippy_lints/src/question_mark_used.rs
index 0a974bf9d2f..96ea485d769 100644
--- a/src/tools/clippy/clippy_lints/src/question_mark_used.rs
+++ b/src/tools/clippy/clippy_lints/src/question_mark_used.rs
@@ -7,10 +7,10 @@ use rustc_session::declare_lint_pass;
 
 declare_clippy_lint! {
     /// ### What it does
-    /// Checks for expressions that use the question mark operator and rejects them.
+    /// Checks for expressions that use the `?` operator and rejects them.
     ///
     /// ### Why restrict this?
-    /// Sometimes code wants to avoid the question mark operator because for instance a local
+    /// Sometimes code wants to avoid the `?` operator because for instance a local
     /// block requires a macro to re-throw errors to attach additional information to the
     /// error.
     ///
@@ -27,7 +27,7 @@ declare_clippy_lint! {
     #[clippy::version = "1.69.0"]
     pub QUESTION_MARK_USED,
     restriction,
-    "complains if the question mark operator is used"
+    "checks if the `?` operator is used"
 }
 
 declare_lint_pass!(QuestionMarkUsed => [QUESTION_MARK_USED]);
@@ -40,15 +40,9 @@ impl<'tcx> LateLintPass<'tcx> for QuestionMarkUsed {
             }
 
             #[expect(clippy::collapsible_span_lint_calls, reason = "rust-clippy#7797")]
-            span_lint_and_then(
-                cx,
-                QUESTION_MARK_USED,
-                expr.span,
-                "question mark operator was used",
-                |diag| {
-                    diag.help("consider using a custom macro or match expression");
-                },
-            );
+            span_lint_and_then(cx, QUESTION_MARK_USED, expr.span, "the `?` operator was used", |diag| {
+                diag.help("consider using a custom macro or match expression");
+            });
         }
     }
 }
diff --git a/src/tools/clippy/clippy_lints/src/slow_vector_initialization.rs b/src/tools/clippy/clippy_lints/src/slow_vector_initialization.rs
index d26288adb39..30a5fe4db27 100644
--- a/src/tools/clippy/clippy_lints/src/slow_vector_initialization.rs
+++ b/src/tools/clippy/clippy_lints/src/slow_vector_initialization.rs
@@ -3,14 +3,13 @@ use clippy_utils::macros::matching_root_macro_call;
 use clippy_utils::sugg::Sugg;
 use clippy_utils::{
     SpanlessEq, get_enclosing_block, is_integer_literal, is_path_diagnostic_item, path_to_local, path_to_local_id,
-    span_contains_comment,
+    span_contains_comment, sym,
 };
 use rustc_errors::Applicability;
 use rustc_hir::intravisit::{Visitor, walk_block, walk_expr, walk_stmt};
 use rustc_hir::{BindingMode, Block, Expr, ExprKind, HirId, PatKind, Stmt, StmtKind};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_session::declare_lint_pass;
-use rustc_span::symbol::sym;
 
 declare_clippy_lint! {
     /// ### What it does
@@ -248,7 +247,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.as_str() == "extend"
+            && path.ident.name == sym::extend
             && self.is_repeat_take(extend_arg)
         {
             self.slow_expression = Some(InitializationType::Extend(expr));
@@ -260,7 +259,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.as_str() == "resize"
+            && path.ident.name == sym::resize
             // Check that is filled with 0
             && is_integer_literal(fill_arg, 0)
         {
@@ -282,7 +281,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.as_str() == "take"
+            && take_path.ident.name == sym::take
             // Check that take is applied to `repeat(0)`
             && self.is_repeat_zero(recv)
         {
diff --git a/src/tools/clippy/clippy_lints/src/strings.rs b/src/tools/clippy/clippy_lints/src/strings.rs
index 43a3e696105..af4d0d541f1 100644
--- a/src/tools/clippy/clippy_lints/src/strings.rs
+++ b/src/tools/clippy/clippy_lints/src/strings.rs
@@ -286,7 +286,7 @@ impl<'tcx> LateLintPass<'tcx> for StringLitAsBytes {
 
         if !e.span.in_external_macro(cx.sess().source_map())
             && let ExprKind::MethodCall(path, receiver, ..) = &e.kind
-            && path.ident.name.as_str() == "as_bytes"
+            && path.ident.name == sym::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.as_str() == "into_bytes"
+            && path.ident.name == sym::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
@@ -556,7 +556,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.as_str() == "split_whitespace"
+            && path.ident.name == sym::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/src/tools/clippy/clippy_lints/src/to_digit_is_some.rs b/src/tools/clippy/clippy_lints/src/to_digit_is_some.rs
index 9993e6ae18b..bb969bc802f 100644
--- a/src/tools/clippy/clippy_lints/src/to_digit_is_some.rs
+++ b/src/tools/clippy/clippy_lints/src/to_digit_is_some.rs
@@ -1,6 +1,6 @@
 use clippy_utils::diagnostics::span_lint_and_sugg;
-use clippy_utils::match_def_path;
 use clippy_utils::source::snippet_with_applicability;
+use clippy_utils::{match_def_path, sym};
 use rustc_errors::Applicability;
 use rustc_hir as hir;
 use rustc_lint::{LateContext, LateLintPass};
@@ -38,11 +38,11 @@ declare_lint_pass!(ToDigitIsSome => [TO_DIGIT_IS_SOME]);
 impl<'tcx> LateLintPass<'tcx> for ToDigitIsSome {
     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>) {
         if let hir::ExprKind::MethodCall(is_some_path, to_digit_expr, [], _) = &expr.kind
-            && is_some_path.ident.name.as_str() == "is_some"
+            && is_some_path.ident.name == sym::is_some
         {
             let match_result = match &to_digit_expr.kind {
                 hir::ExprKind::MethodCall(to_digits_path, char_arg, [radix_arg], _) => {
-                    if to_digits_path.ident.name.as_str() == "to_digit"
+                    if to_digits_path.ident.name == sym::to_digit
                         && let char_arg_ty = cx.typeck_results().expr_ty_adjusted(char_arg)
                         && *char_arg_ty.kind() == ty::Char
                     {
diff --git a/src/tools/clippy/clippy_lints/src/transmute/eager_transmute.rs b/src/tools/clippy/clippy_lints/src/transmute/eager_transmute.rs
index 81c0a57083e..1ccab62708b 100644
--- a/src/tools/clippy/clippy_lints/src/transmute/eager_transmute.rs
+++ b/src/tools/clippy/clippy_lints/src/transmute/eager_transmute.rs
@@ -1,6 +1,6 @@
 use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::ty::is_normalizable;
-use clippy_utils::{eq_expr_value, path_to_local};
+use clippy_utils::{eq_expr_value, path_to_local, sym};
 use rustc_abi::WrappingRange;
 use rustc_errors::Applicability;
 use rustc_hir::{Expr, ExprKind, Node};
@@ -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.as_str() == "contains"
+            if path.ident.name == sym::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.as_str() == "then_some"
+        && path.ident.name == sym::then_some
         && is_local_with_projections(transmutable)
         && binops_with_local(cx, transmutable, receiver)
         && is_normalizable(cx, cx.param_env, from_ty)
diff --git a/src/tools/clippy/clippy_lints/src/types/vec_box.rs b/src/tools/clippy/clippy_lints/src/types/vec_box.rs
index 769244c675e..f13042a6fa6 100644
--- a/src/tools/clippy/clippy_lints/src/types/vec_box.rs
+++ b/src/tools/clippy/clippy_lints/src/types/vec_box.rs
@@ -19,61 +19,58 @@ pub(super) fn check<'tcx>(
     def_id: DefId,
     box_size_threshold: u64,
 ) -> bool {
-    if cx.tcx.is_diagnostic_item(sym::Vec, def_id) {
-        if let Some(last) = last_path_segment(qpath).args
-            // Get the _ part of Vec<_>
-            && let Some(GenericArg::Type(ty)) = last.args.first()
-            // extract allocator from the Vec for later
-            && let vec_alloc_ty = last.args.get(1)
-            // ty is now _ at this point
-            && let TyKind::Path(ref ty_qpath) = ty.kind
-            && let res = cx.qpath_res(ty_qpath, ty.hir_id)
-            && let Some(def_id) = res.opt_def_id()
-            && Some(def_id) == cx.tcx.lang_items().owned_box()
-            // At this point, we know ty is Box<T>, now get T
-            && let Some(last) = last_path_segment(ty_qpath).args
-            && let Some(GenericArg::Type(boxed_ty)) = last.args.first()
-            // extract allocator from the Box for later
-            && let boxed_alloc_ty = last.args.get(1)
-            // we don't expect to encounter `_` here so ignore `GenericArg::Infer` is okay
-            && let ty_ty = lower_ty(cx.tcx, boxed_ty.as_unambig_ty())
-            && !ty_ty.has_escaping_bound_vars()
-            && ty_ty.is_sized(cx.tcx, cx.typing_env())
-            && let Ok(ty_ty_size) = cx.layout_of(ty_ty).map(|l| l.size.bytes())
-            && ty_ty_size < box_size_threshold
-            // https://github.com/rust-lang/rust-clippy/issues/7114
-            && match (vec_alloc_ty, boxed_alloc_ty) {
-                (None, None) => true,
-                // this is in the event that we have something like
-                // Vec<_, Global>, in which case is equivalent to
-                // Vec<_>
-                (None, Some(GenericArg::Type(inner))) | (Some(GenericArg::Type(inner)), None) => {
-                    if let TyKind::Path(path) = inner.kind
-                        && let Some(did) = cx.qpath_res(&path, inner.hir_id).opt_def_id() {
-                        cx.tcx.lang_items().get(LangItem::GlobalAlloc) == Some(did)
-                    } else {
-                        false
-                    }
-                },
-                (Some(GenericArg::Type(l)), Some(GenericArg::Type(r))) =>
-                    // we don't expect to encounter `_` here so ignore `GenericArg::Infer` is okay
-                    lower_ty(cx.tcx, l.as_unambig_ty()) == lower_ty(cx.tcx, r.as_unambig_ty()),
-                _ => false
-            }
-        {
-            span_lint_and_sugg(
-                cx,
-                VEC_BOX,
-                hir_ty.span,
-                "`Vec<T>` is already on the heap, the boxing is unnecessary",
-                "try",
-                format!("Vec<{}>", snippet(cx, boxed_ty.span, "..")),
-                Applicability::Unspecified,
-            );
-            true
-        } else {
-            false
+    if cx.tcx.is_diagnostic_item(sym::Vec, def_id)
+        && let Some(last) = last_path_segment(qpath).args
+        // Get the _ part of Vec<_>
+        && let Some(GenericArg::Type(ty)) = last.args.first()
+        // extract allocator from the Vec for later
+        && let vec_alloc_ty = last.args.get(1)
+        // ty is now _ at this point
+        && let TyKind::Path(ref ty_qpath) = ty.kind
+        && let res = cx.qpath_res(ty_qpath, ty.hir_id)
+        && let Some(def_id) = res.opt_def_id()
+        && Some(def_id) == cx.tcx.lang_items().owned_box()
+        // At this point, we know ty is Box<T>, now get T
+        && let Some(last) = last_path_segment(ty_qpath).args
+        && let Some(GenericArg::Type(boxed_ty)) = last.args.first()
+        // extract allocator from the Box for later
+        && let boxed_alloc_ty = last.args.get(1)
+        // we don't expect to encounter `_` here so ignore `GenericArg::Infer` is okay
+        && let ty_ty = lower_ty(cx.tcx, boxed_ty.as_unambig_ty())
+        && !ty_ty.has_escaping_bound_vars()
+        && ty_ty.is_sized(cx.tcx, cx.typing_env())
+        && let Ok(ty_ty_size) = cx.layout_of(ty_ty).map(|l| l.size.bytes())
+        && ty_ty_size < box_size_threshold
+        // https://github.com/rust-lang/rust-clippy/issues/7114
+        && match (vec_alloc_ty, boxed_alloc_ty) {
+            (None, None) => true,
+            // this is in the event that we have something like
+            // Vec<_, Global>, in which case is equivalent to
+            // Vec<_>
+            (None, Some(GenericArg::Type(inner))) | (Some(GenericArg::Type(inner)), None) => {
+                if let TyKind::Path(path) = inner.kind
+                    && let Some(did) = cx.qpath_res(&path, inner.hir_id).opt_def_id() {
+                    cx.tcx.lang_items().get(LangItem::GlobalAlloc) == Some(did)
+                } else {
+                    false
+                }
+            },
+            (Some(GenericArg::Type(l)), Some(GenericArg::Type(r))) =>
+                // we don't expect to encounter `_` here so ignore `GenericArg::Infer` is okay
+                lower_ty(cx.tcx, l.as_unambig_ty()) == lower_ty(cx.tcx, r.as_unambig_ty()),
+            _ => false
         }
+    {
+        span_lint_and_sugg(
+            cx,
+            VEC_BOX,
+            hir_ty.span,
+            "`Vec<T>` is already on the heap, the boxing is unnecessary",
+            "try",
+            format!("Vec<{}>", snippet(cx, boxed_ty.span, "..")),
+            Applicability::Unspecified,
+        );
+        true
     } else {
         false
     }
diff --git a/src/tools/clippy/clippy_lints/src/uninit_vec.rs b/src/tools/clippy/clippy_lints/src/uninit_vec.rs
index 7803d5115c9..cee4a53f03c 100644
--- a/src/tools/clippy/clippy_lints/src/uninit_vec.rs
+++ b/src/tools/clippy/clippy_lints/src/uninit_vec.rs
@@ -1,12 +1,12 @@
 use clippy_utils::diagnostics::{span_lint, span_lint_and_then};
 use clippy_utils::higher::{VecInitKind, get_vec_init_kind};
 use clippy_utils::ty::{is_type_diagnostic_item, is_uninit_value_valid_for_ty};
-use clippy_utils::{SpanlessEq, is_integer_literal, is_lint_allowed, path_to_local_id, peel_hir_expr_while};
+use clippy_utils::{SpanlessEq, is_integer_literal, is_lint_allowed, path_to_local_id, peel_hir_expr_while, sym};
 use rustc_hir::{Block, Expr, ExprKind, HirId, PatKind, PathSegment, Stmt, StmtKind};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::ty;
 use rustc_session::declare_lint_pass;
-use rustc_span::{Span, sym};
+use rustc_span::Span;
 
 // TODO: add `ReadBuf` (RFC 2930) in "How to fix" once it is available in std
 declare_clippy_lint! {
@@ -187,7 +187,7 @@ fn extract_init_or_reserve_target<'tcx>(cx: &LateContext<'tcx>, stmt: &'tcx Stmt
 
 fn is_reserve(cx: &LateContext<'_>, path: &PathSegment<'_>, self_expr: &Expr<'_>) -> bool {
     is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(self_expr).peel_refs(), sym::Vec)
-        && path.ident.name.as_str() == "reserve"
+        && path.ident.name == sym::reserve
 }
 
 /// Returns self if the expression is `Vec::set_len()`
@@ -209,7 +209,7 @@ fn extract_set_len_self<'tcx>(cx: &LateContext<'_>, expr: &'tcx Expr<'_>) -> Opt
         ExprKind::MethodCall(path, self_expr, [arg], _) => {
             let self_type = cx.typeck_results().expr_ty(self_expr).peel_refs();
             if is_type_diagnostic_item(cx, self_type, sym::Vec)
-                && path.ident.name.as_str() == "set_len"
+                && path.ident.name == sym::set_len
                 && !is_integer_literal(arg, 0)
             {
                 Some((self_expr, expr.span))
diff --git a/src/tools/clippy/clippy_lints/src/unused_self.rs b/src/tools/clippy/clippy_lints/src/unused_self.rs
index d0067b1a65e..12da891a71b 100644
--- a/src/tools/clippy/clippy_lints/src/unused_self.rs
+++ b/src/tools/clippy/clippy_lints/src/unused_self.rs
@@ -1,6 +1,7 @@
 use clippy_config::Conf;
 use clippy_utils::diagnostics::span_lint_and_help;
 use clippy_utils::macros::root_macro_call_first_node;
+use clippy_utils::sym;
 use clippy_utils::visitors::is_local_used;
 use rustc_hir::{Body, Impl, ImplItem, ImplItemKind, ItemKind};
 use rustc_lint::{LateContext, LateLintPass};
@@ -61,12 +62,10 @@ impl<'tcx> LateLintPass<'tcx> for UnusedSelf {
         let assoc_item = cx.tcx.associated_item(impl_item.owner_id);
         let contains_todo = |cx, body: &'_ Body<'_>| -> bool {
             clippy_utils::visitors::for_each_expr_without_closures(body.value, |e| {
-                if let Some(macro_call) = root_macro_call_first_node(cx, e) {
-                    if cx.tcx.item_name(macro_call.def_id).as_str() == "todo" {
-                        ControlFlow::Break(())
-                    } else {
-                        ControlFlow::Continue(())
-                    }
+                if let Some(macro_call) = root_macro_call_first_node(cx, e)
+                    && cx.tcx.is_diagnostic_item(sym::todo_macro, macro_call.def_id)
+                {
+                    ControlFlow::Break(())
                 } else {
                     ControlFlow::Continue(())
                 }
diff --git a/src/tools/clippy/clippy_lints/src/unused_unit.rs b/src/tools/clippy/clippy_lints/src/unused_unit.rs
index d5309aade7a..9859ddfdf7b 100644
--- a/src/tools/clippy/clippy_lints/src/unused_unit.rs
+++ b/src/tools/clippy/clippy_lints/src/unused_unit.rs
@@ -1,11 +1,18 @@
 use clippy_utils::diagnostics::span_lint_and_sugg;
 use clippy_utils::source::{SpanRangeExt, position_before_rarrow};
-use rustc_ast::visit::FnKind;
-use rustc_ast::{ClosureBinder, ast};
+use clippy_utils::{is_never_expr, is_unit_expr};
+use rustc_ast::{Block, StmtKind};
 use rustc_errors::Applicability;
-use rustc_lint::{EarlyContext, EarlyLintPass};
+use rustc_hir::def_id::LocalDefId;
+use rustc_hir::intravisit::FnKind;
+use rustc_hir::{
+    AssocItemConstraintKind, Body, Expr, ExprKind, FnDecl, FnRetTy, GenericArgsParentheses, Node, PolyTraitRef, Term,
+    Ty, TyKind,
+};
+use rustc_lint::{EarlyContext, EarlyLintPass, LateContext, LateLintPass};
 use rustc_session::declare_lint_pass;
-use rustc_span::{BytePos, Span};
+use rustc_span::edition::Edition;
+use rustc_span::{BytePos, Span, sym};
 
 declare_clippy_lint! {
     /// ### What it does
@@ -34,27 +41,89 @@ declare_clippy_lint! {
 
 declare_lint_pass!(UnusedUnit => [UNUSED_UNIT]);
 
-impl EarlyLintPass for UnusedUnit {
-    fn check_fn(&mut self, cx: &EarlyContext<'_>, kind: FnKind<'_>, span: Span, _: ast::NodeId) {
-        if let ast::FnRetTy::Ty(ref ty) = kind.decl().output
-            && let ast::TyKind::Tup(ref vals) = ty.kind
-            && vals.is_empty()
-            && !ty.span.from_expansion()
-            && get_def(span) == get_def(ty.span)
+impl<'tcx> LateLintPass<'tcx> for UnusedUnit {
+    fn check_fn(
+        &mut self,
+        cx: &LateContext<'tcx>,
+        kind: FnKind<'tcx>,
+        decl: &'tcx FnDecl<'tcx>,
+        body: &'tcx Body<'tcx>,
+        span: Span,
+        def_id: LocalDefId,
+    ) {
+        if let FnRetTy::Return(hir_ty) = decl.output
+            && is_unit_ty(hir_ty)
+            && !hir_ty.span.from_expansion()
+            && get_def(span) == get_def(hir_ty.span)
         {
             // implicit types in closure signatures are forbidden when `for<...>` is present
-            if let FnKind::Closure(&ClosureBinder::For { .. }, ..) = kind {
+            if let FnKind::Closure = kind
+                && let Node::Expr(expr) = cx.tcx.hir_node_by_def_id(def_id)
+                && let ExprKind::Closure(closure) = expr.kind
+                && !closure.bound_generic_params.is_empty()
+            {
+                return;
+            }
+
+            // unit never type fallback is no longer supported since Rust 2024. For more information,
+            // see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/never-type-fallback.html>
+            if cx.tcx.sess.edition() >= Edition::Edition2024
+                && let ExprKind::Block(block, _) = body.value.kind
+                && let Some(expr) = block.expr
+                && is_never_expr(cx, expr).is_some()
+            {
                 return;
             }
 
-            lint_unneeded_unit_return(cx, ty, span);
+            lint_unneeded_unit_return(cx, hir_ty.span, span);
         }
     }
 
-    fn check_block(&mut self, cx: &EarlyContext<'_>, block: &ast::Block) {
-        if let Some(stmt) = block.stmts.last()
-            && let ast::StmtKind::Expr(ref expr) = stmt.kind
+    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) {
+        if let ExprKind::Ret(Some(expr)) | ExprKind::Break(_, Some(expr)) = expr.kind
             && is_unit_expr(expr)
+            && !expr.span.from_expansion()
+        {
+            span_lint_and_sugg(
+                cx,
+                UNUSED_UNIT,
+                expr.span,
+                "unneeded `()`",
+                "remove the `()`",
+                String::new(),
+                Applicability::MachineApplicable,
+            );
+        }
+    }
+
+    fn check_poly_trait_ref(&mut self, cx: &LateContext<'tcx>, poly: &'tcx PolyTraitRef<'tcx>) {
+        let segments = &poly.trait_ref.path.segments;
+
+        if segments.len() == 1
+            && ["Fn", "FnMut", "FnOnce"].contains(&segments[0].ident.name.as_str())
+            && let Some(args) = segments[0].args
+            && args.parenthesized == GenericArgsParentheses::ParenSugar
+            && let constraints = &args.constraints
+            && constraints.len() == 1
+            && constraints[0].ident.name == sym::Output
+            && let AssocItemConstraintKind::Equality { term: Term::Ty(hir_ty) } = constraints[0].kind
+            && args.span_ext.hi() != poly.span.hi()
+            && !hir_ty.span.from_expansion()
+            && is_unit_ty(hir_ty)
+        {
+            lint_unneeded_unit_return(cx, hir_ty.span, poly.span);
+        }
+    }
+}
+
+impl EarlyLintPass for UnusedUnit {
+    /// Check for unit expressions in blocks. This is left in the early pass because some macros
+    /// expand its inputs as-is, making it invisible to the late pass. See #4076.
+    fn check_block(&mut self, cx: &EarlyContext<'_>, block: &Block) {
+        if let Some(stmt) = block.stmts.last()
+            && let StmtKind::Expr(expr) = &stmt.kind
+            && let rustc_ast::ExprKind::Tup(inner) = &expr.kind
+            && inner.is_empty()
             && let ctxt = block.span.ctxt()
             && stmt.span.ctxt() == ctxt
             && expr.span.ctxt() == ctxt
@@ -72,39 +141,10 @@ impl EarlyLintPass for UnusedUnit {
             );
         }
     }
+}
 
-    fn check_expr(&mut self, cx: &EarlyContext<'_>, e: &ast::Expr) {
-        match e.kind {
-            ast::ExprKind::Ret(Some(ref expr)) | ast::ExprKind::Break(_, Some(ref expr)) => {
-                if is_unit_expr(expr) && !expr.span.from_expansion() {
-                    span_lint_and_sugg(
-                        cx,
-                        UNUSED_UNIT,
-                        expr.span,
-                        "unneeded `()`",
-                        "remove the `()`",
-                        String::new(),
-                        Applicability::MachineApplicable,
-                    );
-                }
-            },
-            _ => (),
-        }
-    }
-
-    fn check_poly_trait_ref(&mut self, cx: &EarlyContext<'_>, poly: &ast::PolyTraitRef) {
-        let segments = &poly.trait_ref.path.segments;
-
-        if segments.len() == 1
-            && ["Fn", "FnMut", "FnOnce"].contains(&segments[0].ident.name.as_str())
-            && let Some(args) = &segments[0].args
-            && let ast::GenericArgs::Parenthesized(generic_args) = &**args
-            && let ast::FnRetTy::Ty(ty) = &generic_args.output
-            && ty.kind.is_unit()
-        {
-            lint_unneeded_unit_return(cx, ty, generic_args.span);
-        }
-    }
+fn is_unit_ty(ty: &Ty<'_>) -> bool {
+    matches!(ty.kind, TyKind::Tup([]))
 }
 
 // get the def site
@@ -117,24 +157,15 @@ fn get_def(span: Span) -> Option<Span> {
     }
 }
 
-// is this expr a `()` unit?
-fn is_unit_expr(expr: &ast::Expr) -> bool {
-    if let ast::ExprKind::Tup(ref vals) = expr.kind {
-        vals.is_empty()
-    } else {
-        false
-    }
-}
-
-fn lint_unneeded_unit_return(cx: &EarlyContext<'_>, ty: &ast::Ty, span: Span) {
+fn lint_unneeded_unit_return(cx: &LateContext<'_>, ty_span: Span, span: Span) {
     let (ret_span, appl) =
-        span.with_hi(ty.span.hi())
+        span.with_hi(ty_span.hi())
             .get_source_text(cx)
-            .map_or((ty.span, Applicability::MaybeIncorrect), |src| {
-                position_before_rarrow(&src).map_or((ty.span, Applicability::MaybeIncorrect), |rpos| {
+            .map_or((ty_span, Applicability::MaybeIncorrect), |src| {
+                position_before_rarrow(&src).map_or((ty_span, Applicability::MaybeIncorrect), |rpos| {
                     (
                         #[expect(clippy::cast_possible_truncation)]
-                        ty.span.with_lo(BytePos(span.lo().0 + rpos as u32)),
+                        ty_span.with_lo(BytePos(span.lo().0 + rpos as u32)),
                         Applicability::MachineApplicable,
                     )
                 })
diff --git a/src/tools/clippy/clippy_lints/src/unwrap.rs b/src/tools/clippy/clippy_lints/src/unwrap.rs
index ce82b56eb94..ba140788bb5 100644
--- a/src/tools/clippy/clippy_lints/src/unwrap.rs
+++ b/src/tools/clippy/clippy_lints/src/unwrap.rs
@@ -208,7 +208,7 @@ fn is_option_as_mut_use(tcx: TyCtxt<'_>, expr_id: HirId) -> bool {
     if let Node::Expr(mutating_expr) = tcx.parent_hir_node(expr_id)
         && let ExprKind::MethodCall(path, _, [], _) = mutating_expr.kind
     {
-        path.ident.name.as_str() == "as_mut"
+        path.ident.name == sym::as_mut
     } else {
         false
     }
@@ -278,7 +278,7 @@ fn consume_option_as_ref<'tcx>(expr: &'tcx Expr<'tcx>) -> (&'tcx Expr<'tcx>, Opt
     if let ExprKind::MethodCall(path, recv, [], _) = expr.kind {
         if path.ident.name == sym::as_ref {
             (recv, Some(AsRefKind::AsRef))
-        } else if path.ident.name.as_str() == "as_mut" {
+        } else if path.ident.name == sym::as_mut {
             (recv, Some(AsRefKind::AsMut))
         } else {
             (expr, None)
diff --git a/src/tools/clippy/clippy_lints/src/write.rs b/src/tools/clippy/clippy_lints/src/write.rs
index 11c14c14777..f24c127c452 100644
--- a/src/tools/clippy/clippy_lints/src/write.rs
+++ b/src/tools/clippy/clippy_lints/src/write.rs
@@ -1,8 +1,8 @@
 use clippy_config::Conf;
 use clippy_utils::diagnostics::{span_lint, span_lint_and_then};
-use clippy_utils::is_in_test;
 use clippy_utils::macros::{FormatArgsStorage, MacroCall, format_arg_removal_span, root_macro_call_first_node};
 use clippy_utils::source::{SpanRangeExt, expand_past_previous_comma};
+use clippy_utils::{is_in_test, sym};
 use rustc_ast::token::LitKind;
 use rustc_ast::{
     FormatArgPosition, FormatArgPositionKind, FormatArgs, FormatArgsPiece, FormatOptions, FormatPlaceholder,
@@ -12,7 +12,7 @@ use rustc_errors::Applicability;
 use rustc_hir::{Expr, Impl, Item, ItemKind};
 use rustc_lint::{LateContext, LateLintPass, LintContext};
 use rustc_session::impl_lint_pass;
-use rustc_span::{BytePos, Span, sym};
+use rustc_span::{BytePos, Span};
 
 declare_clippy_lint! {
     /// ### What it does
@@ -359,7 +359,7 @@ fn is_debug_impl(cx: &LateContext<'_>, item: &Item<'_>) -> bool {
 }
 
 fn check_newline(cx: &LateContext<'_>, format_args: &FormatArgs, macro_call: &MacroCall, name: &str) {
-    let Some(FormatArgsPiece::Literal(last)) = format_args.template.last() else {
+    let Some(&FormatArgsPiece::Literal(last)) = format_args.template.last() else {
         return;
     };
 
@@ -401,7 +401,7 @@ fn check_newline(cx: &LateContext<'_>, format_args: &FormatArgs, macro_call: &Ma
                     return;
                 };
 
-                if format_args.template.len() == 1 && last.as_str() == "\n" {
+                if format_args.template.len() == 1 && last == sym::LF {
                     // print!("\n"), write!(f, "\n")
 
                     diag.multipart_suggestion(
@@ -427,9 +427,7 @@ fn check_newline(cx: &LateContext<'_>, format_args: &FormatArgs, macro_call: &Ma
 }
 
 fn check_empty_string(cx: &LateContext<'_>, format_args: &FormatArgs, macro_call: &MacroCall, name: &str) {
-    if let [FormatArgsPiece::Literal(literal)] = &format_args.template[..]
-        && literal.as_str() == "\n"
-    {
+    if let [FormatArgsPiece::Literal(sym::LF)] = &format_args.template[..] {
         let mut span = format_args.span;
 
         let lint = if name == "writeln" {
diff --git a/src/tools/clippy/clippy_lints/src/zombie_processes.rs b/src/tools/clippy/clippy_lints/src/zombie_processes.rs
index 39c1aab8967..09f1084fe70 100644
--- a/src/tools/clippy/clippy_lints/src/zombie_processes.rs
+++ b/src/tools/clippy/clippy_lints/src/zombie_processes.rs
@@ -4,6 +4,7 @@ use clippy_utils::{fn_def_id, get_enclosing_block, path_to_local_id};
 use rustc_ast::Mutability;
 use rustc_ast::visit::visit_opt;
 use rustc_errors::Applicability;
+use rustc_hir::def_id::LocalDefId;
 use rustc_hir::intravisit::{Visitor, walk_block, walk_expr, walk_local};
 use rustc_hir::{Expr, ExprKind, HirId, LetStmt, Node, PatKind, Stmt, StmtKind};
 use rustc_lint::{LateContext, LateLintPass};
@@ -68,6 +69,7 @@ impl<'tcx> LateLintPass<'tcx> for ZombieProcesses {
                     let mut vis = WaitFinder {
                         cx,
                         local_id,
+                        body_id: cx.tcx.hir_enclosing_body_owner(expr.hir_id),
                         state: VisitorState::WalkUpToLocal,
                         early_return: None,
                         missing_wait_branch: None,
@@ -129,6 +131,7 @@ struct MaybeWait(Span);
 struct WaitFinder<'a, 'tcx> {
     cx: &'a LateContext<'tcx>,
     local_id: HirId,
+    body_id: LocalDefId,
     state: VisitorState,
     early_return: Option<Span>,
     // When joining two if branches where one of them doesn't call `wait()`, stores its span for more targeted help
@@ -186,7 +189,7 @@ impl<'tcx> Visitor<'tcx> for WaitFinder<'_, 'tcx> {
             }
         } else {
             match ex.kind {
-                ExprKind::Ret(e) => {
+                ExprKind::Ret(e) if self.cx.tcx.hir_enclosing_body_owner(ex.hir_id) == self.body_id => {
                     visit_opt!(self, visit_expr, e);
                     if self.early_return.is_none() {
                         self.early_return = Some(ex.span);
diff --git a/src/tools/clippy/clippy_lints_internal/src/lib.rs b/src/tools/clippy/clippy_lints_internal/src/lib.rs
index 1c42f4112f9..b02d378619c 100644
--- a/src/tools/clippy/clippy_lints_internal/src/lib.rs
+++ b/src/tools/clippy/clippy_lints_internal/src/lib.rs
@@ -2,6 +2,7 @@
 #![allow(
     clippy::missing_docs_in_private_items,
     clippy::must_use_candidate,
+    clippy::symbol_as_str,
     rustc::diagnostic_outside_of_impl,
     rustc::untranslatable_diagnostic
 )]
@@ -31,12 +32,12 @@ extern crate rustc_span;
 
 mod almost_standard_lint_formulation;
 mod collapsible_calls;
-mod interning_literals;
 mod invalid_paths;
 mod lint_without_lint_pass;
 mod msrv_attr_impl;
 mod outer_expn_data_pass;
 mod produce_ice;
+mod symbols;
 mod unnecessary_def_path;
 mod unsorted_clippy_utils_paths;
 
@@ -45,7 +46,6 @@ use rustc_lint::{Lint, LintStore};
 static LINTS: &[&Lint] = &[
     almost_standard_lint_formulation::ALMOST_STANDARD_LINT_FORMULATION,
     collapsible_calls::COLLAPSIBLE_SPAN_LINT_CALLS,
-    interning_literals::INTERNING_LITERALS,
     invalid_paths::INVALID_PATHS,
     lint_without_lint_pass::DEFAULT_LINT,
     lint_without_lint_pass::INVALID_CLIPPY_VERSION_ATTRIBUTE,
@@ -54,6 +54,8 @@ static LINTS: &[&Lint] = &[
     msrv_attr_impl::MISSING_MSRV_ATTR_IMPL,
     outer_expn_data_pass::OUTER_EXPN_EXPN_DATA,
     produce_ice::PRODUCE_ICE,
+    symbols::INTERNING_LITERALS,
+    symbols::SYMBOL_AS_STR,
     unnecessary_def_path::UNNECESSARY_DEF_PATH,
     unsorted_clippy_utils_paths::UNSORTED_CLIPPY_UTILS_PATHS,
 ];
@@ -65,7 +67,7 @@ pub fn register_lints(store: &mut LintStore) {
     store.register_early_pass(|| Box::new(produce_ice::ProduceIce));
     store.register_late_pass(|_| Box::new(collapsible_calls::CollapsibleCalls));
     store.register_late_pass(|_| Box::new(invalid_paths::InvalidPaths));
-    store.register_late_pass(|_| Box::<interning_literals::InterningDefinedSymbol>::default());
+    store.register_late_pass(|_| Box::<symbols::Symbols>::default());
     store.register_late_pass(|_| Box::<lint_without_lint_pass::LintWithoutLintPass>::default());
     store.register_late_pass(|_| Box::<unnecessary_def_path::UnnecessaryDefPath>::default());
     store.register_late_pass(|_| Box::new(outer_expn_data_pass::OuterExpnDataPass));
diff --git a/src/tools/clippy/clippy_lints_internal/src/interning_literals.rs b/src/tools/clippy/clippy_lints_internal/src/symbols.rs
index 6cee3744234..c64e5821916 100644
--- a/src/tools/clippy/clippy_lints_internal/src/interning_literals.rs
+++ b/src/tools/clippy/clippy_lints_internal/src/symbols.rs
@@ -1,7 +1,7 @@
-use clippy_utils::consts::{ConstEvalCtxt, Constant};
 use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::ty::match_type;
-use clippy_utils::{def_path_def_ids, paths};
+use clippy_utils::{def_path_def_ids, match_def_path, paths};
+use rustc_ast::LitKind;
 use rustc_data_structures::fx::FxHashMap;
 use rustc_errors::Applicability;
 use rustc_hir::def::{DefKind, Res};
@@ -11,8 +11,8 @@ use rustc_lint_defs::declare_tool_lint;
 use rustc_middle::mir::ConstValue;
 use rustc_middle::ty;
 use rustc_session::impl_lint_pass;
-use rustc_span::sym;
 use rustc_span::symbol::Symbol;
+use rustc_span::{Span, sym};
 
 declare_tool_lint! {
     /// ### What it does
@@ -36,15 +36,37 @@ declare_tool_lint! {
     report_in_external_macro: true
 }
 
+declare_tool_lint! {
+    /// ### What it does
+    /// Checks for calls to `Symbol::as_str`
+    ///
+    /// ### Why is this bad?
+    /// It's faster and easier to use the symbol constant. If one doesn't exist it can be added to `clippy_utils/src/sym.rs`
+    ///
+    /// ### Example
+    /// ```rust,ignore
+    /// symbol.as_str() == "foo"
+    /// ```
+    ///
+    /// Use instead:
+    /// ```rust,ignore
+    /// symbol == sym::foo
+    /// ```
+    pub clippy::SYMBOL_AS_STR,
+    Warn,
+    "calls to `Symbol::as_str`",
+    report_in_external_macro: true
+}
+
 #[derive(Default)]
-pub struct InterningDefinedSymbol {
+pub struct Symbols {
     // Maps the symbol to the import path
     symbol_map: FxHashMap<u32, (&'static str, Symbol)>,
 }
 
-impl_lint_pass!(InterningDefinedSymbol => [INTERNING_LITERALS]);
+impl_lint_pass!(Symbols => [INTERNING_LITERALS, SYMBOL_AS_STR]);
 
-impl<'tcx> LateLintPass<'tcx> for InterningDefinedSymbol {
+impl<'tcx> LateLintPass<'tcx> for Symbols {
     fn check_crate(&mut self, cx: &LateContext<'_>) {
         let modules = [
             ("kw", &paths::KW_MODULE[..]),
@@ -77,7 +99,8 @@ impl<'tcx> LateLintPass<'tcx> for InterningDefinedSymbol {
         if let ExprKind::Call(func, [arg]) = &expr.kind
             && let ty::FnDef(def_id, _) = cx.typeck_results().expr_ty(func).kind()
             && cx.tcx.is_diagnostic_item(sym::SymbolIntern, *def_id)
-            && let Some(Constant::Str(arg)) = ConstEvalCtxt::new(cx).eval_simple(arg)
+            && let ExprKind::Lit(lit) = arg.kind
+            && let LitKind::Str(name, _) = lit.node
         {
             span_lint_and_then(
                 cx,
@@ -85,18 +108,62 @@ impl<'tcx> LateLintPass<'tcx> for InterningDefinedSymbol {
                 expr.span,
                 "interning a string literal",
                 |diag| {
-                    let value = Symbol::intern(&arg).as_u32();
-                    let (message, path) = if let Some((prefix, name)) = self.symbol_map.get(&value) {
-                        ("use the preinterned symbol", format!("{prefix}::{name}"))
-                    } else {
-                        (
-                            "add the symbol to `clippy_utils/src/sym.rs` and use it",
-                            format!("sym::{}", arg.replace(|ch: char| !ch.is_alphanumeric(), "_")),
-                        )
-                    };
+                    let (message, path) = suggestion(&mut self.symbol_map, name);
                     diag.span_suggestion_verbose(expr.span, message, path, Applicability::MaybeIncorrect);
                 },
             );
         }
+
+        if let ExprKind::Binary(_, lhs, rhs) = expr.kind {
+            check_binary(cx, lhs, rhs, &mut self.symbol_map);
+            check_binary(cx, rhs, lhs, &mut self.symbol_map);
+        }
+    }
+}
+
+fn check_binary(
+    cx: &LateContext<'_>,
+    lhs: &Expr<'_>,
+    rhs: &Expr<'_>,
+    symbols: &mut FxHashMap<u32, (&'static str, Symbol)>,
+) {
+    if let Some(removal_span) = as_str_span(cx, lhs)
+        && let ExprKind::Lit(lit) = rhs.kind
+        && let LitKind::Str(name, _) = lit.node
+    {
+        span_lint_and_then(cx, SYMBOL_AS_STR, lhs.span, "converting a Symbol to a string", |diag| {
+            let (message, path) = suggestion(symbols, name);
+            diag.multipart_suggestion_verbose(
+                message,
+                vec![(removal_span, String::new()), (rhs.span, path)],
+                Applicability::MachineApplicable,
+            );
+        });
+    }
+}
+
+fn suggestion(symbols: &mut FxHashMap<u32, (&'static str, Symbol)>, name: Symbol) -> (&'static str, String) {
+    if let Some((prefix, name)) = symbols.get(&name.as_u32()) {
+        ("use the preinterned symbol", format!("{prefix}::{name}"))
+    } else {
+        (
+            "add the symbol to `clippy_utils/src/sym.rs` and use it",
+            format!("sym::{}", name.as_str().replace(|ch: char| !ch.is_alphanumeric(), "_")),
+        )
+    }
+}
+
+/// ```ignore
+/// symbol.as_str()
+/// //     ^^^^^^^^
+/// ```
+fn as_str_span(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option<Span> {
+    if let ExprKind::MethodCall(_, recv, [], _) = expr.kind
+        && let Some(method_def_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id)
+        && match_def_path(cx, method_def_id, &paths::SYMBOL_AS_STR)
+    {
+        Some(recv.span.shrink_to_hi().to(expr.span.shrink_to_hi()))
+    } else {
+        None
     }
 }
diff --git a/src/tools/clippy/clippy_utils/README.md b/src/tools/clippy/clippy_utils/README.md
index aceff14a159..66192f866fa 100644
--- a/src/tools/clippy/clippy_utils/README.md
+++ b/src/tools/clippy/clippy_utils/README.md
@@ -8,7 +8,7 @@ This crate is only guaranteed to build with this `nightly` toolchain:
 
 <!-- begin autogenerated nightly -->
 ```
-nightly-2025-04-22
+nightly-2025-05-01
 ```
 <!-- end autogenerated nightly -->
 
diff --git a/src/tools/clippy/clippy_utils/src/higher.rs b/src/tools/clippy/clippy_utils/src/higher.rs
index d4e66ebd8e1..dbb99348290 100644
--- a/src/tools/clippy/clippy_utils/src/higher.rs
+++ b/src/tools/clippy/clippy_utils/src/higher.rs
@@ -3,14 +3,14 @@
 #![deny(clippy::missing_docs_in_private_items)]
 
 use crate::consts::{ConstEvalCtxt, Constant};
-use crate::is_expn_of;
 use crate::ty::is_type_diagnostic_item;
+use crate::{is_expn_of, sym};
 
 use rustc_ast::ast;
 use rustc_hir as hir;
 use rustc_hir::{Arm, Block, Expr, ExprKind, HirId, LoopSource, MatchSource, Node, Pat, QPath, StructTailExpr};
 use rustc_lint::LateContext;
-use rustc_span::{Span, sym, symbol};
+use rustc_span::{Span, symbol};
 
 /// The essential nodes of a desugared for loop as well as the entire span:
 /// `for pat in arg { body }` becomes `(pat, arg, body)`. Returns `(pat, arg, body, span)`.
@@ -474,7 +474,7 @@ pub fn get_vec_init_kind<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) -
                     return Some(VecInitKind::New);
                 } else if name.ident.name == symbol::kw::Default {
                     return Some(VecInitKind::Default);
-                } else if name.ident.name.as_str() == "with_capacity" {
+                } else if name.ident.name == sym::with_capacity {
                     let arg = args.first()?;
                     return match ConstEvalCtxt::new(cx).eval_simple(arg) {
                         Some(Constant::Int(num)) => Some(VecInitKind::WithConstCapacity(num)),
diff --git a/src/tools/clippy/clippy_utils/src/hir_utils.rs b/src/tools/clippy/clippy_utils/src/hir_utils.rs
index 17368a7530d..c37231d0931 100644
--- a/src/tools/clippy/clippy_utils/src/hir_utils.rs
+++ b/src/tools/clippy/clippy_utils/src/hir_utils.rs
@@ -1118,8 +1118,8 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> {
                 self.hash_const_arg(e);
             },
             TyPatKind::Or(variants) => {
-                for variant in variants.iter() {
-                    self.hash_ty_pat(variant)
+                for variant in variants {
+                    self.hash_ty_pat(variant);
                 }
             },
             TyPatKind::Err(_) => {},
diff --git a/src/tools/clippy/clippy_utils/src/lib.rs b/src/tools/clippy/clippy_utils/src/lib.rs
index 264b9b0406d..187dfa4dda8 100644
--- a/src/tools/clippy/clippy_utils/src/lib.rs
+++ b/src/tools/clippy/clippy_utils/src/lib.rs
@@ -1412,7 +1412,7 @@ pub fn is_in_panic_handler(cx: &LateContext<'_>, e: &Expr<'_>) -> bool {
 }
 
 /// Gets the name of the item the expression is in, if available.
-pub fn get_item_name(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option<Symbol> {
+pub fn parent_item_name(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option<Symbol> {
     let parent_id = cx.tcx.hir_get_parent_item(expr.hir_id).def_id;
     match cx.tcx.hir_node_by_def_id(parent_id) {
         Node::Item(item) => item.kind.ident().map(|ident| ident.name),
@@ -2088,7 +2088,7 @@ pub fn match_libc_symbol(cx: &LateContext<'_>, did: DefId, name: &str) -> bool {
     let path = cx.get_def_path(did);
     // libc is meant to be used as a flat list of names, but they're all actually defined in different
     // modules based on the target platform. Ignore everything but crate name and the item name.
-    path.first().is_some_and(|s| s.as_str() == "libc") && path.last().is_some_and(|s| s.as_str() == name)
+    path.first().is_some_and(|s| *s == sym::libc) && path.last().is_some_and(|s| s.as_str() == name)
 }
 
 /// Returns the list of condition expressions and the list of blocks in a
@@ -3101,7 +3101,7 @@ pub fn span_find_starting_semi(sm: &SourceMap, span: Span) -> Span {
     sm.span_take_while(span, |&ch| ch == ' ' || ch == ';')
 }
 
-/// Returns whether the given let pattern and else body can be turned into a question mark
+/// Returns whether the given let pattern and else body can be turned into the `?` operator
 ///
 /// For this example:
 /// ```ignore
@@ -3124,8 +3124,7 @@ pub fn span_find_starting_semi(sm: &SourceMap, span: Span) -> Span {
 /// ```
 ///
 /// We output `Some(a)` in the first instance, and `Some(FooBar { a, b })` in the second, because
-/// the question mark operator is applicable here. Callers have to check whether we are in a
-/// constant or not.
+/// the `?` operator is applicable here. Callers have to check whether we are in a constant or not.
 pub fn pat_and_expr_can_be_question_mark<'a, 'hir>(
     cx: &LateContext<'_>,
     pat: &'a Pat<'hir>,
diff --git a/src/tools/clippy/clippy_utils/src/sym.rs b/src/tools/clippy/clippy_utils/src/sym.rs
index 1a30b473d10..38f077134c0 100644
--- a/src/tools/clippy/clippy_utils/src/sym.rs
+++ b/src/tools/clippy/clippy_utils/src/sym.rs
@@ -30,33 +30,75 @@ macro_rules! generate {
 }
 
 generate! {
+    abs,
     as_bytes,
     as_deref_mut,
     as_deref,
     as_mut,
     Binary,
+    build_hasher,
+    cargo_clippy: "cargo-clippy",
     Cargo_toml: "Cargo.toml",
+    cast,
+    chars,
     CLIPPY_ARGS,
     CLIPPY_CONF_DIR,
+    clone_into,
     cloned,
+    collect,
     contains,
     copied,
+    CRLF: "\r\n",
     Current,
+    ends_with,
+    exp,
+    extend,
+    finish_non_exhaustive,
+    finish,
+    flat_map,
+    for_each,
+    from_raw,
+    from_str_radix,
     get,
     insert,
     int_roundings,
+    into_bytes,
+    into_owned,
     IntoIter,
+    is_ascii,
     is_empty,
+    is_err,
+    is_none,
     is_ok,
     is_some,
+    last,
+    LF: "\n",
     LowerExp,
     LowerHex,
+    max,
+    min,
+    mode,
     msrv,
     Octal,
     or_default,
+    parse,
+    push,
     regex,
+    reserve,
+    resize,
+    restriction,
     rustfmt_skip,
+    set_len,
+    set_mode,
+    set_readonly,
+    signum,
+    split_whitespace,
+    split,
     Start,
+    take,
+    TBD,
+    then_some,
+    to_digit,
     to_owned,
     unused_extern_crates,
     unwrap_err,
@@ -66,4 +108,6 @@ generate! {
     V4,
     V6,
     Weak,
+    with_capacity,
+    wrapping_offset,
 }
diff --git a/src/tools/clippy/rust-toolchain.toml b/src/tools/clippy/rust-toolchain.toml
index d2f79da1a54..39c7f0e4ad5 100644
--- a/src/tools/clippy/rust-toolchain.toml
+++ b/src/tools/clippy/rust-toolchain.toml
@@ -1,6 +1,6 @@
 [toolchain]
 # begin autogenerated nightly
-channel = "nightly-2025-04-22"
+channel = "nightly-2025-05-01"
 # end autogenerated nightly
 components = ["cargo", "llvm-tools", "rust-src", "rust-std", "rustc", "rustc-dev", "rustfmt"]
 profile = "minimal"
diff --git a/src/tools/clippy/tests/ui-internal/symbol_as_str.fixed b/src/tools/clippy/tests/ui-internal/symbol_as_str.fixed
new file mode 100644
index 00000000000..3e26732836c
--- /dev/null
+++ b/src/tools/clippy/tests/ui-internal/symbol_as_str.fixed
@@ -0,0 +1,21 @@
+#![feature(rustc_private)]
+
+extern crate rustc_span;
+
+use clippy_utils::sym;
+use rustc_span::{Symbol, kw};
+
+fn f(s: Symbol) {
+    s == sym::f32;
+    //~^ symbol_as_str
+    s == sym::proc_dash_macro;
+    //~^ symbol_as_str
+    s == kw::SelfLower;
+    //~^ symbol_as_str
+    s == sym::msrv;
+    //~^ symbol_as_str
+    s == sym::Cargo_toml;
+    //~^ symbol_as_str
+    sym::get == s;
+    //~^ symbol_as_str
+}
diff --git a/src/tools/clippy/tests/ui-internal/symbol_as_str.rs b/src/tools/clippy/tests/ui-internal/symbol_as_str.rs
new file mode 100644
index 00000000000..334c32d1898
--- /dev/null
+++ b/src/tools/clippy/tests/ui-internal/symbol_as_str.rs
@@ -0,0 +1,21 @@
+#![feature(rustc_private)]
+
+extern crate rustc_span;
+
+use clippy_utils::sym;
+use rustc_span::{Symbol, kw};
+
+fn f(s: Symbol) {
+    s.as_str() == "f32";
+    //~^ symbol_as_str
+    s.as_str() == "proc-macro";
+    //~^ symbol_as_str
+    s.as_str() == "self";
+    //~^ symbol_as_str
+    s.as_str() == "msrv";
+    //~^ symbol_as_str
+    s.as_str() == "Cargo.toml";
+    //~^ symbol_as_str
+    "get" == s.as_str();
+    //~^ symbol_as_str
+}
diff --git a/src/tools/clippy/tests/ui-internal/symbol_as_str.stderr b/src/tools/clippy/tests/ui-internal/symbol_as_str.stderr
new file mode 100644
index 00000000000..39f81f3833c
--- /dev/null
+++ b/src/tools/clippy/tests/ui-internal/symbol_as_str.stderr
@@ -0,0 +1,76 @@
+error: converting a Symbol to a string
+  --> tests/ui-internal/symbol_as_str.rs:9:5
+   |
+LL |     s.as_str() == "f32";
+   |     ^^^^^^^^^^
+   |
+   = note: `-D clippy::symbol-as-str` implied by `-D warnings`
+   = help: to override `-D warnings` add `#[allow(clippy::symbol_as_str)]`
+help: use the preinterned symbol
+   |
+LL -     s.as_str() == "f32";
+LL +     s == sym::f32;
+   |
+
+error: converting a Symbol to a string
+  --> tests/ui-internal/symbol_as_str.rs:11:5
+   |
+LL |     s.as_str() == "proc-macro";
+   |     ^^^^^^^^^^
+   |
+help: use the preinterned symbol
+   |
+LL -     s.as_str() == "proc-macro";
+LL +     s == sym::proc_dash_macro;
+   |
+
+error: converting a Symbol to a string
+  --> tests/ui-internal/symbol_as_str.rs:13:5
+   |
+LL |     s.as_str() == "self";
+   |     ^^^^^^^^^^
+   |
+help: use the preinterned symbol
+   |
+LL -     s.as_str() == "self";
+LL +     s == kw::SelfLower;
+   |
+
+error: converting a Symbol to a string
+  --> tests/ui-internal/symbol_as_str.rs:15:5
+   |
+LL |     s.as_str() == "msrv";
+   |     ^^^^^^^^^^
+   |
+help: use the preinterned symbol
+   |
+LL -     s.as_str() == "msrv";
+LL +     s == sym::msrv;
+   |
+
+error: converting a Symbol to a string
+  --> tests/ui-internal/symbol_as_str.rs:17:5
+   |
+LL |     s.as_str() == "Cargo.toml";
+   |     ^^^^^^^^^^
+   |
+help: use the preinterned symbol
+   |
+LL -     s.as_str() == "Cargo.toml";
+LL +     s == sym::Cargo_toml;
+   |
+
+error: converting a Symbol to a string
+  --> tests/ui-internal/symbol_as_str.rs:19:14
+   |
+LL |     "get" == s.as_str();
+   |              ^^^^^^^^^^
+   |
+help: use the preinterned symbol
+   |
+LL -     "get" == s.as_str();
+LL +     sym::get == s;
+   |
+
+error: aborting due to 6 previous errors
+
diff --git a/src/tools/clippy/tests/ui-internal/symbol_as_str_unfixable.rs b/src/tools/clippy/tests/ui-internal/symbol_as_str_unfixable.rs
new file mode 100644
index 00000000000..635f28007e9
--- /dev/null
+++ b/src/tools/clippy/tests/ui-internal/symbol_as_str_unfixable.rs
@@ -0,0 +1,15 @@
+//@no-rustfix: paths that don't exist yet
+#![feature(rustc_private)]
+
+extern crate rustc_span;
+
+use rustc_span::Symbol;
+
+fn f(s: Symbol) {
+    s.as_str() == "xyz123";
+    //~^ symbol_as_str
+    s.as_str() == "with-dash";
+    //~^ symbol_as_str
+    s.as_str() == "with.dot";
+    //~^ symbol_as_str
+}
diff --git a/src/tools/clippy/tests/ui-internal/symbol_as_str_unfixable.stderr b/src/tools/clippy/tests/ui-internal/symbol_as_str_unfixable.stderr
new file mode 100644
index 00000000000..5349983ca51
--- /dev/null
+++ b/src/tools/clippy/tests/ui-internal/symbol_as_str_unfixable.stderr
@@ -0,0 +1,40 @@
+error: converting a Symbol to a string
+  --> tests/ui-internal/symbol_as_str_unfixable.rs:9:5
+   |
+LL |     s.as_str() == "xyz123";
+   |     ^^^^^^^^^^
+   |
+   = note: `-D clippy::symbol-as-str` implied by `-D warnings`
+   = help: to override `-D warnings` add `#[allow(clippy::symbol_as_str)]`
+help: add the symbol to `clippy_utils/src/sym.rs` and use it
+   |
+LL -     s.as_str() == "xyz123";
+LL +     s == sym::xyz123;
+   |
+
+error: converting a Symbol to a string
+  --> tests/ui-internal/symbol_as_str_unfixable.rs:11:5
+   |
+LL |     s.as_str() == "with-dash";
+   |     ^^^^^^^^^^
+   |
+help: add the symbol to `clippy_utils/src/sym.rs` and use it
+   |
+LL -     s.as_str() == "with-dash";
+LL +     s == sym::with_dash;
+   |
+
+error: converting a Symbol to a string
+  --> tests/ui-internal/symbol_as_str_unfixable.rs:13:5
+   |
+LL |     s.as_str() == "with.dot";
+   |     ^^^^^^^^^^
+   |
+help: add the symbol to `clippy_utils/src/sym.rs` and use it
+   |
+LL -     s.as_str() == "with.dot";
+LL +     s == sym::with_dot;
+   |
+
+error: aborting due to 3 previous errors
+
diff --git a/src/tools/clippy/tests/ui/blocks_in_conditions.fixed b/src/tools/clippy/tests/ui/blocks_in_conditions.fixed
index e696896538e..6ae5b0cb2f0 100644
--- a/src/tools/clippy/tests/ui/blocks_in_conditions.fixed
+++ b/src/tools/clippy/tests/ui/blocks_in_conditions.fixed
@@ -4,7 +4,6 @@
 #![allow(
     unused,
     unnecessary_transmutes,
-    clippy::let_and_return,
     clippy::needless_if,
     clippy::missing_transmute_annotations
 )]
diff --git a/src/tools/clippy/tests/ui/blocks_in_conditions.rs b/src/tools/clippy/tests/ui/blocks_in_conditions.rs
index 8c8f3249b8a..3fd06062072 100644
--- a/src/tools/clippy/tests/ui/blocks_in_conditions.rs
+++ b/src/tools/clippy/tests/ui/blocks_in_conditions.rs
@@ -4,7 +4,6 @@
 #![allow(
     unused,
     unnecessary_transmutes,
-    clippy::let_and_return,
     clippy::needless_if,
     clippy::missing_transmute_annotations
 )]
diff --git a/src/tools/clippy/tests/ui/blocks_in_conditions.stderr b/src/tools/clippy/tests/ui/blocks_in_conditions.stderr
index 41ff59c683e..282c42a98bf 100644
--- a/src/tools/clippy/tests/ui/blocks_in_conditions.stderr
+++ b/src/tools/clippy/tests/ui/blocks_in_conditions.stderr
@@ -1,5 +1,5 @@
 error: in an `if` condition, avoid complex blocks or closures with blocks; instead, move the block or closure higher and bind it with a `let`
-  --> tests/ui/blocks_in_conditions.rs:31:5
+  --> tests/ui/blocks_in_conditions.rs:30:5
    |
 LL | /     if {
 LL | |
@@ -20,13 +20,13 @@ LL ~     }; if res {
    |
 
 error: omit braces around single expression condition
-  --> tests/ui/blocks_in_conditions.rs:43:8
+  --> tests/ui/blocks_in_conditions.rs:42:8
    |
 LL |     if { true } { 6 } else { 10 }
    |        ^^^^^^^^ help: try: `true`
 
 error: this boolean expression can be simplified
-  --> tests/ui/blocks_in_conditions.rs:49:8
+  --> tests/ui/blocks_in_conditions.rs:48:8
    |
 LL |     if true && x == 3 { 6 } else { 10 }
    |        ^^^^^^^^^^^^^^ help: try: `x == 3`
diff --git a/src/tools/clippy/tests/ui/equatable_if_let.fixed b/src/tools/clippy/tests/ui/equatable_if_let.fixed
index 166b1387ba2..ce8b67f9ca7 100644
--- a/src/tools/clippy/tests/ui/equatable_if_let.fixed
+++ b/src/tools/clippy/tests/ui/equatable_if_let.fixed
@@ -103,3 +103,39 @@ fn main() {
 
     external!({ if let 2 = $a {} });
 }
+
+mod issue8710 {
+    fn str_ref(cs: &[char]) {
+        if matches!(cs.iter().next(), Some('i')) {
+            //~^ equatable_if_let
+        } else {
+            todo!();
+        }
+    }
+
+    fn i32_ref(cs: &[i32]) {
+        if matches!(cs.iter().next(), Some(1)) {
+            //~^ equatable_if_let
+        } else {
+            todo!();
+        }
+    }
+
+    fn enum_ref() {
+        #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
+        enum MyEnum {
+            A(i32),
+            B,
+        }
+
+        fn get_enum() -> Option<&'static MyEnum> {
+            todo!()
+        }
+
+        if matches!(get_enum(), Some(MyEnum::B)) {
+            //~^ equatable_if_let
+        } else {
+            todo!();
+        }
+    }
+}
diff --git a/src/tools/clippy/tests/ui/equatable_if_let.rs b/src/tools/clippy/tests/ui/equatable_if_let.rs
index 09c2483ae6d..ff09533f265 100644
--- a/src/tools/clippy/tests/ui/equatable_if_let.rs
+++ b/src/tools/clippy/tests/ui/equatable_if_let.rs
@@ -103,3 +103,39 @@ fn main() {
 
     external!({ if let 2 = $a {} });
 }
+
+mod issue8710 {
+    fn str_ref(cs: &[char]) {
+        if let Some('i') = cs.iter().next() {
+            //~^ equatable_if_let
+        } else {
+            todo!();
+        }
+    }
+
+    fn i32_ref(cs: &[i32]) {
+        if let Some(1) = cs.iter().next() {
+            //~^ equatable_if_let
+        } else {
+            todo!();
+        }
+    }
+
+    fn enum_ref() {
+        #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
+        enum MyEnum {
+            A(i32),
+            B,
+        }
+
+        fn get_enum() -> Option<&'static MyEnum> {
+            todo!()
+        }
+
+        if let Some(MyEnum::B) = get_enum() {
+            //~^ equatable_if_let
+        } else {
+            todo!();
+        }
+    }
+}
diff --git a/src/tools/clippy/tests/ui/equatable_if_let.stderr b/src/tools/clippy/tests/ui/equatable_if_let.stderr
index 81e0e15a5c7..dd1832ad68b 100644
--- a/src/tools/clippy/tests/ui/equatable_if_let.stderr
+++ b/src/tools/clippy/tests/ui/equatable_if_let.stderr
@@ -85,5 +85,23 @@ error: this pattern matching can be expressed using equality
 LL |     if let inline!("abc") = "abc" {
    |        ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `"abc" == inline!("abc")`
 
-error: aborting due to 14 previous errors
+error: this pattern matching can be expressed using `matches!`
+  --> tests/ui/equatable_if_let.rs:109:12
+   |
+LL |         if let Some('i') = cs.iter().next() {
+   |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `matches!(cs.iter().next(), Some('i'))`
+
+error: this pattern matching can be expressed using `matches!`
+  --> tests/ui/equatable_if_let.rs:117:12
+   |
+LL |         if let Some(1) = cs.iter().next() {
+   |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `matches!(cs.iter().next(), Some(1))`
+
+error: this pattern matching can be expressed using `matches!`
+  --> tests/ui/equatable_if_let.rs:135:12
+   |
+LL |         if let Some(MyEnum::B) = get_enum() {
+   |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `matches!(get_enum(), Some(MyEnum::B))`
+
+error: aborting due to 17 previous errors
 
diff --git a/src/tools/clippy/tests/ui/manual_div_ceil.fixed b/src/tools/clippy/tests/ui/manual_div_ceil.fixed
index 57fe8917afe..58ee6978fc1 100644
--- a/src/tools/clippy/tests/ui/manual_div_ceil.fixed
+++ b/src/tools/clippy/tests/ui/manual_div_ceil.fixed
@@ -1,5 +1,21 @@
 #![warn(clippy::manual_div_ceil)]
 
+macro_rules! y {
+    () => {
+        let x = 33u32;
+        let _ = x.div_ceil(8);
+        //~^ manual_div_ceil
+        let _ = x.div_ceil(8);
+        //~^ manual_div_ceil
+    };
+}
+
+macro_rules! eight {
+    () => {
+        8
+    };
+}
+
 fn main() {
     let x = 7_u32;
     let y = 4_u32;
@@ -32,6 +48,13 @@ fn main() {
     let _ = (z as i32 + (y_i - 1)) / y_i;
     let _ = (7_u32 as i32 + (y_i - 1)) / y_i;
     let _ = (7_u32 as i32 + (4 - 1)) / 4;
+
+    // Test lint with macro
+    y!();
+
+    // Also test if RHS should be result of macro expansion
+    let _ = 33u32.div_ceil(eight!());
+    //~^ manual_div_ceil
 }
 
 fn issue_13843() {
diff --git a/src/tools/clippy/tests/ui/manual_div_ceil.rs b/src/tools/clippy/tests/ui/manual_div_ceil.rs
index ec343513e5c..aa0d81b22a0 100644
--- a/src/tools/clippy/tests/ui/manual_div_ceil.rs
+++ b/src/tools/clippy/tests/ui/manual_div_ceil.rs
@@ -1,5 +1,21 @@
 #![warn(clippy::manual_div_ceil)]
 
+macro_rules! y {
+    () => {
+        let x = 33u32;
+        let _ = (x + 7) / 8;
+        //~^ manual_div_ceil
+        let _ = (7 + x) / 8;
+        //~^ manual_div_ceil
+    };
+}
+
+macro_rules! eight {
+    () => {
+        8
+    };
+}
+
 fn main() {
     let x = 7_u32;
     let y = 4_u32;
@@ -32,6 +48,13 @@ fn main() {
     let _ = (z as i32 + (y_i - 1)) / y_i;
     let _ = (7_u32 as i32 + (y_i - 1)) / y_i;
     let _ = (7_u32 as i32 + (4 - 1)) / 4;
+
+    // Test lint with macro
+    y!();
+
+    // Also test if RHS should be result of macro expansion
+    let _ = (33u32 + 7) / eight!();
+    //~^ manual_div_ceil
 }
 
 fn issue_13843() {
diff --git a/src/tools/clippy/tests/ui/manual_div_ceil.stderr b/src/tools/clippy/tests/ui/manual_div_ceil.stderr
index 8e14ab27426..9be5a19bf39 100644
--- a/src/tools/clippy/tests/ui/manual_div_ceil.stderr
+++ b/src/tools/clippy/tests/ui/manual_div_ceil.stderr
@@ -1,5 +1,5 @@
 error: manually reimplementing `div_ceil`
-  --> tests/ui/manual_div_ceil.rs:9:13
+  --> tests/ui/manual_div_ceil.rs:25:13
    |
 LL |     let _ = (x + (y - 1)) / y;
    |             ^^^^^^^^^^^^^^^^^ help: consider using `.div_ceil()`: `x.div_ceil(y)`
@@ -8,94 +8,122 @@ LL |     let _ = (x + (y - 1)) / y;
    = help: to override `-D warnings` add `#[allow(clippy::manual_div_ceil)]`
 
 error: manually reimplementing `div_ceil`
-  --> tests/ui/manual_div_ceil.rs:11:13
+  --> tests/ui/manual_div_ceil.rs:27:13
    |
 LL |     let _ = ((y - 1) + x) / y;
    |             ^^^^^^^^^^^^^^^^^ help: consider using `.div_ceil()`: `x.div_ceil(y)`
 
 error: manually reimplementing `div_ceil`
-  --> tests/ui/manual_div_ceil.rs:13:13
+  --> tests/ui/manual_div_ceil.rs:29:13
    |
 LL |     let _ = (x + y - 1) / y;
    |             ^^^^^^^^^^^^^^^ help: consider using `.div_ceil()`: `x.div_ceil(y)`
 
 error: manually reimplementing `div_ceil`
-  --> tests/ui/manual_div_ceil.rs:16:13
+  --> tests/ui/manual_div_ceil.rs:32:13
    |
 LL |     let _ = (7_u32 + (4 - 1)) / 4;
    |             ^^^^^^^^^^^^^^^^^^^^^ help: consider using `.div_ceil()`: `7_u32.div_ceil(4)`
 
 error: manually reimplementing `div_ceil`
-  --> tests/ui/manual_div_ceil.rs:18:13
+  --> tests/ui/manual_div_ceil.rs:34:13
    |
 LL |     let _ = (7_i32 as u32 + (4 - 1)) / 4;
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `.div_ceil()`: `(7_i32 as u32).div_ceil(4)`
 
 error: manually reimplementing `div_ceil`
-  --> tests/ui/manual_div_ceil.rs:39:13
+  --> tests/ui/manual_div_ceil.rs:6:17
+   |
+LL |         let _ = (x + 7) / 8;
+   |                 ^^^^^^^^^^^ help: consider using `.div_ceil()`: `x.div_ceil(8)`
+...
+LL |     y!();
+   |     ---- in this macro invocation
+   |
+   = note: this error originates in the macro `y` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: manually reimplementing `div_ceil`
+  --> tests/ui/manual_div_ceil.rs:8:17
+   |
+LL |         let _ = (7 + x) / 8;
+   |                 ^^^^^^^^^^^ help: consider using `.div_ceil()`: `x.div_ceil(8)`
+...
+LL |     y!();
+   |     ---- in this macro invocation
+   |
+   = note: this error originates in the macro `y` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: manually reimplementing `div_ceil`
+  --> tests/ui/manual_div_ceil.rs:56:13
+   |
+LL |     let _ = (33u32 + 7) / eight!();
+   |             ^^^^^^^^^^^^^^^^^^^^^^ help: consider using `.div_ceil()`: `33u32.div_ceil(eight!())`
+
+error: manually reimplementing `div_ceil`
+  --> tests/ui/manual_div_ceil.rs:62:13
    |
 LL |     let _ = (2048 + x - 1) / x;
    |             ^^^^^^^^^^^^^^^^^^ help: consider using `.div_ceil()`: `2048_usize.div_ceil(x)`
 
 error: manually reimplementing `div_ceil`
-  --> tests/ui/manual_div_ceil.rs:43:13
+  --> tests/ui/manual_div_ceil.rs:66:13
    |
 LL |     let _ = (2048usize + x - 1) / x;
    |             ^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `.div_ceil()`: `2048usize.div_ceil(x)`
 
 error: manually reimplementing `div_ceil`
-  --> tests/ui/manual_div_ceil.rs:47:13
+  --> tests/ui/manual_div_ceil.rs:70:13
    |
 LL |     let _ = (2048_usize + x - 1) / x;
    |             ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `.div_ceil()`: `2048_usize.div_ceil(x)`
 
 error: manually reimplementing `div_ceil`
-  --> tests/ui/manual_div_ceil.rs:51:13
+  --> tests/ui/manual_div_ceil.rs:74:13
    |
 LL |     let _ = (x + 4 - 1) / 4;
    |             ^^^^^^^^^^^^^^^ help: consider using `.div_ceil()`: `x.div_ceil(4)`
 
 error: manually reimplementing `div_ceil`
-  --> tests/ui/manual_div_ceil.rs:54:18
+  --> tests/ui/manual_div_ceil.rs:77:18
    |
 LL |     let _: u32 = (2048 + 6 - 1) / 6;
    |                  ^^^^^^^^^^^^^^^^^^ help: consider using `.div_ceil()`: `2048_u32.div_ceil(6)`
 
 error: manually reimplementing `div_ceil`
-  --> tests/ui/manual_div_ceil.rs:56:20
+  --> tests/ui/manual_div_ceil.rs:79:20
    |
 LL |     let _: usize = (2048 + 6 - 1) / 6;
    |                    ^^^^^^^^^^^^^^^^^^ help: consider using `.div_ceil()`: `2048_usize.div_ceil(6)`
 
 error: manually reimplementing `div_ceil`
-  --> tests/ui/manual_div_ceil.rs:58:18
+  --> tests/ui/manual_div_ceil.rs:81:18
    |
 LL |     let _: u32 = (0x2048 + 0x6 - 1) / 0x6;
    |                  ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `.div_ceil()`: `0x2048_u32.div_ceil(0x6)`
 
 error: manually reimplementing `div_ceil`
-  --> tests/ui/manual_div_ceil.rs:61:13
+  --> tests/ui/manual_div_ceil.rs:84:13
    |
 LL |     let _ = (2048 + 6u32 - 1) / 6u32;
    |             ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `.div_ceil()`: `2048_u32.div_ceil(6u32)`
 
 error: manually reimplementing `div_ceil`
-  --> tests/ui/manual_div_ceil.rs:64:13
+  --> tests/ui/manual_div_ceil.rs:87:13
    |
 LL |     let _ = (1_000_000 + 6u32 - 1) / 6u32;
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `.div_ceil()`: `1_000_000_u32.div_ceil(6u32)`
 
 error: manually reimplementing `div_ceil`
-  --> tests/ui/manual_div_ceil.rs:70:13
+  --> tests/ui/manual_div_ceil.rs:93:13
    |
 LL |     let _ = (x + 7) / 8;
    |             ^^^^^^^^^^^ help: consider using `.div_ceil()`: `x.div_ceil(8)`
 
 error: manually reimplementing `div_ceil`
-  --> tests/ui/manual_div_ceil.rs:72:13
+  --> tests/ui/manual_div_ceil.rs:95:13
    |
 LL |     let _ = (7 + x) / 8;
    |             ^^^^^^^^^^^ help: consider using `.div_ceil()`: `x.div_ceil(8)`
 
-error: aborting due to 16 previous errors
+error: aborting due to 19 previous errors
 
diff --git a/src/tools/clippy/tests/ui/needless_if.fixed b/src/tools/clippy/tests/ui/needless_if.fixed
index 6208ca19b82..347dbff7c59 100644
--- a/src/tools/clippy/tests/ui/needless_if.fixed
+++ b/src/tools/clippy/tests/ui/needless_if.fixed
@@ -46,9 +46,7 @@ fn main() {
     if let true = true
         && true
     {}
-    if true
-        && let true = true
-    {}
+    if true && let true = true {}
     // Can lint nested `if let`s
     ({
         //~^ needless_if
diff --git a/src/tools/clippy/tests/ui/needless_if.rs b/src/tools/clippy/tests/ui/needless_if.rs
index b459ff877be..5e0f2a14408 100644
--- a/src/tools/clippy/tests/ui/needless_if.rs
+++ b/src/tools/clippy/tests/ui/needless_if.rs
@@ -46,9 +46,7 @@ fn main() {
     if let true = true
         && true
     {}
-    if true
-        && let true = true
-    {}
+    if true && let true = true {}
     // Can lint nested `if let`s
     if {
         //~^ needless_if
diff --git a/src/tools/clippy/tests/ui/needless_if.stderr b/src/tools/clippy/tests/ui/needless_if.stderr
index eeb8d044526..62cdf245944 100644
--- a/src/tools/clippy/tests/ui/needless_if.stderr
+++ b/src/tools/clippy/tests/ui/needless_if.stderr
@@ -31,7 +31,7 @@ LL +     });
    |
 
 error: this `if` branch is empty
-  --> tests/ui/needless_if.rs:53:5
+  --> tests/ui/needless_if.rs:51:5
    |
 LL | /     if {
 LL | |
@@ -57,19 +57,19 @@ LL +     } && true);
    |
 
 error: this `if` branch is empty
-  --> tests/ui/needless_if.rs:98:5
+  --> tests/ui/needless_if.rs:96:5
    |
 LL |     if { maybe_side_effect() } {}
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: you can remove it: `({ maybe_side_effect() });`
 
 error: this `if` branch is empty
-  --> tests/ui/needless_if.rs:101:5
+  --> tests/ui/needless_if.rs:99:5
    |
 LL |     if { maybe_side_effect() } && true {}
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: you can remove it: `({ maybe_side_effect() } && true);`
 
 error: this `if` branch is empty
-  --> tests/ui/needless_if.rs:106:5
+  --> tests/ui/needless_if.rs:104:5
    |
 LL |     if true {}
    |     ^^^^^^^^^^ help: you can remove it: `true;`
diff --git a/src/tools/clippy/tests/ui/needless_late_init.fixed b/src/tools/clippy/tests/ui/needless_late_init.fixed
index 391d4bc3fcc..f832752ccd7 100644
--- a/src/tools/clippy/tests/ui/needless_late_init.fixed
+++ b/src/tools/clippy/tests/ui/needless_late_init.fixed
@@ -246,9 +246,7 @@ fn does_not_lint() {
     }
 
     let x;
-    if true
-        && let Some(n) = Some("let chains too")
-    {
+    if true && let Some(n) = Some("let chains too") {
         x = 1;
     } else {
         x = 2;
diff --git a/src/tools/clippy/tests/ui/needless_late_init.rs b/src/tools/clippy/tests/ui/needless_late_init.rs
index 6096e8300e1..a52fbf52923 100644
--- a/src/tools/clippy/tests/ui/needless_late_init.rs
+++ b/src/tools/clippy/tests/ui/needless_late_init.rs
@@ -246,9 +246,7 @@ fn does_not_lint() {
     }
 
     let x;
-    if true
-        && let Some(n) = Some("let chains too")
-    {
+    if true && let Some(n) = Some("let chains too") {
         x = 1;
     } else {
         x = 2;
diff --git a/src/tools/clippy/tests/ui/needless_late_init.stderr b/src/tools/clippy/tests/ui/needless_late_init.stderr
index e7c36136847..b24c1275881 100644
--- a/src/tools/clippy/tests/ui/needless_late_init.stderr
+++ b/src/tools/clippy/tests/ui/needless_late_init.stderr
@@ -276,7 +276,7 @@ LL ~     };
    |
 
 error: unneeded late initialization
-  --> tests/ui/needless_late_init.rs:302:5
+  --> tests/ui/needless_late_init.rs:300:5
    |
 LL |     let r;
    |     ^^^^^^ created here
diff --git a/src/tools/clippy/tests/ui/needless_question_mark.stderr b/src/tools/clippy/tests/ui/needless_question_mark.stderr
index 55da4f28976..8516cee48e6 100644
--- a/src/tools/clippy/tests/ui/needless_question_mark.stderr
+++ b/src/tools/clippy/tests/ui/needless_question_mark.stderr
@@ -1,100 +1,188 @@
-error: question mark operator is useless here
+error: enclosing `Some` and `?` operator are unneeded
   --> tests/ui/needless_question_mark.rs:20:12
    |
 LL |     return Some(to.magic?);
-   |            ^^^^^^^^^^^^^^^ help: try removing question mark and `Some()`: `to.magic`
+   |            ^^^^^^^^^^^^^^^
    |
    = note: `-D clippy::needless-question-mark` implied by `-D warnings`
    = help: to override `-D warnings` add `#[allow(clippy::needless_question_mark)]`
+help: remove the enclosing `Some` and `?` operator
+   |
+LL -     return Some(to.magic?);
+LL +     return to.magic;
+   |
 
-error: question mark operator is useless here
+error: enclosing `Some` and `?` operator are unneeded
   --> tests/ui/needless_question_mark.rs:29:12
    |
 LL |     return Some(to.magic?)
-   |            ^^^^^^^^^^^^^^^ help: try removing question mark and `Some()`: `to.magic`
+   |            ^^^^^^^^^^^^^^^
+   |
+help: remove the enclosing `Some` and `?` operator
+   |
+LL -     return Some(to.magic?)
+LL +     return to.magic
+   |
 
-error: question mark operator is useless here
+error: enclosing `Some` and `?` operator are unneeded
   --> tests/ui/needless_question_mark.rs:35:5
    |
 LL |     Some(to.magic?)
-   |     ^^^^^^^^^^^^^^^ help: try removing question mark and `Some()`: `to.magic`
+   |     ^^^^^^^^^^^^^^^
+   |
+help: remove the enclosing `Some` and `?` operator
+   |
+LL -     Some(to.magic?)
+LL +     to.magic
+   |
 
-error: question mark operator is useless here
+error: enclosing `Some` and `?` operator are unneeded
   --> tests/ui/needless_question_mark.rs:41:21
    |
 LL |     to.and_then(|t| Some(t.magic?))
-   |                     ^^^^^^^^^^^^^^ help: try removing question mark and `Some()`: `t.magic`
+   |                     ^^^^^^^^^^^^^^
+   |
+help: remove the enclosing `Some` and `?` operator
+   |
+LL -     to.and_then(|t| Some(t.magic?))
+LL +     to.and_then(|t| t.magic)
+   |
 
-error: question mark operator is useless here
+error: enclosing `Some` and `?` operator are unneeded
   --> tests/ui/needless_question_mark.rs:51:9
    |
 LL |         Some(t.magic?)
-   |         ^^^^^^^^^^^^^^ help: try removing question mark and `Some()`: `t.magic`
+   |         ^^^^^^^^^^^^^^
+   |
+help: remove the enclosing `Some` and `?` operator
+   |
+LL -         Some(t.magic?)
+LL +         t.magic
+   |
 
-error: question mark operator is useless here
+error: enclosing `Ok` and `?` operator are unneeded
   --> tests/ui/needless_question_mark.rs:57:12
    |
 LL |     return Ok(tr.magic?);
-   |            ^^^^^^^^^^^^^ help: try removing question mark and `Ok()`: `tr.magic`
+   |            ^^^^^^^^^^^^^
+   |
+help: remove the enclosing `Ok` and `?` operator
+   |
+LL -     return Ok(tr.magic?);
+LL +     return tr.magic;
+   |
 
-error: question mark operator is useless here
+error: enclosing `Ok` and `?` operator are unneeded
   --> tests/ui/needless_question_mark.rs:65:12
    |
 LL |     return Ok(tr.magic?)
-   |            ^^^^^^^^^^^^^ help: try removing question mark and `Ok()`: `tr.magic`
+   |            ^^^^^^^^^^^^^
+   |
+help: remove the enclosing `Ok` and `?` operator
+   |
+LL -     return Ok(tr.magic?)
+LL +     return tr.magic
+   |
 
-error: question mark operator is useless here
+error: enclosing `Ok` and `?` operator are unneeded
   --> tests/ui/needless_question_mark.rs:70:5
    |
 LL |     Ok(tr.magic?)
-   |     ^^^^^^^^^^^^^ help: try removing question mark and `Ok()`: `tr.magic`
+   |     ^^^^^^^^^^^^^
+   |
+help: remove the enclosing `Ok` and `?` operator
+   |
+LL -     Ok(tr.magic?)
+LL +     tr.magic
+   |
 
-error: question mark operator is useless here
+error: enclosing `Ok` and `?` operator are unneeded
   --> tests/ui/needless_question_mark.rs:75:21
    |
 LL |     tr.and_then(|t| Ok(t.magic?))
-   |                     ^^^^^^^^^^^^ help: try removing question mark and `Ok()`: `t.magic`
+   |                     ^^^^^^^^^^^^
+   |
+help: remove the enclosing `Ok` and `?` operator
+   |
+LL -     tr.and_then(|t| Ok(t.magic?))
+LL +     tr.and_then(|t| t.magic)
+   |
 
-error: question mark operator is useless here
+error: enclosing `Ok` and `?` operator are unneeded
   --> tests/ui/needless_question_mark.rs:84:9
    |
 LL |         Ok(t.magic?)
-   |         ^^^^^^^^^^^^ help: try removing question mark and `Ok()`: `t.magic`
+   |         ^^^^^^^^^^^^
+   |
+help: remove the enclosing `Ok` and `?` operator
+   |
+LL -         Ok(t.magic?)
+LL +         t.magic
+   |
 
-error: question mark operator is useless here
+error: enclosing `Ok` and `?` operator are unneeded
   --> tests/ui/needless_question_mark.rs:92:16
    |
 LL |         return Ok(t.magic?);
-   |                ^^^^^^^^^^^^ help: try removing question mark and `Ok()`: `t.magic`
+   |                ^^^^^^^^^^^^
+   |
+help: remove the enclosing `Ok` and `?` operator
+   |
+LL -         return Ok(t.magic?);
+LL +         return t.magic;
+   |
 
-error: question mark operator is useless here
+error: enclosing `Some` and `?` operator are unneeded
   --> tests/ui/needless_question_mark.rs:128:27
    |
 LL |         || -> Option<_> { Some(Some($expr)?) }()
-   |                           ^^^^^^^^^^^^^^^^^^ help: try removing question mark and `Some()`: `Some($expr)`
+   |                           ^^^^^^^^^^^^^^^^^^
 ...
 LL |     let _x = some_and_qmark_in_macro!(x?);
    |              ---------------------------- in this macro invocation
    |
    = note: this error originates in the macro `some_and_qmark_in_macro` (in Nightly builds, run with -Z macro-backtrace for more info)
+help: remove the enclosing `Some` and `?` operator
+   |
+LL -         || -> Option<_> { Some(Some($expr)?) }()
+LL +         || -> Option<_> { Some($expr) }()
+   |
 
-error: question mark operator is useless here
+error: enclosing `Some` and `?` operator are unneeded
   --> tests/ui/needless_question_mark.rs:140:5
    |
 LL |     Some(to.magic?)
-   |     ^^^^^^^^^^^^^^^ help: try removing question mark and `Some()`: `to.magic`
+   |     ^^^^^^^^^^^^^^^
+   |
+help: remove the enclosing `Some` and `?` operator
+   |
+LL -     Some(to.magic?)
+LL +     to.magic
+   |
 
-error: question mark operator is useless here
+error: enclosing `Ok` and `?` operator are unneeded
   --> tests/ui/needless_question_mark.rs:149:5
    |
 LL |     Ok(s.magic?)
-   |     ^^^^^^^^^^^^ help: try removing question mark and `Ok()`: `s.magic`
+   |     ^^^^^^^^^^^^
+   |
+help: remove the enclosing `Ok` and `?` operator
+   |
+LL -     Ok(s.magic?)
+LL +     s.magic
+   |
 
-error: question mark operator is useless here
+error: enclosing `Some` and `?` operator are unneeded
   --> tests/ui/needless_question_mark.rs:154:7
    |
 LL |     { Some(a?) }
-   |       ^^^^^^^^ help: try removing question mark and `Some()`: `a`
+   |       ^^^^^^^^
+   |
+help: remove the enclosing `Some` and `?` operator
+   |
+LL -     { Some(a?) }
+LL +     { a }
+   |
 
 error: aborting due to 15 previous errors
 
diff --git a/src/tools/clippy/tests/ui/ptr_eq.fixed b/src/tools/clippy/tests/ui/ptr_eq.fixed
index 484ff307323..9629b3eea58 100644
--- a/src/tools/clippy/tests/ui/ptr_eq.fixed
+++ b/src/tools/clippy/tests/ui/ptr_eq.fixed
@@ -23,23 +23,25 @@ fn main() {
     //~^ ptr_eq
     let _ = std::ptr::eq(a, b);
     //~^ ptr_eq
-    let _ = std::ptr::eq(a.as_ptr(), b as *const _);
-    //~^ ptr_eq
-    let _ = std::ptr::eq(a.as_ptr(), b.as_ptr());
-    //~^ ptr_eq
 
-    // Do not lint
+    // Do not lint: the rhs conversion is needed
+    let _ = a.as_ptr() == b as *const _;
 
+    // Do not lint: we have two raw pointers already
+    let _ = a.as_ptr() == b.as_ptr();
+
+    // Do not lint
     let _ = mac!(a, b);
     let _ = another_mac!(a, b);
 
     let a = &mut [1, 2, 3];
     let b = &mut [1, 2, 3];
 
-    let _ = std::ptr::eq(a.as_mut_ptr(), b as *mut [i32] as *mut _);
-    //~^ ptr_eq
-    let _ = std::ptr::eq(a.as_mut_ptr(), b.as_mut_ptr());
-    //~^ ptr_eq
+    // Do not lint: the rhs conversion is needed
+    let _ = a.as_mut_ptr() == b as *mut [i32] as *mut _;
+
+    // Do not lint: we have two raw pointers already
+    let _ = a.as_mut_ptr() == b.as_mut_ptr();
 
     let _ = a == b;
     let _ = core::ptr::eq(a, b);
@@ -51,8 +53,12 @@ fn main() {
     let _ = !std::ptr::eq(x, y);
     //~^ ptr_eq
 
-    #[allow(clippy::eq_op)]
-    let _issue14337 = std::ptr::eq(main as *const (), main as *const ());
+    #[expect(clippy::eq_op)]
+    // Do not lint: casts are needed to not change type
+    let _issue14337 = main as *const () == main as *const ();
+
+    // Do not peel the content of macros
+    let _ = std::ptr::eq(mac!(cast a), mac!(cast b));
     //~^ ptr_eq
 
     // Do not peel the content of macros
diff --git a/src/tools/clippy/tests/ui/ptr_eq.rs b/src/tools/clippy/tests/ui/ptr_eq.rs
index f28707cc3e9..2b741d8df46 100644
--- a/src/tools/clippy/tests/ui/ptr_eq.rs
+++ b/src/tools/clippy/tests/ui/ptr_eq.rs
@@ -23,23 +23,25 @@ fn main() {
     //~^ ptr_eq
     let _ = a as *const _ == b as *const _;
     //~^ ptr_eq
+
+    // Do not lint: the rhs conversion is needed
     let _ = a.as_ptr() == b as *const _;
-    //~^ ptr_eq
+
+    // Do not lint: we have two raw pointers already
     let _ = a.as_ptr() == b.as_ptr();
-    //~^ ptr_eq
 
     // Do not lint
-
     let _ = mac!(a, b);
     let _ = another_mac!(a, b);
 
     let a = &mut [1, 2, 3];
     let b = &mut [1, 2, 3];
 
+    // Do not lint: the rhs conversion is needed
     let _ = a.as_mut_ptr() == b as *mut [i32] as *mut _;
-    //~^ ptr_eq
+
+    // Do not lint: we have two raw pointers already
     let _ = a.as_mut_ptr() == b.as_mut_ptr();
-    //~^ ptr_eq
 
     let _ = a == b;
     let _ = core::ptr::eq(a, b);
@@ -51,8 +53,12 @@ fn main() {
     let _ = x as *const u32 != y as *mut u32 as *const u32;
     //~^ ptr_eq
 
-    #[allow(clippy::eq_op)]
+    #[expect(clippy::eq_op)]
+    // Do not lint: casts are needed to not change type
     let _issue14337 = main as *const () == main as *const ();
+
+    // Do not peel the content of macros
+    let _ = mac!(cast a) as *const _ == mac!(cast b) as *const _;
     //~^ ptr_eq
 
     // Do not peel the content of macros
diff --git a/src/tools/clippy/tests/ui/ptr_eq.stderr b/src/tools/clippy/tests/ui/ptr_eq.stderr
index 906831b9e03..e7340624b59 100644
--- a/src/tools/clippy/tests/ui/ptr_eq.stderr
+++ b/src/tools/clippy/tests/ui/ptr_eq.stderr
@@ -14,52 +14,28 @@ LL |     let _ = a as *const _ == b as *const _;
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `std::ptr::eq(a, b)`
 
 error: use `std::ptr::eq` when comparing raw pointers
-  --> tests/ui/ptr_eq.rs:26:13
-   |
-LL |     let _ = a.as_ptr() == b as *const _;
-   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `std::ptr::eq(a.as_ptr(), b as *const _)`
-
-error: use `std::ptr::eq` when comparing raw pointers
-  --> tests/ui/ptr_eq.rs:28:13
-   |
-LL |     let _ = a.as_ptr() == b.as_ptr();
-   |             ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `std::ptr::eq(a.as_ptr(), b.as_ptr())`
-
-error: use `std::ptr::eq` when comparing raw pointers
-  --> tests/ui/ptr_eq.rs:39:13
-   |
-LL |     let _ = a.as_mut_ptr() == b as *mut [i32] as *mut _;
-   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `std::ptr::eq(a.as_mut_ptr(), b as *mut [i32] as *mut _)`
-
-error: use `std::ptr::eq` when comparing raw pointers
-  --> tests/ui/ptr_eq.rs:41:13
-   |
-LL |     let _ = a.as_mut_ptr() == b.as_mut_ptr();
-   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `std::ptr::eq(a.as_mut_ptr(), b.as_mut_ptr())`
-
-error: use `std::ptr::eq` when comparing raw pointers
-  --> tests/ui/ptr_eq.rs:48:13
+  --> tests/ui/ptr_eq.rs:50:13
    |
 LL |     let _ = x as *const u32 == y as *mut u32 as *const u32;
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `std::ptr::eq(x, y)`
 
 error: use `std::ptr::eq` when comparing raw pointers
-  --> tests/ui/ptr_eq.rs:51:13
+  --> tests/ui/ptr_eq.rs:53:13
    |
 LL |     let _ = x as *const u32 != y as *mut u32 as *const u32;
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `!std::ptr::eq(x, y)`
 
 error: use `std::ptr::eq` when comparing raw pointers
-  --> tests/ui/ptr_eq.rs:55:23
+  --> tests/ui/ptr_eq.rs:61:13
    |
-LL |     let _issue14337 = main as *const () == main as *const ();
-   |                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `std::ptr::eq(main as *const (), main as *const ())`
+LL |     let _ = mac!(cast a) as *const _ == mac!(cast b) as *const _;
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `std::ptr::eq(mac!(cast a), mac!(cast b))`
 
 error: use `std::ptr::eq` when comparing raw pointers
-  --> tests/ui/ptr_eq.rs:59:13
+  --> tests/ui/ptr_eq.rs:65:13
    |
 LL |     let _ = mac!(cast a) as *const _ == mac!(cast b) as *const _;
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `std::ptr::eq(mac!(cast a), mac!(cast b))`
 
-error: aborting due to 10 previous errors
+error: aborting due to 6 previous errors
 
diff --git a/src/tools/clippy/tests/ui/ptr_eq_no_std.fixed b/src/tools/clippy/tests/ui/ptr_eq_no_std.fixed
index d8ee4ea88f8..48cbad62e1a 100644
--- a/src/tools/clippy/tests/ui/ptr_eq_no_std.fixed
+++ b/src/tools/clippy/tests/ui/ptr_eq_no_std.fixed
@@ -32,23 +32,25 @@ fn main() {
     //~^ ptr_eq
     let _ = core::ptr::eq(a, b);
     //~^ ptr_eq
-    let _ = core::ptr::eq(a.as_ptr(), b as *const _);
-    //~^ ptr_eq
-    let _ = core::ptr::eq(a.as_ptr(), b.as_ptr());
-    //~^ ptr_eq
 
-    // Do not lint
+    // Do not lint: the rhs conversion is needed
+    let _ = a.as_ptr() == b as *const _;
+
+    // Do not lint: we have two raw pointers already
+    let _ = a.as_ptr() == b.as_ptr();
 
+    // Do not lint
     let _ = mac!(a, b);
     let _ = another_mac!(a, b);
 
     let a = &mut [1, 2, 3];
     let b = &mut [1, 2, 3];
 
-    let _ = core::ptr::eq(a.as_mut_ptr(), b as *mut [i32] as *mut _);
-    //~^ ptr_eq
-    let _ = core::ptr::eq(a.as_mut_ptr(), b.as_mut_ptr());
-    //~^ ptr_eq
+    // Do not lint: the rhs conversion is needed
+    let _ = a.as_mut_ptr() == b as *mut [i32] as *mut _;
+
+    // Do not lint: we have two raw pointers already
+    let _ = a.as_mut_ptr() == b.as_mut_ptr();
 
     let _ = a == b;
     let _ = core::ptr::eq(a, b);
diff --git a/src/tools/clippy/tests/ui/ptr_eq_no_std.rs b/src/tools/clippy/tests/ui/ptr_eq_no_std.rs
index a236314c29b..3827178640e 100644
--- a/src/tools/clippy/tests/ui/ptr_eq_no_std.rs
+++ b/src/tools/clippy/tests/ui/ptr_eq_no_std.rs
@@ -32,23 +32,25 @@ fn main() {
     //~^ ptr_eq
     let _ = a as *const _ == b as *const _;
     //~^ ptr_eq
+
+    // Do not lint: the rhs conversion is needed
     let _ = a.as_ptr() == b as *const _;
-    //~^ ptr_eq
+
+    // Do not lint: we have two raw pointers already
     let _ = a.as_ptr() == b.as_ptr();
-    //~^ ptr_eq
 
     // Do not lint
-
     let _ = mac!(a, b);
     let _ = another_mac!(a, b);
 
     let a = &mut [1, 2, 3];
     let b = &mut [1, 2, 3];
 
+    // Do not lint: the rhs conversion is needed
     let _ = a.as_mut_ptr() == b as *mut [i32] as *mut _;
-    //~^ ptr_eq
+
+    // Do not lint: we have two raw pointers already
     let _ = a.as_mut_ptr() == b.as_mut_ptr();
-    //~^ ptr_eq
 
     let _ = a == b;
     let _ = core::ptr::eq(a, b);
diff --git a/src/tools/clippy/tests/ui/ptr_eq_no_std.stderr b/src/tools/clippy/tests/ui/ptr_eq_no_std.stderr
index 5b8135dc8e8..8c7b1ff7666 100644
--- a/src/tools/clippy/tests/ui/ptr_eq_no_std.stderr
+++ b/src/tools/clippy/tests/ui/ptr_eq_no_std.stderr
@@ -13,29 +13,5 @@ error: use `core::ptr::eq` when comparing raw pointers
 LL |     let _ = a as *const _ == b as *const _;
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `core::ptr::eq(a, b)`
 
-error: use `core::ptr::eq` when comparing raw pointers
-  --> tests/ui/ptr_eq_no_std.rs:35:13
-   |
-LL |     let _ = a.as_ptr() == b as *const _;
-   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `core::ptr::eq(a.as_ptr(), b as *const _)`
-
-error: use `core::ptr::eq` when comparing raw pointers
-  --> tests/ui/ptr_eq_no_std.rs:37:13
-   |
-LL |     let _ = a.as_ptr() == b.as_ptr();
-   |             ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `core::ptr::eq(a.as_ptr(), b.as_ptr())`
-
-error: use `core::ptr::eq` when comparing raw pointers
-  --> tests/ui/ptr_eq_no_std.rs:48:13
-   |
-LL |     let _ = a.as_mut_ptr() == b as *mut [i32] as *mut _;
-   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `core::ptr::eq(a.as_mut_ptr(), b as *mut [i32] as *mut _)`
-
-error: use `core::ptr::eq` when comparing raw pointers
-  --> tests/ui/ptr_eq_no_std.rs:50:13
-   |
-LL |     let _ = a.as_mut_ptr() == b.as_mut_ptr();
-   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `core::ptr::eq(a.as_mut_ptr(), b.as_mut_ptr())`
-
-error: aborting due to 6 previous errors
+error: aborting due to 2 previous errors
 
diff --git a/src/tools/clippy/tests/ui/question_mark.fixed b/src/tools/clippy/tests/ui/question_mark.fixed
index 6bd071d07f5..507bc2b29d8 100644
--- a/src/tools/clippy/tests/ui/question_mark.fixed
+++ b/src/tools/clippy/tests/ui/question_mark.fixed
@@ -301,6 +301,11 @@ fn pattern() -> Result<(), PatternedError> {
     res
 }
 
+fn expect_expr(a: Option<usize>) -> Option<usize> {
+    #[expect(clippy::needless_question_mark)]
+    Some(a?)
+}
+
 fn main() {}
 
 // `?` is not the same as `return None;` if inside of a try block
diff --git a/src/tools/clippy/tests/ui/question_mark.rs b/src/tools/clippy/tests/ui/question_mark.rs
index dd093c9bf48..64b51b849ed 100644
--- a/src/tools/clippy/tests/ui/question_mark.rs
+++ b/src/tools/clippy/tests/ui/question_mark.rs
@@ -371,6 +371,11 @@ fn pattern() -> Result<(), PatternedError> {
     res
 }
 
+fn expect_expr(a: Option<usize>) -> Option<usize> {
+    #[expect(clippy::needless_question_mark)]
+    Some(a?)
+}
+
 fn main() {}
 
 // `?` is not the same as `return None;` if inside of a try block
diff --git a/src/tools/clippy/tests/ui/question_mark.stderr b/src/tools/clippy/tests/ui/question_mark.stderr
index 8fe04b895ce..d8ce4420aee 100644
--- a/src/tools/clippy/tests/ui/question_mark.stderr
+++ b/src/tools/clippy/tests/ui/question_mark.stderr
@@ -198,7 +198,7 @@ LL | |     }
    | |_____^ help: replace it with: `func_returning_result()?;`
 
 error: this block may be rewritten with the `?` operator
-  --> tests/ui/question_mark.rs:390:13
+  --> tests/ui/question_mark.rs:395:13
    |
 LL | /             if a.is_none() {
 LL | |
@@ -208,7 +208,7 @@ LL | |             }
    | |_____________^ help: replace it with: `a?;`
 
 error: this `let...else` may be rewritten with the `?` operator
-  --> tests/ui/question_mark.rs:451:5
+  --> tests/ui/question_mark.rs:456:5
    |
 LL | /     let Some(v) = bar.foo.owned.clone() else {
 LL | |         return None;
@@ -216,7 +216,7 @@ LL | |     };
    | |______^ help: replace it with: `let v = bar.foo.owned.clone()?;`
 
 error: this `let...else` may be rewritten with the `?` operator
-  --> tests/ui/question_mark.rs:466:5
+  --> tests/ui/question_mark.rs:471:5
    |
 LL | /     let Some(ref x) = foo.opt_x else {
 LL | |         return None;
@@ -224,7 +224,7 @@ LL | |     };
    | |______^ help: replace it with: `let x = foo.opt_x.as_ref()?;`
 
 error: this `let...else` may be rewritten with the `?` operator
-  --> tests/ui/question_mark.rs:476:5
+  --> tests/ui/question_mark.rs:481:5
    |
 LL | /     let Some(ref mut x) = foo.opt_x else {
 LL | |         return None;
@@ -232,7 +232,7 @@ LL | |     };
    | |______^ help: replace it with: `let x = foo.opt_x.as_mut()?;`
 
 error: this `let...else` may be rewritten with the `?` operator
-  --> tests/ui/question_mark.rs:487:5
+  --> tests/ui/question_mark.rs:492:5
    |
 LL | /     let Some(ref x @ ref y) = foo.opt_x else {
 LL | |         return None;
@@ -240,7 +240,7 @@ LL | |     };
    | |______^ help: replace it with: `let x @ y = foo.opt_x.as_ref()?;`
 
 error: this `let...else` may be rewritten with the `?` operator
-  --> tests/ui/question_mark.rs:491:5
+  --> tests/ui/question_mark.rs:496:5
    |
 LL | /     let Some(ref x @ WrapperStructWithString(_)) = bar else {
 LL | |         return None;
@@ -248,7 +248,7 @@ LL | |     };
    | |______^ help: replace it with: `let x @ &WrapperStructWithString(_) = bar.as_ref()?;`
 
 error: this `let...else` may be rewritten with the `?` operator
-  --> tests/ui/question_mark.rs:495:5
+  --> tests/ui/question_mark.rs:500:5
    |
 LL | /     let Some(ref mut x @ WrapperStructWithString(_)) = bar else {
 LL | |         return None;
@@ -256,7 +256,7 @@ LL | |     };
    | |______^ help: replace it with: `let x @ &mut WrapperStructWithString(_) = bar.as_mut()?;`
 
 error: this block may be rewritten with the `?` operator
-  --> tests/ui/question_mark.rs:517:5
+  --> tests/ui/question_mark.rs:522:5
    |
 LL | /     if arg.is_none() {
 LL | |
@@ -265,7 +265,7 @@ LL | |     }
    | |_____^ help: replace it with: `arg?;`
 
 error: this `match` expression can be replaced with `?`
-  --> tests/ui/question_mark.rs:521:15
+  --> tests/ui/question_mark.rs:526:15
    |
 LL |       let val = match arg {
    |  _______________^
@@ -276,7 +276,7 @@ LL | |     };
    | |_____^ help: try instead: `arg?`
 
 error: this `let...else` may be rewritten with the `?` operator
-  --> tests/ui/question_mark.rs:531:5
+  --> tests/ui/question_mark.rs:536:5
    |
 LL | /     let Some(a) = *a else {
 LL | |         return None;
diff --git a/src/tools/clippy/tests/ui/question_mark_used.stderr b/src/tools/clippy/tests/ui/question_mark_used.stderr
index 53cb59c0216..82f0d325040 100644
--- a/src/tools/clippy/tests/ui/question_mark_used.stderr
+++ b/src/tools/clippy/tests/ui/question_mark_used.stderr
@@ -1,4 +1,4 @@
-error: question mark operator was used
+error: the `?` operator was used
   --> tests/ui/question_mark_used.rs:11:5
    |
 LL |     other_function()?;
diff --git a/src/tools/clippy/tests/ui/return_and_then.stderr b/src/tools/clippy/tests/ui/return_and_then.stderr
index cc611c3dba6..a7acbe7b340 100644
--- a/src/tools/clippy/tests/ui/return_and_then.stderr
+++ b/src/tools/clippy/tests/ui/return_and_then.stderr
@@ -1,4 +1,4 @@
-error: use the question mark operator instead of an `and_then` call
+error: use the `?` operator instead of an `and_then` call
   --> tests/ui/return_and_then.rs:5:9
    |
 LL | /         opt.and_then(|n| {
@@ -20,7 +20,7 @@ LL +         ret += n;
 LL +         if n > 1 { Some(ret) } else { None }
    |
 
-error: use the question mark operator instead of an `and_then` call
+error: use the `?` operator instead of an `and_then` call
   --> tests/ui/return_and_then.rs:14:9
    |
 LL |         opt.and_then(|n| test_opt_block(Some(n)))
@@ -32,7 +32,7 @@ LL ~         let n = opt?;
 LL +         test_opt_block(Some(n))
    |
 
-error: use the question mark operator instead of an `and_then` call
+error: use the `?` operator instead of an `and_then` call
   --> tests/ui/return_and_then.rs:19:9
    |
 LL |         gen_option(1).and_then(|n| test_opt_block(Some(n)))
@@ -44,7 +44,7 @@ LL ~         let n = gen_option(1)?;
 LL +         test_opt_block(Some(n))
    |
 
-error: use the question mark operator instead of an `and_then` call
+error: use the `?` operator instead of an `and_then` call
   --> tests/ui/return_and_then.rs:24:9
    |
 LL |         opt.and_then(|n| if n > 1 { Ok(n + 1) } else { Err(n) })
@@ -56,7 +56,7 @@ LL ~         let n = opt?;
 LL +         if n > 1 { Ok(n + 1) } else { Err(n) }
    |
 
-error: use the question mark operator instead of an `and_then` call
+error: use the `?` operator instead of an `and_then` call
   --> tests/ui/return_and_then.rs:29:9
    |
 LL |         opt.and_then(|n| test_res_block(Ok(n)))
@@ -68,7 +68,7 @@ LL ~         let n = opt?;
 LL +         test_res_block(Ok(n))
    |
 
-error: use the question mark operator instead of an `and_then` call
+error: use the `?` operator instead of an `and_then` call
   --> tests/ui/return_and_then.rs:35:9
    |
 LL |         Some("").and_then(|x| if x.len() > 2 { Some(3) } else { None })
@@ -80,7 +80,7 @@ LL ~         let x = Some("")?;
 LL +         if x.len() > 2 { Some(3) } else { None }
    |
 
-error: use the question mark operator instead of an `and_then` call
+error: use the `?` operator instead of an `and_then` call
   --> tests/ui/return_and_then.rs:41:9
    |
 LL | /         Some(match (vec![1, 2, 3], vec![1, 2, 4]) {
diff --git a/src/tools/clippy/tests/ui/unnecessary_cast.fixed b/src/tools/clippy/tests/ui/unnecessary_cast.fixed
index ba167e79a30..91ff4b9ee77 100644
--- a/src/tools/clippy/tests/ui/unnecessary_cast.fixed
+++ b/src/tools/clippy/tests/ui/unnecessary_cast.fixed
@@ -266,7 +266,21 @@ mod fixable {
     // Issue #11968: The suggestion for this lint removes the parentheses and leave the code as
     // `*x.pow(2)` which tries to dereference the return value rather than `x`.
     fn issue_11968(x: &usize) -> usize {
-        { *x }.pow(2)
+        (*x).pow(2)
+        //~^ unnecessary_cast
+    }
+
+    #[allow(clippy::cast_lossless)]
+    fn issue_14640() {
+        let x = 5usize;
+        let vec: Vec<u64> = vec![1, 2, 3, 4, 5];
+        assert_eq!(vec.len(), x);
+        //~^ unnecessary_cast
+
+        let _ = (5i32 as i64).abs();
+        //~^ unnecessary_cast
+
+        let _ = 5i32 as i64;
         //~^ unnecessary_cast
     }
 }
diff --git a/src/tools/clippy/tests/ui/unnecessary_cast.rs b/src/tools/clippy/tests/ui/unnecessary_cast.rs
index 0f90a8b0596..5444a914db1 100644
--- a/src/tools/clippy/tests/ui/unnecessary_cast.rs
+++ b/src/tools/clippy/tests/ui/unnecessary_cast.rs
@@ -269,4 +269,18 @@ mod fixable {
         (*x as usize).pow(2)
         //~^ unnecessary_cast
     }
+
+    #[allow(clippy::cast_lossless)]
+    fn issue_14640() {
+        let x = 5usize;
+        let vec: Vec<u64> = vec![1, 2, 3, 4, 5];
+        assert_eq!(vec.len(), x as usize);
+        //~^ unnecessary_cast
+
+        let _ = (5i32 as i64 as i64).abs();
+        //~^ unnecessary_cast
+
+        let _ = 5i32 as i64 as i64;
+        //~^ unnecessary_cast
+    }
 }
diff --git a/src/tools/clippy/tests/ui/unnecessary_cast.stderr b/src/tools/clippy/tests/ui/unnecessary_cast.stderr
index c83770c1a29..3e3c5eb81c1 100644
--- a/src/tools/clippy/tests/ui/unnecessary_cast.stderr
+++ b/src/tools/clippy/tests/ui/unnecessary_cast.stderr
@@ -245,7 +245,25 @@ error: casting to the same type is unnecessary (`usize` -> `usize`)
   --> tests/ui/unnecessary_cast.rs:269:9
    |
 LL |         (*x as usize).pow(2)
-   |         ^^^^^^^^^^^^^ help: try: `{ *x }`
+   |         ^^^^^^^^^^^^^ help: try: `(*x)`
 
-error: aborting due to 41 previous errors
+error: casting to the same type is unnecessary (`usize` -> `usize`)
+  --> tests/ui/unnecessary_cast.rs:277:31
+   |
+LL |         assert_eq!(vec.len(), x as usize);
+   |                               ^^^^^^^^^^ help: try: `x`
+
+error: casting to the same type is unnecessary (`i64` -> `i64`)
+  --> tests/ui/unnecessary_cast.rs:280:17
+   |
+LL |         let _ = (5i32 as i64 as i64).abs();
+   |                 ^^^^^^^^^^^^^^^^^^^^ help: try: `(5i32 as i64)`
+
+error: casting to the same type is unnecessary (`i64` -> `i64`)
+  --> tests/ui/unnecessary_cast.rs:283:17
+   |
+LL |         let _ = 5i32 as i64 as i64;
+   |                 ^^^^^^^^^^^^^^^^^^ help: try: `5i32 as i64`
+
+error: aborting due to 44 previous errors
 
diff --git a/src/tools/clippy/tests/ui/unused_unit.edition2021.fixed b/src/tools/clippy/tests/ui/unused_unit.edition2021.fixed
new file mode 100644
index 00000000000..93dd58b8e9d
--- /dev/null
+++ b/src/tools/clippy/tests/ui/unused_unit.edition2021.fixed
@@ -0,0 +1,146 @@
+//@revisions: edition2021 edition2024
+//@[edition2021] edition:2021
+//@[edition2024] edition:2024
+
+// The output for humans should just highlight the whole span without showing
+// the suggested replacement, but we also want to test that suggested
+// replacement only removes one set of parentheses, rather than naïvely
+// stripping away any starting or ending parenthesis characters—hence this
+// test of the JSON error format.
+
+#![feature(custom_inner_attributes)]
+#![feature(closure_lifetime_binder)]
+#![rustfmt::skip]
+
+#![deny(clippy::unused_unit)]
+#![allow(dead_code)]
+#![allow(clippy::from_over_into)]
+
+struct Unitter;
+impl Unitter {
+    #[allow(clippy::no_effect)]
+    pub fn get_unit<F: Fn(), G>(&self, f: F, _g: G)
+    //~^ unused_unit
+    //~| unused_unit
+    where G: Fn() {
+    //~^ unused_unit
+        let _y: &dyn Fn() = &f;
+        //~^ unused_unit
+        (); // this should not lint, as it's not in return type position
+    }
+}
+
+impl Into<()> for Unitter {
+    #[rustfmt::skip]
+    fn into(self) {
+    //~^ unused_unit
+        
+        //~^ unused_unit
+    }
+}
+
+trait Trait {
+    fn redundant<F: FnOnce(), G, H>(&self, _f: F, _g: G, _h: H)
+    //~^ unused_unit
+    where
+        G: FnMut(),
+        //~^ unused_unit
+        H: Fn();
+        //~^ unused_unit
+}
+
+impl Trait for Unitter {
+    fn redundant<F: FnOnce(), G, H>(&self, _f: F, _g: G, _h: H)
+    //~^ unused_unit
+    where
+        G: FnMut(),
+        //~^ unused_unit
+        H: Fn() {}
+        //~^ unused_unit
+}
+
+fn return_unit() {  }
+//~^ unused_unit
+//~| unused_unit
+
+#[allow(clippy::needless_return)]
+#[allow(clippy::never_loop)]
+#[allow(clippy::unit_cmp)]
+fn main() {
+    let u = Unitter;
+    assert_eq!(u.get_unit(|| {}, return_unit), u.into());
+    return_unit();
+    loop {
+        break;
+        //~^ unused_unit
+    }
+    return;
+    //~^ unused_unit
+}
+
+// https://github.com/rust-lang/rust-clippy/issues/4076
+fn foo() {
+    macro_rules! foo {
+        (recv($r:expr) -> $res:pat => $body:expr) => {
+            $body
+        }
+    }
+
+    foo! {
+        recv(rx) -> _x => ()
+    }
+}
+
+#[rustfmt::skip]
+fn test(){}
+//~^ unused_unit
+
+#[rustfmt::skip]
+fn test2(){}
+//~^ unused_unit
+
+#[rustfmt::skip]
+fn test3(){}
+//~^ unused_unit
+
+fn macro_expr() {
+    macro_rules! e {
+        () => (());
+    }
+    e!()
+}
+
+mod issue9748 {
+    fn main() {
+        let _ = for<'a> |_: &'a u32| -> () {};
+    }
+}
+
+mod issue9949 {
+    fn main() {
+        #[doc = "documentation"]
+        ()
+    }
+}
+
+mod issue14577 {
+    trait Unit {}
+    impl Unit for () {}
+
+    fn run<R: Unit>(f: impl FnOnce() -> R) {
+        f();
+    }
+
+    #[allow(dependency_on_unit_never_type_fallback)]
+    fn bar() {
+        run(|| { todo!() }); 
+        //~[edition2021]^ unused_unit
+    }
+
+    struct UnitStruct;
+    impl UnitStruct {
+        fn apply<F: for<'c> Fn(&'c mut Self)>(&mut self, f: F) {
+            todo!()
+        }
+    }
+}
\ No newline at end of file
diff --git a/src/tools/clippy/tests/ui/unused_unit.edition2021.stderr b/src/tools/clippy/tests/ui/unused_unit.edition2021.stderr
new file mode 100644
index 00000000000..13cc20d4d7a
--- /dev/null
+++ b/src/tools/clippy/tests/ui/unused_unit.edition2021.stderr
@@ -0,0 +1,128 @@
+error: unneeded unit expression
+  --> tests/ui/unused_unit.rs:37:9
+   |
+LL |         ()
+   |         ^^ help: remove the final `()`
+   |
+note: the lint level is defined here
+  --> tests/ui/unused_unit.rs:15:9
+   |
+LL | #![deny(clippy::unused_unit)]
+   |         ^^^^^^^^^^^^^^^^^^^
+
+error: unneeded unit expression
+  --> tests/ui/unused_unit.rs:62:26
+   |
+LL | fn return_unit() -> () { () }
+   |                          ^^ help: remove the final `()`
+
+error: unneeded unit return type
+  --> tests/ui/unused_unit.rs:22:28
+   |
+LL |     pub fn get_unit<F: Fn() -> (), G>(&self, f: F, _g: G) -> ()
+   |                            ^^^^^^ help: remove the `-> ()`
+
+error: unneeded unit return type
+  --> tests/ui/unused_unit.rs:25:18
+   |
+LL |     where G: Fn() -> () {
+   |                  ^^^^^^ help: remove the `-> ()`
+
+error: unneeded unit return type
+  --> tests/ui/unused_unit.rs:22:58
+   |
+LL |     pub fn get_unit<F: Fn() -> (), G>(&self, f: F, _g: G) -> ()
+   |                                                          ^^^^^^ help: remove the `-> ()`
+
+error: unneeded unit return type
+  --> tests/ui/unused_unit.rs:27:26
+   |
+LL |         let _y: &dyn Fn() -> () = &f;
+   |                          ^^^^^^ help: remove the `-> ()`
+
+error: unneeded unit return type
+  --> tests/ui/unused_unit.rs:35:18
+   |
+LL |     fn into(self) -> () {
+   |                  ^^^^^^ help: remove the `-> ()`
+
+error: unneeded unit return type
+  --> tests/ui/unused_unit.rs:43:29
+   |
+LL |     fn redundant<F: FnOnce() -> (), G, H>(&self, _f: F, _g: G, _h: H)
+   |                             ^^^^^^ help: remove the `-> ()`
+
+error: unneeded unit return type
+  --> tests/ui/unused_unit.rs:46:19
+   |
+LL |         G: FnMut() -> (),
+   |                   ^^^^^^ help: remove the `-> ()`
+
+error: unneeded unit return type
+  --> tests/ui/unused_unit.rs:48:16
+   |
+LL |         H: Fn() -> ();
+   |                ^^^^^^ help: remove the `-> ()`
+
+error: unneeded unit return type
+  --> tests/ui/unused_unit.rs:53:29
+   |
+LL |     fn redundant<F: FnOnce() -> (), G, H>(&self, _f: F, _g: G, _h: H)
+   |                             ^^^^^^ help: remove the `-> ()`
+
+error: unneeded unit return type
+  --> tests/ui/unused_unit.rs:56:19
+   |
+LL |         G: FnMut() -> (),
+   |                   ^^^^^^ help: remove the `-> ()`
+
+error: unneeded unit return type
+  --> tests/ui/unused_unit.rs:58:16
+   |
+LL |         H: Fn() -> () {}
+   |                ^^^^^^ help: remove the `-> ()`
+
+error: unneeded unit return type
+  --> tests/ui/unused_unit.rs:62:17
+   |
+LL | fn return_unit() -> () { () }
+   |                 ^^^^^^ help: remove the `-> ()`
+
+error: unneeded `()`
+  --> tests/ui/unused_unit.rs:74:14
+   |
+LL |         break();
+   |              ^^ help: remove the `()`
+
+error: unneeded `()`
+  --> tests/ui/unused_unit.rs:77:11
+   |
+LL |     return();
+   |           ^^ help: remove the `()`
+
+error: unneeded unit return type
+  --> tests/ui/unused_unit.rs:95:10
+   |
+LL | fn test()->(){}
+   |          ^^^^ help: remove the `-> ()`
+
+error: unneeded unit return type
+  --> tests/ui/unused_unit.rs:99:11
+   |
+LL | fn test2() ->(){}
+   |           ^^^^^ help: remove the `-> ()`
+
+error: unneeded unit return type
+  --> tests/ui/unused_unit.rs:103:11
+   |
+LL | fn test3()-> (){}
+   |           ^^^^^ help: remove the `-> ()`
+
+error: unneeded unit return type
+  --> tests/ui/unused_unit.rs:136:15
+   |
+LL |         run(|| -> () { todo!() }); 
+   |               ^^^^^^ help: remove the `-> ()`
+
+error: aborting due to 20 previous errors
+
diff --git a/src/tools/clippy/tests/ui/unused_unit.edition2024.fixed b/src/tools/clippy/tests/ui/unused_unit.edition2024.fixed
new file mode 100644
index 00000000000..987d901b97d
--- /dev/null
+++ b/src/tools/clippy/tests/ui/unused_unit.edition2024.fixed
@@ -0,0 +1,146 @@
+//@revisions: edition2021 edition2024
+//@[edition2021] edition:2021
+//@[edition2024] edition:2024
+
+// The output for humans should just highlight the whole span without showing
+// the suggested replacement, but we also want to test that suggested
+// replacement only removes one set of parentheses, rather than naïvely
+// stripping away any starting or ending parenthesis characters—hence this
+// test of the JSON error format.
+
+#![feature(custom_inner_attributes)]
+#![feature(closure_lifetime_binder)]
+#![rustfmt::skip]
+
+#![deny(clippy::unused_unit)]
+#![allow(dead_code)]
+#![allow(clippy::from_over_into)]
+
+struct Unitter;
+impl Unitter {
+    #[allow(clippy::no_effect)]
+    pub fn get_unit<F: Fn(), G>(&self, f: F, _g: G)
+    //~^ unused_unit
+    //~| unused_unit
+    where G: Fn() {
+    //~^ unused_unit
+        let _y: &dyn Fn() = &f;
+        //~^ unused_unit
+        (); // this should not lint, as it's not in return type position
+    }
+}
+
+impl Into<()> for Unitter {
+    #[rustfmt::skip]
+    fn into(self) {
+    //~^ unused_unit
+        
+        //~^ unused_unit
+    }
+}
+
+trait Trait {
+    fn redundant<F: FnOnce(), G, H>(&self, _f: F, _g: G, _h: H)
+    //~^ unused_unit
+    where
+        G: FnMut(),
+        //~^ unused_unit
+        H: Fn();
+        //~^ unused_unit
+}
+
+impl Trait for Unitter {
+    fn redundant<F: FnOnce(), G, H>(&self, _f: F, _g: G, _h: H)
+    //~^ unused_unit
+    where
+        G: FnMut(),
+        //~^ unused_unit
+        H: Fn() {}
+        //~^ unused_unit
+}
+
+fn return_unit() {  }
+//~^ unused_unit
+//~| unused_unit
+
+#[allow(clippy::needless_return)]
+#[allow(clippy::never_loop)]
+#[allow(clippy::unit_cmp)]
+fn main() {
+    let u = Unitter;
+    assert_eq!(u.get_unit(|| {}, return_unit), u.into());
+    return_unit();
+    loop {
+        break;
+        //~^ unused_unit
+    }
+    return;
+    //~^ unused_unit
+}
+
+// https://github.com/rust-lang/rust-clippy/issues/4076
+fn foo() {
+    macro_rules! foo {
+        (recv($r:expr) -> $res:pat => $body:expr) => {
+            $body
+        }
+    }
+
+    foo! {
+        recv(rx) -> _x => ()
+    }
+}
+
+#[rustfmt::skip]
+fn test(){}
+//~^ unused_unit
+
+#[rustfmt::skip]
+fn test2(){}
+//~^ unused_unit
+
+#[rustfmt::skip]
+fn test3(){}
+//~^ unused_unit
+
+fn macro_expr() {
+    macro_rules! e {
+        () => (());
+    }
+    e!()
+}
+
+mod issue9748 {
+    fn main() {
+        let _ = for<'a> |_: &'a u32| -> () {};
+    }
+}
+
+mod issue9949 {
+    fn main() {
+        #[doc = "documentation"]
+        ()
+    }
+}
+
+mod issue14577 {
+    trait Unit {}
+    impl Unit for () {}
+
+    fn run<R: Unit>(f: impl FnOnce() -> R) {
+        f();
+    }
+
+    #[allow(dependency_on_unit_never_type_fallback)]
+    fn bar() {
+        run(|| -> () { todo!() }); 
+        //~[edition2021]^ unused_unit
+    }
+
+    struct UnitStruct;
+    impl UnitStruct {
+        fn apply<F: for<'c> Fn(&'c mut Self)>(&mut self, f: F) {
+            todo!()
+        }
+    }
+}
\ No newline at end of file
diff --git a/src/tools/clippy/tests/ui/unused_unit.edition2024.stderr b/src/tools/clippy/tests/ui/unused_unit.edition2024.stderr
new file mode 100644
index 00000000000..a79e70e066b
--- /dev/null
+++ b/src/tools/clippy/tests/ui/unused_unit.edition2024.stderr
@@ -0,0 +1,122 @@
+error: unneeded unit expression
+  --> tests/ui/unused_unit.rs:37:9
+   |
+LL |         ()
+   |         ^^ help: remove the final `()`
+   |
+note: the lint level is defined here
+  --> tests/ui/unused_unit.rs:15:9
+   |
+LL | #![deny(clippy::unused_unit)]
+   |         ^^^^^^^^^^^^^^^^^^^
+
+error: unneeded unit expression
+  --> tests/ui/unused_unit.rs:62:26
+   |
+LL | fn return_unit() -> () { () }
+   |                          ^^ help: remove the final `()`
+
+error: unneeded unit return type
+  --> tests/ui/unused_unit.rs:22:28
+   |
+LL |     pub fn get_unit<F: Fn() -> (), G>(&self, f: F, _g: G) -> ()
+   |                            ^^^^^^ help: remove the `-> ()`
+
+error: unneeded unit return type
+  --> tests/ui/unused_unit.rs:25:18
+   |
+LL |     where G: Fn() -> () {
+   |                  ^^^^^^ help: remove the `-> ()`
+
+error: unneeded unit return type
+  --> tests/ui/unused_unit.rs:22:58
+   |
+LL |     pub fn get_unit<F: Fn() -> (), G>(&self, f: F, _g: G) -> ()
+   |                                                          ^^^^^^ help: remove the `-> ()`
+
+error: unneeded unit return type
+  --> tests/ui/unused_unit.rs:27:26
+   |
+LL |         let _y: &dyn Fn() -> () = &f;
+   |                          ^^^^^^ help: remove the `-> ()`
+
+error: unneeded unit return type
+  --> tests/ui/unused_unit.rs:35:18
+   |
+LL |     fn into(self) -> () {
+   |                  ^^^^^^ help: remove the `-> ()`
+
+error: unneeded unit return type
+  --> tests/ui/unused_unit.rs:43:29
+   |
+LL |     fn redundant<F: FnOnce() -> (), G, H>(&self, _f: F, _g: G, _h: H)
+   |                             ^^^^^^ help: remove the `-> ()`
+
+error: unneeded unit return type
+  --> tests/ui/unused_unit.rs:46:19
+   |
+LL |         G: FnMut() -> (),
+   |                   ^^^^^^ help: remove the `-> ()`
+
+error: unneeded unit return type
+  --> tests/ui/unused_unit.rs:48:16
+   |
+LL |         H: Fn() -> ();
+   |                ^^^^^^ help: remove the `-> ()`
+
+error: unneeded unit return type
+  --> tests/ui/unused_unit.rs:53:29
+   |
+LL |     fn redundant<F: FnOnce() -> (), G, H>(&self, _f: F, _g: G, _h: H)
+   |                             ^^^^^^ help: remove the `-> ()`
+
+error: unneeded unit return type
+  --> tests/ui/unused_unit.rs:56:19
+   |
+LL |         G: FnMut() -> (),
+   |                   ^^^^^^ help: remove the `-> ()`
+
+error: unneeded unit return type
+  --> tests/ui/unused_unit.rs:58:16
+   |
+LL |         H: Fn() -> () {}
+   |                ^^^^^^ help: remove the `-> ()`
+
+error: unneeded unit return type
+  --> tests/ui/unused_unit.rs:62:17
+   |
+LL | fn return_unit() -> () { () }
+   |                 ^^^^^^ help: remove the `-> ()`
+
+error: unneeded `()`
+  --> tests/ui/unused_unit.rs:74:14
+   |
+LL |         break();
+   |              ^^ help: remove the `()`
+
+error: unneeded `()`
+  --> tests/ui/unused_unit.rs:77:11
+   |
+LL |     return();
+   |           ^^ help: remove the `()`
+
+error: unneeded unit return type
+  --> tests/ui/unused_unit.rs:95:10
+   |
+LL | fn test()->(){}
+   |          ^^^^ help: remove the `-> ()`
+
+error: unneeded unit return type
+  --> tests/ui/unused_unit.rs:99:11
+   |
+LL | fn test2() ->(){}
+   |           ^^^^^ help: remove the `-> ()`
+
+error: unneeded unit return type
+  --> tests/ui/unused_unit.rs:103:11
+   |
+LL | fn test3()-> (){}
+   |           ^^^^^ help: remove the `-> ()`
+
+error: aborting due to 19 previous errors
+
diff --git a/src/tools/clippy/tests/ui/unused_unit.fixed b/src/tools/clippy/tests/ui/unused_unit.fixed
index e3c02681c9f..6668bf90c09 100644
--- a/src/tools/clippy/tests/ui/unused_unit.fixed
+++ b/src/tools/clippy/tests/ui/unused_unit.fixed
@@ -120,3 +120,24 @@ mod issue9949 {
         ()
     }
 }
+
+#[clippy::msrv = "1.85"]
+mod issue14577 {
+    trait Unit {}
+    impl Unit for () {}
+
+    fn run<R: Unit>(f: impl FnOnce() -> R) {
+        f();
+    }
+
+    fn bar() {
+        run(|| -> () { todo!() });
+    }
+
+    struct UnitStruct;
+    impl UnitStruct {
+        fn apply<F: for<'c> Fn(&'c mut Self)>(&mut self, f: F) {
+            todo!()
+        }
+    }
+}
\ No newline at end of file
diff --git a/src/tools/clippy/tests/ui/unused_unit.rs b/src/tools/clippy/tests/ui/unused_unit.rs
index 4353026c594..b7645f7b6a2 100644
--- a/src/tools/clippy/tests/ui/unused_unit.rs
+++ b/src/tools/clippy/tests/ui/unused_unit.rs
@@ -1,4 +1,6 @@
-
+//@revisions: edition2021 edition2024
+//@[edition2021] edition:2021
+//@[edition2024] edition:2024
 
 // The output for humans should just highlight the whole span without showing
 // the suggested replacement, but we also want to test that suggested
@@ -120,3 +122,25 @@ mod issue9949 {
         ()
     }
 }
+
+mod issue14577 {
+    trait Unit {}
+    impl Unit for () {}
+
+    fn run<R: Unit>(f: impl FnOnce() -> R) {
+        f();
+    }
+
+    #[allow(dependency_on_unit_never_type_fallback)]
+    fn bar() {
+        run(|| -> () { todo!() }); 
+        //~[edition2021]^ unused_unit
+    }
+
+    struct UnitStruct;
+    impl UnitStruct {
+        fn apply<F: for<'c> Fn(&'c mut Self)>(&mut self, f: F) {
+            todo!()
+        }
+    }
+}
\ No newline at end of file
diff --git a/src/tools/clippy/tests/ui/unused_unit.stderr b/src/tools/clippy/tests/ui/unused_unit.stderr
index 172fe065502..366f2142095 100644
--- a/src/tools/clippy/tests/ui/unused_unit.stderr
+++ b/src/tools/clippy/tests/ui/unused_unit.stderr
@@ -1,8 +1,8 @@
-error: unneeded unit return type
-  --> tests/ui/unused_unit.rs:20:58
+error: unneeded unit expression
+  --> tests/ui/unused_unit.rs:35:9
    |
-LL |     pub fn get_unit<F: Fn() -> (), G>(&self, f: F, _g: G) -> ()
-   |                                                          ^^^^^^ help: remove the `-> ()`
+LL |         ()
+   |         ^^ help: remove the final `()`
    |
 note: the lint level is defined here
   --> tests/ui/unused_unit.rs:13:9
@@ -10,6 +10,12 @@ note: the lint level is defined here
 LL | #![deny(clippy::unused_unit)]
    |         ^^^^^^^^^^^^^^^^^^^
 
+error: unneeded unit expression
+  --> tests/ui/unused_unit.rs:60:26
+   |
+LL | fn return_unit() -> () { () }
+   |                          ^^ help: remove the final `()`
+
 error: unneeded unit return type
   --> tests/ui/unused_unit.rs:20:28
    |
@@ -23,6 +29,12 @@ LL |     where G: Fn() -> () {
    |                  ^^^^^^ help: remove the `-> ()`
 
 error: unneeded unit return type
+  --> tests/ui/unused_unit.rs:20:58
+   |
+LL |     pub fn get_unit<F: Fn() -> (), G>(&self, f: F, _g: G) -> ()
+   |                                                          ^^^^^^ help: remove the `-> ()`
+
+error: unneeded unit return type
   --> tests/ui/unused_unit.rs:25:26
    |
 LL |         let _y: &dyn Fn() -> () = &f;
@@ -34,12 +46,6 @@ error: unneeded unit return type
 LL |     fn into(self) -> () {
    |                  ^^^^^^ help: remove the `-> ()`
 
-error: unneeded unit expression
-  --> tests/ui/unused_unit.rs:35:9
-   |
-LL |         ()
-   |         ^^ help: remove the final `()`
-
 error: unneeded unit return type
   --> tests/ui/unused_unit.rs:41:29
    |
@@ -82,12 +88,6 @@ error: unneeded unit return type
 LL | fn return_unit() -> () { () }
    |                 ^^^^^^ help: remove the `-> ()`
 
-error: unneeded unit expression
-  --> tests/ui/unused_unit.rs:60:26
-   |
-LL | fn return_unit() -> () { () }
-   |                          ^^ help: remove the final `()`
-
 error: unneeded `()`
   --> tests/ui/unused_unit.rs:72:14
    |
diff --git a/src/tools/clippy/tests/ui/zombie_processes.rs b/src/tools/clippy/tests/ui/zombie_processes.rs
index 25bbc02ffb7..395f9dd2def 100644
--- a/src/tools/clippy/tests/ui/zombie_processes.rs
+++ b/src/tools/clippy/tests/ui/zombie_processes.rs
@@ -176,3 +176,25 @@ fn return_wait() -> ExitStatus {
     let mut x = Command::new("").spawn().unwrap();
     return x.wait().unwrap();
 }
+
+mod issue14677 {
+    use std::io;
+    use std::process::Command;
+
+    fn do_something<F: Fn() -> Result<(), ()>>(f: F) {
+        todo!()
+    }
+
+    fn foo() {
+        let mut child = Command::new("true").spawn().unwrap();
+        let some_condition = true;
+        do_something(|| {
+            if some_condition {
+                return Err(());
+            }
+            Ok(())
+        });
+        child.kill().unwrap();
+        child.wait().unwrap();
+    }
+}
diff --git a/src/tools/clippy/util/etc/pre-commit.sh b/src/tools/clippy/util/etc/pre-commit.sh
index 5dd2ba3d5f5..528f8953b25 100755
--- a/src/tools/clippy/util/etc/pre-commit.sh
+++ b/src/tools/clippy/util/etc/pre-commit.sh
@@ -6,7 +6,6 @@ set -e
 # Update lints
 cargo dev update_lints
 git add clippy_lints/src/lib.rs
-git add clippy_lints/src/lib.*.rs
 
 # Formatting:
 #     Git will not automatically add the formatted code to the staged changes once