Skip to content

Commit

Permalink
Add empty closure lint
Browse files Browse the repository at this point in the history
  • Loading branch information
ThibsG committed Mar 22, 2020
1 parent 0e5e2c4 commit 9480856
Show file tree
Hide file tree
Showing 10 changed files with 86 additions and 4 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -1242,6 +1242,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_closure`]: https://rust-lang.github.io/rust-clippy/master/index.html#empty_closure
[`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
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

A collection of lints to catch common mistakes and improve your [Rust](https://github.com/rust-lang/rust) code.

[There are 361 lints included in this crate!](https://rust-lang.github.io/rust-clippy/master/index.html)
[There are 362 lints included in this crate!](https://rust-lang.github.io/rust-clippy/master/index.html)

We have a bunch of lint categories to allow you to choose how much Clippy is supposed to ~~annoy~~ help you:

Expand Down
43 changes: 43 additions & 0 deletions clippy_lints/src/empty_closure.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
use crate::utils::span_lint;
use if_chain::if_chain;
use rustc_hir::{Expr, ExprKind};
use rustc_lint::{LateContext, LateLintPass};
use rustc_session::{declare_lint_pass, declare_tool_lint};

declare_clippy_lint! {
/// **What it does:** Checks for empty closure.
///
/// **Why is this bad?** Empty closure does nothing, thus it can be removed.
///
/// **Known problems:** None.
///
/// **Example:**
///
/// ```rust
/// std::thread::spawn(|| {});
/// ```
pub EMPTY_CLOSURE,
style,
"closure with empty body"
}

declare_lint_pass!(EmptyClosure => [EMPTY_CLOSURE]);

impl LateLintPass<'_, '_> for EmptyClosure {
fn check_expr(&mut self, cx: &LateContext<'_, '_>, expr: &'_ Expr<'_>) {
if_chain! {
if let ExprKind::Closure(_, _, body_id, ..) = expr.kind;
let body = cx.tcx.hir().body(body_id);
if let ExprKind::Block(ref b, _) = body.value.kind;
if b.stmts.is_empty() && b.expr.is_none();
then {
span_lint(
cx,
EMPTY_CLOSURE,
expr.span,
"Empty closure may be removed",
);
}
}
}
}
5 changes: 5 additions & 0 deletions clippy_lints/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -197,6 +197,7 @@ pub mod drop_bounds;
pub mod drop_forget_ref;
pub mod duration_subsec;
pub mod else_if_without_else;
pub mod empty_closure;
pub mod empty_enum;
pub mod entry;
pub mod enum_clike;
Expand Down Expand Up @@ -521,6 +522,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
&drop_forget_ref::FORGET_REF,
&duration_subsec::DURATION_SUBSEC,
&else_if_without_else::ELSE_IF_WITHOUT_ELSE,
&empty_closure::EMPTY_CLOSURE,
&empty_enum::EMPTY_ENUM,
&entry::MAP_ENTRY,
&enum_clike::ENUM_CLIKE_UNPORTABLE_VARIANT,
Expand Down Expand Up @@ -1021,6 +1023,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
store.register_late_pass(|| box wildcard_imports::WildcardImports);
store.register_early_pass(|| box macro_use::MacroUseImports);
store.register_late_pass(|| box verbose_file_reads::VerboseFileReads);
store.register_late_pass(|| box empty_closure::EmptyClosure);

store.register_group(true, "clippy::restriction", Some("clippy_restriction"), vec![
LintId::of(&arithmetic::FLOAT_ARITHMETIC),
Expand Down Expand Up @@ -1166,6 +1169,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
LintId::of(&drop_forget_ref::FORGET_COPY),
LintId::of(&drop_forget_ref::FORGET_REF),
LintId::of(&duration_subsec::DURATION_SUBSEC),
LintId::of(&empty_closure::EMPTY_CLOSURE),
LintId::of(&entry::MAP_ENTRY),
LintId::of(&enum_clike::ENUM_CLIKE_UNPORTABLE_VARIANT),
LintId::of(&enum_variants::ENUM_VARIANT_NAMES),
Expand Down Expand Up @@ -1400,6 +1404,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
LintId::of(&comparison_chain::COMPARISON_CHAIN),
LintId::of(&doc::MISSING_SAFETY_DOC),
LintId::of(&doc::NEEDLESS_DOCTEST_MAIN),
LintId::of(&empty_closure::EMPTY_CLOSURE),
LintId::of(&enum_variants::ENUM_VARIANT_NAMES),
LintId::of(&enum_variants::MODULE_INCEPTION),
LintId::of(&eq_op::OP_REF),
Expand Down
9 changes: 8 additions & 1 deletion src/lintlist/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ pub use lint::Lint;
pub use lint::LINT_LEVELS;

// begin lint list, do not remove this comment, it’s used in `update_lints`
pub const ALL_LINTS: [Lint; 361] = [
pub const ALL_LINTS: [Lint; 362] = [
Lint {
name: "absurd_extreme_comparisons",
group: "correctness",
Expand Down Expand Up @@ -427,6 +427,13 @@ pub const ALL_LINTS: [Lint; 361] = [
deprecation: None,
module: "else_if_without_else",
},
Lint {
name: "empty_closure",
group: "style",
desc: "closure with empty body",
deprecation: None,
module: "empty_closure",
},
Lint {
name: "empty_enum",
group: "pedantic",
Expand Down
8 changes: 8 additions & 0 deletions tests/ui/empty_closure.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
#![warn(clippy::empty_closure)]

fn main() {
// Lint
std::thread::spawn(|| {});
// Lint
vec![0, 1, 2].iter().map(|_| {}).collect::<Vec<()>>();
}
16 changes: 16 additions & 0 deletions tests/ui/empty_closure.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
error: Empty closure may be removed
--> $DIR/empty_closure.rs:5:24
|
LL | std::thread::spawn(|| {});
| ^^^^^
|
= note: `-D clippy::empty-closure` implied by `-D warnings`

error: Empty closure may be removed
--> $DIR/empty_closure.rs:7:30
|
LL | vec![0, 1, 2].iter().map(|_| {}).collect::<Vec<()>>();
| ^^^^^^

error: aborting due to 2 previous errors

1 change: 1 addition & 0 deletions tests/ui/unused_unit.fixed
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ fn return_unit() { }
#[allow(clippy::needless_return)]
#[allow(clippy::never_loop)]
#[allow(clippy::unit_cmp)]
#[allow(clippy::empty_closure)]
fn main() {
let u = Unitter;
assert_eq!(u.get_unit(|| {}, return_unit), u.into());
Expand Down
1 change: 1 addition & 0 deletions tests/ui/unused_unit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ fn return_unit() -> () { () }
#[allow(clippy::needless_return)]
#[allow(clippy::never_loop)]
#[allow(clippy::unit_cmp)]
#[allow(clippy::empty_closure)]
fn main() {
let u = Unitter;
assert_eq!(u.get_unit(|| {}, return_unit), u.into());
Expand Down
4 changes: 2 additions & 2 deletions tests/ui/unused_unit.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -37,13 +37,13 @@ LL | fn return_unit() -> () { () }
| ^^ help: remove the final `()`

error: unneeded `()`
--> $DIR/unused_unit.rs:44:14
--> $DIR/unused_unit.rs:45:14
|
LL | break();
| ^^ help: remove the `()`

error: unneeded `()`
--> $DIR/unused_unit.rs:46:11
--> $DIR/unused_unit.rs:47:11
|
LL | return();
| ^^ help: remove the `()`
Expand Down

0 comments on commit 9480856

Please sign in to comment.