diff --git a/clippy_lints/src/matches/rest_pat_in_fully_bound_struct.rs b/clippy_lints/src/matches/rest_pat_in_fully_bound_struct.rs index 316b2f63e..2154cd5b2 100644 --- a/clippy_lints/src/matches/rest_pat_in_fully_bound_struct.rs +++ b/clippy_lints/src/matches/rest_pat_in_fully_bound_struct.rs @@ -1,4 +1,4 @@ -use clippy_utils::diagnostics::span_lint_and_help; +use clippy_utils::diagnostics::span_lint_and_then; use rustc_hir::{Pat, PatKind, QPath}; use rustc_lint::LateContext; use rustc_middle::ty; @@ -15,13 +15,15 @@ pub(crate) fn check(cx: &LateContext<'_>, pat: &Pat<'_>) { && fields.len() == def.non_enum_variant().fields.len() && !def.non_enum_variant().is_field_list_non_exhaustive() { - span_lint_and_help( + #[expect(clippy::collapsible_span_lint_calls, reason = "rust-clippy#7797")] + span_lint_and_then( cx, REST_PAT_IN_FULLY_BOUND_STRUCTS, pat.span, "unnecessary use of `..` pattern in struct binding. All fields were already bound", - None, - "consider removing `..` from this binding", + |diag| { + diag.help("consider removing `..` from this binding"); + }, ); } } diff --git a/clippy_lints/src/misc_early/literal_suffix.rs b/clippy_lints/src/misc_early/literal_suffix.rs index e0a5e401a..22467999c 100644 --- a/clippy_lints/src/misc_early/literal_suffix.rs +++ b/clippy_lints/src/misc_early/literal_suffix.rs @@ -1,4 +1,4 @@ -use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::diagnostics::span_lint_and_then; use rustc_errors::Applicability; use rustc_lint::EarlyContext; use rustc_span::Span; @@ -12,24 +12,36 @@ pub(super) fn check(cx: &EarlyContext<'_>, lit_span: Span, lit_snip: &str, suffi // Do not lint when literal is unsuffixed. if !suffix.is_empty() { if lit_snip.as_bytes()[maybe_last_sep_idx] == b'_' { - span_lint_and_sugg( + #[expect(clippy::collapsible_span_lint_calls, reason = "rust-clippy#7797")] + span_lint_and_then( cx, SEPARATED_LITERAL_SUFFIX, lit_span, format!("{sugg_type} type suffix should not be separated by an underscore"), - "remove the underscore", - format!("{}{suffix}", &lit_snip[..maybe_last_sep_idx]), - Applicability::MachineApplicable, + |diag| { + diag.span_suggestion( + lit_span, + "remove the underscore", + format!("{}{suffix}", &lit_snip[..maybe_last_sep_idx]), + Applicability::MachineApplicable, + ); + }, ); } else { - span_lint_and_sugg( + #[expect(clippy::collapsible_span_lint_calls, reason = "rust-clippy#7797")] + span_lint_and_then( cx, UNSEPARATED_LITERAL_SUFFIX, lit_span, format!("{sugg_type} type suffix should be separated by an underscore"), - "add an underscore", - format!("{}_{suffix}", &lit_snip[..=maybe_last_sep_idx]), - Applicability::MachineApplicable, + |diag| { + diag.span_suggestion( + lit_span, + "add an underscore", + format!("{}_{suffix}", &lit_snip[..=maybe_last_sep_idx]), + Applicability::MachineApplicable, + ); + }, ); } } diff --git a/clippy_lints/src/question_mark_used.rs b/clippy_lints/src/question_mark_used.rs index f5e6cb804..0a974bf9d 100644 --- a/clippy_lints/src/question_mark_used.rs +++ b/clippy_lints/src/question_mark_used.rs @@ -1,4 +1,4 @@ -use clippy_utils::diagnostics::span_lint_and_help; +use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::macros::span_is_local; use rustc_hir::{Expr, ExprKind, MatchSource}; @@ -39,13 +39,15 @@ impl<'tcx> LateLintPass<'tcx> for QuestionMarkUsed { return; } - span_lint_and_help( + #[expect(clippy::collapsible_span_lint_calls, reason = "rust-clippy#7797")] + span_lint_and_then( cx, QUESTION_MARK_USED, expr.span, "question mark operator was used", - None, - "consider using a custom macro or match expression", + |diag| { + diag.help("consider using a custom macro or match expression"); + }, ); } } diff --git a/clippy_lints/src/ref_patterns.rs b/clippy_lints/src/ref_patterns.rs index 467038523..002c6c41d 100644 --- a/clippy_lints/src/ref_patterns.rs +++ b/clippy_lints/src/ref_patterns.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::{BindingMode, Pat, PatKind}; use rustc_lint::{EarlyContext, EarlyLintPass}; use rustc_session::declare_lint_pass; @@ -33,14 +33,10 @@ impl EarlyLintPass for RefPatterns { if let PatKind::Ident(BindingMode::REF, _, _) = pat.kind && !pat.span.from_expansion() { - span_lint_and_help( - cx, - REF_PATTERNS, - pat.span, - "usage of ref pattern", - None, - "consider using `&` for clarity instead", - ); + #[expect(clippy::collapsible_span_lint_calls, reason = "rust-clippy#7797")] + span_lint_and_then(cx, REF_PATTERNS, pat.span, "usage of ref pattern", |diag| { + diag.help("consider using `&` for clarity instead"); + }); } } } diff --git a/clippy_lints/src/shadow.rs b/clippy_lints/src/shadow.rs index 80f5fd0b4..7ae0310b6 100644 --- a/clippy_lints/src/shadow.rs +++ b/clippy_lints/src/shadow.rs @@ -1,4 +1,4 @@ -use clippy_utils::diagnostics::span_lint_and_note; +use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::source::snippet; use clippy_utils::visitors::is_local_used; use rustc_data_structures::fx::FxHashMap; @@ -194,14 +194,9 @@ fn lint_shadow(cx: &LateContext<'_>, pat: &Pat<'_>, shadowed: HirId, span: Span) (SHADOW_UNRELATED, msg) }, }; - span_lint_and_note( - cx, - lint, - span, - msg, - Some(cx.tcx.hir().span(shadowed)), - "previous binding is here", - ); + span_lint_and_then(cx, lint, span, msg, |diag| { + diag.span_note(cx.tcx.hir().span(shadowed), "previous binding is here"); + }); } /// Returns true if the expression is a simple transformation of a local binding such as `&x` diff --git a/clippy_lints/src/single_char_lifetime_names.rs b/clippy_lints/src/single_char_lifetime_names.rs index 72feb977c..d92b89095 100644 --- a/clippy_lints/src/single_char_lifetime_names.rs +++ b/clippy_lints/src/single_char_lifetime_names.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::{GenericParam, GenericParamKind}; use rustc_lint::{EarlyContext, EarlyLintPass, LintContext}; use rustc_middle::lint::in_external_macro; @@ -48,13 +48,15 @@ impl EarlyLintPass for SingleCharLifetimeNames { if let GenericParamKind::Lifetime = param.kind { if !param.is_placeholder && param.ident.as_str().len() <= 2 { - span_lint_and_help( + #[expect(clippy::collapsible_span_lint_calls, reason = "rust-clippy#7797")] + span_lint_and_then( ctx, SINGLE_CHAR_LIFETIME_NAMES, param.ident.span, "single-character lifetime names are likely uninformative", - None, - "use a more informative name", + |diag| { + diag.help("use a more informative name"); + }, ); } } diff --git a/clippy_lints/src/std_instead_of_core.rs b/clippy_lints/src/std_instead_of_core.rs index 84bf4e876..974e21df8 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/clippy_lints/src/strings.rs b/clippy_lints/src/strings.rs index 7da661485..cfc387886 100644 --- a/clippy_lints/src/strings.rs +++ b/clippy_lints/src/strings.rs @@ -1,4 +1,4 @@ -use clippy_utils::diagnostics::{span_lint, span_lint_and_help, span_lint_and_sugg}; +use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg, span_lint_and_then}; use clippy_utils::source::{snippet, snippet_with_applicability}; use clippy_utils::ty::is_type_lang_item; use clippy_utils::{ @@ -399,17 +399,16 @@ impl<'tcx> LateLintPass<'tcx> for StrToString { && let ty::Ref(_, ty, ..) = ty.kind() && ty.is_str() { - let mut applicability = Applicability::MachineApplicable; - let snippet = snippet_with_applicability(cx, self_arg.span, "..", &mut applicability); - - span_lint_and_sugg( + span_lint_and_then( cx, STR_TO_STRING, expr.span, "`to_string()` called on a `&str`", - "try", - format!("{snippet}.to_owned()"), - applicability, + |diag| { + let mut applicability = Applicability::MachineApplicable; + let snippet = snippet_with_applicability(cx, self_arg.span, "..", &mut applicability); + diag.span_suggestion(expr.span, "try", format!("{snippet}.to_owned()"), applicability); + }, ); } } @@ -455,13 +454,15 @@ impl<'tcx> LateLintPass<'tcx> for StringToString { && let ty = cx.typeck_results().expr_ty(self_arg) && is_type_lang_item(cx, ty, LangItem::String) { - span_lint_and_help( + #[expect(clippy::collapsible_span_lint_calls, reason = "rust-clippy#7797")] + span_lint_and_then( cx, STRING_TO_STRING, expr.span, "`to_string()` called on a `String`", - None, - "consider using `.clone()`", + |diag| { + diag.help("consider using `.clone()`"); + }, ); } } diff --git a/clippy_lints/src/suspicious_xor_used_as_pow.rs b/clippy_lints/src/suspicious_xor_used_as_pow.rs index d150a5f85..d1d822a55 100644 --- a/clippy_lints/src/suspicious_xor_used_as_pow.rs +++ b/clippy_lints/src/suspicious_xor_used_as_pow.rs @@ -1,4 +1,4 @@ -use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::numeric_literal::NumericLiteral; use clippy_utils::source::snippet; use rustc_ast::LitKind; @@ -43,14 +43,19 @@ impl LateLintPass<'_> for ConfusingXorAndPow { && NumericLiteral::from_lit_kind(&snippet(cx, lit_right.span, ".."), &lit_right.node) .is_some_and(|x| x.is_decimal()) { - span_lint_and_sugg( + span_lint_and_then( cx, SUSPICIOUS_XOR_USED_AS_POW, expr.span, "`^` is not the exponentiation operator", - "did you mean to write", - format!("{}.pow({})", lit_left.node, lit_right.node), - Applicability::MaybeIncorrect, + |diag| { + diag.span_suggestion_verbose( + expr.span, + "did you mean to write", + format!("{}.pow({})", lit_left.node, lit_right.node), + Applicability::MaybeIncorrect, + ); + }, ); } } diff --git a/clippy_lints/src/types/rc_buffer.rs b/clippy_lints/src/types/rc_buffer.rs index f6c2d8d5a..d691f1878 100644 --- a/clippy_lints/src/types/rc_buffer.rs +++ b/clippy_lints/src/types/rc_buffer.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_applicability; use clippy_utils::{path_def_id, qpath_generic_tys}; use rustc_errors::Applicability; @@ -13,14 +13,15 @@ pub(super) fn check(cx: &LateContext<'_>, hir_ty: &hir::Ty<'_>, qpath: &QPath<'_ let app = Applicability::Unspecified; if cx.tcx.is_diagnostic_item(sym::Rc, def_id) { if let Some(alternate) = match_buffer_type(cx, qpath) { - span_lint_and_sugg( + #[expect(clippy::collapsible_span_lint_calls, reason = "rust-clippy#7797")] + span_lint_and_then( cx, RC_BUFFER, hir_ty.span, "usage of `Rc` when T is a buffer type", - "try", - format!("Rc<{alternate}>"), - app, + |diag| { + diag.span_suggestion(hir_ty.span, "try", format!("Rc<{alternate}>"), app); + }, ); } else { let Some(ty) = qpath_generic_tys(qpath).next() else { @@ -35,31 +36,37 @@ pub(super) fn check(cx: &LateContext<'_>, hir_ty: &hir::Ty<'_>, qpath: &QPath<'_ Some(ty) => ty.span, None => return false, }; - let mut applicability = app; - span_lint_and_sugg( + span_lint_and_then( cx, RC_BUFFER, hir_ty.span, "usage of `Rc` when T is a buffer type", - "try", - format!( - "Rc<[{}]>", - snippet_with_applicability(cx, inner_span, "..", &mut applicability) - ), - app, + |diag| { + let mut applicability = app; + diag.span_suggestion( + hir_ty.span, + "try", + format!( + "Rc<[{}]>", + snippet_with_applicability(cx, inner_span, "..", &mut applicability) + ), + app, + ); + }, ); return true; } } else if cx.tcx.is_diagnostic_item(sym::Arc, def_id) { if let Some(alternate) = match_buffer_type(cx, qpath) { - span_lint_and_sugg( + #[expect(clippy::collapsible_span_lint_calls, reason = "rust-clippy#7797")] + span_lint_and_then( cx, RC_BUFFER, hir_ty.span, "usage of `Arc` when T is a buffer type", - "try", - format!("Arc<{alternate}>"), - app, + |diag| { + diag.span_suggestion(hir_ty.span, "try", format!("Arc<{alternate}>"), app); + }, ); } else if let Some(ty) = qpath_generic_tys(qpath).next() { let Some(id) = path_def_id(cx, ty) else { return false }; @@ -71,18 +78,23 @@ pub(super) fn check(cx: &LateContext<'_>, hir_ty: &hir::Ty<'_>, qpath: &QPath<'_ Some(ty) => ty.span, None => return false, }; - let mut applicability = app; - span_lint_and_sugg( + span_lint_and_then( cx, RC_BUFFER, hir_ty.span, "usage of `Arc` when T is a buffer type", - "try", - format!( - "Arc<[{}]>", - snippet_with_applicability(cx, inner_span, "..", &mut applicability) - ), - app, + |diag| { + let mut applicability = app; + diag.span_suggestion( + hir_ty.span, + "try", + format!( + "Arc<[{}]>", + snippet_with_applicability(cx, inner_span, "..", &mut applicability) + ), + app, + ); + }, ); return true; } diff --git a/clippy_lints/src/types/rc_mutex.rs b/clippy_lints/src/types/rc_mutex.rs index afc319217..7b13debc0 100644 --- a/clippy_lints/src/types/rc_mutex.rs +++ b/clippy_lints/src/types/rc_mutex.rs @@ -1,4 +1,4 @@ -use clippy_utils::diagnostics::span_lint_and_help; +use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::{path_def_id, qpath_generic_tys}; use rustc_hir::def_id::DefId; use rustc_hir::{self as hir, QPath}; @@ -13,14 +13,10 @@ pub(super) fn check(cx: &LateContext<'_>, hir_ty: &hir::Ty<'_>, qpath: &QPath<'_ && let Some(id) = path_def_id(cx, arg) && cx.tcx.is_diagnostic_item(sym::Mutex, id) { - span_lint_and_help( - cx, - RC_MUTEX, - hir_ty.span, - "usage of `Rc>`", - None, - "consider using `Rc>` or `Arc>` instead", - ); + #[expect(clippy::collapsible_span_lint_calls, reason = "rust-clippy#7797")] + span_lint_and_then(cx, RC_MUTEX, hir_ty.span, "usage of `Rc>`", |diag| { + diag.help("consider using `Rc>` or `Arc>` instead"); + }); return true; } diff --git a/tests/ui/suspicious_xor_used_as_pow.stderr b/tests/ui/suspicious_xor_used_as_pow.stderr index 4faf0237c..43b03676b 100644 --- a/tests/ui/suspicious_xor_used_as_pow.stderr +++ b/tests/ui/suspicious_xor_used_as_pow.stderr @@ -2,51 +2,84 @@ error: `^` is not the exponentiation operator --> tests/ui/suspicious_xor_used_as_pow.rs:19:13 | LL | let _ = 2 ^ 5; - | ^^^^^ help: did you mean to write: `2.pow(5)` + | ^^^^^ | = note: `-D clippy::suspicious-xor-used-as-pow` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::suspicious_xor_used_as_pow)]` +help: did you mean to write + | +LL | let _ = 2.pow(5); + | ~~~~~~~~ error: `^` is not the exponentiation operator --> tests/ui/suspicious_xor_used_as_pow.rs:22:13 | LL | let _ = 2i32 ^ 9i32; - | ^^^^^^^^^^^ help: did you mean to write: `2i32.pow(9i32)` + | ^^^^^^^^^^^ + | +help: did you mean to write + | +LL | let _ = 2i32.pow(9i32); + | ~~~~~~~~~~~~~~ error: `^` is not the exponentiation operator --> tests/ui/suspicious_xor_used_as_pow.rs:24:13 | LL | let _ = 2i32 ^ 2i32; - | ^^^^^^^^^^^ help: did you mean to write: `2i32.pow(2i32)` + | ^^^^^^^^^^^ + | +help: did you mean to write + | +LL | let _ = 2i32.pow(2i32); + | ~~~~~~~~~~~~~~ error: `^` is not the exponentiation operator --> tests/ui/suspicious_xor_used_as_pow.rs:26:13 | LL | let _ = 50i32 ^ 3i32; - | ^^^^^^^^^^^^ help: did you mean to write: `50i32.pow(3i32)` + | ^^^^^^^^^^^^ + | +help: did you mean to write + | +LL | let _ = 50i32.pow(3i32); + | ~~~~~~~~~~~~~~~ error: `^` is not the exponentiation operator --> tests/ui/suspicious_xor_used_as_pow.rs:28:13 | LL | let _ = 5i32 ^ 8i32; - | ^^^^^^^^^^^ help: did you mean to write: `5i32.pow(8i32)` + | ^^^^^^^^^^^ + | +help: did you mean to write + | +LL | let _ = 5i32.pow(8i32); + | ~~~~~~~~~~~~~~ error: `^` is not the exponentiation operator --> tests/ui/suspicious_xor_used_as_pow.rs:30:13 | LL | let _ = 2i32 ^ 32i32; - | ^^^^^^^^^^^^ help: did you mean to write: `2i32.pow(32i32)` + | ^^^^^^^^^^^^ + | +help: did you mean to write + | +LL | let _ = 2i32.pow(32i32); + | ~~~~~~~~~~~~~~~ error: `^` is not the exponentiation operator --> tests/ui/suspicious_xor_used_as_pow.rs:13:9 | LL | 1 ^ 2 // should warn even if inside macro - | ^^^^^ help: did you mean to write: `1.pow(2)` + | ^^^^^ ... LL | macro_test_inside!(); | -------------------- in this macro invocation | = note: this error originates in the macro `macro_test_inside` (in Nightly builds, run with -Z macro-backtrace for more info) +help: did you mean to write + | +LL | 1.pow(2) // should warn even if inside macro + | ~~~~~~~~ error: aborting due to 7 previous errors