Add empty_drop lint

This commit is contained in:
Gryffon Bellish 2022-03-25 15:31:52 -04:00 committed by flip1995
parent 4c25880f0c
commit 8de3fb159d
No known key found for this signature in database
GPG key ID: 1CA0DF2AF59D68A5
8 changed files with 146 additions and 0 deletions

View file

@ -3365,6 +3365,7 @@ Released 2018-09-13
[`duplicate_underscore_argument`]: https://rust-lang.github.io/rust-clippy/master/index.html#duplicate_underscore_argument
[`duration_subsec`]: https://rust-lang.github.io/rust-clippy/master/index.html#duration_subsec
[`else_if_without_else`]: https://rust-lang.github.io/rust-clippy/master/index.html#else_if_without_else
[`empty_drop`]: https://rust-lang.github.io/rust-clippy/master/index.html#empty_drop
[`empty_enum`]: https://rust-lang.github.io/rust-clippy/master/index.html#empty_enum
[`empty_line_after_outer_attr`]: https://rust-lang.github.io/rust-clippy/master/index.html#empty_line_after_outer_attr
[`empty_loop`]: https://rust-lang.github.io/rust-clippy/master/index.html#empty_loop

View file

@ -0,0 +1,65 @@
use clippy_utils::{diagnostics::span_lint_and_sugg, peel_blocks};
use if_chain::if_chain;
use rustc_errors::Applicability;
use rustc_hir::{Body, ExprKind, Impl, ImplItemKind, Item, ItemKind, Node};
use rustc_lint::{LateContext, LateLintPass};
use rustc_session::{declare_lint_pass, declare_tool_lint};
declare_clippy_lint! {
/// ### What it does
/// Checks for empty `Drop` implementations.
///
/// ### Why is this bad?
/// Empty `Drop` implementations have no effect when dropping an instance of the type. They are
/// most likely useless. However, an empty `Drop` implementation prevents a type from being
/// destructured, which might be the intention behind adding the implementation as a marker.
///
/// ### Example
/// ```rust
/// struct S;
///
/// impl Drop for S {
/// fn drop(&mut self) {}
/// }
/// ```
/// Use instead:
/// ```rust
/// struct S;
/// ```
#[clippy::version = "1.61.0"]
pub EMPTY_DROP,
restriction,
"empty `Drop` implementations"
}
declare_lint_pass!(EmptyDrop => [EMPTY_DROP]);
impl LateLintPass<'_> for EmptyDrop {
fn check_item(&mut self, cx: &LateContext<'_>, item: &Item<'_>) {
if_chain! {
if let ItemKind::Impl(Impl {
of_trait: Some(ref trait_ref),
items: [child],
..
}) = item.kind;
if trait_ref.trait_def_id() == cx.tcx.lang_items().drop_trait();
if let impl_item_hir = child.id.hir_id();
if let Some(Node::ImplItem(impl_item)) = cx.tcx.hir().find(impl_item_hir);
if let ImplItemKind::Fn(_, b) = &impl_item.kind;
if let Body { value: func_expr, .. } = cx.tcx.hir().body(*b);
let func_expr = peel_blocks(func_expr);
if let ExprKind::Block(block, _) = func_expr.kind;
if block.stmts.is_empty() && block.expr.is_none();
then {
span_lint_and_sugg(
cx,
EMPTY_DROP,
item.span,
"empty drop implementation",
"try removing this impl",
String::new(),
Applicability::MaybeIncorrect
);
}
}
}
}

View file

@ -134,6 +134,7 @@ store.register_lints(&[
drop_forget_ref::UNDROPPED_MANUALLY_DROPS,
duration_subsec::DURATION_SUBSEC,
else_if_without_else::ELSE_IF_WITHOUT_ELSE,
empty_drop::EMPTY_DROP,
empty_enum::EMPTY_ENUM,
empty_structs_with_brackets::EMPTY_STRUCTS_WITH_BRACKETS,
entry::MAP_ENTRY,

View file

@ -16,6 +16,7 @@ store.register_group(true, "clippy::restriction", Some("clippy_restriction"), ve
LintId::of(default_union_representation::DEFAULT_UNION_REPRESENTATION),
LintId::of(disallowed_script_idents::DISALLOWED_SCRIPT_IDENTS),
LintId::of(else_if_without_else::ELSE_IF_WITHOUT_ELSE),
LintId::of(empty_drop::EMPTY_DROP),
LintId::of(empty_structs_with_brackets::EMPTY_STRUCTS_WITH_BRACKETS),
LintId::of(exhaustive_items::EXHAUSTIVE_ENUMS),
LintId::of(exhaustive_items::EXHAUSTIVE_STRUCTS),

View file

@ -210,6 +210,7 @@ mod double_parens;
mod drop_forget_ref;
mod duration_subsec;
mod else_if_without_else;
mod empty_drop;
mod empty_enum;
mod empty_structs_with_brackets;
mod entry;
@ -822,6 +823,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
store.register_late_pass(move || Box::new(disallowed_methods::DisallowedMethods::new(disallowed_methods.clone())));
store.register_early_pass(|| Box::new(asm_syntax::InlineAsmX86AttSyntax));
store.register_early_pass(|| Box::new(asm_syntax::InlineAsmX86IntelSyntax));
store.register_late_pass(|| Box::new(empty_drop::EmptyDrop));
store.register_late_pass(|| Box::new(strings::StrToString));
store.register_late_pass(|| Box::new(strings::StringToString));
store.register_late_pass(|| Box::new(zero_sized_map_values::ZeroSizedMapValues));

24
tests/ui/empty_drop.fixed Normal file
View file

@ -0,0 +1,24 @@
// run-rustfix
#![warn(clippy::empty_drop)]
#![allow(unused)]
// should cause an error
struct Foo;
// shouldn't cause an error
struct Bar;
impl Drop for Bar {
fn drop(&mut self) {
println!("dropping bar!");
}
}
// should error
struct Baz;
fn main() {}

30
tests/ui/empty_drop.rs Normal file
View file

@ -0,0 +1,30 @@
// run-rustfix
#![warn(clippy::empty_drop)]
#![allow(unused)]
// should cause an error
struct Foo;
impl Drop for Foo {
fn drop(&mut self) {}
}
// shouldn't cause an error
struct Bar;
impl Drop for Bar {
fn drop(&mut self) {
println!("dropping bar!");
}
}
// should error
struct Baz;
impl Drop for Baz {
fn drop(&mut self) {
{}
}
}
fn main() {}

View file

@ -0,0 +1,22 @@
error: empty drop implementation
--> $DIR/empty_drop.rs:8:1
|
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`
error: empty drop implementation
--> $DIR/empty_drop.rs:24:1
|
LL | / impl Drop for Baz {
LL | | fn drop(&mut self) {
LL | | {}
LL | | }
LL | | }
| |_^ help: try removing this impl
error: aborting due to 2 previous errors