diff --git a/clippy_lints/src/as_conversions.rs b/clippy_lints/src/as_conversions.rs index 4d8bbcd31024..0c8efd755146 100644 --- a/clippy_lints/src/as_conversions.rs +++ b/clippy_lints/src/as_conversions.rs @@ -50,6 +50,7 @@ impl EarlyLintPass for AsConversions { AS_CONVERSIONS, expr.span, "using a potentially dangerous silent `as` conversion", + None, "consider using a safe wrapper for this conversion", ); } diff --git a/clippy_lints/src/assertions_on_constants.rs b/clippy_lints/src/assertions_on_constants.rs index e2fe5f2400f4..f8a8fdcd3aa3 100644 --- a/clippy_lints/src/assertions_on_constants.rs +++ b/clippy_lints/src/assertions_on_constants.rs @@ -41,6 +41,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for AssertionsOnConstants { } else { "`assert!(true)` will be optimized out by the compiler" }, + None, "remove it", ); }; @@ -50,6 +51,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for AssertionsOnConstants { ASSERTIONS_ON_CONSTANTS, e.span, "`assert!(false)` should probably be replaced", + None, "use `panic!()` or `unreachable!()`", ); }; @@ -59,6 +61,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for AssertionsOnConstants { ASSERTIONS_ON_CONSTANTS, e.span, &format!("`assert!(false, {})` should probably be replaced", panic_message), + None, &format!("use `panic!({})` or `unreachable!({})`", panic_message, panic_message), ) }; diff --git a/clippy_lints/src/atomic_ordering.rs b/clippy_lints/src/atomic_ordering.rs index d9ff1fe0a1d0..73b4cef47250 100644 --- a/clippy_lints/src/atomic_ordering.rs +++ b/clippy_lints/src/atomic_ordering.rs @@ -85,6 +85,7 @@ fn check_atomic_load_store(cx: &LateContext<'_, '_>, expr: &Expr<'_>) { INVALID_ATOMIC_ORDERING, ordering_arg.span, "atomic loads cannot have `Release` and `AcqRel` ordering", + None, "consider using ordering modes `Acquire`, `SeqCst` or `Relaxed`" ); } else if method == "store" && @@ -94,6 +95,7 @@ fn check_atomic_load_store(cx: &LateContext<'_, '_>, expr: &Expr<'_>) { INVALID_ATOMIC_ORDERING, ordering_arg.span, "atomic stores cannot have `Acquire` and `AcqRel` ordering", + None, "consider using ordering modes `Release`, `SeqCst` or `Relaxed`" ); } @@ -118,6 +120,7 @@ fn check_memory_fence(cx: &LateContext<'_, '_>, expr: &Expr<'_>) { INVALID_ATOMIC_ORDERING, args[0].span, "memory fences cannot have `Relaxed` ordering", + None, "consider using ordering modes `Acquire`, `Release`, `AcqRel` or `SeqCst`" ); } diff --git a/clippy_lints/src/cognitive_complexity.rs b/clippy_lints/src/cognitive_complexity.rs index 93a394b79e55..e842388ac982 100644 --- a/clippy_lints/src/cognitive_complexity.rs +++ b/clippy_lints/src/cognitive_complexity.rs @@ -105,6 +105,7 @@ impl CognitiveComplexity { rust_cc, self.limit.limit() ), + None, "you could split it up into multiple smaller functions", ); } diff --git a/clippy_lints/src/comparison_chain.rs b/clippy_lints/src/comparison_chain.rs index e0c381ddbfc4..96df3ffe3ce6 100644 --- a/clippy_lints/src/comparison_chain.rs +++ b/clippy_lints/src/comparison_chain.rs @@ -104,6 +104,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for ComparisonChain { COMPARISON_CHAIN, expr.span, "`if` chain can be rewritten with `match`", + None, "Consider rewriting the `if` chain to use `cmp` and `match`.", ) } diff --git a/clippy_lints/src/copies.rs b/clippy_lints/src/copies.rs index 1afd401ca681..66722786eab4 100644 --- a/clippy_lints/src/copies.rs +++ b/clippy_lints/src/copies.rs @@ -183,7 +183,7 @@ fn lint_same_then_else(cx: &LateContext<'_, '_>, blocks: &[&Block<'_>]) { IF_SAME_THEN_ELSE, j.span, "this `if` has identical blocks", - i.span, + Some(i.span), "same as this", ); } @@ -206,7 +206,7 @@ fn lint_same_cond(cx: &LateContext<'_, '_>, conds: &[&Expr<'_>]) { IFS_SAME_COND, j.span, "this `if` has the same condition as a previous `if`", - i.span, + Some(i.span), "same as this", ); } @@ -234,7 +234,7 @@ fn lint_same_fns_in_if_cond(cx: &LateContext<'_, '_>, conds: &[&Expr<'_>]) { SAME_FUNCTIONS_IN_IF_CONDITION, j.span, "this `if` has the same function call as a previous `if`", - i.span, + Some(i.span), "same as this", ); } diff --git a/clippy_lints/src/copy_iterator.rs b/clippy_lints/src/copy_iterator.rs index 3e2d5b88e7b7..d79aa2ef0209 100644 --- a/clippy_lints/src/copy_iterator.rs +++ b/clippy_lints/src/copy_iterator.rs @@ -46,7 +46,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for CopyIterator { COPY_ITERATOR, item.span, "you are implementing `Iterator` on a `Copy` type", - item.span, + None, "consider implementing `IntoIterator` instead", ); } diff --git a/clippy_lints/src/dbg_macro.rs b/clippy_lints/src/dbg_macro.rs index f9bf1141a8b2..e513dcce64e5 100644 --- a/clippy_lints/src/dbg_macro.rs +++ b/clippy_lints/src/dbg_macro.rs @@ -48,6 +48,7 @@ impl EarlyLintPass for DbgMacro { DBG_MACRO, mac.span(), "`dbg!` macro is intended as a debugging tool", + None, "ensure to avoid having uses of it in version control", ); } diff --git a/clippy_lints/src/derive.rs b/clippy_lints/src/derive.rs index 7756fdfdd07a..f5a358d424f7 100644 --- a/clippy_lints/src/derive.rs +++ b/clippy_lints/src/derive.rs @@ -1,5 +1,5 @@ use crate::utils::paths; -use crate::utils::{is_automatically_derived, is_copy, match_path, span_lint_and_then}; +use crate::utils::{is_automatically_derived, is_copy, match_path, span_lint_and_note, span_lint_and_then}; use if_chain::if_chain; use rustc_hir::{Item, ItemKind, TraitRef}; use rustc_lint::{LateContext, LateLintPass}; @@ -163,14 +163,13 @@ fn check_copy_clone<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, item: &Item<'_>, trait _ => (), } - span_lint_and_then( + span_lint_and_note( cx, EXPL_IMPL_CLONE_ON_COPY, item.span, "you are implementing `Clone` explicitly on a `Copy` type", - |diag| { - diag.span_note(item.span, "consider deriving `Clone` or removing `Copy`"); - }, + Some(item.span), + "consider deriving `Clone` or removing `Copy`", ); } } diff --git a/clippy_lints/src/drop_forget_ref.rs b/clippy_lints/src/drop_forget_ref.rs index 9a60b2f027ab..9de9056c1402 100644 --- a/clippy_lints/src/drop_forget_ref.rs +++ b/clippy_lints/src/drop_forget_ref.rs @@ -135,7 +135,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for DropForgetRef { lint, expr.span, &msg, - arg.span, + Some(arg.span), &format!("argument has type `{}`", arg_ty)); } else if is_copy(cx, arg_ty) { if match_def_path(cx, def_id, &paths::DROP) { @@ -151,7 +151,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for DropForgetRef { lint, expr.span, &msg, - arg.span, + Some(arg.span), &format!("argument has type {}", arg_ty)); } } diff --git a/clippy_lints/src/else_if_without_else.rs b/clippy_lints/src/else_if_without_else.rs index fb10ca48074e..95123e6ff6fe 100644 --- a/clippy_lints/src/else_if_without_else.rs +++ b/clippy_lints/src/else_if_without_else.rs @@ -61,6 +61,7 @@ impl EarlyLintPass for ElseIfWithoutElse { ELSE_IF_WITHOUT_ELSE, els.span, "`if` expression with an `else if`, but without a final `else`", + None, "add an `else` block here", ); } diff --git a/clippy_lints/src/empty_enum.rs b/clippy_lints/src/empty_enum.rs index 77ae6dbde72b..3bfef6f4bed1 100644 --- a/clippy_lints/src/empty_enum.rs +++ b/clippy_lints/src/empty_enum.rs @@ -1,6 +1,6 @@ //! lint when there is an enum with no variants -use crate::utils::span_lint_and_then; +use crate::utils::span_lint_and_help; use rustc_hir::{Item, ItemKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; @@ -45,13 +45,15 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for EmptyEnum { let ty = cx.tcx.type_of(did); let adt = ty.ty_adt_def().expect("already checked whether this is an enum"); if adt.variants.is_empty() { - span_lint_and_then(cx, EMPTY_ENUM, item.span, "enum with no variants", |diag| { - diag.span_help( - item.span, - "consider using the uninhabited type `!` (never type) or a wrapper \ - around it to introduce a type which can't be instantiated", - ); - }); + span_lint_and_help( + cx, + EMPTY_ENUM, + item.span, + "enum with no variants", + None, + "consider using the uninhabited type `!` (never type) or a wrapper \ + around it to introduce a type which can't be instantiated", + ); } } } diff --git a/clippy_lints/src/enum_variants.rs b/clippy_lints/src/enum_variants.rs index 882020a7adc7..a5871cf0cd4d 100644 --- a/clippy_lints/src/enum_variants.rs +++ b/clippy_lints/src/enum_variants.rs @@ -206,6 +206,7 @@ fn check_variant( lint, span, &format!("All variants have the same {}fix: `{}`", what, value), + None, &format!( "remove the {}fixes and use full paths to \ the variants instead of glob imports", diff --git a/clippy_lints/src/eta_reduction.rs b/clippy_lints/src/eta_reduction.rs index 3d27d8d5c8ae..e3e1136b6769 100644 --- a/clippy_lints/src/eta_reduction.rs +++ b/clippy_lints/src/eta_reduction.rs @@ -7,7 +7,8 @@ use rustc_middle::ty::{self, Ty}; use rustc_session::{declare_lint_pass, declare_tool_lint}; use crate::utils::{ - implements_trait, is_adjusted, iter_input_pats, snippet_opt, span_lint_and_then, type_is_unsafe_function, + implements_trait, is_adjusted, iter_input_pats, snippet_opt, span_lint_and_sugg, span_lint_and_then, + type_is_unsafe_function, }; declare_clippy_lint! { @@ -131,14 +132,15 @@ fn check_closure(cx: &LateContext<'_, '_>, expr: &Expr<'_>) { if let Some(name) = get_ufcs_type_name(cx, method_def_id, &args[0]); then { - span_lint_and_then(cx, REDUNDANT_CLOSURE_FOR_METHOD_CALLS, expr.span, "redundant closure found", |diag| { - diag.span_suggestion( - expr.span, - "remove closure as shown", - format!("{}::{}", name, path.ident.name), - Applicability::MachineApplicable, - ); - }); + span_lint_and_sugg( + cx, + REDUNDANT_CLOSURE_FOR_METHOD_CALLS, + expr.span, + "redundant closure found", + "remove closure as shown", + format!("{}::{}", name, path.ident.name), + Applicability::MachineApplicable, + ); } ); } diff --git a/clippy_lints/src/eval_order_dependence.rs b/clippy_lints/src/eval_order_dependence.rs index 48b761260a55..5206266ccf2a 100644 --- a/clippy_lints/src/eval_order_dependence.rs +++ b/clippy_lints/src/eval_order_dependence.rs @@ -310,7 +310,7 @@ impl<'a, 'tcx> Visitor<'tcx> for ReadVisitor<'a, 'tcx> { EVAL_ORDER_DEPENDENCE, expr.span, "unsequenced read of a variable", - self.write_expr.span, + Some(self.write_expr.span), "whether read occurs before this write depends on evaluation order" ); } diff --git a/clippy_lints/src/excessive_bools.rs b/clippy_lints/src/excessive_bools.rs index ddbc3c377a27..82ca4baacb7a 100644 --- a/clippy_lints/src/excessive_bools.rs +++ b/clippy_lints/src/excessive_bools.rs @@ -114,6 +114,7 @@ impl ExcessiveBools { FN_PARAMS_EXCESSIVE_BOOLS, span, &format!("more than {} bools in function parameters", self.max_fn_params_bools), + None, "consider refactoring bools into two-variant enums", ); } @@ -153,6 +154,7 @@ impl EarlyLintPass for ExcessiveBools { STRUCT_EXCESSIVE_BOOLS, item.span, &format!("more than {} bools in a struct", self.max_struct_bools), + None, "consider using a state machine or refactoring bools into two-variant enums", ); } diff --git a/clippy_lints/src/formatting.rs b/clippy_lints/src/formatting.rs index 8f5f82b0a2ce..eb4b7a826f2c 100644 --- a/clippy_lints/src/formatting.rs +++ b/clippy_lints/src/formatting.rs @@ -149,7 +149,7 @@ fn check_assign(cx: &EarlyContext<'_>, expr: &Expr) { really are doing `.. = ({op} ..)`", op = op ), - eqop_span, + None, &format!("to remove this lint, use either `{op}=` or `= {op}`", op = op), ); } @@ -188,6 +188,7 @@ fn check_unop(cx: &EarlyContext<'_>, expr: &Expr) { binop = binop_str, unop = unop_str ), + None, &format!( "put a space between `{binop}` and `{unop}` and remove the space after `{unop}`", binop = binop_str, @@ -226,7 +227,7 @@ fn check_else(cx: &EarlyContext<'_>, expr: &Expr) { SUSPICIOUS_ELSE_FORMATTING, else_span, &format!("this is an `else {}` but the formatting might hide it", else_desc), - else_span, + None, &format!( "to remove this lint, remove the `else` or remove the new line between \ `else` and `{}`", @@ -265,7 +266,7 @@ fn check_array(cx: &EarlyContext<'_>, expr: &Expr) { POSSIBLE_MISSING_COMMA, lint_span, "possibly missing a comma here", - lint_span, + None, "to remove this lint, add a comma or write the expr in a single line", ); } @@ -296,7 +297,7 @@ fn check_missing_else(cx: &EarlyContext<'_>, first: &Expr, second: &Expr) { SUSPICIOUS_ELSE_FORMATTING, else_span, &format!("this looks like {} but the `else` is missing", looks_like), - else_span, + None, &format!( "to remove this lint, add the missing `else` or add a new line before {}", next_thing, diff --git a/clippy_lints/src/functions.rs b/clippy_lints/src/functions.rs index 7100bad996cd..c8c562fe29f5 100644 --- a/clippy_lints/src/functions.rs +++ b/clippy_lints/src/functions.rs @@ -431,6 +431,7 @@ fn check_needless_must_use( DOUBLE_MUST_USE, fn_header_span, "this function has an empty `#[must_use]` attribute, but returns a type already marked as `#[must_use]`", + None, "either add some descriptive text or remove the attribute", ); } diff --git a/clippy_lints/src/identity_conversion.rs b/clippy_lints/src/identity_conversion.rs index 4b7c2c4156ec..33a9478f0588 100644 --- a/clippy_lints/src/identity_conversion.rs +++ b/clippy_lints/src/identity_conversion.rs @@ -1,5 +1,5 @@ use crate::utils::{ - match_def_path, match_trait_method, paths, same_tys, snippet, snippet_with_macro_callsite, span_lint_and_then, + match_def_path, match_trait_method, paths, same_tys, snippet, snippet_with_macro_callsite, span_lint_and_sugg, }; use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind, HirId, MatchSource}; @@ -58,14 +58,15 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for IdentityConversion { if same_tys(cx, a, b) { let sugg = snippet_with_macro_callsite(cx, args[0].span, "").to_string(); - span_lint_and_then(cx, IDENTITY_CONVERSION, e.span, "identical conversion", |diag| { - diag.span_suggestion( - e.span, - "consider removing `.into()`", - sugg, - Applicability::MachineApplicable, // snippet - ); - }); + span_lint_and_sugg( + cx, + IDENTITY_CONVERSION, + e.span, + "identical conversion", + "consider removing `.into()`", + sugg, + Applicability::MachineApplicable, // snippet + ); } } if match_trait_method(cx, e, &paths::INTO_ITERATOR) && &*name.ident.as_str() == "into_iter" { @@ -73,14 +74,15 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for IdentityConversion { let b = cx.tables.expr_ty(&args[0]); if same_tys(cx, a, b) { let sugg = snippet(cx, args[0].span, "").into_owned(); - span_lint_and_then(cx, IDENTITY_CONVERSION, e.span, "identical conversion", |diag| { - diag.span_suggestion( - e.span, - "consider removing `.into_iter()`", - sugg, - Applicability::MachineApplicable, // snippet - ); - }); + span_lint_and_sugg( + cx, + IDENTITY_CONVERSION, + e.span, + "identical conversion", + "consider removing `.into_iter()`", + sugg, + Applicability::MachineApplicable, // snippet + ); } } }, @@ -95,14 +97,15 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for IdentityConversion { let sugg = snippet(cx, args[0].span.source_callsite(), "").into_owned(); let sugg_msg = format!("consider removing `{}()`", snippet(cx, path.span, "From::from")); - span_lint_and_then(cx, IDENTITY_CONVERSION, e.span, "identical conversion", |diag| { - diag.span_suggestion( - e.span, - &sugg_msg, - sugg, - Applicability::MachineApplicable, // snippet - ); - }); + span_lint_and_sugg( + cx, + IDENTITY_CONVERSION, + e.span, + "identical conversion", + &sugg_msg, + sugg, + Applicability::MachineApplicable, // snippet + ); } } } diff --git a/clippy_lints/src/if_not_else.rs b/clippy_lints/src/if_not_else.rs index 271df5b03e38..c11e291f98e4 100644 --- a/clippy_lints/src/if_not_else.rs +++ b/clippy_lints/src/if_not_else.rs @@ -61,6 +61,7 @@ impl EarlyLintPass for IfNotElse { IF_NOT_ELSE, item.span, "Unnecessary boolean `not` operation", + None, "remove the `!` and swap the blocks of the `if`/`else`", ); }, @@ -70,6 +71,7 @@ impl EarlyLintPass for IfNotElse { IF_NOT_ELSE, item.span, "Unnecessary `!=` operation", + None, "change to `==` and swap the blocks of the `if`/`else`", ); }, diff --git a/clippy_lints/src/indexing_slicing.rs b/clippy_lints/src/indexing_slicing.rs index a2b1085a36e6..c5808dd540b6 100644 --- a/clippy_lints/src/indexing_slicing.rs +++ b/clippy_lints/src/indexing_slicing.rs @@ -138,7 +138,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for IndexingSlicing { (None, None) => return, // [..] is ok. }; - span_lint_and_help(cx, INDEXING_SLICING, expr.span, "slicing may panic.", help_msg); + span_lint_and_help(cx, INDEXING_SLICING, expr.span, "slicing may panic.", None, help_msg); } else { // Catchall non-range index, i.e., [n] or [n << m] if let ty::Array(..) = ty.kind { @@ -154,6 +154,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for IndexingSlicing { INDEXING_SLICING, expr.span, "indexing may panic.", + None, "Consider using `.get(n)` or `.get_mut(n)` instead", ); } diff --git a/clippy_lints/src/inherent_to_string.rs b/clippy_lints/src/inherent_to_string.rs index ca8e834e347c..e343d690f6cd 100644 --- a/clippy_lints/src/inherent_to_string.rs +++ b/clippy_lints/src/inherent_to_string.rs @@ -137,6 +137,7 @@ fn show_lint(cx: &LateContext<'_, '_>, item: &ImplItem<'_>) { "type `{}` implements inherent method `to_string(&self) -> String` which shadows the implementation of `Display`", self_type.to_string() ), + None, &format!("remove the inherent method from type `{}`", self_type.to_string()) ); } else { @@ -148,6 +149,7 @@ fn show_lint(cx: &LateContext<'_, '_>, item: &ImplItem<'_>) { "implementation of inherent method `to_string(&self) -> String` for type `{}`", self_type.to_string() ), + None, &format!("implement trait `Display` for type `{}` instead", self_type.to_string()), ); } diff --git a/clippy_lints/src/int_plus_one.rs b/clippy_lints/src/int_plus_one.rs index 2392ad4d7a12..d5dbd495680b 100644 --- a/clippy_lints/src/int_plus_one.rs +++ b/clippy_lints/src/int_plus_one.rs @@ -5,7 +5,7 @@ use rustc_errors::Applicability; use rustc_lint::{EarlyContext, EarlyLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; -use crate::utils::{snippet_opt, span_lint_and_then}; +use crate::utils::{snippet_opt, span_lint_and_sugg}; declare_clippy_lint! { /// **What it does:** Checks for usage of `x >= y + 1` or `x - 1 >= y` (and `<=`) in a block @@ -149,19 +149,14 @@ impl IntPlusOne { } fn emit_warning(cx: &EarlyContext<'_>, block: &Expr, recommendation: String) { - span_lint_and_then( + span_lint_and_sugg( cx, INT_PLUS_ONE, block.span, "Unnecessary `>= y + 1` or `x - 1 >=`", - |diag| { - diag.span_suggestion( - block.span, - "change it to", - recommendation, - Applicability::MachineApplicable, // snippet - ); - }, + "change it to", + recommendation, + Applicability::MachineApplicable, // snippet ); } } diff --git a/clippy_lints/src/integer_division.rs b/clippy_lints/src/integer_division.rs index 053d66e6af74..fe34d33fe652 100644 --- a/clippy_lints/src/integer_division.rs +++ b/clippy_lints/src/integer_division.rs @@ -35,6 +35,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for IntegerDivision { INTEGER_DIVISION, expr.span, "integer division", + None, "division of integers may cause loss of precision. consider using floats.", ); } diff --git a/clippy_lints/src/large_stack_arrays.rs b/clippy_lints/src/large_stack_arrays.rs index f67fce9697af..deb57db16789 100644 --- a/clippy_lints/src/large_stack_arrays.rs +++ b/clippy_lints/src/large_stack_arrays.rs @@ -57,6 +57,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for LargeStackArrays { "allocating a local array larger than {} bytes", self.maximum_allowed_size ), + None, &format!( "consider allocating on the heap with `vec!{}.into_boxed_slice()`", snippet(cx, expr.span, "[...]") diff --git a/clippy_lints/src/let_underscore.rs b/clippy_lints/src/let_underscore.rs index f8f84f3d42d0..710dec8d33fc 100644 --- a/clippy_lints/src/let_underscore.rs +++ b/clippy_lints/src/let_underscore.rs @@ -90,6 +90,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for LetUnderscore { LET_UNDERSCORE_LOCK, local.span, "non-binding let on a synchronization lock", + None, "consider using an underscore-prefixed named \ binding or dropping explicitly with `std::mem::drop`" ) @@ -99,6 +100,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for LetUnderscore { LET_UNDERSCORE_MUST_USE, local.span, "non-binding let on an expression with `#[must_use]` type", + None, "consider explicitly using expression value" ) } else if is_must_use_func_call(cx, init) { @@ -107,6 +109,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for LetUnderscore { LET_UNDERSCORE_MUST_USE, local.span, "non-binding let on a result of a `#[must_use]` function", + None, "consider explicitly using function result" ) } diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index b8415fa3af12..19c46476263b 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -838,6 +838,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: &unwrap::UNNECESSARY_UNWRAP, &use_self::USE_SELF, &utils::internal_lints::CLIPPY_LINTS_INTERNAL, + &utils::internal_lints::COLLAPSIBLE_SPAN_LINT_CALLS, &utils::internal_lints::COMPILER_LINT_FUNCTIONS, &utils::internal_lints::DEFAULT_LINT, &utils::internal_lints::LINT_WITHOUT_LINT_PASS, @@ -1051,6 +1052,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_late_pass(|| box unnamed_address::UnnamedAddress); store.register_late_pass(|| box dereference::Dereferencing); store.register_late_pass(|| box future_not_send::FutureNotSend); + store.register_late_pass(|| box utils::internal_lints::CollapsibleCalls); store.register_group(true, "clippy::restriction", Some("clippy_restriction"), vec![ LintId::of(&arithmetic::FLOAT_ARITHMETIC), @@ -1162,6 +1164,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_group(true, "clippy::internal", Some("clippy_internal"), vec![ LintId::of(&utils::internal_lints::CLIPPY_LINTS_INTERNAL), + LintId::of(&utils::internal_lints::COLLAPSIBLE_SPAN_LINT_CALLS), LintId::of(&utils::internal_lints::COMPILER_LINT_FUNCTIONS), LintId::of(&utils::internal_lints::DEFAULT_LINT), LintId::of(&utils::internal_lints::LINT_WITHOUT_LINT_PASS), diff --git a/clippy_lints/src/loops.rs b/clippy_lints/src/loops.rs index 3172bbfb406b..d76df908f093 100644 --- a/clippy_lints/src/loops.rs +++ b/clippy_lints/src/loops.rs @@ -1402,6 +1402,7 @@ fn check_arg_type(cx: &LateContext<'_, '_>, pat: &Pat<'_>, arg: &Expr<'_>) { `if let` statement.", snippet(cx, arg.span, "_") ), + None, &format!( "consider replacing `for {0} in {1}` with `if let Some({0}) = {1}`", snippet(cx, pat.span, "_"), @@ -1418,6 +1419,7 @@ fn check_arg_type(cx: &LateContext<'_, '_>, pat: &Pat<'_>, arg: &Expr<'_>) { `if let` statement.", snippet(cx, arg.span, "_") ), + None, &format!( "consider replacing `for {0} in {1}` with `if let Ok({0}) = {1}`", snippet(cx, pat.span, "_"), @@ -2471,45 +2473,53 @@ fn check_needless_collect<'a, 'tcx>(expr: &'tcx Expr<'_>, cx: &LateContext<'a, ' match_type(cx, ty, &paths::HASHMAP) { if method.ident.name == sym!(len) { let span = shorten_needless_collect_span(expr); - span_lint_and_then(cx, NEEDLESS_COLLECT, span, NEEDLESS_COLLECT_MSG, |diag| { - diag.span_suggestion( - span, - "replace with", - ".count()".to_string(), - Applicability::MachineApplicable, - ); - }); + span_lint_and_sugg( + cx, + NEEDLESS_COLLECT, + span, + NEEDLESS_COLLECT_MSG, + "replace with", + ".count()".to_string(), + Applicability::MachineApplicable, + ); } if method.ident.name == sym!(is_empty) { let span = shorten_needless_collect_span(expr); - span_lint_and_then(cx, NEEDLESS_COLLECT, span, NEEDLESS_COLLECT_MSG, |diag| { - diag.span_suggestion( - span, - "replace with", - ".next().is_none()".to_string(), - Applicability::MachineApplicable, - ); - }); + span_lint_and_sugg( + cx, + NEEDLESS_COLLECT, + span, + NEEDLESS_COLLECT_MSG, + "replace with", + ".next().is_none()".to_string(), + Applicability::MachineApplicable, + ); } if method.ident.name == sym!(contains) { let contains_arg = snippet(cx, args[1].span, "??"); let span = shorten_needless_collect_span(expr); - span_lint_and_then(cx, NEEDLESS_COLLECT, span, NEEDLESS_COLLECT_MSG, |diag| { - let (arg, pred) = if contains_arg.starts_with('&') { - ("x", &contains_arg[1..]) - } else { - ("&x", &*contains_arg) - }; - diag.span_suggestion( - span, - "replace with", - format!( - ".any(|{}| x == {})", - arg, pred - ), - Applicability::MachineApplicable, - ); - }); + span_lint_and_then( + cx, + NEEDLESS_COLLECT, + span, + NEEDLESS_COLLECT_MSG, + |diag| { + let (arg, pred) = if contains_arg.starts_with('&') { + ("x", &contains_arg[1..]) + } else { + ("&x", &*contains_arg) + }; + diag.span_suggestion( + span, + "replace with", + format!( + ".any(|{}| x == {})", + arg, pred + ), + Applicability::MachineApplicable, + ); + } + ); } } } diff --git a/clippy_lints/src/main_recursion.rs b/clippy_lints/src/main_recursion.rs index 7854873509ea..8a0e47a3d31c 100644 --- a/clippy_lints/src/main_recursion.rs +++ b/clippy_lints/src/main_recursion.rs @@ -53,6 +53,7 @@ impl LateLintPass<'_, '_> for MainRecursion { MAIN_RECURSION, func.span, &format!("recursing into entrypoint `{}`", snippet(cx, func.span, "main")), + None, "consider using another function for this recursion" ) } diff --git a/clippy_lints/src/matches.rs b/clippy_lints/src/matches.rs index a3a05fd1caa3..270e306e15f7 100644 --- a/clippy_lints/src/matches.rs +++ b/clippy_lints/src/matches.rs @@ -441,6 +441,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Matches { 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", ); } @@ -636,7 +637,7 @@ fn check_overlapping_arms<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, ex: &'tcx Expr<' MATCH_OVERLAPPING_ARM, start.span, "some ranges overlap", - end.span, + Some(end.span), "overlaps with this", ); } @@ -674,7 +675,7 @@ fn check_wild_err_arm(cx: &LateContext<'_, '_>, ex: &Expr<'_>, arms: &[Arm<'_>]) MATCH_WILD_ERR_ARM, arm.pat.span, &format!("`Err({})` matches all errors", &ident_bind_name), - arm.pat.span, + None, "match each error separately or use the error output", ); } @@ -887,6 +888,7 @@ fn check_wild_in_or_pats(cx: &LateContext<'_, '_>, arms: &[Arm<'_>]) { WILDCARD_IN_OR_PATTERNS, arm.pat.span, "wildcard pattern covers any other pattern as it will match anyway.", + None, "Consider handling `_` separately.", ); } diff --git a/clippy_lints/src/mem_replace.rs b/clippy_lints/src/mem_replace.rs index 69639f453233..ab6865bf0f3b 100644 --- a/clippy_lints/src/mem_replace.rs +++ b/clippy_lints/src/mem_replace.rs @@ -148,6 +148,7 @@ fn check_replace_with_uninit(cx: &LateContext<'_, '_>, src: &Expr<'_>, expr_span MEM_REPLACE_WITH_UNINIT, expr_span, "replacing with `mem::uninitialized()`", + None, "consider using the `take_mut` crate instead", ); } else if cx.tcx.is_diagnostic_item(sym::mem_zeroed, repl_def_id) && @@ -157,6 +158,7 @@ fn check_replace_with_uninit(cx: &LateContext<'_, '_>, src: &Expr<'_>, expr_span MEM_REPLACE_WITH_UNINIT, expr_span, "replacing with `mem::zeroed()`", + None, "consider using a default value or the `take_mut` crate instead", ); } diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 2337380c7dd1..7c652229d33d 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -2255,6 +2255,7 @@ fn lint_iter_nth<'a, 'tcx>( ITER_NTH, expr.span, &format!("called `.iter{0}().nth()` on a {1}", mut_str, caller_type), + None, &format!("calling `.get{}()` is both faster and more readable", mut_str), ); } @@ -2364,6 +2365,7 @@ fn lint_iter_skip_next(cx: &LateContext<'_, '_>, expr: &hir::Expr<'_>) { ITER_SKIP_NEXT, expr.span, "called `skip(x).next()` on an iterator", + None, "this is more succinctly expressed by calling `nth(x)`", ); } @@ -2431,6 +2433,7 @@ fn lint_unwrap(cx: &LateContext<'_, '_>, expr: &hir::Expr<'_>, unwrap_args: &[hi lint, expr.span, &format!("used `unwrap()` on `{}` value", kind,), + None, &format!( "if you don't want to handle the `{}` case gracefully, consider \ using `expect()` to provide a better panic message", @@ -2458,6 +2461,7 @@ fn lint_expect(cx: &LateContext<'_, '_>, expr: &hir::Expr<'_>, expect_args: &[hi lint, expr.span, &format!("used `expect()` on `{}` value", kind,), + None, &format!("if this value is an `{}`, it will panic", none_value,), ); } @@ -2478,6 +2482,7 @@ fn lint_ok_expect(cx: &LateContext<'_, '_>, expr: &hir::Expr<'_>, ok_args: &[hir OK_EXPECT, expr.span, "called `ok().expect()` on a `Result` value", + None, "you can call `expect()` directly on the `Result`", ); } @@ -2572,7 +2577,7 @@ fn lint_map_unwrap_or_else<'a, 'tcx>( }, expr.span, msg, - expr.span, + None, &format!( "replace `map({0}).unwrap_or_else({1})` with `map_or_else({1}, {0})`", map_snippet, unwrap_snippet, @@ -2752,7 +2757,7 @@ fn lint_filter_next<'a, 'tcx>( FILTER_NEXT, expr.span, msg, - expr.span, + None, &format!("replace `filter({0}).next()` with `find({0})`", filter_snippet), ); } else { @@ -2774,6 +2779,7 @@ fn lint_skip_while_next<'a, 'tcx>( SKIP_WHILE_NEXT, expr.span, "called `skip_while(p).next()` on an `Iterator`", + None, "this is more succinctly expressed by calling `.find(!p)` instead", ); } @@ -2790,7 +2796,7 @@ fn lint_filter_map<'a, 'tcx>( if match_trait_method(cx, expr, &paths::ITERATOR) { let msg = "called `filter(p).map(q)` on an `Iterator`"; let hint = "this is more succinctly expressed by calling `.filter_map(..)` instead"; - span_lint_and_help(cx, FILTER_MAP, expr.span, msg, hint); + span_lint_and_help(cx, FILTER_MAP, expr.span, msg, None, hint); } } @@ -2810,7 +2816,7 @@ fn lint_filter_map_next<'a, 'tcx>( FILTER_MAP_NEXT, expr.span, msg, - expr.span, + None, &format!("replace `filter_map({0}).next()` with `find_map({0})`", filter_snippet), ); } else { @@ -2830,7 +2836,7 @@ fn lint_find_map<'a, 'tcx>( if match_trait_method(cx, &map_args[0], &paths::ITERATOR) { let msg = "called `find(p).map(q)` on an `Iterator`"; let hint = "this is more succinctly expressed by calling `.find_map(..)` instead"; - span_lint_and_help(cx, FIND_MAP, expr.span, msg, hint); + span_lint_and_help(cx, FIND_MAP, expr.span, msg, None, hint); } } @@ -2845,7 +2851,7 @@ fn lint_filter_map_map<'a, 'tcx>( if match_trait_method(cx, expr, &paths::ITERATOR) { let msg = "called `filter_map(p).map(q)` on an `Iterator`"; let hint = "this is more succinctly expressed by only calling `.filter_map(..)` instead"; - span_lint_and_help(cx, FILTER_MAP, expr.span, msg, hint); + span_lint_and_help(cx, FILTER_MAP, expr.span, msg, None, hint); } } @@ -2861,7 +2867,7 @@ fn lint_filter_flat_map<'a, 'tcx>( let msg = "called `filter(p).flat_map(q)` on an `Iterator`"; let hint = "this is more succinctly expressed by calling `.flat_map(..)` \ and filtering by returning `iter::empty()`"; - span_lint_and_help(cx, FILTER_MAP, expr.span, msg, hint); + span_lint_and_help(cx, FILTER_MAP, expr.span, msg, None, hint); } } @@ -2877,7 +2883,7 @@ fn lint_filter_map_flat_map<'a, 'tcx>( let msg = "called `filter_map(p).flat_map(q)` on an `Iterator`"; let hint = "this is more succinctly expressed by calling `.flat_map(..)` \ and filtering by returning `iter::empty()`"; - span_lint_and_help(cx, FILTER_MAP, expr.span, msg, hint); + span_lint_and_help(cx, FILTER_MAP, expr.span, msg, None, hint); } } @@ -3260,6 +3266,7 @@ fn lint_suspicious_map(cx: &LateContext<'_, '_>, expr: &hir::Expr<'_>) { SUSPICIOUS_MAP, expr.span, "this call to `map()` won't have an effect on the call to `count()`", + None, "make sure you did not confuse `map` with `filter` or `for_each`", ); } @@ -3640,7 +3647,7 @@ fn lint_filetype_is_file(cx: &LateContext<'_, '_>, expr: &hir::Expr<'_>, args: & } let lint_msg = format!("`{}FileType::is_file()` only {} regular files", lint_unary, verb); let help_msg = format!("use `{}FileType::is_dir()` instead", help_unary); - span_lint_and_help(cx, FILETYPE_IS_FILE, span, &lint_msg, &help_msg); + span_lint_and_help(cx, FILETYPE_IS_FILE, span, &lint_msg, None, &help_msg); } fn fn_header_equals(expected: hir::FnHeader, actual: hir::FnHeader) -> bool { diff --git a/clippy_lints/src/misc_early.rs b/clippy_lints/src/misc_early.rs index 75bbf0514c2d..adfd8dfb1c18 100644 --- a/clippy_lints/src/misc_early.rs +++ b/clippy_lints/src/misc_early.rs @@ -313,6 +313,7 @@ impl EarlyLintPass for MiscEarlyLints { UNNEEDED_FIELD_PATTERN, pat.span, "All the struct fields are matched to a wildcard pattern, consider using `..`.", + None, &format!("Try with `{} {{ .. }}` instead", type_name), ); return; @@ -348,6 +349,7 @@ impl EarlyLintPass for MiscEarlyLints { field.span, "You matched a field with a wildcard pattern. Consider using `..` \ instead", + None, &format!("Try with `{} {{ {}, .. }}`", type_name, normal[..].join(", ")), ); } diff --git a/clippy_lints/src/needless_continue.rs b/clippy_lints/src/needless_continue.rs index 6be4b1effeae..28183810df48 100644 --- a/clippy_lints/src/needless_continue.rs +++ b/clippy_lints/src/needless_continue.rs @@ -304,6 +304,7 @@ fn emit_warning<'a>(cx: &EarlyContext<'_>, data: &'a LintData<'_>, header: &str, NEEDLESS_CONTINUE, expr.span, message, + None, &format!("{}\n{}", header, snip), ); } diff --git a/clippy_lints/src/option_env_unwrap.rs b/clippy_lints/src/option_env_unwrap.rs index 96ab4238008d..66dfa20edb5e 100644 --- a/clippy_lints/src/option_env_unwrap.rs +++ b/clippy_lints/src/option_env_unwrap.rs @@ -46,6 +46,7 @@ impl EarlyLintPass for OptionEnvUnwrap { OPTION_ENV_UNWRAP, expr.span, "this will panic at run-time if the environment variable doesn't exist at compile-time", + None, "consider using the `env!` macro instead" ); } diff --git a/clippy_lints/src/ptr.rs b/clippy_lints/src/ptr.rs index c190ed42e3f0..1e2afb7a6740 100644 --- a/clippy_lints/src/ptr.rs +++ b/clippy_lints/src/ptr.rs @@ -2,8 +2,8 @@ use crate::utils::ptr::get_spans; use crate::utils::{ - is_type_diagnostic_item, match_qpath, match_type, paths, snippet_opt, span_lint, span_lint_and_then, - walk_ptrs_hir_ty, + is_type_diagnostic_item, match_qpath, match_type, paths, snippet_opt, span_lint, span_lint_and_sugg, + span_lint_and_then, walk_ptrs_hir_ty, }; use if_chain::if_chain; use rustc_errors::Applicability; @@ -234,19 +234,14 @@ fn check_fn(cx: &LateContext<'_, '_>, decl: &FnDecl<'_>, fn_id: HirId, opt_body_ then { let replacement = snippet_opt(cx, inner.span); if let Some(r) = replacement { - span_lint_and_then( + span_lint_and_sugg( cx, PTR_ARG, arg.span, "using a reference to `Cow` is not recommended.", - |diag| { - diag.span_suggestion( - arg.span, - "change this to", - "&".to_owned() + &r, - Applicability::Unspecified, - ); - }, + "change this to", + "&".to_owned() + &r, + Applicability::Unspecified, ); } } diff --git a/clippy_lints/src/regex.rs b/clippy_lints/src/regex.rs index 4bcb9198792d..30084e3e1ffc 100644 --- a/clippy_lints/src/regex.rs +++ b/clippy_lints/src/regex.rs @@ -208,7 +208,7 @@ fn check_regex<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr<'_>, utf8: match parser.parse(r) { Ok(r) => { if let Some(repl) = is_trivial_regex(&r) { - span_lint_and_help(cx, TRIVIAL_REGEX, expr.span, "trivial regex", repl); + span_lint_and_help(cx, TRIVIAL_REGEX, expr.span, "trivial regex", None, repl); } }, Err(regex_syntax::Error::Parse(e)) => { @@ -236,7 +236,7 @@ fn check_regex<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr<'_>, utf8: match parser.parse(&r) { Ok(r) => { if let Some(repl) = is_trivial_regex(&r) { - span_lint_and_help(cx, TRIVIAL_REGEX, expr.span, "trivial regex", repl); + span_lint_and_help(cx, TRIVIAL_REGEX, expr.span, "trivial regex", None, repl); } }, Err(regex_syntax::Error::Parse(e)) => { diff --git a/clippy_lints/src/returns.rs b/clippy_lints/src/returns.rs index f7ab00b73047..5c9117d5b81c 100644 --- a/clippy_lints/src/returns.rs +++ b/clippy_lints/src/returns.rs @@ -8,7 +8,7 @@ use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::source_map::Span; use rustc_span::BytePos; -use crate::utils::{in_macro, match_path_ast, snippet_opt, span_lint_and_then}; +use crate::utils::{in_macro, match_path_ast, snippet_opt, span_lint_and_sugg, span_lint_and_then}; declare_clippy_lint! { /// **What it does:** Checks for return statements at the end of a block. @@ -162,24 +162,26 @@ impl Return { }, None => match replacement { RetReplacement::Empty => { - span_lint_and_then(cx, NEEDLESS_RETURN, ret_span, "unneeded `return` statement", |diag| { - diag.span_suggestion( - ret_span, - "remove `return`", - String::new(), - Applicability::MachineApplicable, - ); - }); + span_lint_and_sugg( + cx, + NEEDLESS_RETURN, + ret_span, + "unneeded `return` statement", + "remove `return`", + String::new(), + Applicability::MachineApplicable, + ); }, RetReplacement::Block => { - span_lint_and_then(cx, NEEDLESS_RETURN, ret_span, "unneeded `return` statement", |diag| { - diag.span_suggestion( - ret_span, - "replace `return` with an empty block", - "{}".to_string(), - Applicability::MachineApplicable, - ); - }); + span_lint_and_sugg( + cx, + NEEDLESS_RETURN, + ret_span, + "unneeded `return` statement", + "replace `return` with an empty block", + "{}".to_string(), + Applicability::MachineApplicable, + ); }, }, } @@ -259,14 +261,15 @@ impl EarlyLintPass for Return { } else { (ty.span, Applicability::MaybeIncorrect) }; - span_lint_and_then(cx, UNUSED_UNIT, rspan, "unneeded unit return type", |diag| { - diag.span_suggestion( - rspan, - "remove the `-> ()`", - String::new(), - appl, - ); - }); + span_lint_and_sugg( + cx, + UNUSED_UNIT, + rspan, + "unneeded unit return type", + "remove the `-> ()`", + String::new(), + appl, + ); } } } @@ -279,14 +282,15 @@ impl EarlyLintPass for Return { if is_unit_expr(expr) && !stmt.span.from_expansion(); then { let sp = expr.span; - span_lint_and_then(cx, UNUSED_UNIT, sp, "unneeded unit expression", |diag| { - diag.span_suggestion( - sp, - "remove the final `()`", - String::new(), - Applicability::MachineApplicable, - ); - }); + span_lint_and_sugg( + cx, + UNUSED_UNIT, + sp, + "unneeded unit expression", + "remove the final `()`", + String::new(), + Applicability::MachineApplicable, + ); } } } @@ -295,14 +299,15 @@ impl EarlyLintPass for Return { match e.kind { ast::ExprKind::Ret(Some(ref expr)) | ast::ExprKind::Break(_, Some(ref expr)) => { if is_unit_expr(expr) && !expr.span.from_expansion() { - span_lint_and_then(cx, UNUSED_UNIT, expr.span, "unneeded `()`", |diag| { - diag.span_suggestion( - expr.span, - "remove the `()`", - String::new(), - Applicability::MachineApplicable, - ); - }); + span_lint_and_sugg( + cx, + UNUSED_UNIT, + expr.span, + "unneeded `()`", + "remove the `()`", + String::new(), + Applicability::MachineApplicable, + ); } }, _ => (), diff --git a/clippy_lints/src/trait_bounds.rs b/clippy_lints/src/trait_bounds.rs index 075df19a71e2..67121729663c 100644 --- a/clippy_lints/src/trait_bounds.rs +++ b/clippy_lints/src/trait_bounds.rs @@ -76,6 +76,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for TraitBounds { TYPE_REPETITION_IN_BOUNDS, p.span, "this type has already been used as a bound predicate", + None, &hint_string, ); } diff --git a/clippy_lints/src/transmute.rs b/clippy_lints/src/transmute.rs index b99d583c4bec..e24d2c4f495d 100644 --- a/clippy_lints/src/transmute.rs +++ b/clippy_lints/src/transmute.rs @@ -1,5 +1,6 @@ use crate::utils::{ - is_normalizable, last_path_segment, match_def_path, paths, snippet, span_lint, span_lint_and_then, sugg, + is_normalizable, last_path_segment, match_def_path, paths, snippet, span_lint, span_lint_and_sugg, + span_lint_and_then, sugg, }; use if_chain::if_chain; use rustc_ast::ast; @@ -441,24 +442,19 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Transmute { "" }; - span_lint_and_then( + span_lint_and_sugg( cx, TRANSMUTE_BYTES_TO_STR, e.span, &format!("transmute from a `{}` to a `{}`", from_ty, to_ty), - |diag| { - diag.span_suggestion( - e.span, - "consider using", - format!( - "std::str::from_utf8{}({}).unwrap()", - postfix, - snippet(cx, args[0].span, ".."), - ), - Applicability::Unspecified, - ); - } - ) + "consider using", + format!( + "std::str::from_utf8{}({}).unwrap()", + postfix, + snippet(cx, args[0].span, ".."), + ), + Applicability::Unspecified, + ); } else { if cx.tcx.erase_regions(&from_ty) != cx.tcx.erase_regions(&to_ty) { span_lint_and_then( diff --git a/clippy_lints/src/types.rs b/clippy_lints/src/types.rs index 153a2b7249c1..4d853b99bafa 100644 --- a/clippy_lints/src/types.rs +++ b/clippy_lints/src/types.rs @@ -343,6 +343,7 @@ impl Types { BOX_VEC, hir_ty.span, "you seem to be trying to use `Box>`. Consider using just `Vec`", + None, "`Vec` is already on the heap, `Box>` makes an extra allocation.", ); return; // don't recurse into the type @@ -437,6 +438,7 @@ impl Types { LINKEDLIST, hir_ty.span, "I see you're using a LinkedList! Perhaps you meant some other data structure?", + None, "a `VecDeque` might work", ); return; // don't recurse into the type @@ -1900,7 +1902,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for AbsurdExtremeComparisons { conclusion ); - span_lint_and_help(cx, ABSURD_EXTREME_COMPARISONS, expr.span, msg, &help); + span_lint_and_help(cx, ABSURD_EXTREME_COMPARISONS, expr.span, msg, None, &help); } } } diff --git a/clippy_lints/src/unnamed_address.rs b/clippy_lints/src/unnamed_address.rs index b6473fc594ee..4e077b95b5c6 100644 --- a/clippy_lints/src/unnamed_address.rs +++ b/clippy_lints/src/unnamed_address.rs @@ -89,6 +89,7 @@ impl LateLintPass<'_, '_> for UnnamedAddress { VTABLE_ADDRESS_COMPARISONS, expr.span, "comparing trait object pointers compares a non-unique vtable address", + None, "consider extracting and comparing data pointers only", ); } @@ -109,6 +110,7 @@ impl LateLintPass<'_, '_> for UnnamedAddress { VTABLE_ADDRESS_COMPARISONS, expr.span, "comparing trait object pointers compares a non-unique vtable address", + None, "consider extracting and comparing data pointers only", ); } diff --git a/clippy_lints/src/unused_self.rs b/clippy_lints/src/unused_self.rs index 4483059e9eca..3d5e2f9fd215 100644 --- a/clippy_lints/src/unused_self.rs +++ b/clippy_lints/src/unused_self.rs @@ -69,6 +69,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnusedSelf { UNUSED_SELF, self_param.span, "unused `self` argument", + None, "consider refactoring to a associated function", ); return; diff --git a/clippy_lints/src/utils/diagnostics.rs b/clippy_lints/src/utils/diagnostics.rs index 4ad6689f3e06..093ef3191088 100644 --- a/clippy_lints/src/utils/diagnostics.rs +++ b/clippy_lints/src/utils/diagnostics.rs @@ -62,10 +62,21 @@ pub fn span_lint(cx: &T, lint: &'static Lint, sp: impl Into(cx: &'a T, lint: &'static Lint, span: Span, msg: &str, help: &str) { +pub fn span_lint_and_help<'a, T: LintContext>( + cx: &'a T, + lint: &'static Lint, + span: Span, + msg: &str, + help_span: Option, + help: &str, +) { cx.struct_span_lint(lint, span, |diag| { let mut diag = diag.build(msg); - diag.help(help); + if let Some(help_span) = help_span { + diag.span_help(help_span, help); + } else { + diag.help(help); + } docs_link(&mut diag, lint); diag.emit(); }); @@ -97,15 +108,15 @@ pub fn span_lint_and_note<'a, T: LintContext>( lint: &'static Lint, span: Span, msg: &str, - note_span: Span, + note_span: Option, note: &str, ) { cx.struct_span_lint(lint, span, |diag| { let mut diag = diag.build(msg); - if note_span == span { - diag.note(note); - } else { + if let Some(note_span) = note_span { diag.span_note(note_span, note); + } else { + diag.note(note); } docs_link(&mut diag, lint); diag.emit(); @@ -166,6 +177,7 @@ pub fn span_lint_hir_and_then( /// | /// = note: `-D fold-any` implied by `-D warnings` /// ``` +#[allow(clippy::collapsible_span_lint_calls)] pub fn span_lint_and_sugg<'a, T: LintContext>( cx: &'a T, lint: &'static Lint, diff --git a/clippy_lints/src/utils/internal_lints.rs b/clippy_lints/src/utils/internal_lints.rs index bc2200800de3..6eb6c2d98e91 100644 --- a/clippy_lints/src/utils/internal_lints.rs +++ b/clippy_lints/src/utils/internal_lints.rs @@ -1,6 +1,7 @@ +use crate::utils::SpanlessEq; use crate::utils::{ - is_expn_of, match_def_path, match_type, method_calls, paths, span_lint, span_lint_and_help, span_lint_and_sugg, - walk_ptrs_ty, + is_expn_of, match_def_path, match_qpath, match_type, method_calls, paths, snippet, span_lint, span_lint_and_help, + span_lint_and_sugg, walk_ptrs_ty, }; use if_chain::if_chain; use rustc_ast::ast::{Crate as AstCrate, ItemKind, LitKind, Name, NodeId}; @@ -10,13 +11,15 @@ use rustc_errors::Applicability; use rustc_hir as hir; use rustc_hir::def::{DefKind, Res}; use rustc_hir::intravisit::{walk_expr, NestedVisitorMap, Visitor}; -use rustc_hir::{Crate, Expr, ExprKind, HirId, Item, MutTy, Mutability, Path, Ty, TyKind}; +use rustc_hir::{Crate, Expr, ExprKind, HirId, Item, MutTy, Mutability, Path, StmtKind, Ty, TyKind}; use rustc_lint::{EarlyContext, EarlyLintPass, LateContext, LateLintPass}; use rustc_middle::hir::map::Map; use rustc_session::{declare_lint_pass, declare_tool_lint, impl_lint_pass}; use rustc_span::source_map::{Span, Spanned}; use rustc_span::symbol::SymbolStr; +use std::borrow::{Borrow, Cow}; + declare_clippy_lint! { /// **What it does:** Checks for various things we like to keep tidy in clippy. /// @@ -142,6 +145,67 @@ declare_clippy_lint! { "found 'default lint description' in a lint declaration" } +declare_clippy_lint! { + /// **What it does:** Lints `span_lint_and_then` function calls, where the + /// closure argument has only one statement and that statement is a method + /// call to `span_suggestion`, `span_help`, `span_note` (using the same + /// span), `help` or `note`. + /// + /// These usages of `span_lint_and_then` should be replaced with one of the + /// wrapper functions `span_lint_and_sugg`, span_lint_and_help`, or + /// `span_lint_and_note`. + /// + /// **Why is this bad?** Using the wrapper `span_lint_and_*` functions, is more + /// convenient, readable and less error prone. + /// + /// **Known problems:** None + /// + /// *Example:** + /// Bad: + /// ```rust,ignore + /// span_lint_and_then(cx, TEST_LINT, expr.span, lint_msg, |diag| { + /// diag.span_suggestion( + /// expr.span, + /// help_msg, + /// sugg.to_string(), + /// Applicability::MachineApplicable, + /// ); + /// }); + /// span_lint_and_then(cx, TEST_LINT, expr.span, lint_msg, |diag| { + /// diag.span_help(expr.span, help_msg); + /// }); + /// span_lint_and_then(cx, TEST_LINT, expr.span, lint_msg, |diag| { + /// diag.help(help_msg); + /// }); + /// span_lint_and_then(cx, TEST_LINT, expr.span, lint_msg, |diag| { + /// diag.span_note(expr.span, note_msg); + /// }); + /// span_lint_and_then(cx, TEST_LINT, expr.span, lint_msg, |diag| { + /// diag.note(note_msg); + /// }); + /// ``` + /// + /// Good: + /// ```rust,ignore + /// span_lint_and_sugg( + /// cx, + /// TEST_LINT, + /// expr.span, + /// lint_msg, + /// help_msg, + /// sugg.to_string(), + /// Applicability::MachineApplicable, + /// ); + /// span_lint_and_help(cx, TEST_LINT, expr.span, lint_msg, Some(expr.span), help_msg); + /// span_lint_and_help(cx, TEST_LINT, expr.span, lint_msg, None, help_msg); + /// span_lint_and_note(cx, TEST_LINT, expr.span, lint_msg, Some(expr.span), note_msg); + /// span_lint_and_note(cx, TEST_LINT, expr.span, lint_msg, None, note_msg); + /// ``` + pub COLLAPSIBLE_SPAN_LINT_CALLS, + internal, + "found collapsible `span_lint_and_then` calls" +} + declare_lint_pass!(ClippyLintsInternal => [CLIPPY_LINTS_INTERNAL]); impl EarlyLintPass for ClippyLintsInternal { @@ -194,9 +258,10 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for LintWithoutLintPass { if_chain! { if let ExprKind::AddrOf(_, _, ref inner_exp) = expr.kind; if let ExprKind::Struct(_, ref fields, _) = inner_exp.kind; - let field = fields.iter() - .find(|f| f.ident.as_str() == "desc") - .expect("lints must have a description field"); + let field = fields + .iter() + .find(|f| f.ident.as_str() == "desc") + .expect("lints must have a description field"); if let ExprKind::Lit(Spanned { node: LitKind::Str(ref sym, _), .. @@ -339,6 +404,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for CompilerLintFunctions { COMPILER_LINT_FUNCTIONS, path.ident.span, "usage of a compiler lint function", + None, &format!("please use the Clippy variant of this function: `{}`", sugg), ); } @@ -391,3 +457,184 @@ fn is_trigger_fn(fn_kind: FnKind<'_>) -> bool { FnKind::Closure(..) => false, } } + +declare_lint_pass!(CollapsibleCalls => [COLLAPSIBLE_SPAN_LINT_CALLS]); + +impl<'a, 'tcx> LateLintPass<'a, 'tcx> for CollapsibleCalls { + fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx hir::Expr<'_>) { + if_chain! { + if let ExprKind::Call(ref func, ref and_then_args) = expr.kind; + if let ExprKind::Path(ref path) = func.kind; + if match_qpath(path, &["span_lint_and_then"]); + if and_then_args.len() == 5; + if let ExprKind::Closure(_, _, body_id, _, _) = &and_then_args[4].kind; + let body = cx.tcx.hir().body(*body_id); + if let ExprKind::Block(block, _) = &body.value.kind; + let stmts = &block.stmts; + if stmts.len() == 1 && block.expr.is_none(); + if let StmtKind::Semi(only_expr) = &stmts[0].kind; + if let ExprKind::MethodCall(ref ps, _, ref span_call_args) = &only_expr.kind; + let and_then_snippets = get_and_then_snippets(cx, and_then_args); + let mut sle = SpanlessEq::new(cx).ignore_fn(); + then { + match &*ps.ident.as_str() { + "span_suggestion" if sle.eq_expr(&and_then_args[2], &span_call_args[1]) => { + suggest_suggestion(cx, expr, &and_then_snippets, &span_suggestion_snippets(cx, span_call_args)); + }, + "span_help" if sle.eq_expr(&and_then_args[2], &span_call_args[1]) => { + let help_snippet = snippet(cx, span_call_args[2].span, r#""...""#); + suggest_help(cx, expr, &and_then_snippets, help_snippet.borrow(), true); + }, + "span_note" if sle.eq_expr(&and_then_args[2], &span_call_args[1]) => { + let note_snippet = snippet(cx, span_call_args[2].span, r#""...""#); + suggest_note(cx, expr, &and_then_snippets, note_snippet.borrow(), true); + }, + "help" => { + let help_snippet = snippet(cx, span_call_args[1].span, r#""...""#); + suggest_help(cx, expr, &and_then_snippets, help_snippet.borrow(), false); + } + "note" => { + let note_snippet = snippet(cx, span_call_args[1].span, r#""...""#); + suggest_note(cx, expr, &and_then_snippets, note_snippet.borrow(), false); + } + _ => (), + } + } + } + } +} + +struct AndThenSnippets<'a> { + cx: Cow<'a, str>, + lint: Cow<'a, str>, + span: Cow<'a, str>, + msg: Cow<'a, str>, +} + +fn get_and_then_snippets<'a, 'hir>( + cx: &LateContext<'_, '_>, + and_then_snippets: &'hir [Expr<'hir>], +) -> AndThenSnippets<'a> { + let cx_snippet = snippet(cx, and_then_snippets[0].span, "cx"); + let lint_snippet = snippet(cx, and_then_snippets[1].span, ".."); + let span_snippet = snippet(cx, and_then_snippets[2].span, "span"); + let msg_snippet = snippet(cx, and_then_snippets[3].span, r#""...""#); + + AndThenSnippets { + cx: cx_snippet, + lint: lint_snippet, + span: span_snippet, + msg: msg_snippet, + } +} + +struct SpanSuggestionSnippets<'a> { + help: Cow<'a, str>, + sugg: Cow<'a, str>, + applicability: Cow<'a, str>, +} + +fn span_suggestion_snippets<'a, 'hir>( + cx: &LateContext<'_, '_>, + span_call_args: &'hir [Expr<'hir>], +) -> SpanSuggestionSnippets<'a> { + let help_snippet = snippet(cx, span_call_args[2].span, r#""...""#); + let sugg_snippet = snippet(cx, span_call_args[3].span, ".."); + let applicability_snippet = snippet(cx, span_call_args[4].span, "Applicability::MachineApplicable"); + + SpanSuggestionSnippets { + help: help_snippet, + sugg: sugg_snippet, + applicability: applicability_snippet, + } +} + +fn suggest_suggestion( + cx: &LateContext<'_, '_>, + expr: &Expr<'_>, + and_then_snippets: &AndThenSnippets<'_>, + span_suggestion_snippets: &SpanSuggestionSnippets<'_>, +) { + span_lint_and_sugg( + cx, + COLLAPSIBLE_SPAN_LINT_CALLS, + expr.span, + "this call is collapsible", + "collapse into", + format!( + "span_lint_and_sugg({}, {}, {}, {}, {}, {}, {})", + and_then_snippets.cx, + and_then_snippets.lint, + and_then_snippets.span, + and_then_snippets.msg, + span_suggestion_snippets.help, + span_suggestion_snippets.sugg, + span_suggestion_snippets.applicability + ), + Applicability::MachineApplicable, + ); +} + +fn suggest_help( + cx: &LateContext<'_, '_>, + expr: &Expr<'_>, + and_then_snippets: &AndThenSnippets<'_>, + help: &str, + with_span: bool, +) { + let option_span = if with_span { + format!("Some({})", and_then_snippets.span) + } else { + "None".to_string() + }; + + span_lint_and_sugg( + cx, + COLLAPSIBLE_SPAN_LINT_CALLS, + expr.span, + "this call is collapsible", + "collapse into", + format!( + "span_lint_and_help({}, {}, {}, {}, {}, {})", + and_then_snippets.cx, + and_then_snippets.lint, + and_then_snippets.span, + and_then_snippets.msg, + &option_span, + help + ), + Applicability::MachineApplicable, + ); +} + +fn suggest_note( + cx: &LateContext<'_, '_>, + expr: &Expr<'_>, + and_then_snippets: &AndThenSnippets<'_>, + note: &str, + with_span: bool, +) { + let note_span = if with_span { + format!("Some({})", and_then_snippets.span) + } else { + "None".to_string() + }; + + span_lint_and_sugg( + cx, + COLLAPSIBLE_SPAN_LINT_CALLS, + expr.span, + "this call is collspible", + "collapse into", + format!( + "span_lint_and_note({}, {}, {}, {}, {}, {})", + and_then_snippets.cx, + and_then_snippets.lint, + and_then_snippets.span, + and_then_snippets.msg, + note_span, + note + ), + Applicability::MachineApplicable, + ); +} diff --git a/clippy_lints/src/verbose_file_reads.rs b/clippy_lints/src/verbose_file_reads.rs index 55d7983249ae..4d8d4438d881 100644 --- a/clippy_lints/src/verbose_file_reads.rs +++ b/clippy_lints/src/verbose_file_reads.rs @@ -40,6 +40,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for VerboseFileReads { VERBOSE_FILE_READS, expr.span, "use of `File::read_to_end`", + None, "consider using `fs::read` instead", ); } else if is_file_read_to_string(cx, expr) { @@ -48,6 +49,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for VerboseFileReads { VERBOSE_FILE_READS, expr.span, "use of `File::read_to_string`", + None, "consider using `fs::read_to_string` instead", ) } diff --git a/clippy_lints/src/zero_div_zero.rs b/clippy_lints/src/zero_div_zero.rs index afd10d9ed53f..fb4700d8743f 100644 --- a/clippy_lints/src/zero_div_zero.rs +++ b/clippy_lints/src/zero_div_zero.rs @@ -49,6 +49,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for ZeroDiv { ZERO_DIVIDED_BY_ZERO, expr.span, "constant division of `0.0` with `0.0` will always result in NaN", + None, &format!( "Consider using `{}::NAN` if you would like a constant representing NaN", float_type, diff --git a/doc/adding_lints.md b/doc/adding_lints.md index a66d4e66add2..94d6ccb316ea 100644 --- a/doc/adding_lints.md +++ b/doc/adding_lints.md @@ -265,6 +265,7 @@ impl EarlyLintPass for FooFunctions { FOO_FUNCTIONS, span, "function named `foo`", + None, "consider using a more meaningful name" ); } @@ -296,6 +297,7 @@ impl EarlyLintPass for FooFunctions { FOO_FUNCTIONS, span, "function named `foo`", + None, "consider using a more meaningful name" ); } diff --git a/tests/ui/collapsible_span_lint_calls.fixed b/tests/ui/collapsible_span_lint_calls.fixed new file mode 100644 index 000000000000..e588c23345e2 --- /dev/null +++ b/tests/ui/collapsible_span_lint_calls.fixed @@ -0,0 +1,91 @@ +// run-rustfix +#![deny(clippy::internal)] +#![feature(rustc_private)] + +extern crate rustc_ast; +extern crate rustc_errors; +extern crate rustc_lint; +extern crate rustc_session; +extern crate rustc_span; + +use rustc_ast::ast::Expr; +use rustc_errors::{Applicability, DiagnosticBuilder}; +use rustc_lint::{EarlyContext, EarlyLintPass, Lint, LintContext}; +use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_span::source_map::Span; + +#[allow(unused_variables)] +pub fn span_lint_and_then<'a, T: LintContext, F>(cx: &'a T, lint: &'static Lint, sp: Span, msg: &str, f: F) +where + F: for<'b> FnOnce(&mut DiagnosticBuilder<'b>), +{ +} + +#[allow(unused_variables)] +fn span_lint_and_help<'a, T: LintContext>( + cx: &'a T, + lint: &'static Lint, + span: Span, + msg: &str, + option_span: Option, + help: &str, +) { +} + +#[allow(unused_variables)] +fn span_lint_and_note<'a, T: LintContext>( + cx: &'a T, + lint: &'static Lint, + span: Span, + msg: &str, + note_span: Option, + note: &str, +) { +} + +#[allow(unused_variables)] +fn span_lint_and_sugg<'a, T: LintContext>( + cx: &'a T, + lint: &'static Lint, + sp: Span, + msg: &str, + help: &str, + sugg: String, + applicability: Applicability, +) { +} + +declare_tool_lint! { + pub clippy::TEST_LINT, + Warn, + "", + report_in_external_macro: true +} + +declare_lint_pass!(Pass => [TEST_LINT]); + +impl EarlyLintPass for Pass { + fn check_expr(&mut self, cx: &EarlyContext, expr: &Expr) { + let lint_msg = "lint message"; + let help_msg = "help message"; + let note_msg = "note message"; + let sugg = "new_call()"; + let predicate = true; + + span_lint_and_sugg(cx, TEST_LINT, expr.span, lint_msg, help_msg, sugg.to_string(), Applicability::MachineApplicable); + span_lint_and_help(cx, TEST_LINT, expr.span, lint_msg, Some(expr.span), help_msg); + span_lint_and_help(cx, TEST_LINT, expr.span, lint_msg, None, help_msg); + span_lint_and_note(cx, TEST_LINT, expr.span, lint_msg, Some(expr.span), note_msg); + span_lint_and_note(cx, TEST_LINT, expr.span, lint_msg, None, note_msg); + + // This expr shouldn't trigger this lint. + span_lint_and_then(cx, TEST_LINT, expr.span, lint_msg, |db| { + db.note(note_msg); + if predicate { + db.note(note_msg); + } + }) + } +} + +fn main() {} diff --git a/tests/ui/collapsible_span_lint_calls.rs b/tests/ui/collapsible_span_lint_calls.rs new file mode 100644 index 000000000000..d5dd3bb562b4 --- /dev/null +++ b/tests/ui/collapsible_span_lint_calls.rs @@ -0,0 +1,101 @@ +// run-rustfix +#![deny(clippy::internal)] +#![feature(rustc_private)] + +extern crate rustc_ast; +extern crate rustc_errors; +extern crate rustc_lint; +extern crate rustc_session; +extern crate rustc_span; + +use rustc_ast::ast::Expr; +use rustc_errors::{Applicability, DiagnosticBuilder}; +use rustc_lint::{EarlyContext, EarlyLintPass, Lint, LintContext}; +use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_span::source_map::Span; + +#[allow(unused_variables)] +pub fn span_lint_and_then<'a, T: LintContext, F>(cx: &'a T, lint: &'static Lint, sp: Span, msg: &str, f: F) +where + F: for<'b> FnOnce(&mut DiagnosticBuilder<'b>), +{ +} + +#[allow(unused_variables)] +fn span_lint_and_help<'a, T: LintContext>( + cx: &'a T, + lint: &'static Lint, + span: Span, + msg: &str, + option_span: Option, + help: &str, +) { +} + +#[allow(unused_variables)] +fn span_lint_and_note<'a, T: LintContext>( + cx: &'a T, + lint: &'static Lint, + span: Span, + msg: &str, + note_span: Option, + note: &str, +) { +} + +#[allow(unused_variables)] +fn span_lint_and_sugg<'a, T: LintContext>( + cx: &'a T, + lint: &'static Lint, + sp: Span, + msg: &str, + help: &str, + sugg: String, + applicability: Applicability, +) { +} + +declare_tool_lint! { + pub clippy::TEST_LINT, + Warn, + "", + report_in_external_macro: true +} + +declare_lint_pass!(Pass => [TEST_LINT]); + +impl EarlyLintPass for Pass { + fn check_expr(&mut self, cx: &EarlyContext, expr: &Expr) { + let lint_msg = "lint message"; + let help_msg = "help message"; + let note_msg = "note message"; + let sugg = "new_call()"; + let predicate = true; + + span_lint_and_then(cx, TEST_LINT, expr.span, lint_msg, |db| { + db.span_suggestion(expr.span, help_msg, sugg.to_string(), Applicability::MachineApplicable); + }); + span_lint_and_then(cx, TEST_LINT, expr.span, lint_msg, |db| { + db.span_help(expr.span, help_msg); + }); + span_lint_and_then(cx, TEST_LINT, expr.span, lint_msg, |db| { + db.help(help_msg); + }); + span_lint_and_then(cx, TEST_LINT, expr.span, lint_msg, |db| { + db.span_note(expr.span, note_msg); + }); + span_lint_and_then(cx, TEST_LINT, expr.span, lint_msg, |db| { + db.note(note_msg); + }); + + // This expr shouldn't trigger this lint. + span_lint_and_then(cx, TEST_LINT, expr.span, lint_msg, |db| { + db.note(note_msg); + if predicate { + db.note(note_msg); + } + }) + } +} + +fn main() {} diff --git a/tests/ui/collapsible_span_lint_calls.stderr b/tests/ui/collapsible_span_lint_calls.stderr new file mode 100644 index 000000000000..874d4a9f255c --- /dev/null +++ b/tests/ui/collapsible_span_lint_calls.stderr @@ -0,0 +1,49 @@ +error: this call is collapsible + --> $DIR/collapsible_span_lint_calls.rs:75:9 + | +LL | / span_lint_and_then(cx, TEST_LINT, expr.span, lint_msg, |db| { +LL | | db.span_suggestion(expr.span, help_msg, sugg.to_string(), Applicability::MachineApplicable); +LL | | }); + | |__________^ help: collapse into: `span_lint_and_sugg(cx, TEST_LINT, expr.span, lint_msg, help_msg, sugg.to_string(), Applicability::MachineApplicable)` + | +note: the lint level is defined here + --> $DIR/collapsible_span_lint_calls.rs:2:9 + | +LL | #![deny(clippy::internal)] + | ^^^^^^^^^^^^^^^^ + = note: `#[deny(clippy::collapsible_span_lint_calls)]` implied by `#[deny(clippy::internal)]` + +error: this call is collapsible + --> $DIR/collapsible_span_lint_calls.rs:78:9 + | +LL | / span_lint_and_then(cx, TEST_LINT, expr.span, lint_msg, |db| { +LL | | db.span_help(expr.span, help_msg); +LL | | }); + | |__________^ help: collapse into: `span_lint_and_help(cx, TEST_LINT, expr.span, lint_msg, Some(expr.span), help_msg)` + +error: this call is collapsible + --> $DIR/collapsible_span_lint_calls.rs:81:9 + | +LL | / span_lint_and_then(cx, TEST_LINT, expr.span, lint_msg, |db| { +LL | | db.help(help_msg); +LL | | }); + | |__________^ help: collapse into: `span_lint_and_help(cx, TEST_LINT, expr.span, lint_msg, None, help_msg)` + +error: this call is collspible + --> $DIR/collapsible_span_lint_calls.rs:84:9 + | +LL | / span_lint_and_then(cx, TEST_LINT, expr.span, lint_msg, |db| { +LL | | db.span_note(expr.span, note_msg); +LL | | }); + | |__________^ help: collapse into: `span_lint_and_note(cx, TEST_LINT, expr.span, lint_msg, Some(expr.span), note_msg)` + +error: this call is collspible + --> $DIR/collapsible_span_lint_calls.rs:87:9 + | +LL | / span_lint_and_then(cx, TEST_LINT, expr.span, lint_msg, |db| { +LL | | db.note(note_msg); +LL | | }); + | |__________^ help: collapse into: `span_lint_and_note(cx, TEST_LINT, expr.span, lint_msg, None, note_msg)` + +error: aborting due to 5 previous errors + diff --git a/tests/ui/empty_enum.stderr b/tests/ui/empty_enum.stderr index b1e4eb277550..466dfbe7cee7 100644 --- a/tests/ui/empty_enum.stderr +++ b/tests/ui/empty_enum.stderr @@ -5,11 +5,7 @@ LL | enum Empty {} | ^^^^^^^^^^^^^ | = note: `-D clippy::empty-enum` implied by `-D warnings` -help: consider using the uninhabited type `!` (never type) or a wrapper around it to introduce a type which can't be instantiated - --> $DIR/empty_enum.rs:4:1 - | -LL | enum Empty {} - | ^^^^^^^^^^^^^ + = help: consider using the uninhabited type `!` (never type) or a wrapper around it to introduce a type which can't be instantiated error: aborting due to previous error