Skip to content

Commit d6c2fb7

Browse files
committed
Auto merge of #4730 - yerke:fix-check_infinite_loop, r=flip1995
Fix check_infinite_loop (while_immutable_condition) by checking for break or return inside loop body changelog: Fix check_infinite_loop (while_immutable_condition) by checking for break or return inside loop body fixes #4648
2 parents 35a559f + 1cba0c9 commit d6c2fb7

File tree

3 files changed

+109
-13
lines changed

3 files changed

+109
-13
lines changed

clippy_lints/src/loops.rs

+43-3
Original file line numberDiff line numberDiff line change
@@ -2367,17 +2367,57 @@ fn check_infinite_loop<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, cond: &'tcx Expr, e
23672367
return;
23682368
};
23692369
let mutable_static_in_cond = var_visitor.def_ids.iter().any(|(_, v)| *v);
2370+
2371+
let mut has_break_or_return_visitor = HasBreakOrReturnVisitor {
2372+
has_break_or_return: false,
2373+
};
2374+
has_break_or_return_visitor.visit_expr(expr);
2375+
let has_break_or_return = has_break_or_return_visitor.has_break_or_return;
2376+
23702377
if no_cond_variable_mutated && !mutable_static_in_cond {
2371-
span_lint(
2378+
span_lint_and_then(
23722379
cx,
23732380
WHILE_IMMUTABLE_CONDITION,
23742381
cond.span,
2375-
"Variable in the condition are not mutated in the loop body. \
2376-
This either leads to an infinite or to a never running loop.",
2382+
"variables in the condition are not mutated in the loop body",
2383+
|db| {
2384+
db.note("this may lead to an infinite or to a never running loop");
2385+
2386+
if has_break_or_return {
2387+
db.note("this loop contains `return`s or `break`s");
2388+
db.help("rewrite it as `if cond { loop { } }`");
2389+
}
2390+
},
23772391
);
23782392
}
23792393
}
23802394

2395+
struct HasBreakOrReturnVisitor {
2396+
has_break_or_return: bool,
2397+
}
2398+
2399+
impl<'a, 'tcx> Visitor<'tcx> for HasBreakOrReturnVisitor {
2400+
fn visit_expr(&mut self, expr: &'tcx Expr) {
2401+
if self.has_break_or_return {
2402+
return;
2403+
}
2404+
2405+
match expr.kind {
2406+
ExprKind::Ret(_) | ExprKind::Break(_, _) => {
2407+
self.has_break_or_return = true;
2408+
return;
2409+
},
2410+
_ => {},
2411+
}
2412+
2413+
walk_expr(self, expr);
2414+
}
2415+
2416+
fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> {
2417+
NestedVisitorMap::None
2418+
}
2419+
}
2420+
23812421
/// Collects the set of variables in an expression
23822422
/// Stops analysis if a function call is found
23832423
/// Note: In some cases such as `self`, there are no mutable annotation,

tests/ui/infinite_loop.rs

+19
Original file line numberDiff line numberDiff line change
@@ -177,6 +177,23 @@ impl Counter {
177177
}
178178
}
179179

180+
fn while_loop_with_break_and_return() {
181+
let y = 0;
182+
while y < 10 {
183+
if y == 0 {
184+
break;
185+
}
186+
println!("KO - loop contains break");
187+
}
188+
189+
while y < 10 {
190+
if y == 0 {
191+
return;
192+
}
193+
println!("KO - loop contains return");
194+
}
195+
}
196+
180197
fn main() {
181198
immutable_condition();
182199
unused_var();
@@ -186,4 +203,6 @@ fn main() {
186203
let mut c = Counter { count: 0 };
187204
c.inc_n(5);
188205
c.print_n(2);
206+
207+
while_loop_with_break_and_return();
189208
}

tests/ui/infinite_loop.stderr

+47-10
Original file line numberDiff line numberDiff line change
@@ -1,58 +1,95 @@
1-
error: Variable in the condition are not mutated in the loop body. This either leads to an infinite or to a never running loop.
1+
error: variables in the condition are not mutated in the loop body
22
--> $DIR/infinite_loop.rs:23:11
33
|
44
LL | while y < 10 {
55
| ^^^^^^
66
|
77
= note: `#[deny(clippy::while_immutable_condition)]` on by default
8+
= note: this may lead to an infinite or to a never running loop
89

9-
error: Variable in the condition are not mutated in the loop body. This either leads to an infinite or to a never running loop.
10+
error: variables in the condition are not mutated in the loop body
1011
--> $DIR/infinite_loop.rs:28:11
1112
|
1213
LL | while y < 10 && x < 3 {
1314
| ^^^^^^^^^^^^^^^
15+
|
16+
= note: this may lead to an infinite or to a never running loop
1417

15-
error: Variable in the condition are not mutated in the loop body. This either leads to an infinite or to a never running loop.
18+
error: variables in the condition are not mutated in the loop body
1619
--> $DIR/infinite_loop.rs:35:11
1720
|
1821
LL | while !cond {
1922
| ^^^^^
23+
|
24+
= note: this may lead to an infinite or to a never running loop
2025

21-
error: Variable in the condition are not mutated in the loop body. This either leads to an infinite or to a never running loop.
26+
error: variables in the condition are not mutated in the loop body
2227
--> $DIR/infinite_loop.rs:79:11
2328
|
2429
LL | while i < 3 {
2530
| ^^^^^
31+
|
32+
= note: this may lead to an infinite or to a never running loop
2633

27-
error: Variable in the condition are not mutated in the loop body. This either leads to an infinite or to a never running loop.
34+
error: variables in the condition are not mutated in the loop body
2835
--> $DIR/infinite_loop.rs:84:11
2936
|
3037
LL | while i < 3 && j > 0 {
3138
| ^^^^^^^^^^^^^^
39+
|
40+
= note: this may lead to an infinite or to a never running loop
3241

33-
error: Variable in the condition are not mutated in the loop body. This either leads to an infinite or to a never running loop.
42+
error: variables in the condition are not mutated in the loop body
3443
--> $DIR/infinite_loop.rs:88:11
3544
|
3645
LL | while i < 3 {
3746
| ^^^^^
47+
|
48+
= note: this may lead to an infinite or to a never running loop
3849

39-
error: Variable in the condition are not mutated in the loop body. This either leads to an infinite or to a never running loop.
50+
error: variables in the condition are not mutated in the loop body
4051
--> $DIR/infinite_loop.rs:103:11
4152
|
4253
LL | while i < 3 {
4354
| ^^^^^
55+
|
56+
= note: this may lead to an infinite or to a never running loop
4457

45-
error: Variable in the condition are not mutated in the loop body. This either leads to an infinite or to a never running loop.
58+
error: variables in the condition are not mutated in the loop body
4659
--> $DIR/infinite_loop.rs:108:11
4760
|
4861
LL | while i < 3 {
4962
| ^^^^^
63+
|
64+
= note: this may lead to an infinite or to a never running loop
5065

51-
error: Variable in the condition are not mutated in the loop body. This either leads to an infinite or to a never running loop.
66+
error: variables in the condition are not mutated in the loop body
5267
--> $DIR/infinite_loop.rs:174:15
5368
|
5469
LL | while self.count < n {
5570
| ^^^^^^^^^^^^^^
71+
|
72+
= note: this may lead to an infinite or to a never running loop
73+
74+
error: variables in the condition are not mutated in the loop body
75+
--> $DIR/infinite_loop.rs:182:11
76+
|
77+
LL | while y < 10 {
78+
| ^^^^^^
79+
|
80+
= note: this may lead to an infinite or to a never running loop
81+
= note: this loop contains `return`s or `break`s
82+
= help: rewrite it as `if cond { loop { } }`
83+
84+
error: variables in the condition are not mutated in the loop body
85+
--> $DIR/infinite_loop.rs:189:11
86+
|
87+
LL | while y < 10 {
88+
| ^^^^^^
89+
|
90+
= note: this may lead to an infinite or to a never running loop
91+
= note: this loop contains `return`s or `break`s
92+
= help: rewrite it as `if cond { loop { } }`
5693

57-
error: aborting due to 9 previous errors
94+
error: aborting due to 11 previous errors
5895

0 commit comments

Comments
 (0)