diff --git a/clippy_lints/src/as_conversions.rs b/clippy_lints/src/as_conversions.rs index cfa25005a05e..fefd8195f8e7 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 7217686dcca5..f1cb4a05af86 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 df9994086cd4..a5a7b9f74a69 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 4b42616a636b..4ab97118df1d 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 826589bf303b..75de53f73ee7 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 27c00948a8f2..b49a977dbeaf 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 788c6f3ada29..93c8fff05e9e 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 9af73db6849f..a74b3a8c8362 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 3fa9bad0d03d..9f020d3081c4 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 7a6dc4697276..02f9c2c36488 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 c5fc72b5e2d8..b66dd2108fc9 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 5bba9c562b93..209104c5385c 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 0f4176ec73bb..9bf3baba4b59 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 bb74e345703f..95b8e882da79 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 a75538dd329b..d05c5a01f41c 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 39ea16b05d1a..87fe7ecf9bfe 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 a102b434cfab..b926e1e62ba0 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 b685d1dad1a7..259e4d6c08fb 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 926bd06bacbd..e0826b53004b 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 eab536b88a5b..2ab0401947c4 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 455274a44285..c6285c87a263 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 c77f3938b4a2..1c10e84d3caf 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 84bf4e87672e..974e21df817a 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 41d5afd3efec..320578bfabce 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 9c6e640ca784..ab51705bb55a 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 7d3c3f7c918e..b3d74b9ff617 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 16e51f4742e3..b8e91906b931 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 4223ddaf3fba..d4d020fec30c 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 e5bb8d132697..a05b7138bc99 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 a08b6657dcc7..0f8b279da1e7 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 000000000000..ad13372a68b7 --- /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(v: T) -> Option { + Some(v) +} + +fn into_none() -> Option { + 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 { + // 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 ccde154bd56c..73edbb7da2a8 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 e0a95aebdc13..aed01e026cbe 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 f06d4e983c57..3b06f26f5a05 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