diff --git a/README.md b/README.md index 44262eba8a1..138900937f7 100644 --- a/README.md +++ b/README.md @@ -20,6 +20,7 @@ name [cmp_nan](https://github.com/Manishearth/rust-clippy/wiki#cmp_nan) | deny | comparisons to NAN (which will always return false, which is probably not intended) [cmp_owned](https://github.com/Manishearth/rust-clippy/wiki#cmp_owned) | warn | creating owned instances for comparing with others, e.g. `x == "foo".to_string()` [collapsible_if](https://github.com/Manishearth/rust-clippy/wiki#collapsible_if) | warn | two nested `if`-expressions can be collapsed into one, e.g. `if x { if y { foo() } }` can be written as `if x && y { foo() }` +[empty_loop](https://github.com/Manishearth/rust-clippy/wiki#empty_loop) | warn | empty `loop {}` detected [eq_op](https://github.com/Manishearth/rust-clippy/wiki#eq_op) | warn | equal operands on both sides of a comparison or bitwise combination (e.g. `x == x`) [explicit_counter_loop](https://github.com/Manishearth/rust-clippy/wiki#explicit_counter_loop) | warn | for-looping with an explicit counter when `_.enumerate()` would do [explicit_iter_loop](https://github.com/Manishearth/rust-clippy/wiki#explicit_iter_loop) | warn | for-looping over `_.iter()` or `_.iter_mut()` when `&_` or `&mut _` would do diff --git a/src/lib.rs b/src/lib.rs index 8675eb01527..fd7adbed16d 100755 --- a/src/lib.rs +++ b/src/lib.rs @@ -122,6 +122,7 @@ pub fn plugin_registrar(reg: &mut Registry) { len_zero::LEN_WITHOUT_IS_EMPTY, len_zero::LEN_ZERO, lifetimes::NEEDLESS_LIFETIMES, + loops::EMPTY_LOOP, loops::EXPLICIT_COUNTER_LOOP, loops::EXPLICIT_ITER_LOOP, loops::ITER_NEXT_LOOP, diff --git a/src/loops.rs b/src/loops.rs index ee978932d09..10f58716dc7 100644 --- a/src/loops.rs +++ b/src/loops.rs @@ -36,13 +36,16 @@ declare_lint!{ pub REVERSE_RANGE_LOOP, Warn, declare_lint!{ pub EXPLICIT_COUNTER_LOOP, Warn, "for-looping with an explicit counter when `_.enumerate()` would do" } +declare_lint!{ pub EMPTY_LOOP, Warn, "empty `loop {}` detected" } + #[derive(Copy, Clone)] pub struct LoopsPass; impl LintPass for LoopsPass { fn get_lints(&self) -> LintArray { lint_array!(NEEDLESS_RANGE_LOOP, EXPLICIT_ITER_LOOP, ITER_NEXT_LOOP, - WHILE_LET_LOOP, UNUSED_COLLECT, REVERSE_RANGE_LOOP, EXPLICIT_COUNTER_LOOP) + WHILE_LET_LOOP, UNUSED_COLLECT, REVERSE_RANGE_LOOP, + EXPLICIT_COUNTER_LOOP, EMPTY_LOOP) } } @@ -163,6 +166,14 @@ impl LateLintPass for LoopsPass { // (also matches an explicit "match" instead of "if let") // (even if the "match" or "if let" is used for declaration) if let ExprLoop(ref block, _) = expr.node { + // also check for empty `loop {}` statements + if block.stmts.is_empty() && block.expr.is_none() { + span_lint(cx, EMPTY_LOOP, expr.span, + "empty `loop {}` detected. You may want to either \ + use `panic!()` or add `std::thread::sleep(..);` to \ + the loop body."); + } + // extract the first statement (if any) in a block let inner_stmt = extract_expr_from_first_stmt(block); // extract a single expression diff --git a/tests/compile-fail/while_loop.rs b/tests/compile-fail/while_loop.rs index eca2c7e12ae..8e51bf84887 100755 --- a/tests/compile-fail/while_loop.rs +++ b/tests/compile-fail/while_loop.rs @@ -1,7 +1,7 @@ #![feature(plugin)] #![plugin(clippy)] -#![deny(while_let_loop)] +#![deny(while_let_loop, empty_loop)] #![allow(dead_code, unused)] fn main() { @@ -58,6 +58,6 @@ fn no_panic(slice: &[T]) { Some(ele) => ele, None => break }; - loop {} + loop {} //~ERROR empty `loop {}` detected. } }