From eba6c789dcfca7065d1c292c06eb447ac9895db3 Mon Sep 17 00:00:00 2001 From: Aaron Kofsky Date: Fri, 3 Jun 2022 21:33:13 -0400 Subject: [PATCH] Show code suggestions in `let_undescore` lint messages. This commit uses `span_suggestion_verbose` to add what specific code changes can be done as suggested by the lint--in this case, either binding the expression to an unused variable or using `std::mem::drop` to drop the value explicitly. --- compiler/rustc_lint/src/let_underscore.rs | 60 +++++++++++++++---- .../let_underscore/let_underscore_drop.stderr | 10 +++- .../let_underscore/let_underscore_lock.stderr | 10 +++- .../let_underscore_must_use.stderr | 20 +++++-- 4 files changed, 79 insertions(+), 21 deletions(-) diff --git a/compiler/rustc_lint/src/let_underscore.rs b/compiler/rustc_lint/src/let_underscore.rs index 985c7300efa..4e4cedaeb78 100644 --- a/compiler/rustc_lint/src/let_underscore.rs +++ b/compiler/rustc_lint/src/let_underscore.rs @@ -1,6 +1,10 @@ use crate::{LateContext, LateLintPass, LintContext}; +use rustc_errors::Applicability; use rustc_hir as hir; -use rustc_middle::ty::{self, subst::GenericArgKind, Ty}; +use rustc_middle::{ + lint::LintDiagnosticBuilder, + ty::{self, subst::GenericArgKind, Ty}, +}; use rustc_span::Symbol; declare_lint! { @@ -141,30 +145,60 @@ fn check_local(&mut self, cx: &LateContext<'_>, local: &hir::Local<'_>) { }); let is_must_use_ty = is_must_use_ty(cx, cx.typeck_results().expr_ty(init)); let is_must_use_func_call = is_must_use_func_call(cx, init); + if is_sync_lock { cx.struct_span_lint(LET_UNDERSCORE_LOCK, local.span, |lint| { - lint.build("non-binding let on a synchronization lock") - .help("consider binding to an unused variable") - .help("consider explicitly droping with `std::mem::drop`") - .emit(); + build_and_emit_lint( + lint, + local, + init.span, + "non-binding let on a synchronization lock", + ) }) } else if is_must_use_ty || is_must_use_func_call { cx.struct_span_lint(LET_UNDERSCORE_MUST_USE, local.span, |lint| { - lint.build("non-binding let on a expression marked `must_use`") - .help("consider binding to an unused variable") - .help("consider explicitly droping with `std::mem::drop`") - .emit(); + build_and_emit_lint( + lint, + local, + init.span, + "non-binding let on a expression marked `must_use`", + ); }) } else if needs_drop { cx.struct_span_lint(LET_UNDERSCORE_DROP, local.span, |lint| { - lint.build("non-binding let on a type that implements `Drop`") - .help("consider binding to an unused variable") - .help("consider explicitly droping with `std::mem::drop`") - .emit(); + build_and_emit_lint( + lint, + local, + init.span, + "non-binding let on a type that implements `Drop`", + ); }) } } + fn build_and_emit_lint( + lint: LintDiagnosticBuilder<'_, ()>, + local: &hir::Local<'_>, + init_span: rustc_span::Span, + msg: &str, + ) { + lint.build(msg) + .span_suggestion_verbose( + local.pat.span, + "consider binding to an unused variable", + "_unused", + Applicability::MachineApplicable, + ) + .span_suggestion_verbose( + init_span, + "consider explicitly droping with `std::mem::drop`", + "drop(...)", + Applicability::HasPlaceholders, + ) + .emit(); + } + + // return true if `ty` is a type that is marked as `must_use` fn is_must_use_ty<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool { match ty.kind() { ty::Adt(adt, _) => has_must_use_attr(cx, adt.did()), diff --git a/src/test/ui/let_underscore/let_underscore_drop.stderr b/src/test/ui/let_underscore/let_underscore_drop.stderr index f4fd663c7f9..5034f682bb7 100644 --- a/src/test/ui/let_underscore/let_underscore_drop.stderr +++ b/src/test/ui/let_underscore/let_underscore_drop.stderr @@ -5,8 +5,14 @@ LL | let _ = NontrivialDrop; | ^^^^^^^^^^^^^^^^^^^^^^^ | = note: requested on the command line with `-W let-underscore-drop` - = help: consider binding to an unused variable - = help: consider explicitly droping with `std::mem::drop` +help: consider binding to an unused variable + | +LL | let _unused = NontrivialDrop; + | ~~~~~~~ +help: consider explicitly droping with `std::mem::drop` + | +LL | let _ = drop(...); + | ~~~~~~~~~ warning: 1 warning emitted diff --git a/src/test/ui/let_underscore/let_underscore_lock.stderr b/src/test/ui/let_underscore/let_underscore_lock.stderr index 77379d8c3db..08f81962f3c 100644 --- a/src/test/ui/let_underscore/let_underscore_lock.stderr +++ b/src/test/ui/let_underscore/let_underscore_lock.stderr @@ -5,8 +5,14 @@ LL | let _ = data.lock().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: `#[warn(let_underscore_lock)]` on by default - = help: consider binding to an unused variable - = help: consider explicitly droping with `std::mem::drop` +help: consider binding to an unused variable + | +LL | let _unused = data.lock().unwrap(); + | ~~~~~~~ +help: consider explicitly droping with `std::mem::drop` + | +LL | let _ = drop(...); + | ~~~~~~~~~ warning: 1 warning emitted diff --git a/src/test/ui/let_underscore/let_underscore_must_use.stderr b/src/test/ui/let_underscore/let_underscore_must_use.stderr index ea1de45e17b..959572edd7c 100644 --- a/src/test/ui/let_underscore/let_underscore_must_use.stderr +++ b/src/test/ui/let_underscore/let_underscore_must_use.stderr @@ -5,8 +5,14 @@ LL | let _ = MustUseType; | ^^^^^^^^^^^^^^^^^^^^ | = note: requested on the command line with `-W let-underscore-must-use` - = help: consider binding to an unused variable - = help: consider explicitly droping with `std::mem::drop` +help: consider binding to an unused variable + | +LL | let _unused = MustUseType; + | ~~~~~~~ +help: consider explicitly droping with `std::mem::drop` + | +LL | let _ = drop(...); + | ~~~~~~~~~ warning: non-binding let on a expression marked `must_use` --> $DIR/let_underscore_must_use.rs:12:5 @@ -14,8 +20,14 @@ warning: non-binding let on a expression marked `must_use` LL | let _ = must_use_function(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = help: consider binding to an unused variable - = help: consider explicitly droping with `std::mem::drop` +help: consider binding to an unused variable + | +LL | let _unused = must_use_function(); + | ~~~~~~~ +help: consider explicitly droping with `std::mem::drop` + | +LL | let _ = drop(...); + | ~~~~~~~~~ warning: 2 warnings emitted