about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2024-08-05 13:33:16 +0000
committerbors <bors@rust-lang.org>2024-08-05 13:33:16 +0000
commitc082bc2cb85313901ed3565fcd285592ed93df0f (patch)
treefc37b0b084729b9d6b93ec704d6e36f51b741a8e
parente17d254e2bd3fc78bbff021171813cc0e9424b97 (diff)
parent053210424727ff279515f4b9a7f0cf6e5632acf3 (diff)
downloadrust-c082bc2cb85313901ed3565fcd285592ed93df0f.tar.gz
rust-c082bc2cb85313901ed3565fcd285592ed93df0f.zip
Auto merge of #13136 - xFrednet:07797-restriction-and-then, r=blyxyas
Make restriction lint's use `span_lint_and_then` (a -> e)

This migrates a few restriction lints to use `span_lint_and_then`. This change is motivated by https://github.com/rust-lang/rust-clippy/issues/7797.

I'm also interested if it will have an impact on performance. With some of these lints, like [`clippy::implicit_return`](https://rust-lang.github.io/rust-clippy/master/index.html#/implicit_return) I expect an impact, as it was previously creating a suggestion **for every implicit return** which is just wild.

I've also cleaned up some lint message. Mostly minor stuff. For example: suggestions with a longer message than `"try"` now use `SuggestionStyle::ShowAlways`

---

`@blyxyas` Could you benchmark this PR? I want to get all the numbers :3

---

This also crashed our new lintcheck CI with the following message:

> Error: $GITHUB_STEP_SUMMARY upload aborted, supports content up to a size of 1024k, got 46731k. For more information see: https://docs.github.com/actions/using-workflows/workflow-commands-for-github-actions#adding-a-markdown-summary

Which is just wild. Like, I've [tested the first 20 lints](https://github.com/xFrednet/rust-clippy/actions/runs/10027528172) and got like four changes and then this. 50 MB of changed lint messages o.O. Looks like I'll create a separate PR to fix that step ^^

---

cc: https://github.com/rust-lang/rust-clippy/issues/7797

changelog: none

r? `@blyxyas`
-rw-r--r--clippy_lints/src/as_conversions.rs10
-rw-r--r--clippy_lints/src/assertions_on_result_states.rs47
-rw-r--r--clippy_lints/src/attrs/allow_attributes.rs20
-rw-r--r--clippy_lints/src/attrs/allow_attributes_without_reason.rs10
-rw-r--r--clippy_lints/src/casts/fn_to_numeric_cast_any.rs37
-rw-r--r--clippy_lints/src/create_dir.rs24
-rw-r--r--clippy_lints/src/dbg_macro.rs108
-rw-r--r--clippy_lints/src/default_numeric_fallback.rs23
-rw-r--r--clippy_lints/src/default_union_representation.rs16
-rw-r--r--clippy_lints/src/else_if_without_else.rs10
-rw-r--r--clippy_lints/src/empty_drop.rs19
-rw-r--r--clippy_lints/src/endian_bytes.rs89
-rw-r--r--clippy_lints/src/exhaustive_items.rs6
-rw-r--r--clippy_lints/src/field_scoped_visibility_modifiers.rs10
-rw-r--r--clippy_lints/src/format_push_string.rs10
-rw-r--r--clippy_lints/src/if_then_some_else_none.rs41
-rw-r--r--clippy_lints/src/implicit_return.rs21
-rw-r--r--clippy_lints/src/literal_representation.rs77
-rw-r--r--clippy_lints/src/methods/clone_on_ref_ptr.rs23
-rw-r--r--clippy_lints/src/methods/filetype_is_file.rs9
-rw-r--r--clippy_lints/src/methods/get_unwrap.rs44
-rw-r--r--clippy_lints/src/redundant_slicing.rs53
-rw-r--r--clippy_lints/src/std_instead_of_core.rs16
-rw-r--r--tests/ui-toml/unwrap_used/unwrap_used.stderr134
-rw-r--r--tests/ui/create_dir.stderr13
-rw-r--r--tests/ui/dbg_macro/dbg_macro.stderr4
-rw-r--r--tests/ui/dbg_macro/dbg_macro_unfixable.stderr2
-rw-r--r--tests/ui/empty_drop.stderr7
-rw-r--r--tests/ui/fn_to_numeric_cast_any.stderr118
-rw-r--r--tests/ui/get_unwrap.stderr152
-rw-r--r--tests/ui/if_then_some_else_none.fixed119
-rw-r--r--tests/ui/if_then_some_else_none.rs2
-rw-r--r--tests/ui/if_then_some_else_none.stderr19
-rw-r--r--tests/ui/implicit_return.stderr104
34 files changed, 927 insertions, 470 deletions
diff --git a/clippy_lints/src/as_conversions.rs b/clippy_lints/src/as_conversions.rs
index cfa25005a05..fefd8195f8e 100644
--- a/clippy_lints/src/as_conversions.rs
+++ b/clippy_lints/src/as_conversions.rs
@@ -1,4 +1,4 @@
-use clippy_utils::diagnostics::span_lint_and_help;
+use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::is_from_proc_macro;
 use rustc_hir::{Expr, ExprKind};
 use rustc_lint::{LateContext, LateLintPass, LintContext};
@@ -52,13 +52,15 @@ impl<'tcx> LateLintPass<'tcx> for AsConversions {
             && !in_external_macro(cx.sess(), expr.span)
             && !is_from_proc_macro(cx, expr)
         {
-            span_lint_and_help(
+            #[expect(clippy::collapsible_span_lint_calls, reason = "rust-clippy#7797")]
+            span_lint_and_then(
                 cx,
                 AS_CONVERSIONS,
                 expr.span,
                 "using a potentially dangerous silent `as` conversion",
-                None,
-                "consider using a safe wrapper for this conversion",
+                |diag| {
+                    diag.help("consider using a safe wrapper for this conversion");
+                },
             );
         }
     }
diff --git a/clippy_lints/src/assertions_on_result_states.rs b/clippy_lints/src/assertions_on_result_states.rs
index 7217686dcca..f1cb4a05af8 100644
--- a/clippy_lints/src/assertions_on_result_states.rs
+++ b/clippy_lints/src/assertions_on_result_states.rs
@@ -1,4 +1,4 @@
-use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::macros::{find_assert_args, root_macro_call_first_node, PanicExpn};
 use clippy_utils::source::snippet_with_context;
 use clippy_utils::ty::{has_debug_impl, is_copy, is_type_diagnostic_item};
@@ -68,39 +68,28 @@ impl<'tcx> LateLintPass<'tcx> for AssertionsOnResultStates {
                     return;
                 }
             }
-            let semicolon = if is_expr_final_block_expr(cx.tcx, e) { ";" } else { "" };
-            let mut app = Applicability::MachineApplicable;
-            match method_segment.ident.as_str() {
+            let (message, replacement) = match method_segment.ident.as_str() {
                 "is_ok" if type_suitable_to_unwrap(cx, args.type_at(1)) => {
-                    span_lint_and_sugg(
-                        cx,
-                        ASSERTIONS_ON_RESULT_STATES,
-                        macro_call.span,
-                        "called `assert!` with `Result::is_ok`",
-                        "replace with",
-                        format!(
-                            "{}.unwrap(){semicolon}",
-                            snippet_with_context(cx, recv.span, condition.span.ctxt(), "..", &mut app).0
-                        ),
-                        app,
-                    );
+                    ("called `assert!` with `Result::is_ok`", "unwrap")
                 },
                 "is_err" if type_suitable_to_unwrap(cx, args.type_at(0)) => {
-                    span_lint_and_sugg(
-                        cx,
-                        ASSERTIONS_ON_RESULT_STATES,
-                        macro_call.span,
-                        "called `assert!` with `Result::is_err`",
-                        "replace with",
-                        format!(
-                            "{}.unwrap_err(){semicolon}",
-                            snippet_with_context(cx, recv.span, condition.span.ctxt(), "..", &mut app).0
-                        ),
-                        app,
-                    );
+                    ("called `assert!` with `Result::is_err`", "unwrap_err")
                 },
-                _ => (),
+                _ => return,
             };
+            span_lint_and_then(cx, ASSERTIONS_ON_RESULT_STATES, macro_call.span, message, |diag| {
+                let semicolon = if is_expr_final_block_expr(cx.tcx, e) { ";" } else { "" };
+                let mut app = Applicability::MachineApplicable;
+                diag.span_suggestion(
+                    macro_call.span,
+                    "replace with",
+                    format!(
+                        "{}.{replacement}(){semicolon}",
+                        snippet_with_context(cx, recv.span, condition.span.ctxt(), "..", &mut app).0
+                    ),
+                    app,
+                );
+            });
         }
     }
 }
diff --git a/clippy_lints/src/attrs/allow_attributes.rs b/clippy_lints/src/attrs/allow_attributes.rs
index df9994086cd..a5a7b9f74a6 100644
--- a/clippy_lints/src/attrs/allow_attributes.rs
+++ b/clippy_lints/src/attrs/allow_attributes.rs
@@ -1,5 +1,5 @@
 use super::ALLOW_ATTRIBUTES;
-use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::is_from_proc_macro;
 use rustc_ast::{AttrStyle, Attribute};
 use rustc_errors::Applicability;
@@ -13,14 +13,14 @@ pub fn check<'cx>(cx: &LateContext<'cx>, attr: &'cx Attribute) {
         && let Some(ident) = attr.ident()
         && !is_from_proc_macro(cx, attr)
     {
-        span_lint_and_sugg(
-            cx,
-            ALLOW_ATTRIBUTES,
-            ident.span,
-            "#[allow] attribute found",
-            "replace it with",
-            "expect".into(),
-            Applicability::MachineApplicable,
-        );
+        #[expect(clippy::collapsible_span_lint_calls, reason = "rust-clippy#7797")]
+        span_lint_and_then(cx, ALLOW_ATTRIBUTES, ident.span, "#[allow] attribute found", |diag| {
+            diag.span_suggestion(
+                ident.span,
+                "replace it with",
+                "expect",
+                Applicability::MachineApplicable,
+            );
+        });
     }
 }
diff --git a/clippy_lints/src/attrs/allow_attributes_without_reason.rs b/clippy_lints/src/attrs/allow_attributes_without_reason.rs
index 4b42616a636..4ab97118df1 100644
--- a/clippy_lints/src/attrs/allow_attributes_without_reason.rs
+++ b/clippy_lints/src/attrs/allow_attributes_without_reason.rs
@@ -1,5 +1,5 @@
 use super::{Attribute, ALLOW_ATTRIBUTES_WITHOUT_REASON};
-use clippy_utils::diagnostics::span_lint_and_help;
+use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::is_from_proc_macro;
 use rustc_ast::{MetaItemKind, NestedMetaItem};
 use rustc_lint::{LateContext, LintContext};
@@ -21,12 +21,14 @@ pub(super) fn check<'cx>(cx: &LateContext<'cx>, name: Symbol, items: &[NestedMet
         return;
     }
 
-    span_lint_and_help(
+    #[expect(clippy::collapsible_span_lint_calls, reason = "rust-clippy#7797")]
+    span_lint_and_then(
         cx,
         ALLOW_ATTRIBUTES_WITHOUT_REASON,
         attr.span,
         format!("`{}` attribute without specifying a reason", name.as_str()),
-        None,
-        "try adding a reason at the end with `, reason = \"..\"`",
+        |diag| {
+            diag.help("try adding a reason at the end with `, reason = \"..\"`");
+        },
     );
 }
diff --git a/clippy_lints/src/casts/fn_to_numeric_cast_any.rs b/clippy_lints/src/casts/fn_to_numeric_cast_any.rs
index 826589bf303..75de53f73ee 100644
--- a/clippy_lints/src/casts/fn_to_numeric_cast_any.rs
+++ b/clippy_lints/src/casts/fn_to_numeric_cast_any.rs
@@ -1,6 +1,6 @@
-use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::source::snippet_with_applicability;
-use rustc_errors::Applicability;
+use rustc_errors::{Applicability, SuggestionStyle};
 use rustc_hir::Expr;
 use rustc_lint::LateContext;
 use rustc_middle::ty::{self, Ty};
@@ -14,21 +14,24 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, cast_expr: &Expr<'_>,
         _ => { /* continue to checks */ },
     }
 
-    match cast_from.kind() {
-        ty::FnDef(..) | ty::FnPtr(_) => {
-            let mut applicability = Applicability::MaybeIncorrect;
-            let from_snippet = snippet_with_applicability(cx, cast_expr.span, "..", &mut applicability);
+    if let ty::FnDef(..) | ty::FnPtr(_) = cast_from.kind() {
+        let mut applicability = Applicability::MaybeIncorrect;
+        let from_snippet = snippet_with_applicability(cx, cast_expr.span, "..", &mut applicability);
 
-            span_lint_and_sugg(
-                cx,
-                FN_TO_NUMERIC_CAST_ANY,
-                expr.span,
-                format!("casting function pointer `{from_snippet}` to `{cast_to}`"),
-                "did you mean to invoke the function?",
-                format!("{from_snippet}() as {cast_to}"),
-                applicability,
-            );
-        },
-        _ => {},
+        span_lint_and_then(
+            cx,
+            FN_TO_NUMERIC_CAST_ANY,
+            expr.span,
+            format!("casting function pointer `{from_snippet}` to `{cast_to}`"),
+            |diag| {
+                diag.span_suggestion_with_style(
+                    expr.span,
+                    "did you mean to invoke the function?",
+                    format!("{from_snippet}() as {cast_to}"),
+                    applicability,
+                    SuggestionStyle::ShowAlways,
+                );
+            },
+        );
     }
 }
diff --git a/clippy_lints/src/create_dir.rs b/clippy_lints/src/create_dir.rs
index 27c00948a8f..b49a977dbea 100644
--- a/clippy_lints/src/create_dir.rs
+++ b/clippy_lints/src/create_dir.rs
@@ -1,6 +1,6 @@
-use clippy_utils::diagnostics::span_lint_and_sugg;
-use clippy_utils::source::snippet;
-use rustc_errors::Applicability;
+use clippy_utils::diagnostics::span_lint_and_then;
+use clippy_utils::source::snippet_with_applicability;
+use rustc_errors::{Applicability, SuggestionStyle};
 use rustc_hir::{Expr, ExprKind};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_session::declare_lint_pass;
@@ -39,14 +39,24 @@ impl LateLintPass<'_> for CreateDir {
             && let Some(def_id) = cx.qpath_res(path, func.hir_id).opt_def_id()
             && cx.tcx.is_diagnostic_item(sym::fs_create_dir, def_id)
         {
-            span_lint_and_sugg(
+            span_lint_and_then(
                 cx,
                 CREATE_DIR,
                 expr.span,
                 "calling `std::fs::create_dir` where there may be a better way",
-                "consider calling `std::fs::create_dir_all` instead",
-                format!("create_dir_all({})", snippet(cx, arg.span, "..")),
-                Applicability::MaybeIncorrect,
+                |diag| {
+                    let mut app = Applicability::MaybeIncorrect;
+                    diag.span_suggestion_with_style(
+                        expr.span,
+                        "consider calling `std::fs::create_dir_all` instead",
+                        format!(
+                            "create_dir_all({})",
+                            snippet_with_applicability(cx, arg.span, "..", &mut app)
+                        ),
+                        app,
+                        SuggestionStyle::ShowAlways,
+                    );
+                },
             );
         }
     }
diff --git a/clippy_lints/src/dbg_macro.rs b/clippy_lints/src/dbg_macro.rs
index 788c6f3ada2..93c8fff05e9 100644
--- a/clippy_lints/src/dbg_macro.rs
+++ b/clippy_lints/src/dbg_macro.rs
@@ -1,5 +1,5 @@
 use clippy_config::Conf;
-use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::is_in_test;
 use clippy_utils::macros::{macro_backtrace, MacroCall};
 use clippy_utils::source::snippet_with_applicability;
@@ -65,61 +65,67 @@ impl LateLintPass<'_> for DbgMacro {
             // allows `dbg!` in test code if allow-dbg-in-test is set to true in clippy.toml
             !(self.allow_dbg_in_tests && is_in_test(cx.tcx, expr.hir_id))
         {
-            let mut applicability = Applicability::MachineApplicable;
-
-            let (sugg_span, suggestion) = match expr.peel_drop_temps().kind {
-                // dbg!()
-                ExprKind::Block(..) => {
-                    // If the `dbg!` macro is a "free" statement and not contained within other expressions,
-                    // remove the whole statement.
-                    if let Node::Stmt(_) = cx.tcx.parent_hir_node(expr.hir_id)
-                        && let Some(semi_span) = cx.sess().source_map().mac_call_stmt_semi_span(macro_call.span)
-                    {
-                        (macro_call.span.to(semi_span), String::new())
-                    } else {
-                        (macro_call.span, String::from("()"))
-                    }
-                },
-                // dbg!(1)
-                ExprKind::Match(val, ..) => (
-                    macro_call.span,
-                    snippet_with_applicability(cx, val.span.source_callsite(), "..", &mut applicability).to_string(),
-                ),
-                // dbg!(2, 3)
-                ExprKind::Tup(
-                    [
-                        Expr {
-                            kind: ExprKind::Match(first, ..),
-                            ..
-                        },
-                        ..,
-                        Expr {
-                            kind: ExprKind::Match(last, ..),
-                            ..
-                        },
-                    ],
-                ) => {
-                    let snippet = snippet_with_applicability(
-                        cx,
-                        first.span.source_callsite().to(last.span.source_callsite()),
-                        "..",
-                        &mut applicability,
-                    );
-                    (macro_call.span, format!("({snippet})"))
-                },
-                _ => return,
-            };
-
             self.prev_ctxt = cur_syntax_ctxt;
 
-            span_lint_and_sugg(
+            span_lint_and_then(
                 cx,
                 DBG_MACRO,
-                sugg_span,
+                macro_call.span,
                 "the `dbg!` macro is intended as a debugging tool",
-                "remove the invocation before committing it to a version control system",
-                suggestion,
-                applicability,
+                |diag| {
+                    let mut applicability = Applicability::MachineApplicable;
+
+                    let (sugg_span, suggestion) = match expr.peel_drop_temps().kind {
+                        // dbg!()
+                        ExprKind::Block(..) => {
+                            // If the `dbg!` macro is a "free" statement and not contained within other expressions,
+                            // remove the whole statement.
+                            if let Node::Stmt(_) = cx.tcx.parent_hir_node(expr.hir_id)
+                                && let Some(semi_span) = cx.sess().source_map().mac_call_stmt_semi_span(macro_call.span)
+                            {
+                                (macro_call.span.to(semi_span), String::new())
+                            } else {
+                                (macro_call.span, String::from("()"))
+                            }
+                        },
+                        // dbg!(1)
+                        ExprKind::Match(val, ..) => (
+                            macro_call.span,
+                            snippet_with_applicability(cx, val.span.source_callsite(), "..", &mut applicability)
+                                .to_string(),
+                        ),
+                        // dbg!(2, 3)
+                        ExprKind::Tup(
+                            [
+                                Expr {
+                                    kind: ExprKind::Match(first, ..),
+                                    ..
+                                },
+                                ..,
+                                Expr {
+                                    kind: ExprKind::Match(last, ..),
+                                    ..
+                                },
+                            ],
+                        ) => {
+                            let snippet = snippet_with_applicability(
+                                cx,
+                                first.span.source_callsite().to(last.span.source_callsite()),
+                                "..",
+                                &mut applicability,
+                            );
+                            (macro_call.span, format!("({snippet})"))
+                        },
+                        _ => unreachable!(),
+                    };
+
+                    diag.span_suggestion(
+                        sugg_span,
+                        "remove the invocation before committing it to a version control system",
+                        suggestion,
+                        applicability,
+                    );
+                },
             );
         }
     }
diff --git a/clippy_lints/src/default_numeric_fallback.rs b/clippy_lints/src/default_numeric_fallback.rs
index 9af73db6849..a74b3a8c836 100644
--- a/clippy_lints/src/default_numeric_fallback.rs
+++ b/clippy_lints/src/default_numeric_fallback.rs
@@ -92,20 +92,8 @@ impl<'a, 'tcx> NumericFallbackVisitor<'a, 'tcx> {
             let (suffix, is_float) = match lit_ty.kind() {
                 ty::Int(IntTy::I32) => ("i32", false),
                 ty::Float(FloatTy::F64) => ("f64", true),
-                // Default numeric fallback never results in other types.
                 _ => return,
             };
-
-            let src = if let Some(src) = snippet_opt(self.cx, lit.span) {
-                src
-            } else {
-                match lit.node {
-                    LitKind::Int(src, _) => format!("{src}"),
-                    LitKind::Float(src, _) => format!("{src}"),
-                    _ => return,
-                }
-            };
-            let sugg = numeric_literal::format(&src, Some(suffix), is_float);
             span_lint_hir_and_then(
                 self.cx,
                 DEFAULT_NUMERIC_FALLBACK,
@@ -113,6 +101,17 @@ impl<'a, 'tcx> NumericFallbackVisitor<'a, 'tcx> {
                 lit.span,
                 "default numeric fallback might occur",
                 |diag| {
+                    let src = if let Some(src) = snippet_opt(self.cx, lit.span) {
+                        src
+                    } else {
+                        match lit.node {
+                            LitKind::Int(src, _) => format!("{src}"),
+                            LitKind::Float(src, _) => format!("{src}"),
+                            _ => unreachable!("Default numeric fallback never results in other types"),
+                        }
+                    };
+
+                    let sugg = numeric_literal::format(&src, Some(suffix), is_float);
                     diag.span_suggestion(lit.span, "consider adding suffix", sugg, Applicability::MaybeIncorrect);
                 },
             );
diff --git a/clippy_lints/src/default_union_representation.rs b/clippy_lints/src/default_union_representation.rs
index 3fa9bad0d03..9f020d3081c 100644
--- a/clippy_lints/src/default_union_representation.rs
+++ b/clippy_lints/src/default_union_representation.rs
@@ -1,4 +1,4 @@
-use clippy_utils::diagnostics::span_lint_and_help;
+use clippy_utils::diagnostics::span_lint_and_then;
 use rustc_hir::{HirId, Item, ItemKind};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::ty::layout::LayoutOf;
@@ -56,16 +56,18 @@ impl<'tcx> LateLintPass<'tcx> for DefaultUnionRepresentation {
             && is_union_with_two_non_zst_fields(cx, item)
             && !has_c_repr_attr(cx, item.hir_id())
         {
-            span_lint_and_help(
+            #[expect(clippy::collapsible_span_lint_calls, reason = "rust-clippy#7797")]
+            span_lint_and_then(
                 cx,
                 DEFAULT_UNION_REPRESENTATION,
                 item.span,
                 "this union has the default representation",
-                None,
-                format!(
-                    "consider annotating `{}` with `#[repr(C)]` to explicitly specify memory layout",
-                    cx.tcx.def_path_str(item.owner_id)
-                ),
+                |diag| {
+                    diag.help(format!(
+                        "consider annotating `{}` with `#[repr(C)]` to explicitly specify memory layout",
+                        cx.tcx.def_path_str(item.owner_id)
+                    ));
+                },
             );
         }
     }
diff --git a/clippy_lints/src/else_if_without_else.rs b/clippy_lints/src/else_if_without_else.rs
index 7a6dc469727..02f9c2c3648 100644
--- a/clippy_lints/src/else_if_without_else.rs
+++ b/clippy_lints/src/else_if_without_else.rs
@@ -1,6 +1,6 @@
 //! Lint on if expressions with an else if, but without a final else branch.
 
-use clippy_utils::diagnostics::span_lint_and_help;
+use clippy_utils::diagnostics::span_lint_and_then;
 use rustc_ast::ast::{Expr, ExprKind};
 use rustc_lint::{EarlyContext, EarlyLintPass, LintContext};
 use rustc_middle::lint::in_external_macro;
@@ -54,13 +54,15 @@ impl EarlyLintPass for ElseIfWithoutElse {
             && let ExprKind::If(_, _, None) = els.kind
             && !in_external_macro(cx.sess(), item.span)
         {
-            span_lint_and_help(
+            #[expect(clippy::collapsible_span_lint_calls, reason = "rust-clippy#7797")]
+            span_lint_and_then(
                 cx,
                 ELSE_IF_WITHOUT_ELSE,
                 els.span,
                 "`if` expression with an `else if`, but without a final `else`",
-                None,
-                "add an `else` block here",
+                |diag| {
+                    diag.help("add an `else` block here");
+                },
             );
         }
     }
diff --git a/clippy_lints/src/empty_drop.rs b/clippy_lints/src/empty_drop.rs
index c5fc72b5e2d..b66dd2108fc 100644
--- a/clippy_lints/src/empty_drop.rs
+++ b/clippy_lints/src/empty_drop.rs
@@ -1,4 +1,4 @@
-use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::peel_blocks;
 use rustc_errors::Applicability;
 use rustc_hir::{Body, ExprKind, Impl, ImplItemKind, Item, ItemKind, Node};
@@ -50,15 +50,14 @@ impl LateLintPass<'_> for EmptyDrop {
             && block.stmts.is_empty()
             && block.expr.is_none()
         {
-            span_lint_and_sugg(
-                cx,
-                EMPTY_DROP,
-                item.span,
-                "empty drop implementation",
-                "try removing this impl",
-                String::new(),
-                Applicability::MaybeIncorrect,
-            );
+            span_lint_and_then(cx, EMPTY_DROP, item.span, "empty drop implementation", |diag| {
+                diag.span_suggestion_hidden(
+                    item.span,
+                    "try removing this impl",
+                    String::new(),
+                    Applicability::MaybeIncorrect,
+                );
+            });
         }
     }
 }
diff --git a/clippy_lints/src/endian_bytes.rs b/clippy_lints/src/endian_bytes.rs
index 5bba9c562b9..209104c5385 100644
--- a/clippy_lints/src/endian_bytes.rs
+++ b/clippy_lints/src/endian_bytes.rs
@@ -7,7 +7,6 @@ use rustc_middle::lint::in_external_macro;
 use rustc_middle::ty::Ty;
 use rustc_session::declare_lint_pass;
 use rustc_span::Symbol;
-use std::borrow::Cow;
 
 declare_clippy_lint! {
     /// ### What it does
@@ -141,52 +140,6 @@ fn maybe_lint_endian_bytes(cx: &LateContext<'_>, expr: &Expr<'_>, prefix: Prefix
         _ => return,
     };
 
-    let mut help = None;
-
-    'build_help: {
-        // all lints disallowed, don't give help here
-        if [&[lint], other_lints.as_slice()]
-            .concat()
-            .iter()
-            .all(|lint| !lint.allowed(cx, expr))
-        {
-            break 'build_help;
-        }
-
-        // ne_bytes and all other lints allowed
-        if lint.as_name(prefix) == ne && other_lints.iter().all(|lint| lint.allowed(cx, expr)) {
-            help = Some(Cow::Borrowed("specify the desired endianness explicitly"));
-            break 'build_help;
-        }
-
-        // le_bytes where ne_bytes allowed but be_bytes is not, or le_bytes where ne_bytes allowed but
-        // le_bytes is not
-        if (lint.as_name(prefix) == le || lint.as_name(prefix) == be) && LintKind::Host.allowed(cx, expr) {
-            help = Some(Cow::Borrowed("use the native endianness instead"));
-            break 'build_help;
-        }
-
-        let allowed_lints = other_lints.iter().filter(|lint| lint.allowed(cx, expr));
-        let len = allowed_lints.clone().count();
-
-        let mut help_str = "use ".to_owned();
-
-        for (i, lint) in allowed_lints.enumerate() {
-            let only_one = len == 1;
-            if !only_one {
-                help_str.push_str("either of ");
-            }
-
-            help_str.push_str(&format!("`{ty}::{}` ", lint.as_name(prefix)));
-
-            if i != len && !only_one {
-                help_str.push_str("or ");
-            }
-        }
-
-        help = Some(Cow::Owned(help_str + "instead"));
-    }
-
     span_lint_and_then(
         cx,
         lint.as_lint(),
@@ -198,9 +151,47 @@ fn maybe_lint_endian_bytes(cx: &LateContext<'_>, expr: &Expr<'_>, prefix: Prefix
             if prefix == Prefix::To { " method" } else { "" },
         ),
         move |diag| {
-            if let Some(help) = help {
-                diag.help(help);
+            // all lints disallowed, don't give help here
+            if [&[lint], other_lints.as_slice()]
+                .concat()
+                .iter()
+                .all(|lint| !lint.allowed(cx, expr))
+            {
+                return;
+            }
+
+            // ne_bytes and all other lints allowed
+            if lint.as_name(prefix) == ne && other_lints.iter().all(|lint| lint.allowed(cx, expr)) {
+                diag.help("specify the desired endianness explicitly");
+                return;
+            }
+
+            // le_bytes where ne_bytes allowed but be_bytes is not, or le_bytes where ne_bytes allowed but
+            // le_bytes is not
+            if (lint.as_name(prefix) == le || lint.as_name(prefix) == be) && LintKind::Host.allowed(cx, expr) {
+                diag.help("use the native endianness instead");
+                return;
+            }
+
+            let allowed_lints = other_lints.iter().filter(|lint| lint.allowed(cx, expr));
+            let len = allowed_lints.clone().count();
+
+            let mut help_str = "use ".to_owned();
+
+            for (i, lint) in allowed_lints.enumerate() {
+                let only_one = len == 1;
+                if !only_one {
+                    help_str.push_str("either of ");
+                }
+
+                help_str.push_str(&format!("`{ty}::{}` ", lint.as_name(prefix)));
+
+                if i != len && !only_one {
+                    help_str.push_str("or ");
+                }
             }
+            help_str.push_str("instead");
+            diag.help(help_str);
         },
     );
 }
diff --git a/clippy_lints/src/exhaustive_items.rs b/clippy_lints/src/exhaustive_items.rs
index 0f4176ec73b..9bf3baba4b5 100644
--- a/clippy_lints/src/exhaustive_items.rs
+++ b/clippy_lints/src/exhaustive_items.rs
@@ -88,11 +88,11 @@ impl LateLintPass<'_> for ExhaustiveItems {
             && !attrs.iter().any(|a| a.has_name(sym::non_exhaustive))
             && fields.iter().all(|f| cx.tcx.visibility(f.def_id).is_public())
         {
-            let suggestion_span = item.span.shrink_to_lo();
-            let indent = " ".repeat(indent_of(cx, item.span).unwrap_or(0));
             span_lint_and_then(cx, lint, item.span, msg, |diag| {
+                let suggestion_span = item.span.shrink_to_lo();
+                let indent = " ".repeat(indent_of(cx, item.span).unwrap_or(0));
                 let sugg = format!("#[non_exhaustive]\n{indent}");
-                diag.span_suggestion(
+                diag.span_suggestion_verbose(
                     suggestion_span,
                     "try adding #[non_exhaustive]",
                     sugg,
diff --git a/clippy_lints/src/field_scoped_visibility_modifiers.rs b/clippy_lints/src/field_scoped_visibility_modifiers.rs
index bb74e345703..95b8e882da7 100644
--- a/clippy_lints/src/field_scoped_visibility_modifiers.rs
+++ b/clippy_lints/src/field_scoped_visibility_modifiers.rs
@@ -1,4 +1,4 @@
-use clippy_utils::diagnostics::span_lint_and_help;
+use clippy_utils::diagnostics::span_lint_and_then;
 use rustc_ast::ast::{Item, ItemKind, VisibilityKind};
 use rustc_lint::{EarlyContext, EarlyLintPass};
 use rustc_session::declare_lint_pass;
@@ -62,13 +62,15 @@ impl EarlyLintPass for FieldScopedVisibilityModifiers {
                 // pub(self) is equivalent to not using pub at all, so we ignore it
                 continue;
             }
-            span_lint_and_help(
+            #[expect(clippy::collapsible_span_lint_calls, reason = "rust-clippy#7797")]
+            span_lint_and_then(
                 cx,
                 FIELD_SCOPED_VISIBILITY_MODIFIERS,
                 field.vis.span,
                 "scoped visibility modifier on a field",
-                None,
-                "consider making the field private and adding a scoped visibility method for it",
+                |diag| {
+                    diag.help("consider making the field private and adding a scoped visibility method for it");
+                },
             );
         }
     }
diff --git a/clippy_lints/src/format_push_string.rs b/clippy_lints/src/format_push_string.rs
index a75538dd329..d05c5a01f41 100644
--- a/clippy_lints/src/format_push_string.rs
+++ b/clippy_lints/src/format_push_string.rs
@@ -1,4 +1,4 @@
-use clippy_utils::diagnostics::span_lint_and_help;
+use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::ty::is_type_lang_item;
 use clippy_utils::{higher, match_def_path, paths};
 use rustc_hir::{BinOpKind, Expr, ExprKind, LangItem, MatchSource};
@@ -81,13 +81,15 @@ impl<'tcx> LateLintPass<'tcx> for FormatPushString {
             _ => return,
         };
         if is_format(cx, arg) {
-            span_lint_and_help(
+            #[expect(clippy::collapsible_span_lint_calls, reason = "rust-clippy#7797")]
+            span_lint_and_then(
                 cx,
                 FORMAT_PUSH_STRING,
                 expr.span,
                 "`format!(..)` appended to existing `String`",
-                None,
-                "consider using `write!` to avoid the extra allocation",
+                |diag| {
+                    diag.help("consider using `write!` to avoid the extra allocation");
+                },
             );
         }
     }
diff --git a/clippy_lints/src/if_then_some_else_none.rs b/clippy_lints/src/if_then_some_else_none.rs
index 39ea16b05d1..87fe7ecf9bf 100644
--- a/clippy_lints/src/if_then_some_else_none.rs
+++ b/clippy_lints/src/if_then_some_else_none.rs
@@ -1,6 +1,6 @@
 use clippy_config::msrvs::{self, Msrv};
 use clippy_config::Conf;
-use clippy_utils::diagnostics::span_lint_and_help;
+use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::eager_or_lazy::switch_to_eager_eval;
 use clippy_utils::source::snippet_with_context;
 use clippy_utils::sugg::Sugg;
@@ -81,32 +81,39 @@ impl<'tcx> LateLintPass<'tcx> for IfThenSomeElseNone {
             && self.msrv.meets(msrvs::BOOL_THEN)
             && !contains_return(then_block.stmts)
         {
-            let mut app = Applicability::Unspecified;
-            let cond_snip = Sugg::hir_with_context(cx, cond, expr.span.ctxt(), "[condition]", &mut app)
-                .maybe_par()
-                .to_string();
-            let arg_snip = snippet_with_context(cx, then_arg.span, ctxt, "[body]", &mut app).0;
-            let mut method_body = if then_block.stmts.is_empty() {
-                arg_snip.into_owned()
-            } else {
-                format!("{{ /* snippet */ {arg_snip} }}")
-            };
             let method_name = if switch_to_eager_eval(cx, expr) && self.msrv.meets(msrvs::BOOL_THEN_SOME) {
                 "then_some"
             } else {
-                method_body.insert_str(0, "|| ");
                 "then"
             };
 
-            let help =
-                format!("consider using `bool::{method_name}` like: `{cond_snip}.{method_name}({method_body})`",);
-            span_lint_and_help(
+            span_lint_and_then(
                 cx,
                 IF_THEN_SOME_ELSE_NONE,
                 expr.span,
                 format!("this could be simplified with `bool::{method_name}`"),
-                None,
-                help,
+                |diag| {
+                    let mut app = Applicability::Unspecified;
+                    let cond_snip = Sugg::hir_with_context(cx, cond, expr.span.ctxt(), "[condition]", &mut app)
+                        .maybe_par()
+                        .to_string();
+                    let arg_snip = snippet_with_context(cx, then_arg.span, ctxt, "[body]", &mut app).0;
+                    let method_body = if let Some(first_stmt) = then_block.stmts.first() {
+                        let (block_snippet, _) =
+                            snippet_with_context(cx, first_stmt.span.until(then_arg.span), ctxt, "..", &mut app);
+                        let closure = if method_name == "then" { "|| " } else { "" };
+                        format!("{closure} {{ {block_snippet}; {arg_snip} }}")
+                    } else {
+                        arg_snip.into_owned()
+                    };
+
+                    diag.span_suggestion(
+                        expr.span,
+                        "try",
+                        format!("{cond_snip}.{method_name}({method_body})"),
+                        app,
+                    );
+                },
             );
         }
     }
diff --git a/clippy_lints/src/implicit_return.rs b/clippy_lints/src/implicit_return.rs
index a102b434cfa..b926e1e62ba 100644
--- a/clippy_lints/src/implicit_return.rs
+++ b/clippy_lints/src/implicit_return.rs
@@ -3,7 +3,7 @@ use clippy_utils::source::{snippet_with_applicability, snippet_with_context, wal
 use clippy_utils::visitors::for_each_expr_without_closures;
 use clippy_utils::{get_async_fn_body, is_async_fn, is_from_proc_macro};
 use core::ops::ControlFlow;
-use rustc_errors::Applicability;
+use rustc_errors::{Applicability, SuggestionStyle};
 use rustc_hir::intravisit::FnKind;
 use rustc_hir::{Block, Body, Expr, ExprKind, FnDecl, FnRetTy, HirId};
 use rustc_lint::{LateContext, LateLintPass, LintContext};
@@ -45,8 +45,6 @@ declare_clippy_lint! {
 declare_lint_pass!(ImplicitReturn => [IMPLICIT_RETURN]);
 
 fn lint_return(cx: &LateContext<'_>, emission_place: HirId, span: Span) {
-    let mut app = Applicability::MachineApplicable;
-    let snip = snippet_with_applicability(cx, span, "..", &mut app);
     span_lint_hir_and_then(
         cx,
         IMPLICIT_RETURN,
@@ -54,14 +52,20 @@ fn lint_return(cx: &LateContext<'_>, emission_place: HirId, span: Span) {
         span,
         "missing `return` statement",
         |diag| {
-            diag.span_suggestion(span, "add `return` as shown", format!("return {snip}"), app);
+            let mut app = Applicability::MachineApplicable;
+            let snip = snippet_with_applicability(cx, span, "..", &mut app);
+            diag.span_suggestion_with_style(
+                span,
+                "add `return` as shown",
+                format!("return {snip}"),
+                app,
+                SuggestionStyle::ShowAlways,
+            );
         },
     );
 }
 
 fn lint_break(cx: &LateContext<'_>, emission_place: HirId, break_span: Span, expr_span: Span) {
-    let mut app = Applicability::MachineApplicable;
-    let snip = snippet_with_context(cx, expr_span, break_span.ctxt(), "..", &mut app).0;
     span_lint_hir_and_then(
         cx,
         IMPLICIT_RETURN,
@@ -69,11 +73,14 @@ fn lint_break(cx: &LateContext<'_>, emission_place: HirId, break_span: Span, exp
         break_span,
         "missing `return` statement",
         |diag| {
-            diag.span_suggestion(
+            let mut app = Applicability::MachineApplicable;
+            let snip = snippet_with_context(cx, expr_span, break_span.ctxt(), "..", &mut app).0;
+            diag.span_suggestion_with_style(
                 break_span,
                 "change `break` to `return` as shown",
                 format!("return {snip}"),
                 app,
+                SuggestionStyle::ShowAlways,
             );
         },
     );
diff --git a/clippy_lints/src/literal_representation.rs b/clippy_lints/src/literal_representation.rs
index b685d1dad1a..259e4d6c08f 100644
--- a/clippy_lints/src/literal_representation.rs
+++ b/clippy_lints/src/literal_representation.rs
@@ -2,13 +2,13 @@
 //! floating-point literal expressions.
 
 use clippy_config::Conf;
-use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::numeric_literal::{NumericLiteral, Radix};
 use clippy_utils::source::snippet_opt;
 use rustc_ast::ast::{Expr, ExprKind, LitKind};
 use rustc_ast::token;
 use rustc_errors::Applicability;
-use rustc_lint::{EarlyContext, EarlyLintPass, LintContext};
+use rustc_lint::{EarlyContext, EarlyLintPass, Lint, LintContext};
 use rustc_middle::lint::in_external_macro;
 use rustc_session::impl_lint_pass;
 use rustc_span::Span;
@@ -159,63 +159,39 @@ enum WarningType {
 }
 
 impl WarningType {
-    fn display(&self, suggested_format: String, cx: &EarlyContext<'_>, span: Span) {
+    fn lint_and_text(&self) -> (&'static Lint, &'static str, &'static str) {
         match self {
-            Self::MistypedLiteralSuffix => span_lint_and_sugg(
-                cx,
+            Self::MistypedLiteralSuffix => (
                 MISTYPED_LITERAL_SUFFIXES,
-                span,
                 "mistyped literal suffix",
                 "did you mean to write",
-                suggested_format,
-                Applicability::MaybeIncorrect,
             ),
-            Self::UnreadableLiteral => span_lint_and_sugg(
-                cx,
-                UNREADABLE_LITERAL,
-                span,
-                "long literal lacking separators",
-                "consider",
-                suggested_format,
-                Applicability::MachineApplicable,
-            ),
-            Self::LargeDigitGroups => span_lint_and_sugg(
-                cx,
-                LARGE_DIGIT_GROUPS,
-                span,
-                "digit groups should be smaller",
-                "consider",
-                suggested_format,
-                Applicability::MachineApplicable,
-            ),
-            Self::InconsistentDigitGrouping => span_lint_and_sugg(
-                cx,
+            Self::UnreadableLiteral => (UNREADABLE_LITERAL, "long literal lacking separators", "consider"),
+            Self::LargeDigitGroups => (LARGE_DIGIT_GROUPS, "digit groups should be smaller", "consider"),
+            Self::InconsistentDigitGrouping => (
                 INCONSISTENT_DIGIT_GROUPING,
-                span,
                 "digits grouped inconsistently by underscores",
                 "consider",
-                suggested_format,
-                Applicability::MachineApplicable,
             ),
-            Self::DecimalRepresentation => span_lint_and_sugg(
-                cx,
+            Self::DecimalRepresentation => (
                 DECIMAL_LITERAL_REPRESENTATION,
-                span,
                 "integer literal has a better hexadecimal representation",
                 "consider",
-                suggested_format,
-                Applicability::MachineApplicable,
             ),
-            Self::UnusualByteGroupings => span_lint_and_sugg(
-                cx,
+            Self::UnusualByteGroupings => (
                 UNUSUAL_BYTE_GROUPINGS,
-                span,
                 "digits of hex, binary or octal literal not in groups of equal size",
                 "consider",
-                suggested_format,
-                Applicability::MachineApplicable,
             ),
-        };
+        }
+    }
+
+    fn display(&self, num_lit: &NumericLiteral<'_>, cx: &EarlyContext<'_>, span: Span) {
+        let (lint, message, try_msg) = self.lint_and_text();
+        #[expect(clippy::collapsible_span_lint_calls, reason = "rust-clippy#7797")]
+        span_lint_and_then(cx, lint, span, message, |diag| {
+            diag.span_suggestion(span, try_msg, num_lit.format(), Applicability::MaybeIncorrect);
+        });
     }
 }
 
@@ -293,7 +269,7 @@ impl LiteralDigitGrouping {
                     WarningType::DecimalRepresentation | WarningType::MistypedLiteralSuffix => true,
                 };
                 if should_warn {
-                    warning_type.display(num_lit.format(), cx, span);
+                    warning_type.display(&num_lit, cx, span);
                 }
             }
         }
@@ -346,11 +322,14 @@ impl LiteralDigitGrouping {
                 }
             }
             *part = main_part;
-            let mut sugg = num_lit.format();
-            sugg.push('_');
-            sugg.push(missing_char);
-            sugg.push_str(last_group);
-            WarningType::MistypedLiteralSuffix.display(sugg, cx, span);
+            let (lint, message, try_msg) = WarningType::MistypedLiteralSuffix.lint_and_text();
+            span_lint_and_then(cx, lint, span, message, |diag| {
+                let mut sugg = num_lit.format();
+                sugg.push('_');
+                sugg.push(missing_char);
+                sugg.push_str(last_group);
+                diag.span_suggestion(span, try_msg, sugg, Applicability::MaybeIncorrect);
+            });
             false
         } else {
             true
@@ -471,7 +450,7 @@ impl DecimalLiteralRepresentation {
             let hex = format!("{val:#X}");
             let num_lit = NumericLiteral::new(&hex, num_lit.suffix, false);
             let _: Result<(), ()> = Self::do_lint(num_lit.integer).map_err(|warning_type| {
-                warning_type.display(num_lit.format(), cx, span);
+                warning_type.display(&num_lit, cx, span);
             });
         }
     }
diff --git a/clippy_lints/src/methods/clone_on_ref_ptr.rs b/clippy_lints/src/methods/clone_on_ref_ptr.rs
index 926bd06bacb..e0826b53004 100644
--- a/clippy_lints/src/methods/clone_on_ref_ptr.rs
+++ b/clippy_lints/src/methods/clone_on_ref_ptr.rs
@@ -1,4 +1,4 @@
-use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::source::snippet_with_context;
 use rustc_errors::Applicability;
 use rustc_hir as hir;
@@ -29,19 +29,22 @@ pub(super) fn check(
             sym::RcWeak | sym::ArcWeak => "Weak",
             _ => return,
         };
-
-        // Sometimes unnecessary ::<_> after Rc/Arc/Weak
-        let mut app = Applicability::Unspecified;
-        let snippet = snippet_with_context(cx, receiver.span, expr.span.ctxt(), "..", &mut app).0;
-
-        span_lint_and_sugg(
+        span_lint_and_then(
             cx,
             CLONE_ON_REF_PTR,
             expr.span,
             "using `.clone()` on a ref-counted pointer",
-            "try",
-            format!("{caller_type}::<{}>::clone(&{snippet})", subst.type_at(0)),
-            app,
+            |diag| {
+                // Sometimes unnecessary ::<_> after Rc/Arc/Weak
+                let mut app = Applicability::Unspecified;
+                let snippet = snippet_with_context(cx, receiver.span, expr.span.ctxt(), "..", &mut app).0;
+                diag.span_suggestion(
+                    expr.span,
+                    "try",
+                    format!("{caller_type}::<{}>::clone(&{snippet})", subst.type_at(0)),
+                    app,
+                );
+            },
         );
     }
 }
diff --git a/clippy_lints/src/methods/filetype_is_file.rs b/clippy_lints/src/methods/filetype_is_file.rs
index eab536b88a5..2ab0401947c 100644
--- a/clippy_lints/src/methods/filetype_is_file.rs
+++ b/clippy_lints/src/methods/filetype_is_file.rs
@@ -1,4 +1,4 @@
-use clippy_utils::diagnostics::span_lint_and_help;
+use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::get_parent_expr;
 use clippy_utils::ty::is_type_diagnostic_item;
 use rustc_hir as hir;
@@ -33,6 +33,9 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, recv: &hir::Expr
         span = expr.span;
     }
     let lint_msg = format!("`{lint_unary}FileType::is_file()` only {verb} regular files");
-    let help_msg = format!("use `{help_unary}FileType::is_dir()` instead");
-    span_lint_and_help(cx, FILETYPE_IS_FILE, span, lint_msg, None, help_msg);
+
+    #[expect(clippy::collapsible_span_lint_calls, reason = "rust-clippy#7797")]
+    span_lint_and_then(cx, FILETYPE_IS_FILE, span, lint_msg, |diag| {
+        diag.help(format!("use `{help_unary}FileType::is_dir()` instead"));
+    });
 }
diff --git a/clippy_lints/src/methods/get_unwrap.rs b/clippy_lints/src/methods/get_unwrap.rs
index 455274a4428..c6285c87a26 100644
--- a/clippy_lints/src/methods/get_unwrap.rs
+++ b/clippy_lints/src/methods/get_unwrap.rs
@@ -1,5 +1,5 @@
 use super::utils::derefs_to_slice;
-use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::get_parent_expr;
 use clippy_utils::source::snippet_with_applicability;
 use clippy_utils::ty::is_type_diagnostic_item;
@@ -19,9 +19,7 @@ pub(super) fn check<'tcx>(
 ) {
     // Note: we don't want to lint `get_mut().unwrap` for `HashMap` or `BTreeMap`,
     // because they do not implement `IndexMut`
-    let mut applicability = Applicability::MachineApplicable;
     let expr_ty = cx.typeck_results().expr_ty(recv);
-    let get_args_str = snippet_with_applicability(cx, get_arg.span, "..", &mut applicability);
     let caller_type = if derefs_to_slice(cx, recv, expr_ty).is_some() {
         "slice"
     } else if is_type_diagnostic_item(cx, expr_ty, sym::Vec) {
@@ -58,24 +56,34 @@ pub(super) fn check<'tcx>(
     };
 
     let mut_str = if is_mut { "_mut" } else { "" };
-    let borrow_str = if !needs_ref {
-        ""
-    } else if is_mut {
-        "&mut "
-    } else {
-        "&"
-    };
 
-    span_lint_and_sugg(
+    span_lint_and_then(
         cx,
         GET_UNWRAP,
         span,
-        format!("called `.get{mut_str}().unwrap()` on a {caller_type}. Using `[]` is more clear and more concise"),
-        "try",
-        format!(
-            "{borrow_str}{}[{get_args_str}]",
-            snippet_with_applicability(cx, recv.span, "..", &mut applicability)
-        ),
-        applicability,
+        format!("called `.get{mut_str}().unwrap()` on a {caller_type}"),
+        |diag| {
+            let mut applicability = Applicability::MachineApplicable;
+            let get_args_str = snippet_with_applicability(cx, get_arg.span, "..", &mut applicability);
+
+            let borrow_str = if !needs_ref {
+                ""
+            } else if is_mut {
+                "&mut "
+            } else {
+                "&"
+            };
+
+            diag.span_suggestion_with_style(
+                span,
+                "using `[]` is clearer and more concise",
+                format!(
+                    "{borrow_str}{}[{get_args_str}]",
+                    snippet_with_applicability(cx, recv.span, "..", &mut applicability)
+                ),
+                applicability,
+                rustc_errors::SuggestionStyle::ShowAlways,
+            );
+        },
     );
 }
diff --git a/clippy_lints/src/redundant_slicing.rs b/clippy_lints/src/redundant_slicing.rs
index c77f3938b4a..1c10e84d3ca 100644
--- a/clippy_lints/src/redundant_slicing.rs
+++ b/clippy_lints/src/redundant_slicing.rs
@@ -1,4 +1,4 @@
-use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::source::snippet_with_context;
 use clippy_utils::ty::is_type_lang_item;
 use clippy_utils::{get_parent_expr, peel_middle_ty_refs};
@@ -86,9 +86,8 @@ impl<'tcx> LateLintPass<'tcx> for RedundantSlicing {
             let (indexed_ty, indexed_ref_count) = peel_middle_ty_refs(cx.typeck_results().expr_ty(indexed));
             let parent_expr = get_parent_expr(cx, expr);
             let needs_parens_for_prefix = parent_expr.map_or(false, |parent| parent.precedence().order() > PREC_PREFIX);
-            let mut app = Applicability::MachineApplicable;
 
-            let ((lint, msg), help, sugg) = if expr_ty == indexed_ty {
+            if expr_ty == indexed_ty {
                 if expr_ref_count > indexed_ref_count {
                     // Indexing takes self by reference and can't return a reference to that
                     // reference as it's a local variable. The only way this could happen is if
@@ -99,7 +98,7 @@ impl<'tcx> LateLintPass<'tcx> for RedundantSlicing {
                 }
                 let deref_count = indexed_ref_count - expr_ref_count;
 
-                let (lint, reborrow_str, help_str) = if mutability == Mutability::Mut {
+                let ((lint, msg), reborrow_str, help_msg) = if mutability == Mutability::Mut {
                     // The slice was used to reborrow the mutable reference.
                     (DEREF_BY_SLICING_LINT, "&mut *", "reborrow the original value instead")
                 } else if matches!(
@@ -125,38 +124,36 @@ impl<'tcx> LateLintPass<'tcx> for RedundantSlicing {
                     (REDUNDANT_SLICING_LINT, "", "use the original value instead")
                 };
 
-                let snip = snippet_with_context(cx, indexed.span, ctxt, "..", &mut app).0;
-                let sugg = if (deref_count != 0 || !reborrow_str.is_empty()) && needs_parens_for_prefix {
-                    format!("({reborrow_str}{}{snip})", "*".repeat(deref_count))
-                } else {
-                    format!("{reborrow_str}{}{snip}", "*".repeat(deref_count))
-                };
-
-                (lint, help_str, sugg)
+                span_lint_and_then(cx, lint, expr.span, msg, |diag| {
+                    let mut app = Applicability::MachineApplicable;
+                    let snip = snippet_with_context(cx, indexed.span, ctxt, "..", &mut app).0;
+                    let sugg = if (deref_count != 0 || !reborrow_str.is_empty()) && needs_parens_for_prefix {
+                        format!("({reborrow_str}{}{snip})", "*".repeat(deref_count))
+                    } else {
+                        format!("{reborrow_str}{}{snip}", "*".repeat(deref_count))
+                    };
+                    diag.span_suggestion(expr.span, help_msg, sugg, app);
+                });
             } else if let Some(target_id) = cx.tcx.lang_items().deref_target() {
                 if let Ok(deref_ty) = cx.tcx.try_normalize_erasing_regions(
                     cx.param_env,
                     Ty::new_projection_from_args(cx.tcx, target_id, cx.tcx.mk_args(&[GenericArg::from(indexed_ty)])),
                 ) {
                     if deref_ty == expr_ty {
-                        let snip = snippet_with_context(cx, indexed.span, ctxt, "..", &mut app).0;
-                        let sugg = if needs_parens_for_prefix {
-                            format!("(&{}{}*{snip})", mutability.prefix_str(), "*".repeat(indexed_ref_count))
-                        } else {
-                            format!("&{}{}*{snip}", mutability.prefix_str(), "*".repeat(indexed_ref_count))
-                        };
-                        (DEREF_BY_SLICING_LINT, "dereference the original value instead", sugg)
-                    } else {
-                        return;
+                        let (lint, msg) = DEREF_BY_SLICING_LINT;
+                        span_lint_and_then(cx, lint, expr.span, msg, |diag| {
+                            let mut app = Applicability::MachineApplicable;
+                            let snip = snippet_with_context(cx, indexed.span, ctxt, "..", &mut app).0;
+                            let sugg = if needs_parens_for_prefix {
+                                format!("(&{}{}*{snip})", mutability.prefix_str(), "*".repeat(indexed_ref_count))
+                            } else {
+                                format!("&{}{}*{snip}", mutability.prefix_str(), "*".repeat(indexed_ref_count))
+                            };
+                            diag.span_suggestion(expr.span, "dereference the original value instead", sugg, app);
+                        });
                     }
-                } else {
-                    return;
                 }
-            } else {
-                return;
-            };
-
-            span_lint_and_sugg(cx, lint, expr.span, msg, help, sugg, app);
+            }
         }
     }
 }
diff --git a/clippy_lints/src/std_instead_of_core.rs b/clippy_lints/src/std_instead_of_core.rs
index 84bf4e87672..974e21df817 100644
--- a/clippy_lints/src/std_instead_of_core.rs
+++ b/clippy_lints/src/std_instead_of_core.rs
@@ -1,6 +1,6 @@
 use clippy_config::msrvs::Msrv;
 use clippy_config::Conf;
-use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::is_from_proc_macro;
 use rustc_attr::{StabilityLevel, StableSince};
 use rustc_errors::Applicability;
@@ -136,14 +136,20 @@ impl<'tcx> LateLintPass<'tcx> for StdReexports {
                 _ => return,
             };
             if first_segment.ident.span != self.prev_span {
-                span_lint_and_sugg(
+                #[expect(clippy::collapsible_span_lint_calls, reason = "rust-clippy#7797")]
+                span_lint_and_then(
                     cx,
                     lint,
                     first_segment.ident.span,
                     format!("used import from `{used_mod}` instead of `{replace_with}`"),
-                    format!("consider importing the item from `{replace_with}`"),
-                    replace_with.to_string(),
-                    Applicability::MachineApplicable,
+                    |diag| {
+                        diag.span_suggestion(
+                            first_segment.ident.span,
+                            format!("consider importing the item from `{replace_with}`"),
+                            replace_with.to_string(),
+                            Applicability::MachineApplicable,
+                        );
+                    },
                 );
                 self.prev_span = first_segment.ident.span;
             }
diff --git a/tests/ui-toml/unwrap_used/unwrap_used.stderr b/tests/ui-toml/unwrap_used/unwrap_used.stderr
index 41d5afd3efe..320578bfabc 100644
--- a/tests/ui-toml/unwrap_used/unwrap_used.stderr
+++ b/tests/ui-toml/unwrap_used/unwrap_used.stderr
@@ -1,11 +1,15 @@
-error: called `.get().unwrap()` on a slice. Using `[]` is more clear and more concise
+error: called `.get().unwrap()` on a slice
   --> tests/ui-toml/unwrap_used/unwrap_used.rs:38:17
    |
 LL |         let _ = boxed_slice.get(1).unwrap();
-   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&boxed_slice[1]`
+   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = note: `-D clippy::get-unwrap` implied by `-D warnings`
    = help: to override `-D warnings` add `#[allow(clippy::get_unwrap)]`
+help: using `[]` is clearer and more concise
+   |
+LL |         let _ = &boxed_slice[1];
+   |                 ~~~~~~~~~~~~~~~
 
 error: used `unwrap()` on an `Option` value
   --> tests/ui-toml/unwrap_used/unwrap_used.rs:38:17
@@ -18,11 +22,16 @@ LL |         let _ = boxed_slice.get(1).unwrap();
    = note: `-D clippy::unwrap-used` implied by `-D warnings`
    = help: to override `-D warnings` add `#[allow(clippy::unwrap_used)]`
 
-error: called `.get().unwrap()` on a slice. Using `[]` is more clear and more concise
+error: called `.get().unwrap()` on a slice
   --> tests/ui-toml/unwrap_used/unwrap_used.rs:39:17
    |
 LL |         let _ = some_slice.get(0).unwrap();
-   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&some_slice[0]`
+   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: using `[]` is clearer and more concise
+   |
+LL |         let _ = &some_slice[0];
+   |                 ~~~~~~~~~~~~~~
 
 error: used `unwrap()` on an `Option` value
   --> tests/ui-toml/unwrap_used/unwrap_used.rs:39:17
@@ -33,11 +42,16 @@ LL |         let _ = some_slice.get(0).unwrap();
    = note: if this value is `None`, it will panic
    = help: consider using `expect()` to provide a better panic message
 
-error: called `.get().unwrap()` on a Vec. Using `[]` is more clear and more concise
+error: called `.get().unwrap()` on a Vec
   --> tests/ui-toml/unwrap_used/unwrap_used.rs:40:17
    |
 LL |         let _ = some_vec.get(0).unwrap();
-   |                 ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&some_vec[0]`
+   |                 ^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: using `[]` is clearer and more concise
+   |
+LL |         let _ = &some_vec[0];
+   |                 ~~~~~~~~~~~~
 
 error: used `unwrap()` on an `Option` value
   --> tests/ui-toml/unwrap_used/unwrap_used.rs:40:17
@@ -48,11 +62,16 @@ LL |         let _ = some_vec.get(0).unwrap();
    = note: if this value is `None`, it will panic
    = help: consider using `expect()` to provide a better panic message
 
-error: called `.get().unwrap()` on a VecDeque. Using `[]` is more clear and more concise
+error: called `.get().unwrap()` on a VecDeque
   --> tests/ui-toml/unwrap_used/unwrap_used.rs:41:17
    |
 LL |         let _ = some_vecdeque.get(0).unwrap();
-   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&some_vecdeque[0]`
+   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: using `[]` is clearer and more concise
+   |
+LL |         let _ = &some_vecdeque[0];
+   |                 ~~~~~~~~~~~~~~~~~
 
 error: used `unwrap()` on an `Option` value
   --> tests/ui-toml/unwrap_used/unwrap_used.rs:41:17
@@ -63,11 +82,16 @@ LL |         let _ = some_vecdeque.get(0).unwrap();
    = note: if this value is `None`, it will panic
    = help: consider using `expect()` to provide a better panic message
 
-error: called `.get().unwrap()` on a HashMap. Using `[]` is more clear and more concise
+error: called `.get().unwrap()` on a HashMap
   --> tests/ui-toml/unwrap_used/unwrap_used.rs:42:17
    |
 LL |         let _ = some_hashmap.get(&1).unwrap();
-   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&some_hashmap[&1]`
+   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: using `[]` is clearer and more concise
+   |
+LL |         let _ = &some_hashmap[&1];
+   |                 ~~~~~~~~~~~~~~~~~
 
 error: used `unwrap()` on an `Option` value
   --> tests/ui-toml/unwrap_used/unwrap_used.rs:42:17
@@ -78,11 +102,16 @@ LL |         let _ = some_hashmap.get(&1).unwrap();
    = note: if this value is `None`, it will panic
    = help: consider using `expect()` to provide a better panic message
 
-error: called `.get().unwrap()` on a BTreeMap. Using `[]` is more clear and more concise
+error: called `.get().unwrap()` on a BTreeMap
   --> tests/ui-toml/unwrap_used/unwrap_used.rs:43:17
    |
 LL |         let _ = some_btreemap.get(&1).unwrap();
-   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&some_btreemap[&1]`
+   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: using `[]` is clearer and more concise
+   |
+LL |         let _ = &some_btreemap[&1];
+   |                 ~~~~~~~~~~~~~~~~~~
 
 error: used `unwrap()` on an `Option` value
   --> tests/ui-toml/unwrap_used/unwrap_used.rs:43:17
@@ -93,11 +122,16 @@ LL |         let _ = some_btreemap.get(&1).unwrap();
    = note: if this value is `None`, it will panic
    = help: consider using `expect()` to provide a better panic message
 
-error: called `.get().unwrap()` on a slice. Using `[]` is more clear and more concise
+error: called `.get().unwrap()` on a slice
   --> tests/ui-toml/unwrap_used/unwrap_used.rs:47:21
    |
 LL |         let _: u8 = *boxed_slice.get(1).unwrap();
-   |                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `boxed_slice[1]`
+   |                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: using `[]` is clearer and more concise
+   |
+LL |         let _: u8 = boxed_slice[1];
+   |                     ~~~~~~~~~~~~~~
 
 error: used `unwrap()` on an `Option` value
   --> tests/ui-toml/unwrap_used/unwrap_used.rs:47:22
@@ -108,11 +142,16 @@ LL |         let _: u8 = *boxed_slice.get(1).unwrap();
    = note: if this value is `None`, it will panic
    = help: consider using `expect()` to provide a better panic message
 
-error: called `.get_mut().unwrap()` on a slice. Using `[]` is more clear and more concise
+error: called `.get_mut().unwrap()` on a slice
   --> tests/ui-toml/unwrap_used/unwrap_used.rs:52:9
    |
 LL |         *boxed_slice.get_mut(0).unwrap() = 1;
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `boxed_slice[0]`
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: using `[]` is clearer and more concise
+   |
+LL |         boxed_slice[0] = 1;
+   |         ~~~~~~~~~~~~~~
 
 error: used `unwrap()` on an `Option` value
   --> tests/ui-toml/unwrap_used/unwrap_used.rs:52:10
@@ -123,11 +162,16 @@ LL |         *boxed_slice.get_mut(0).unwrap() = 1;
    = note: if this value is `None`, it will panic
    = help: consider using `expect()` to provide a better panic message
 
-error: called `.get_mut().unwrap()` on a slice. Using `[]` is more clear and more concise
+error: called `.get_mut().unwrap()` on a slice
   --> tests/ui-toml/unwrap_used/unwrap_used.rs:53:9
    |
 LL |         *some_slice.get_mut(0).unwrap() = 1;
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `some_slice[0]`
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: using `[]` is clearer and more concise
+   |
+LL |         some_slice[0] = 1;
+   |         ~~~~~~~~~~~~~
 
 error: used `unwrap()` on an `Option` value
   --> tests/ui-toml/unwrap_used/unwrap_used.rs:53:10
@@ -138,11 +182,16 @@ LL |         *some_slice.get_mut(0).unwrap() = 1;
    = note: if this value is `None`, it will panic
    = help: consider using `expect()` to provide a better panic message
 
-error: called `.get_mut().unwrap()` on a Vec. Using `[]` is more clear and more concise
+error: called `.get_mut().unwrap()` on a Vec
   --> tests/ui-toml/unwrap_used/unwrap_used.rs:54:9
    |
 LL |         *some_vec.get_mut(0).unwrap() = 1;
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `some_vec[0]`
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: using `[]` is clearer and more concise
+   |
+LL |         some_vec[0] = 1;
+   |         ~~~~~~~~~~~
 
 error: used `unwrap()` on an `Option` value
   --> tests/ui-toml/unwrap_used/unwrap_used.rs:54:10
@@ -153,11 +202,16 @@ LL |         *some_vec.get_mut(0).unwrap() = 1;
    = note: if this value is `None`, it will panic
    = help: consider using `expect()` to provide a better panic message
 
-error: called `.get_mut().unwrap()` on a VecDeque. Using `[]` is more clear and more concise
+error: called `.get_mut().unwrap()` on a VecDeque
   --> tests/ui-toml/unwrap_used/unwrap_used.rs:55:9
    |
 LL |         *some_vecdeque.get_mut(0).unwrap() = 1;
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `some_vecdeque[0]`
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: using `[]` is clearer and more concise
+   |
+LL |         some_vecdeque[0] = 1;
+   |         ~~~~~~~~~~~~~~~~
 
 error: used `unwrap()` on an `Option` value
   --> tests/ui-toml/unwrap_used/unwrap_used.rs:55:10
@@ -168,11 +222,16 @@ LL |         *some_vecdeque.get_mut(0).unwrap() = 1;
    = note: if this value is `None`, it will panic
    = help: consider using `expect()` to provide a better panic message
 
-error: called `.get().unwrap()` on a Vec. Using `[]` is more clear and more concise
+error: called `.get().unwrap()` on a Vec
   --> tests/ui-toml/unwrap_used/unwrap_used.rs:67:17
    |
 LL |         let _ = some_vec.get(0..1).unwrap().to_vec();
-   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `some_vec[0..1]`
+   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: using `[]` is clearer and more concise
+   |
+LL |         let _ = some_vec[0..1].to_vec();
+   |                 ~~~~~~~~~~~~~~
 
 error: used `unwrap()` on an `Option` value
   --> tests/ui-toml/unwrap_used/unwrap_used.rs:67:17
@@ -183,11 +242,16 @@ LL |         let _ = some_vec.get(0..1).unwrap().to_vec();
    = note: if this value is `None`, it will panic
    = help: consider using `expect()` to provide a better panic message
 
-error: called `.get_mut().unwrap()` on a Vec. Using `[]` is more clear and more concise
+error: called `.get_mut().unwrap()` on a Vec
   --> tests/ui-toml/unwrap_used/unwrap_used.rs:68:17
    |
 LL |         let _ = some_vec.get_mut(0..1).unwrap().to_vec();
-   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `some_vec[0..1]`
+   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: using `[]` is clearer and more concise
+   |
+LL |         let _ = some_vec[0..1].to_vec();
+   |                 ~~~~~~~~~~~~~~
 
 error: used `unwrap()` on an `Option` value
   --> tests/ui-toml/unwrap_used/unwrap_used.rs:68:17
@@ -198,17 +262,27 @@ LL |         let _ = some_vec.get_mut(0..1).unwrap().to_vec();
    = note: if this value is `None`, it will panic
    = help: consider using `expect()` to provide a better panic message
 
-error: called `.get().unwrap()` on a slice. Using `[]` is more clear and more concise
+error: called `.get().unwrap()` on a slice
   --> tests/ui-toml/unwrap_used/unwrap_used.rs:75:13
    |
 LL |     let _ = boxed_slice.get(1).unwrap();
-   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&boxed_slice[1]`
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: using `[]` is clearer and more concise
+   |
+LL |     let _ = &boxed_slice[1];
+   |             ~~~~~~~~~~~~~~~
 
-error: called `.get().unwrap()` on a slice. Using `[]` is more clear and more concise
+error: called `.get().unwrap()` on a slice
   --> tests/ui-toml/unwrap_used/unwrap_used.rs:93:17
    |
 LL |         let _ = Box::new([0]).get(1).unwrap();
-   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&Box::new([0])[1]`
+   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: using `[]` is clearer and more concise
+   |
+LL |         let _ = &Box::new([0])[1];
+   |                 ~~~~~~~~~~~~~~~~~
 
 error: aborting due to 28 previous errors
 
diff --git a/tests/ui/create_dir.stderr b/tests/ui/create_dir.stderr
index 9c6e640ca78..ab51705bb55 100644
--- a/tests/ui/create_dir.stderr
+++ b/tests/ui/create_dir.stderr
@@ -2,16 +2,25 @@ error: calling `std::fs::create_dir` where there may be a better way
   --> tests/ui/create_dir.rs:10:5
    |
 LL |     std::fs::create_dir("foo");
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling `std::fs::create_dir_all` instead: `create_dir_all("foo")`
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = note: `-D clippy::create-dir` implied by `-D warnings`
    = help: to override `-D warnings` add `#[allow(clippy::create_dir)]`
+help: consider calling `std::fs::create_dir_all` instead
+   |
+LL |     create_dir_all("foo");
+   |     ~~~~~~~~~~~~~~~~~~~~~
 
 error: calling `std::fs::create_dir` where there may be a better way
   --> tests/ui/create_dir.rs:11:5
    |
 LL |     std::fs::create_dir("bar").unwrap();
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling `std::fs::create_dir_all` instead: `create_dir_all("bar")`
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: consider calling `std::fs::create_dir_all` instead
+   |
+LL |     create_dir_all("bar").unwrap();
+   |     ~~~~~~~~~~~~~~~~~~~~~
 
 error: aborting due to 2 previous errors
 
diff --git a/tests/ui/dbg_macro/dbg_macro.stderr b/tests/ui/dbg_macro/dbg_macro.stderr
index 7d3c3f7c918..b3d74b9ff61 100644
--- a/tests/ui/dbg_macro/dbg_macro.stderr
+++ b/tests/ui/dbg_macro/dbg_macro.stderr
@@ -81,7 +81,7 @@ error: the `dbg!` macro is intended as a debugging tool
   --> tests/ui/dbg_macro/dbg_macro.rs:48:5
    |
 LL |     dbg!();
-   |     ^^^^^^^
+   |     ^^^^^^
    |
 help: remove the invocation before committing it to a version control system
    |
@@ -136,7 +136,7 @@ error: the `dbg!` macro is intended as a debugging tool
   --> tests/ui/dbg_macro/dbg_macro.rs:43:13
    |
 LL |             dbg!();
-   |             ^^^^^^^
+   |             ^^^^^^
 ...
 LL |     expand_to_dbg!();
    |     ---------------- in this macro invocation
diff --git a/tests/ui/dbg_macro/dbg_macro_unfixable.stderr b/tests/ui/dbg_macro/dbg_macro_unfixable.stderr
index 16e51f4742e..b8e91906b93 100644
--- a/tests/ui/dbg_macro/dbg_macro_unfixable.stderr
+++ b/tests/ui/dbg_macro/dbg_macro_unfixable.stderr
@@ -2,7 +2,7 @@ error: the `dbg!` macro is intended as a debugging tool
   --> tests/ui/dbg_macro/auxiliary/submodule.rs:2:5
    |
 LL |     dbg!();
-   |     ^^^^^^^
+   |     ^^^^^^
    |
    = note: `-D clippy::dbg-macro` implied by `-D warnings`
    = help: to override `-D warnings` add `#[allow(clippy::dbg_macro)]`
diff --git a/tests/ui/empty_drop.stderr b/tests/ui/empty_drop.stderr
index 4223ddaf3fb..d4d020fec30 100644
--- a/tests/ui/empty_drop.stderr
+++ b/tests/ui/empty_drop.stderr
@@ -4,10 +4,11 @@ error: empty drop implementation
 LL | / impl Drop for Foo {
 LL | |     fn drop(&mut self) {}
 LL | | }
-   | |_^ help: try removing this impl
+   | |_^
    |
    = note: `-D clippy::empty-drop` implied by `-D warnings`
    = help: to override `-D warnings` add `#[allow(clippy::empty_drop)]`
+   = help: try removing this impl
 
 error: empty drop implementation
   --> tests/ui/empty_drop.rs:23:1
@@ -17,7 +18,9 @@ LL | |     fn drop(&mut self) {
 LL | |         {}
 LL | |     }
 LL | | }
-   | |_^ help: try removing this impl
+   | |_^
+   |
+   = help: try removing this impl
 
 error: aborting due to 2 previous errors
 
diff --git a/tests/ui/fn_to_numeric_cast_any.stderr b/tests/ui/fn_to_numeric_cast_any.stderr
index e5bb8d13269..a05b7138bc9 100644
--- a/tests/ui/fn_to_numeric_cast_any.stderr
+++ b/tests/ui/fn_to_numeric_cast_any.stderr
@@ -2,106 +2,190 @@ error: casting function pointer `foo` to `i8`
   --> tests/ui/fn_to_numeric_cast_any.rs:23:13
    |
 LL |     let _ = foo as i8;
-   |             ^^^^^^^^^ help: did you mean to invoke the function?: `foo() as i8`
+   |             ^^^^^^^^^
    |
    = note: `-D clippy::fn-to-numeric-cast-any` implied by `-D warnings`
    = help: to override `-D warnings` add `#[allow(clippy::fn_to_numeric_cast_any)]`
+help: did you mean to invoke the function?
+   |
+LL |     let _ = foo() as i8;
+   |             ~~~~~~~~~~~
 
 error: casting function pointer `foo` to `i16`
   --> tests/ui/fn_to_numeric_cast_any.rs:26:13
    |
 LL |     let _ = foo as i16;
-   |             ^^^^^^^^^^ help: did you mean to invoke the function?: `foo() as i16`
+   |             ^^^^^^^^^^
+   |
+help: did you mean to invoke the function?
+   |
+LL |     let _ = foo() as i16;
+   |             ~~~~~~~~~~~~
 
 error: casting function pointer `foo` to `i32`
   --> tests/ui/fn_to_numeric_cast_any.rs:28:13
    |
 LL |     let _ = foo as i32;
-   |             ^^^^^^^^^^ help: did you mean to invoke the function?: `foo() as i32`
+   |             ^^^^^^^^^^
+   |
+help: did you mean to invoke the function?
+   |
+LL |     let _ = foo() as i32;
+   |             ~~~~~~~~~~~~
 
 error: casting function pointer `foo` to `i64`
   --> tests/ui/fn_to_numeric_cast_any.rs:30:13
    |
 LL |     let _ = foo as i64;
-   |             ^^^^^^^^^^ help: did you mean to invoke the function?: `foo() as i64`
+   |             ^^^^^^^^^^
+   |
+help: did you mean to invoke the function?
+   |
+LL |     let _ = foo() as i64;
+   |             ~~~~~~~~~~~~
 
 error: casting function pointer `foo` to `i128`
   --> tests/ui/fn_to_numeric_cast_any.rs:32:13
    |
 LL |     let _ = foo as i128;
-   |             ^^^^^^^^^^^ help: did you mean to invoke the function?: `foo() as i128`
+   |             ^^^^^^^^^^^
+   |
+help: did you mean to invoke the function?
+   |
+LL |     let _ = foo() as i128;
+   |             ~~~~~~~~~~~~~
 
 error: casting function pointer `foo` to `isize`
   --> tests/ui/fn_to_numeric_cast_any.rs:34:13
    |
 LL |     let _ = foo as isize;
-   |             ^^^^^^^^^^^^ help: did you mean to invoke the function?: `foo() as isize`
+   |             ^^^^^^^^^^^^
+   |
+help: did you mean to invoke the function?
+   |
+LL |     let _ = foo() as isize;
+   |             ~~~~~~~~~~~~~~
 
 error: casting function pointer `foo` to `u8`
   --> tests/ui/fn_to_numeric_cast_any.rs:37:13
    |
 LL |     let _ = foo as u8;
-   |             ^^^^^^^^^ help: did you mean to invoke the function?: `foo() as u8`
+   |             ^^^^^^^^^
+   |
+help: did you mean to invoke the function?
+   |
+LL |     let _ = foo() as u8;
+   |             ~~~~~~~~~~~
 
 error: casting function pointer `foo` to `u16`
   --> tests/ui/fn_to_numeric_cast_any.rs:39:13
    |
 LL |     let _ = foo as u16;
-   |             ^^^^^^^^^^ help: did you mean to invoke the function?: `foo() as u16`
+   |             ^^^^^^^^^^
+   |
+help: did you mean to invoke the function?
+   |
+LL |     let _ = foo() as u16;
+   |             ~~~~~~~~~~~~
 
 error: casting function pointer `foo` to `u32`
   --> tests/ui/fn_to_numeric_cast_any.rs:41:13
    |
 LL |     let _ = foo as u32;
-   |             ^^^^^^^^^^ help: did you mean to invoke the function?: `foo() as u32`
+   |             ^^^^^^^^^^
+   |
+help: did you mean to invoke the function?
+   |
+LL |     let _ = foo() as u32;
+   |             ~~~~~~~~~~~~
 
 error: casting function pointer `foo` to `u64`
   --> tests/ui/fn_to_numeric_cast_any.rs:43:13
    |
 LL |     let _ = foo as u64;
-   |             ^^^^^^^^^^ help: did you mean to invoke the function?: `foo() as u64`
+   |             ^^^^^^^^^^
+   |
+help: did you mean to invoke the function?
+   |
+LL |     let _ = foo() as u64;
+   |             ~~~~~~~~~~~~
 
 error: casting function pointer `foo` to `u128`
   --> tests/ui/fn_to_numeric_cast_any.rs:45:13
    |
 LL |     let _ = foo as u128;
-   |             ^^^^^^^^^^^ help: did you mean to invoke the function?: `foo() as u128`
+   |             ^^^^^^^^^^^
+   |
+help: did you mean to invoke the function?
+   |
+LL |     let _ = foo() as u128;
+   |             ~~~~~~~~~~~~~
 
 error: casting function pointer `foo` to `usize`
   --> tests/ui/fn_to_numeric_cast_any.rs:47:13
    |
 LL |     let _ = foo as usize;
-   |             ^^^^^^^^^^^^ help: did you mean to invoke the function?: `foo() as usize`
+   |             ^^^^^^^^^^^^
+   |
+help: did you mean to invoke the function?
+   |
+LL |     let _ = foo() as usize;
+   |             ~~~~~~~~~~~~~~
 
 error: casting function pointer `Struct::static_method` to `usize`
   --> tests/ui/fn_to_numeric_cast_any.rs:52:13
    |
 LL |     let _ = Struct::static_method as usize;
-   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: did you mean to invoke the function?: `Struct::static_method() as usize`
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: did you mean to invoke the function?
+   |
+LL |     let _ = Struct::static_method() as usize;
+   |             ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
 error: casting function pointer `f` to `usize`
   --> tests/ui/fn_to_numeric_cast_any.rs:57:5
    |
 LL |     f as usize
-   |     ^^^^^^^^^^ help: did you mean to invoke the function?: `f() as usize`
+   |     ^^^^^^^^^^
+   |
+help: did you mean to invoke the function?
+   |
+LL |     f() as usize
+   |
 
 error: casting function pointer `T::static_method` to `usize`
   --> tests/ui/fn_to_numeric_cast_any.rs:62:5
    |
 LL |     T::static_method as usize
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^ help: did you mean to invoke the function?: `T::static_method() as usize`
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: did you mean to invoke the function?
+   |
+LL |     T::static_method() as usize
+   |
 
 error: casting function pointer `(clos as fn(u32) -> u32)` to `usize`
   --> tests/ui/fn_to_numeric_cast_any.rs:69:13
    |
 LL |     let _ = (clos as fn(u32) -> u32) as usize;
-   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: did you mean to invoke the function?: `(clos as fn(u32) -> u32)() as usize`
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: did you mean to invoke the function?
+   |
+LL |     let _ = (clos as fn(u32) -> u32)() as usize;
+   |             ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
 error: casting function pointer `foo` to `*const ()`
   --> tests/ui/fn_to_numeric_cast_any.rs:74:13
    |
 LL |     let _ = foo as *const ();
-   |             ^^^^^^^^^^^^^^^^ help: did you mean to invoke the function?: `foo() as *const ()`
+   |             ^^^^^^^^^^^^^^^^
+   |
+help: did you mean to invoke the function?
+   |
+LL |     let _ = foo() as *const ();
+   |             ~~~~~~~~~~~~~~~~~~
 
 error: aborting due to 17 previous errors
 
diff --git a/tests/ui/get_unwrap.stderr b/tests/ui/get_unwrap.stderr
index a08b6657dcc..0f8b279da1e 100644
--- a/tests/ui/get_unwrap.stderr
+++ b/tests/ui/get_unwrap.stderr
@@ -1,14 +1,18 @@
-error: called `.get().unwrap()` on a slice. Using `[]` is more clear and more concise
+error: called `.get().unwrap()` on a slice
   --> tests/ui/get_unwrap.rs:37:17
    |
 LL |         let _ = boxed_slice.get(1).unwrap();
-   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&boxed_slice[1]`
+   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
 note: the lint level is defined here
   --> tests/ui/get_unwrap.rs:9:9
    |
 LL | #![deny(clippy::get_unwrap)]
    |         ^^^^^^^^^^^^^^^^^^
+help: using `[]` is clearer and more concise
+   |
+LL |         let _ = &boxed_slice[1];
+   |                 ~~~~~~~~~~~~~~~
 
 error: used `unwrap()` on an `Option` value
   --> tests/ui/get_unwrap.rs:37:17
@@ -21,11 +25,16 @@ LL |         let _ = boxed_slice.get(1).unwrap();
    = note: `-D clippy::unwrap-used` implied by `-D warnings`
    = help: to override `-D warnings` add `#[allow(clippy::unwrap_used)]`
 
-error: called `.get().unwrap()` on a slice. Using `[]` is more clear and more concise
+error: called `.get().unwrap()` on a slice
   --> tests/ui/get_unwrap.rs:38:17
    |
 LL |         let _ = some_slice.get(0).unwrap();
-   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&some_slice[0]`
+   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: using `[]` is clearer and more concise
+   |
+LL |         let _ = &some_slice[0];
+   |                 ~~~~~~~~~~~~~~
 
 error: used `unwrap()` on an `Option` value
   --> tests/ui/get_unwrap.rs:38:17
@@ -36,11 +45,16 @@ LL |         let _ = some_slice.get(0).unwrap();
    = note: if this value is `None`, it will panic
    = help: consider using `expect()` to provide a better panic message
 
-error: called `.get().unwrap()` on a Vec. Using `[]` is more clear and more concise
+error: called `.get().unwrap()` on a Vec
   --> tests/ui/get_unwrap.rs:39:17
    |
 LL |         let _ = some_vec.get(0).unwrap();
-   |                 ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&some_vec[0]`
+   |                 ^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: using `[]` is clearer and more concise
+   |
+LL |         let _ = &some_vec[0];
+   |                 ~~~~~~~~~~~~
 
 error: used `unwrap()` on an `Option` value
   --> tests/ui/get_unwrap.rs:39:17
@@ -51,11 +65,16 @@ LL |         let _ = some_vec.get(0).unwrap();
    = note: if this value is `None`, it will panic
    = help: consider using `expect()` to provide a better panic message
 
-error: called `.get().unwrap()` on a VecDeque. Using `[]` is more clear and more concise
+error: called `.get().unwrap()` on a VecDeque
   --> tests/ui/get_unwrap.rs:40:17
    |
 LL |         let _ = some_vecdeque.get(0).unwrap();
-   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&some_vecdeque[0]`
+   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: using `[]` is clearer and more concise
+   |
+LL |         let _ = &some_vecdeque[0];
+   |                 ~~~~~~~~~~~~~~~~~
 
 error: used `unwrap()` on an `Option` value
   --> tests/ui/get_unwrap.rs:40:17
@@ -66,11 +85,16 @@ LL |         let _ = some_vecdeque.get(0).unwrap();
    = note: if this value is `None`, it will panic
    = help: consider using `expect()` to provide a better panic message
 
-error: called `.get().unwrap()` on a HashMap. Using `[]` is more clear and more concise
+error: called `.get().unwrap()` on a HashMap
   --> tests/ui/get_unwrap.rs:41:17
    |
 LL |         let _ = some_hashmap.get(&1).unwrap();
-   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&some_hashmap[&1]`
+   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: using `[]` is clearer and more concise
+   |
+LL |         let _ = &some_hashmap[&1];
+   |                 ~~~~~~~~~~~~~~~~~
 
 error: used `unwrap()` on an `Option` value
   --> tests/ui/get_unwrap.rs:41:17
@@ -81,11 +105,16 @@ LL |         let _ = some_hashmap.get(&1).unwrap();
    = note: if this value is `None`, it will panic
    = help: consider using `expect()` to provide a better panic message
 
-error: called `.get().unwrap()` on a BTreeMap. Using `[]` is more clear and more concise
+error: called `.get().unwrap()` on a BTreeMap
   --> tests/ui/get_unwrap.rs:42:17
    |
 LL |         let _ = some_btreemap.get(&1).unwrap();
-   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&some_btreemap[&1]`
+   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: using `[]` is clearer and more concise
+   |
+LL |         let _ = &some_btreemap[&1];
+   |                 ~~~~~~~~~~~~~~~~~~
 
 error: used `unwrap()` on an `Option` value
   --> tests/ui/get_unwrap.rs:42:17
@@ -96,11 +125,16 @@ LL |         let _ = some_btreemap.get(&1).unwrap();
    = note: if this value is `None`, it will panic
    = help: consider using `expect()` to provide a better panic message
 
-error: called `.get().unwrap()` on a slice. Using `[]` is more clear and more concise
+error: called `.get().unwrap()` on a slice
   --> tests/ui/get_unwrap.rs:46:21
    |
 LL |         let _: u8 = *boxed_slice.get(1).unwrap();
-   |                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `boxed_slice[1]`
+   |                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: using `[]` is clearer and more concise
+   |
+LL |         let _: u8 = boxed_slice[1];
+   |                     ~~~~~~~~~~~~~~
 
 error: used `unwrap()` on an `Option` value
   --> tests/ui/get_unwrap.rs:46:22
@@ -111,11 +145,16 @@ LL |         let _: u8 = *boxed_slice.get(1).unwrap();
    = note: if this value is `None`, it will panic
    = help: consider using `expect()` to provide a better panic message
 
-error: called `.get_mut().unwrap()` on a slice. Using `[]` is more clear and more concise
+error: called `.get_mut().unwrap()` on a slice
   --> tests/ui/get_unwrap.rs:51:9
    |
 LL |         *boxed_slice.get_mut(0).unwrap() = 1;
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `boxed_slice[0]`
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: using `[]` is clearer and more concise
+   |
+LL |         boxed_slice[0] = 1;
+   |         ~~~~~~~~~~~~~~
 
 error: used `unwrap()` on an `Option` value
   --> tests/ui/get_unwrap.rs:51:10
@@ -126,11 +165,16 @@ LL |         *boxed_slice.get_mut(0).unwrap() = 1;
    = note: if this value is `None`, it will panic
    = help: consider using `expect()` to provide a better panic message
 
-error: called `.get_mut().unwrap()` on a slice. Using `[]` is more clear and more concise
+error: called `.get_mut().unwrap()` on a slice
   --> tests/ui/get_unwrap.rs:52:9
    |
 LL |         *some_slice.get_mut(0).unwrap() = 1;
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `some_slice[0]`
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: using `[]` is clearer and more concise
+   |
+LL |         some_slice[0] = 1;
+   |         ~~~~~~~~~~~~~
 
 error: used `unwrap()` on an `Option` value
   --> tests/ui/get_unwrap.rs:52:10
@@ -141,11 +185,16 @@ LL |         *some_slice.get_mut(0).unwrap() = 1;
    = note: if this value is `None`, it will panic
    = help: consider using `expect()` to provide a better panic message
 
-error: called `.get_mut().unwrap()` on a Vec. Using `[]` is more clear and more concise
+error: called `.get_mut().unwrap()` on a Vec
   --> tests/ui/get_unwrap.rs:53:9
    |
 LL |         *some_vec.get_mut(0).unwrap() = 1;
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `some_vec[0]`
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: using `[]` is clearer and more concise
+   |
+LL |         some_vec[0] = 1;
+   |         ~~~~~~~~~~~
 
 error: used `unwrap()` on an `Option` value
   --> tests/ui/get_unwrap.rs:53:10
@@ -156,11 +205,16 @@ LL |         *some_vec.get_mut(0).unwrap() = 1;
    = note: if this value is `None`, it will panic
    = help: consider using `expect()` to provide a better panic message
 
-error: called `.get_mut().unwrap()` on a VecDeque. Using `[]` is more clear and more concise
+error: called `.get_mut().unwrap()` on a VecDeque
   --> tests/ui/get_unwrap.rs:54:9
    |
 LL |         *some_vecdeque.get_mut(0).unwrap() = 1;
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `some_vecdeque[0]`
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: using `[]` is clearer and more concise
+   |
+LL |         some_vecdeque[0] = 1;
+   |         ~~~~~~~~~~~~~~~~
 
 error: used `unwrap()` on an `Option` value
   --> tests/ui/get_unwrap.rs:54:10
@@ -171,11 +225,16 @@ LL |         *some_vecdeque.get_mut(0).unwrap() = 1;
    = note: if this value is `None`, it will panic
    = help: consider using `expect()` to provide a better panic message
 
-error: called `.get().unwrap()` on a Vec. Using `[]` is more clear and more concise
+error: called `.get().unwrap()` on a Vec
   --> tests/ui/get_unwrap.rs:66:17
    |
 LL |         let _ = some_vec.get(0..1).unwrap().to_vec();
-   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `some_vec[0..1]`
+   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: using `[]` is clearer and more concise
+   |
+LL |         let _ = some_vec[0..1].to_vec();
+   |                 ~~~~~~~~~~~~~~
 
 error: used `unwrap()` on an `Option` value
   --> tests/ui/get_unwrap.rs:66:17
@@ -186,11 +245,16 @@ LL |         let _ = some_vec.get(0..1).unwrap().to_vec();
    = note: if this value is `None`, it will panic
    = help: consider using `expect()` to provide a better panic message
 
-error: called `.get_mut().unwrap()` on a Vec. Using `[]` is more clear and more concise
+error: called `.get_mut().unwrap()` on a Vec
   --> tests/ui/get_unwrap.rs:67:17
    |
 LL |         let _ = some_vec.get_mut(0..1).unwrap().to_vec();
-   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `some_vec[0..1]`
+   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: using `[]` is clearer and more concise
+   |
+LL |         let _ = some_vec[0..1].to_vec();
+   |                 ~~~~~~~~~~~~~~
 
 error: used `unwrap()` on an `Option` value
   --> tests/ui/get_unwrap.rs:67:17
@@ -201,29 +265,49 @@ LL |         let _ = some_vec.get_mut(0..1).unwrap().to_vec();
    = note: if this value is `None`, it will panic
    = help: consider using `expect()` to provide a better panic message
 
-error: called `.get().unwrap()` on a slice. Using `[]` is more clear and more concise
+error: called `.get().unwrap()` on a slice
   --> tests/ui/get_unwrap.rs:77:24
    |
 LL |         let _x: &i32 = f.get(1 + 2).unwrap();
-   |                        ^^^^^^^^^^^^^^^^^^^^^ help: try: `&f[1 + 2]`
+   |                        ^^^^^^^^^^^^^^^^^^^^^
+   |
+help: using `[]` is clearer and more concise
+   |
+LL |         let _x: &i32 = &f[1 + 2];
+   |                        ~~~~~~~~~
 
-error: called `.get().unwrap()` on a slice. Using `[]` is more clear and more concise
+error: called `.get().unwrap()` on a slice
   --> tests/ui/get_unwrap.rs:80:18
    |
 LL |         let _x = f.get(1 + 2).unwrap().to_string();
-   |                  ^^^^^^^^^^^^^^^^^^^^^ help: try: `f[1 + 2]`
+   |                  ^^^^^^^^^^^^^^^^^^^^^
+   |
+help: using `[]` is clearer and more concise
+   |
+LL |         let _x = f[1 + 2].to_string();
+   |                  ~~~~~~~~
 
-error: called `.get().unwrap()` on a slice. Using `[]` is more clear and more concise
+error: called `.get().unwrap()` on a slice
   --> tests/ui/get_unwrap.rs:83:18
    |
 LL |         let _x = f.get(1 + 2).unwrap().abs();
-   |                  ^^^^^^^^^^^^^^^^^^^^^ help: try: `f[1 + 2]`
+   |                  ^^^^^^^^^^^^^^^^^^^^^
+   |
+help: using `[]` is clearer and more concise
+   |
+LL |         let _x = f[1 + 2].abs();
+   |                  ~~~~~~~~
 
-error: called `.get_mut().unwrap()` on a slice. Using `[]` is more clear and more concise
+error: called `.get_mut().unwrap()` on a slice
   --> tests/ui/get_unwrap.rs:100:33
    |
 LL |                         let b = rest.get_mut(linidx(j, k) - linidx(i, k) - 1).unwrap();
-   |                                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&mut rest[linidx(j, k) - linidx(i, k) - 1]`
+   |                                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: using `[]` is clearer and more concise
+   |
+LL |                         let b = &mut rest[linidx(j, k) - linidx(i, k) - 1];
+   |                                 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
 error: aborting due to 30 previous errors
 
diff --git a/tests/ui/if_then_some_else_none.fixed b/tests/ui/if_then_some_else_none.fixed
new file mode 100644
index 00000000000..ad13372a68b
--- /dev/null
+++ b/tests/ui/if_then_some_else_none.fixed
@@ -0,0 +1,119 @@
+#![warn(clippy::if_then_some_else_none)]
+#![allow(clippy::redundant_pattern_matching, clippy::unnecessary_lazy_evaluations)]
+
+fn main() {
+    // Should issue an error.
+    let _ = foo().then(||  { println!("true!"); "foo" });
+
+    // Should issue an error when macros are used.
+    let _ = matches!(true, true).then(||  { println!("true!"); matches!(true, false) });
+
+    // Should issue an error. Binary expression `o < 32` should be parenthesized.
+    let x = Some(5);
+    let _ = x.and_then(|o| (o < 32).then_some(o));
+    //~^ ERROR: this could be simplified with `bool::then_some`
+
+    // Should issue an error. Unary expression `!x` should be parenthesized.
+    let x = true;
+    let _ = (!x).then_some(0);
+    //~^ ERROR: this could be simplified with `bool::then_some`
+
+    // Should not issue an error since the `else` block has a statement besides `None`.
+    let _ = if foo() {
+        println!("true!");
+        Some("foo")
+    } else {
+        eprintln!("false...");
+        None
+    };
+
+    // Should not issue an error since there are more than 2 blocks in the if-else chain.
+    let _ = if foo() {
+        println!("foo true!");
+        Some("foo")
+    } else if bar() {
+        println!("bar true!");
+        Some("bar")
+    } else {
+        None
+    };
+
+    let _ = if foo() {
+        println!("foo true!");
+        Some("foo")
+    } else {
+        bar().then(|| {
+            println!("bar true!");
+            "bar"
+        })
+    };
+
+    // Should not issue an error since the `then` block has `None`, not `Some`.
+    let _ = if foo() { None } else { Some("foo is false") };
+
+    // Should not issue an error since the `else` block doesn't use `None` directly.
+    let _ = if foo() { Some("foo is true") } else { into_none() };
+
+    // Should not issue an error since the `then` block doesn't use `Some` directly.
+    let _ = if foo() { into_some("foo") } else { None };
+}
+
+#[clippy::msrv = "1.49"]
+fn _msrv_1_49() {
+    // `bool::then` was stabilized in 1.50. Do not lint this
+    let _ = if foo() {
+        println!("true!");
+        Some(149)
+    } else {
+        None
+    };
+}
+
+#[clippy::msrv = "1.50"]
+fn _msrv_1_50() {
+    let _ = foo().then(||  { println!("true!"); 150 });
+}
+
+fn foo() -> bool {
+    unimplemented!()
+}
+
+fn bar() -> bool {
+    unimplemented!()
+}
+
+fn into_some<T>(v: T) -> Option<T> {
+    Some(v)
+}
+
+fn into_none<T>() -> Option<T> {
+    None
+}
+
+// Should not warn
+fn f(b: bool, v: Option<()>) -> Option<()> {
+    if b {
+        v?; // This is a potential early return, is not equivalent with `bool::then`
+
+        Some(())
+    } else {
+        None
+    }
+}
+
+fn issue11394(b: bool, v: Result<(), ()>) -> Result<(), ()> {
+    let x = if b {
+        #[allow(clippy::let_unit_value)]
+        let _ = v?;
+        Some(())
+    } else {
+        None
+    };
+
+    Ok(())
+}
+
+const fn issue12103(x: u32) -> Option<u32> {
+    // Should not issue an error in `const` context
+    if x > 42 { Some(150) } else { None }
+}
diff --git a/tests/ui/if_then_some_else_none.rs b/tests/ui/if_then_some_else_none.rs
index ccde154bd56..73edbb7da2a 100644
--- a/tests/ui/if_then_some_else_none.rs
+++ b/tests/ui/if_then_some_else_none.rs
@@ -1,5 +1,5 @@
 #![warn(clippy::if_then_some_else_none)]
-#![allow(clippy::redundant_pattern_matching)]
+#![allow(clippy::redundant_pattern_matching, clippy::unnecessary_lazy_evaluations)]
 
 fn main() {
     // Should issue an error.
diff --git a/tests/ui/if_then_some_else_none.stderr b/tests/ui/if_then_some_else_none.stderr
index e0a95aebdc1..aed01e026cb 100644
--- a/tests/ui/if_then_some_else_none.stderr
+++ b/tests/ui/if_then_some_else_none.stderr
@@ -9,9 +9,8 @@ LL | |         Some("foo")
 LL | |     } else {
 LL | |         None
 LL | |     };
-   | |_____^
+   | |_____^ help: try: `foo().then(||  { println!("true!"); "foo" })`
    |
-   = help: consider using `bool::then` like: `foo().then(|| { /* snippet */ "foo" })`
    = note: `-D clippy::if-then-some-else-none` implied by `-D warnings`
    = help: to override `-D warnings` add `#[allow(clippy::if_then_some_else_none)]`
 
@@ -26,25 +25,19 @@ LL | |         Some(matches!(true, false))
 LL | |     } else {
 LL | |         None
 LL | |     };
-   | |_____^
-   |
-   = help: consider using `bool::then` like: `matches!(true, true).then(|| { /* snippet */ matches!(true, false) })`
+   | |_____^ help: try: `matches!(true, true).then(||  { println!("true!"); matches!(true, false) })`
 
 error: this could be simplified with `bool::then_some`
   --> tests/ui/if_then_some_else_none.rs:25:28
    |
 LL |     let _ = x.and_then(|o| if o < 32 { Some(o) } else { None });
-   |                            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = help: consider using `bool::then_some` like: `(o < 32).then_some(o)`
+   |                            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `(o < 32).then_some(o)`
 
 error: this could be simplified with `bool::then_some`
   --> tests/ui/if_then_some_else_none.rs:30:13
    |
 LL |     let _ = if !x { Some(0) } else { None };
-   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = help: consider using `bool::then_some` like: `(!x).then_some(0)`
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `(!x).then_some(0)`
 
 error: this could be simplified with `bool::then`
   --> tests/ui/if_then_some_else_none.rs:86:13
@@ -57,9 +50,7 @@ LL | |         Some(150)
 LL | |     } else {
 LL | |         None
 LL | |     };
-   | |_____^
-   |
-   = help: consider using `bool::then` like: `foo().then(|| { /* snippet */ 150 })`
+   | |_____^ help: try: `foo().then(||  { println!("true!"); 150 })`
 
 error: aborting due to 5 previous errors
 
diff --git a/tests/ui/implicit_return.stderr b/tests/ui/implicit_return.stderr
index f06d4e983c5..3b06f26f5a0 100644
--- a/tests/ui/implicit_return.stderr
+++ b/tests/ui/implicit_return.stderr
@@ -2,88 +2,157 @@ error: missing `return` statement
   --> tests/ui/implicit_return.rs:15:5
    |
 LL |     true
-   |     ^^^^ help: add `return` as shown: `return true`
+   |     ^^^^
    |
    = note: `-D clippy::implicit-return` implied by `-D warnings`
    = help: to override `-D warnings` add `#[allow(clippy::implicit_return)]`
+help: add `return` as shown
+   |
+LL |     return true
+   |
 
 error: missing `return` statement
   --> tests/ui/implicit_return.rs:19:15
    |
 LL |     if true { true } else { false }
-   |               ^^^^ help: add `return` as shown: `return true`
+   |               ^^^^
+   |
+help: add `return` as shown
+   |
+LL |     if true { return true } else { false }
+   |               ~~~~~~~~~~~
 
 error: missing `return` statement
   --> tests/ui/implicit_return.rs:19:29
    |
 LL |     if true { true } else { false }
-   |                             ^^^^^ help: add `return` as shown: `return false`
+   |                             ^^^^^
+   |
+help: add `return` as shown
+   |
+LL |     if true { true } else { return false }
+   |                             ~~~~~~~~~~~~
 
 error: missing `return` statement
   --> tests/ui/implicit_return.rs:25:17
    |
 LL |         true => false,
-   |                 ^^^^^ help: add `return` as shown: `return false`
+   |                 ^^^^^
+   |
+help: add `return` as shown
+   |
+LL |         true => return false,
+   |                 ~~~~~~~~~~~~
 
 error: missing `return` statement
   --> tests/ui/implicit_return.rs:26:20
    |
 LL |         false => { true },
-   |                    ^^^^ help: add `return` as shown: `return true`
+   |                    ^^^^
+   |
+help: add `return` as shown
+   |
+LL |         false => { return true },
+   |                    ~~~~~~~~~~~
 
 error: missing `return` statement
   --> tests/ui/implicit_return.rs:39:9
    |
 LL |         break true;
-   |         ^^^^^^^^^^ help: change `break` to `return` as shown: `return true`
+   |         ^^^^^^^^^^
+   |
+help: change `break` to `return` as shown
+   |
+LL |         return true;
+   |         ~~~~~~~~~~~
 
 error: missing `return` statement
   --> tests/ui/implicit_return.rs:46:13
    |
 LL |             break true;
-   |             ^^^^^^^^^^ help: change `break` to `return` as shown: `return true`
+   |             ^^^^^^^^^^
+   |
+help: change `break` to `return` as shown
+   |
+LL |             return true;
+   |             ~~~~~~~~~~~
 
 error: missing `return` statement
   --> tests/ui/implicit_return.rs:54:13
    |
 LL |             break true;
-   |             ^^^^^^^^^^ help: change `break` to `return` as shown: `return true`
+   |             ^^^^^^^^^^
+   |
+help: change `break` to `return` as shown
+   |
+LL |             return true;
+   |             ~~~~~~~~~~~
 
 error: missing `return` statement
   --> tests/ui/implicit_return.rs:72:18
    |
 LL |     let _ = || { true };
-   |                  ^^^^ help: add `return` as shown: `return true`
+   |                  ^^^^
+   |
+help: add `return` as shown
+   |
+LL |     let _ = || { return true };
+   |                  ~~~~~~~~~~~
 
 error: missing `return` statement
   --> tests/ui/implicit_return.rs:73:16
    |
 LL |     let _ = || true;
-   |                ^^^^ help: add `return` as shown: `return true`
+   |                ^^^^
+   |
+help: add `return` as shown
+   |
+LL |     let _ = || return true;
+   |                ~~~~~~~~~~~
 
 error: missing `return` statement
   --> tests/ui/implicit_return.rs:81:5
    |
 LL |     format!("test {}", "test")
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: add `return` as shown: `return format!("test {}", "test")`
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: add `return` as shown
+   |
+LL |     return format!("test {}", "test")
+   |
 
 error: missing `return` statement
   --> tests/ui/implicit_return.rs:90:5
    |
 LL |     m!(true, false)
-   |     ^^^^^^^^^^^^^^^ help: add `return` as shown: `return m!(true, false)`
+   |     ^^^^^^^^^^^^^^^
+   |
+help: add `return` as shown
+   |
+LL |     return m!(true, false)
+   |
 
 error: missing `return` statement
   --> tests/ui/implicit_return.rs:96:13
    |
 LL |             break true;
-   |             ^^^^^^^^^^ help: change `break` to `return` as shown: `return true`
+   |             ^^^^^^^^^^
+   |
+help: change `break` to `return` as shown
+   |
+LL |             return true;
+   |             ~~~~~~~~~~~
 
 error: missing `return` statement
   --> tests/ui/implicit_return.rs:101:17
    |
 LL |                 break 'outer false;
-   |                 ^^^^^^^^^^^^^^^^^^ help: change `break` to `return` as shown: `return false`
+   |                 ^^^^^^^^^^^^^^^^^^
+   |
+help: change `break` to `return` as shown
+   |
+LL |                 return false;
+   |                 ~~~~~~~~~~~~
 
 error: missing `return` statement
   --> tests/ui/implicit_return.rs:116:5
@@ -104,7 +173,12 @@ error: missing `return` statement
   --> tests/ui/implicit_return.rs:130:5
    |
 LL |     true
-   |     ^^^^ help: add `return` as shown: `return true`
+   |     ^^^^
+   |
+help: add `return` as shown
+   |
+LL |     return true
+   |
 
 error: aborting due to 16 previous errors