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.
This commit is contained in:
parent
ae2ac3b4c5
commit
eba6c789dc
@ -1,6 +1,10 @@
|
|||||||
use crate::{LateContext, LateLintPass, LintContext};
|
use crate::{LateContext, LateLintPass, LintContext};
|
||||||
|
use rustc_errors::Applicability;
|
||||||
use rustc_hir as hir;
|
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;
|
use rustc_span::Symbol;
|
||||||
|
|
||||||
declare_lint! {
|
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_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);
|
let is_must_use_func_call = is_must_use_func_call(cx, init);
|
||||||
|
|
||||||
if is_sync_lock {
|
if is_sync_lock {
|
||||||
cx.struct_span_lint(LET_UNDERSCORE_LOCK, local.span, |lint| {
|
cx.struct_span_lint(LET_UNDERSCORE_LOCK, local.span, |lint| {
|
||||||
lint.build("non-binding let on a synchronization lock")
|
build_and_emit_lint(
|
||||||
.help("consider binding to an unused variable")
|
lint,
|
||||||
.help("consider explicitly droping with `std::mem::drop`")
|
local,
|
||||||
.emit();
|
init.span,
|
||||||
|
"non-binding let on a synchronization lock",
|
||||||
|
)
|
||||||
})
|
})
|
||||||
} else if is_must_use_ty || is_must_use_func_call {
|
} else if is_must_use_ty || is_must_use_func_call {
|
||||||
cx.struct_span_lint(LET_UNDERSCORE_MUST_USE, local.span, |lint| {
|
cx.struct_span_lint(LET_UNDERSCORE_MUST_USE, local.span, |lint| {
|
||||||
lint.build("non-binding let on a expression marked `must_use`")
|
build_and_emit_lint(
|
||||||
.help("consider binding to an unused variable")
|
lint,
|
||||||
.help("consider explicitly droping with `std::mem::drop`")
|
local,
|
||||||
.emit();
|
init.span,
|
||||||
|
"non-binding let on a expression marked `must_use`",
|
||||||
|
);
|
||||||
})
|
})
|
||||||
} else if needs_drop {
|
} else if needs_drop {
|
||||||
cx.struct_span_lint(LET_UNDERSCORE_DROP, local.span, |lint| {
|
cx.struct_span_lint(LET_UNDERSCORE_DROP, local.span, |lint| {
|
||||||
lint.build("non-binding let on a type that implements `Drop`")
|
build_and_emit_lint(
|
||||||
.help("consider binding to an unused variable")
|
lint,
|
||||||
.help("consider explicitly droping with `std::mem::drop`")
|
local,
|
||||||
.emit();
|
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 {
|
fn is_must_use_ty<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool {
|
||||||
match ty.kind() {
|
match ty.kind() {
|
||||||
ty::Adt(adt, _) => has_must_use_attr(cx, adt.did()),
|
ty::Adt(adt, _) => has_must_use_attr(cx, adt.did()),
|
||||||
|
@ -5,8 +5,14 @@ LL | let _ = NontrivialDrop;
|
|||||||
| ^^^^^^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
|
|
||||||
= note: requested on the command line with `-W let-underscore-drop`
|
= note: requested on the command line with `-W let-underscore-drop`
|
||||||
= help: consider binding to an unused variable
|
help: consider binding to an unused variable
|
||||||
= help: consider explicitly droping with `std::mem::drop`
|
|
|
||||||
|
LL | let _unused = NontrivialDrop;
|
||||||
|
| ~~~~~~~
|
||||||
|
help: consider explicitly droping with `std::mem::drop`
|
||||||
|
|
|
||||||
|
LL | let _ = drop(...);
|
||||||
|
| ~~~~~~~~~
|
||||||
|
|
||||||
warning: 1 warning emitted
|
warning: 1 warning emitted
|
||||||
|
|
||||||
|
@ -5,8 +5,14 @@ LL | let _ = data.lock().unwrap();
|
|||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
|
|
||||||
= note: `#[warn(let_underscore_lock)]` on by default
|
= note: `#[warn(let_underscore_lock)]` on by default
|
||||||
= help: consider binding to an unused variable
|
help: consider binding to an unused variable
|
||||||
= help: consider explicitly droping with `std::mem::drop`
|
|
|
||||||
|
LL | let _unused = data.lock().unwrap();
|
||||||
|
| ~~~~~~~
|
||||||
|
help: consider explicitly droping with `std::mem::drop`
|
||||||
|
|
|
||||||
|
LL | let _ = drop(...);
|
||||||
|
| ~~~~~~~~~
|
||||||
|
|
||||||
warning: 1 warning emitted
|
warning: 1 warning emitted
|
||||||
|
|
||||||
|
@ -5,8 +5,14 @@ LL | let _ = MustUseType;
|
|||||||
| ^^^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
|
|
||||||
= note: requested on the command line with `-W let-underscore-must-use`
|
= note: requested on the command line with `-W let-underscore-must-use`
|
||||||
= help: consider binding to an unused variable
|
help: consider binding to an unused variable
|
||||||
= help: consider explicitly droping with `std::mem::drop`
|
|
|
||||||
|
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`
|
warning: non-binding let on a expression marked `must_use`
|
||||||
--> $DIR/let_underscore_must_use.rs:12:5
|
--> $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();
|
LL | let _ = must_use_function();
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
|
|
||||||
= help: consider binding to an unused variable
|
help: consider binding to an unused variable
|
||||||
= help: consider explicitly droping with `std::mem::drop`
|
|
|
||||||
|
LL | let _unused = must_use_function();
|
||||||
|
| ~~~~~~~
|
||||||
|
help: consider explicitly droping with `std::mem::drop`
|
||||||
|
|
|
||||||
|
LL | let _ = drop(...);
|
||||||
|
| ~~~~~~~~~
|
||||||
|
|
||||||
warning: 2 warnings emitted
|
warning: 2 warnings emitted
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user