Skip to content

Commit a73edc0

Browse files
committed
add tests and fixes
1 parent 20728fb commit a73edc0

File tree

4 files changed

+212
-44
lines changed

4 files changed

+212
-44
lines changed

clippy_lints/src/loops.rs

Lines changed: 20 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -330,6 +330,18 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass {
330330
if let Some((pat, arg, body)) = higher::for_loop(expr) {
331331
check_for_loop(cx, pat, arg, body, expr);
332332
}
333+
334+
// check for never_loop
335+
match expr.node {
336+
ExprWhile(_, ref block, _) |
337+
ExprLoop(ref block, _, _) => {
338+
if never_loop(block, &expr.id) {
339+
span_lint(cx, NEVER_LOOP, expr.span, "this loop never actually loops");
340+
}
341+
},
342+
_ => (),
343+
}
344+
333345
// check for `loop { if let {} else break }` that could be `while let`
334346
// (also matches an explicit "match" instead of "if let")
335347
// (even if the "match" or "if let" is used for declaration)
@@ -342,9 +354,6 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass {
342354
"empty `loop {}` detected. You may want to either use `panic!()` or add \
343355
`std::thread::sleep(..);` to the loop body.");
344356
}
345-
if never_loop(block, &expr.id) {
346-
span_lint(cx, NEVER_LOOP, expr.span, "this loop never actually loops");
347-
}
348357

349358
// extract the expression from the first statement (if any) in a block
350359
let inner_stmt_expr = extract_expr_from_first_stmt(block);
@@ -456,14 +465,17 @@ fn contains_continue_expr(expr: &Expr, dest: &NodeId) -> bool {
456465
ExprTupField(ref e, _) |
457466
ExprAddrOf(_, ref e) |
458467
ExprRepeat(ref e, _) => contains_continue_expr(e, dest),
468+
ExprArray(ref es) |
469+
ExprMethodCall(_, _, ref es) |
470+
ExprTup(ref es) => es.iter().any(|e| contains_continue_expr(e, dest)),
471+
ExprCall(ref e, ref es) => contains_continue_expr(e, dest) || es.iter().any(|e| contains_continue_expr(e, dest)),
459472
ExprBinary(_, ref e1, ref e2) |
460473
ExprAssign(ref e1, ref e2) |
461474
ExprAssignOp(_, ref e1, ref e2) |
462475
ExprIndex(ref e1, ref e2) => [e1, e2].iter().any(|e| contains_continue_expr(e, dest)),
463-
ExprArray(ref es) |
464-
ExprTup(ref es) |
465-
ExprMethodCall(_, _, ref es) => es.iter().any(|e| contains_continue_expr(e, dest)),
466-
ExprCall(ref e, ref es) => contains_continue_expr(e, dest) || es.iter().any(|e| contains_continue_expr(e, dest)),
476+
ExprIf(ref e, ref e2, ref e3) => [e, e2].iter().chain(e3.as_ref().iter()).any(|e| contains_continue_expr(e, dest)),
477+
ExprWhile(ref e, ref b, _) => contains_continue_expr(e, dest) || contains_continue_block(b, dest),
478+
ExprMatch(ref e, ref arms, _) => contains_continue_expr(e, dest) || arms.iter().any(|a| contains_continue_expr(&a.body, dest)),
467479
ExprBlock(ref block) => contains_continue_block(block, dest),
468480
ExprStruct(_, _, ref base) => base.as_ref().map_or(false, |e| contains_continue_expr(e, dest)),
469481
ExprAgain(d) => d.target_id.opt_id().map_or(false, |id| id == *dest),
@@ -501,8 +513,8 @@ fn loop_exit_expr(expr: &Expr) -> bool {
501513
ExprTupField(ref e, _) |
502514
ExprAddrOf(_, ref e) |
503515
ExprRepeat(ref e, _) => loop_exit_expr(e),
504-
ExprMethodCall(_, _, ref es) => es.iter().any(|e| loop_exit_expr(e)),
505516
ExprArray(ref es) |
517+
ExprMethodCall(_, _, ref es) |
506518
ExprTup(ref es) => es.iter().any(|e| loop_exit_expr(e)),
507519
ExprCall(ref e, ref es) => loop_exit_expr(e) || es.iter().any(|e| loop_exit_expr(e)),
508520
ExprBinary(_, ref e1, ref e2) |

clippy_tests/examples/for_loop.stderr

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,28 @@ error: for loop over `v.iter().next().ok_or("x not found")`, which is a `Result`
5353
= note: `-D for-loop-over-result` implied by `-D warnings`
5454
= help: consider replacing `for x in v.iter().next().ok_or("x not found")` with `if let Ok(x) = v.iter().next().ok_or("x not found")`
5555

56+
error: this loop never actually loops
57+
--> for_loop.rs:52:5
58+
|
59+
52 | / while let Some(x) = option {
60+
53 | | println!("{}", x);
61+
54 | | break;
62+
55 | | }
63+
| |_____^
64+
|
65+
= note: `-D never-loop` implied by `-D warnings`
66+
67+
error: this loop never actually loops
68+
--> for_loop.rs:58:5
69+
|
70+
58 | / while let Ok(x) = result {
71+
59 | | println!("{}", x);
72+
60 | | break;
73+
61 | | }
74+
| |_____^
75+
|
76+
= note: `-D never-loop` implied by `-D warnings`
77+
5678
error: the loop variable `i` is only used to index `vec`.
5779
--> for_loop.rs:84:5
5880
|

clippy_tests/examples/never_loop.rs

Lines changed: 86 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,57 +1,118 @@
11
#![feature(plugin)]
22
#![plugin(clippy)]
3+
#![allow(single_match, unused_assignments, unused_variables)]
34

4-
#![warn(never_loop)]
5-
#![allow(single_match, while_true)]
6-
7-
fn break_stmt() {
8-
loop {
5+
fn test1() {
6+
let mut x = 0;
7+
loop { // never_loop
8+
x += 1;
9+
if x == 1 {
10+
return
11+
}
912
break;
1013
}
1114
}
1215

13-
fn conditional_break() {
14-
let mut x = 5;
16+
fn test2() {
17+
let mut x = 0;
1518
loop {
16-
x -= 1;
19+
x += 1;
1720
if x == 1 {
1821
break
1922
}
2023
}
2124
}
2225

23-
fn nested_loop() {
24-
loop {
25-
while true {
26-
break
27-
}
26+
fn test3() {
27+
let mut x = 0;
28+
loop { // never loops
29+
x += 1;
2830
break
2931
}
3032
}
3133

32-
fn if_false() {
33-
let x = 1;
34+
fn test4() {
35+
let mut x = 1;
3436
loop {
35-
if x == 1 {
36-
return
37+
x += 1;
38+
match x {
39+
5 => return,
40+
_ => (),
3741
}
3842
}
3943
}
4044

41-
fn match_false() {
42-
let x = 1;
45+
fn test5() {
46+
let i = 0;
47+
loop { // never loops
48+
while i == 0 { // never loops
49+
break
50+
}
51+
return
52+
}
53+
}
54+
55+
fn test6() {
56+
let mut x = 0;
57+
'outer: loop { // never loops
58+
x += 1;
59+
loop { // never loops
60+
if x == 5 { break }
61+
continue 'outer
62+
}
63+
return
64+
}
65+
}
66+
67+
fn test7() {
68+
let mut x = 0;
4369
loop {
70+
x += 1;
4471
match x {
45-
1 => return,
72+
1 => continue,
4673
_ => (),
4774
}
75+
return
76+
}
77+
}
78+
79+
fn test8() {
80+
let mut x = 0;
81+
loop {
82+
x += 1;
83+
match x {
84+
5 => return,
85+
_ => continue,
86+
}
87+
}
88+
}
89+
90+
fn test9() {
91+
let x = Some(1);
92+
while let Some(y) = x { // never loops
93+
return
94+
}
95+
}
96+
97+
fn test10() {
98+
for x in 0..10 { // never loops
99+
match x {
100+
1 => break,
101+
_ => return,
102+
}
48103
}
49104
}
50105

51106
fn main() {
52-
break_stmt();
53-
conditional_break();
54-
nested_loop();
55-
if_false();
56-
match_false();
107+
test1();
108+
test2();
109+
test3();
110+
test4();
111+
test5();
112+
test6();
113+
test7();
114+
test8();
115+
test9();
116+
test10();
57117
}
118+

clippy_tests/examples/never_loop.stderr

Lines changed: 84 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,99 @@
11
error: this loop never actually loops
2-
--> never_loop.rs:8:5
2+
--> never_loop.rs:7:5
33
|
4-
8 | / loop {
5-
9 | | break;
6-
10 | | }
4+
7 | / loop { // never_loop
5+
8 | | x += 1;
6+
9 | | if x == 1 {
7+
10 | | return
8+
11 | | }
9+
12 | | break;
10+
13 | | }
711
| |_____^
812
|
913
= note: `-D never-loop` implied by `-D warnings`
1014

1115
error: this loop never actually loops
12-
--> never_loop.rs:24:5
16+
--> never_loop.rs:28:5
1317
|
14-
24 | / loop {
15-
25 | | while true {
16-
26 | | break
17-
27 | | }
18-
28 | | break
19-
29 | | }
18+
28 | / loop { // never loops
19+
29 | | x += 1;
20+
30 | | break
21+
31 | | }
2022
| |_____^
2123
|
2224
= note: `-D never-loop` implied by `-D warnings`
2325

26+
error: this loop never actually loops
27+
--> never_loop.rs:47:2
28+
|
29+
47 | / loop { // never loops
30+
48 | | while i == 0 { // never loops
31+
49 | | break
32+
50 | | }
33+
51 | | return
34+
52 | | }
35+
| |__^
36+
|
37+
= note: `-D never-loop` implied by `-D warnings`
38+
39+
error: this loop never actually loops
40+
--> never_loop.rs:48:9
41+
|
42+
48 | / while i == 0 { // never loops
43+
49 | | break
44+
50 | | }
45+
| |_________^
46+
|
47+
= note: `-D never-loop` implied by `-D warnings`
48+
49+
error: this loop never actually loops
50+
--> never_loop.rs:57:5
51+
|
52+
57 | / 'outer: loop { // never loops
53+
58 | | x += 1;
54+
59 | | loop { // never loops
55+
60 | | if x == 5 { break }
56+
... |
57+
63 | | return
58+
64 | | }
59+
| |__^
60+
|
61+
= note: `-D never-loop` implied by `-D warnings`
62+
63+
error: this loop never actually loops
64+
--> never_loop.rs:59:3
65+
|
66+
59 | / loop { // never loops
67+
60 | | if x == 5 { break }
68+
61 | | continue 'outer
69+
62 | | }
70+
| |___^
71+
|
72+
= note: `-D never-loop` implied by `-D warnings`
73+
74+
error: this loop never actually loops
75+
--> never_loop.rs:92:5
76+
|
77+
92 | / while let Some(y) = x { // never loops
78+
93 | | return
79+
94 | | }
80+
| |_____^
81+
|
82+
= note: `-D never-loop` implied by `-D warnings`
83+
84+
error: this loop never actually loops
85+
--> never_loop.rs:98:5
86+
|
87+
98 | / for x in 0..10 { // never loops
88+
99 | | match x {
89+
100 | | 1 => break,
90+
101 | | _ => return,
91+
102 | | }
92+
103 | | }
93+
| |_____^
94+
|
95+
= note: `-D never-loop` implied by `-D warnings`
96+
2497
error: aborting due to previous error(s)
2598

2699
error: Could not compile `clippy_tests`.

0 commit comments

Comments
 (0)