Add let_underscore_drop

This commit is contained in:
Samuel E. Moelius III 2020-11-07 18:26:14 -05:00
parent 96d5f45ade
commit f1f780c942
6 changed files with 111 additions and 2 deletions

View File

@ -1787,6 +1787,7 @@ Released 2018-09-13
[`len_without_is_empty`]: https://rust-lang.github.io/rust-clippy/master/index.html#len_without_is_empty
[`len_zero`]: https://rust-lang.github.io/rust-clippy/master/index.html#len_zero
[`let_and_return`]: https://rust-lang.github.io/rust-clippy/master/index.html#let_and_return
[`let_underscore_drop`]: https://rust-lang.github.io/rust-clippy/master/index.html#let_underscore_drop
[`let_underscore_lock`]: https://rust-lang.github.io/rust-clippy/master/index.html#let_underscore_lock
[`let_underscore_must_use`]: https://rust-lang.github.io/rust-clippy/master/index.html#let_underscore_must_use
[`let_unit_value`]: https://rust-lang.github.io/rust-clippy/master/index.html#let_unit_value

View File

@ -5,7 +5,7 @@
use rustc_middle::ty::subst::GenericArgKind;
use rustc_session::{declare_lint_pass, declare_tool_lint};
use crate::utils::{is_must_use_func_call, is_must_use_ty, match_type, paths, span_lint_and_help};
use crate::utils::{implements_trait, is_must_use_func_call, is_must_use_ty, match_type, paths, span_lint_and_help};
declare_clippy_lint! {
/// **What it does:** Checks for `let _ = <expr>`
@ -58,7 +58,40 @@
"non-binding let on a synchronization lock"
}
declare_lint_pass!(LetUnderscore => [LET_UNDERSCORE_MUST_USE, LET_UNDERSCORE_LOCK]);
declare_clippy_lint! {
/// **What it does:** Checks for `let _ = <expr>`
/// where expr has a type that implements `Drop`
///
/// **Why is this bad?** This statement immediately drops the initializer
/// expression instead of extending its lifetime to the end of the scope, which
/// is often not intended. To extend the expression's lifetime to the end of the
/// scope, use an underscore-prefixed name instead (i.e. _var). If you want to
/// explicitly drop the expression, `std::mem::drop` conveys your intention
/// better and is less error-prone.
///
/// **Known problems:** None.
///
/// **Example:**
///
/// Bad:
/// ```rust,ignore
/// struct Droppable;
/// impl Drop for Droppable {
/// fn drop(&mut self) {}
/// }
/// let _ = Droppable;
/// ```
///
/// Good:
/// ```rust,ignore
/// let _droppable = Droppable;
/// ```
pub LET_UNDERSCORE_DROP,
correctness,
"non-binding let on a type that implements `Drop`"
}
declare_lint_pass!(LetUnderscore => [LET_UNDERSCORE_MUST_USE, LET_UNDERSCORE_LOCK, LET_UNDERSCORE_DROP]);
const SYNC_GUARD_PATHS: [&[&str]; 3] = [
&paths::MUTEX_GUARD,
@ -84,6 +117,15 @@ fn check_local(&mut self, cx: &LateContext<'_>, local: &Local<'_>) {
GenericArgKind::Lifetime(_) | GenericArgKind::Const(_) => false,
});
let implements_drop = cx.tcx.lang_items().drop_trait().map_or(false, |drop_trait|
init_ty.walk().any(|inner| match inner.unpack() {
GenericArgKind::Type(inner_ty) => {
implements_trait(cx, inner_ty, drop_trait, &[])
},
GenericArgKind::Lifetime(_) | GenericArgKind::Const(_) => false,
})
);
if contains_sync_guard {
span_lint_and_help(
cx,
@ -94,6 +136,16 @@ fn check_local(&mut self, cx: &LateContext<'_>, local: &Local<'_>) {
"consider using an underscore-prefixed named \
binding or dropping explicitly with `std::mem::drop`"
)
} else if implements_drop {
span_lint_and_help(
cx,
LET_UNDERSCORE_DROP,
local.span,
"non-binding let on a type that implements `Drop`",
None,
"consider using an underscore-prefixed named \
binding or dropping explicitly with `std::mem::drop`"
)
} else if is_must_use_ty(cx, cx.typeck_results().expr_ty(init)) {
span_lint_and_help(
cx,

View File

@ -622,6 +622,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
&len_zero::LEN_WITHOUT_IS_EMPTY,
&len_zero::LEN_ZERO,
&let_if_seq::USELESS_LET_IF_SEQ,
&let_underscore::LET_UNDERSCORE_DROP,
&let_underscore::LET_UNDERSCORE_LOCK,
&let_underscore::LET_UNDERSCORE_MUST_USE,
&lifetimes::EXTRA_UNUSED_LIFETIMES,
@ -1383,6 +1384,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
LintId::of(&len_zero::COMPARISON_TO_EMPTY),
LintId::of(&len_zero::LEN_WITHOUT_IS_EMPTY),
LintId::of(&len_zero::LEN_ZERO),
LintId::of(&let_underscore::LET_UNDERSCORE_DROP),
LintId::of(&let_underscore::LET_UNDERSCORE_LOCK),
LintId::of(&lifetimes::EXTRA_UNUSED_LIFETIMES),
LintId::of(&lifetimes::NEEDLESS_LIFETIMES),
@ -1809,6 +1811,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
LintId::of(&infinite_iter::INFINITE_ITER),
LintId::of(&inherent_to_string::INHERENT_TO_STRING_SHADOW_DISPLAY),
LintId::of(&inline_fn_without_body::INLINE_FN_WITHOUT_BODY),
LintId::of(&let_underscore::LET_UNDERSCORE_DROP),
LintId::of(&let_underscore::LET_UNDERSCORE_LOCK),
LintId::of(&literal_representation::MISTYPED_LITERAL_SUFFIXES),
LintId::of(&loops::FOR_LOOPS_OVER_FALLIBLES),

View File

@ -1117,6 +1117,13 @@
deprecation: None,
module: "returns",
},
Lint {
name: "let_underscore_drop",
group: "correctness",
desc: "non-binding let on a type that implements `Drop`",
deprecation: None,
module: "let_underscore",
},
Lint {
name: "let_underscore_lock",
group: "correctness",

View File

@ -0,0 +1,19 @@
#![warn(clippy::let_underscore_drop)]
struct Droppable;
impl Drop for Droppable {
fn drop(&mut self) {}
}
fn main() {
let unit = ();
let boxed = Box::new(());
let droppable = Droppable;
let optional = Some(Droppable);
let _ = ();
let _ = Box::new(());
let _ = Droppable;
let _ = Some(Droppable);
}

View File

@ -0,0 +1,27 @@
error: non-binding let on a type that implements `Drop`
--> $DIR/let_underscore_drop.rs:16:5
|
LL | let _ = Box::new(());
| ^^^^^^^^^^^^^^^^^^^^^
|
= note: `-D clippy::let-underscore-drop` implied by `-D warnings`
= help: consider using an underscore-prefixed named binding or dropping explicitly with `std::mem::drop`
error: non-binding let on a type that implements `Drop`
--> $DIR/let_underscore_drop.rs:17:5
|
LL | let _ = Droppable;
| ^^^^^^^^^^^^^^^^^^
|
= help: consider using an underscore-prefixed named binding or dropping explicitly with `std::mem::drop`
error: non-binding let on a type that implements `Drop`
--> $DIR/let_underscore_drop.rs:18:5
|
LL | let _ = Some(Droppable);
| ^^^^^^^^^^^^^^^^^^^^^^^^
|
= help: consider using an underscore-prefixed named binding or dropping explicitly with `std::mem::drop`
error: aborting due to 3 previous errors