Skip to content

Commit f3c3e02

Browse files
committed
Suggest for loop instead of while-let when looping over iterators
1 parent a927bc0 commit f3c3e02

File tree

4 files changed

+37
-3
lines changed

4 files changed

+37
-3
lines changed

README.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,8 @@ A collection of lints to catch common mistakes and improve your Rust code.
66
[Jump to usage instructions](#usage)
77

88
##Lints
9-
There are 68 lints included in this crate:
9+
There are 69 lints included in this crate:
10+
There are 65 lints included in this crate:
1011

1112
name | default | meaning
1213
-------------------------------------------------------------------------------------------------------|---------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
@@ -74,6 +75,7 @@ name
7475
[unstable_as_slice](https://github.com/Manishearth/rust-clippy/wiki#unstable_as_slice) | warn | as_slice is not stable and can be replaced by & v[..]see https://github.com/rust-lang/rust/issues/27729
7576
[unused_collect](https://github.com/Manishearth/rust-clippy/wiki#unused_collect) | warn | `collect()`ing an iterator without using the result; this is usually better written as a for loop
7677
[while_let_loop](https://github.com/Manishearth/rust-clippy/wiki#while_let_loop) | warn | `loop { if let { ... } else break }` can be written as a `while let` loop
78+
[while_let_on_iterator](https://github.com/Manishearth/rust-clippy/wiki#while_let_on_iterator) | warn | using a while-let loop instead of a for loop on an iterator
7779
[wrong_pub_self_convention](https://github.com/Manishearth/rust-clippy/wiki#wrong_pub_self_convention) | allow | defining a public method named with an established prefix (like "into_") that takes `self` with the wrong convention
7880
[wrong_self_convention](https://github.com/Manishearth/rust-clippy/wiki#wrong_self_convention) | warn | defining a method named with an established prefix (like "into_") that takes `self` with the wrong convention
7981
[zero_divided_by_zero](https://github.com/Manishearth/rust-clippy/wiki#zero_divided_by_zero) | warn | usage of `0.0 / 0.0` to obtain NaN instead of std::f32::NaN or std::f64::NaN

src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,7 @@ pub fn plugin_registrar(reg: &mut Registry) {
138138
loops::REVERSE_RANGE_LOOP,
139139
loops::UNUSED_COLLECT,
140140
loops::WHILE_LET_LOOP,
141+
loops::WHILE_LET_ON_ITERATOR,
141142
matches::MATCH_BOOL,
142143
matches::MATCH_REF_PATS,
143144
matches::SINGLE_MATCH,

src/loops.rs

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,14 +38,17 @@ declare_lint!{ pub EXPLICIT_COUNTER_LOOP, Warn,
3838

3939
declare_lint!{ pub EMPTY_LOOP, Warn, "empty `loop {}` detected" }
4040

41+
declare_lint!{ pub WHILE_LET_ON_ITERATOR, Warn, "using a while-let loop instead of a for loop on an iterator" }
42+
4143
#[derive(Copy, Clone)]
4244
pub struct LoopsPass;
4345

4446
impl LintPass for LoopsPass {
4547
fn get_lints(&self) -> LintArray {
4648
lint_array!(NEEDLESS_RANGE_LOOP, EXPLICIT_ITER_LOOP, ITER_NEXT_LOOP,
4749
WHILE_LET_LOOP, UNUSED_COLLECT, REVERSE_RANGE_LOOP,
48-
EXPLICIT_COUNTER_LOOP, EMPTY_LOOP)
50+
EXPLICIT_COUNTER_LOOP, EMPTY_LOOP,
51+
WHILE_LET_ON_ITERATOR)
4952
}
5053
}
5154

@@ -228,6 +231,17 @@ impl LateLintPass for LoopsPass {
228231
}
229232
}
230233
}
234+
if let ExprMatch(ref expr, ref arms, MatchSource::WhileLetDesugar) = expr.node {
235+
let pat = &arms[0].pats[0].node;
236+
if let (&PatEnum(ref path, _), &ExprMethodCall(method_name, _, _)) = (pat, &expr.node) {
237+
if method_name.node.as_str() == "next" &&
238+
match_trait_method(cx, expr, &["core", "iter", "Iterator"]) &&
239+
path.segments.last().unwrap().identifier.name.as_str() == "Some" {
240+
span_lint(cx, WHILE_LET_ON_ITERATOR, expr.span,
241+
"this loop could be written as a `for` loop");
242+
}
243+
}
244+
}
231245
}
232246

233247
fn check_stmt(&mut self, cx: &LateContext, stmt: &Stmt) {

tests/compile-fail/while_loop.rs

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
#![feature(plugin)]
22
#![plugin(clippy)]
33

4-
#![deny(while_let_loop, empty_loop)]
4+
#![deny(while_let_loop, empty_loop, while_let_on_iterator)]
55
#![allow(dead_code, unused)]
66

77
fn main() {
@@ -53,6 +53,23 @@ fn main() {
5353
while let Some(x) = y { // no error, obviously
5454
println!("{}", x);
5555
}
56+
57+
58+
while let Option::Some(x) = (1..20).next() { //~ERROR this loop could be written as a `for` loop
59+
println!("{}", x);
60+
}
61+
62+
while let Some(x) = (1..20).next() { //~ERROR this loop could be written as a `for` loop
63+
println!("{}", x);
64+
}
65+
66+
while let Some(_) = (1..20).next() {} //~ERROR this loop could be written as a `for` loop
67+
68+
while let None = (1..20).next() {} // this is fine (if nonsensical)
69+
70+
if let Some(x) = (1..20).next() { // also fine
71+
println!("{}", x)
72+
}
5673
}
5774

5875
// regression test (#360)

0 commit comments

Comments
 (0)