Skip to content

Commit b01b008

Browse files
authored
Merge pull request #2576 from kimsnj/infinite_loop
while_immutable_condition: fix handling of self
2 parents f7c4bb6 + 737247e commit b01b008

File tree

3 files changed

+86
-63
lines changed

3 files changed

+86
-63
lines changed

clippy_lints/src/loops.rs

Lines changed: 34 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -2140,7 +2140,7 @@ fn check_infinite_loop<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, cond: &'tcx Expr, b
21402140
return;
21412141
}
21422142

2143-
let mut mut_var_visitor = MutableVarsVisitor {
2143+
let mut mut_var_visitor = VarCollectorVisitor {
21442144
cx,
21452145
ids: HashMap::new(),
21462146
skip: false,
@@ -2150,49 +2150,51 @@ fn check_infinite_loop<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, cond: &'tcx Expr, b
21502150
return;
21512151
}
21522152

2153-
if mut_var_visitor.ids.is_empty() {
2154-
span_lint(
2155-
cx,
2156-
WHILE_IMMUTABLE_CONDITION,
2157-
cond.span,
2158-
"all variables in condition are immutable. This either leads to an infinite or to a never running loop.",
2159-
);
2160-
return;
2161-
}
2162-
2163-
21642153
let mut delegate = MutVarsDelegate {
2165-
mut_spans: mut_var_visitor.ids,
2154+
used_mutably: mut_var_visitor.ids,
21662155
};
21672156
let def_id = def_id::DefId::local(block.hir_id.owner);
21682157
let region_scope_tree = &cx.tcx.region_scope_tree(def_id);
21692158
ExprUseVisitor::new(&mut delegate, cx.tcx, cx.param_env, region_scope_tree, cx.tables, None).walk_expr(expr);
21702159

2171-
if !delegate.mut_spans.iter().any(|(_, v)| v.is_some()) {
2160+
if !delegate.used_mutably.iter().any(|(_, v)| *v) {
21722161
span_lint(
21732162
cx,
21742163
WHILE_IMMUTABLE_CONDITION,
2175-
expr.span,
2164+
cond.span,
21762165
"Variable in the condition are not mutated in the loop body. This either leads to an infinite or to a never running loop.",
21772166
);
21782167
}
21792168
}
21802169

2181-
/// Collects the set of mutable variable in an expression
2170+
/// Collects the set of variables in an expression
21822171
/// Stops analysis if a function call is found
2183-
struct MutableVarsVisitor<'a, 'tcx: 'a> {
2172+
/// Note: In some cases such as `self`, there are no mutable annotation,
2173+
/// All variables definition IDs are collected
2174+
struct VarCollectorVisitor<'a, 'tcx: 'a> {
21842175
cx: &'a LateContext<'a, 'tcx>,
2185-
ids: HashMap<NodeId, Option<Span>>,
2176+
ids: HashMap<NodeId, bool>,
21862177
skip: bool,
21872178
}
21882179

2189-
impl<'a, 'tcx> Visitor<'tcx> for MutableVarsVisitor<'a, 'tcx> {
2180+
impl<'a, 'tcx> VarCollectorVisitor<'a, 'tcx> {
2181+
fn insert_def_id(&mut self, ex: &'tcx Expr) {
2182+
if_chain! {
2183+
if let ExprPath(ref qpath) = ex.node;
2184+
if let QPath::Resolved(None, _) = *qpath;
2185+
let def = self.cx.tables.qpath_def(qpath, ex.hir_id);
2186+
if let Def::Local(node_id) = def;
2187+
then {
2188+
self.ids.insert(node_id, false);
2189+
}
2190+
}
2191+
}
2192+
}
2193+
2194+
impl<'a, 'tcx> Visitor<'tcx> for VarCollectorVisitor<'a, 'tcx> {
21902195
fn visit_expr(&mut self, ex: &'tcx Expr) {
21912196
match ex.node {
2192-
ExprPath(_) => if let Some(node_id) = check_for_mutability(self.cx, ex) {
2193-
self.ids.insert(node_id, None);
2194-
},
2195-
2197+
ExprPath(_) => self.insert_def_id(ex),
21962198
// If there is any fuction/method call… we just stop analysis
21972199
ExprCall(..) | ExprMethodCall(..) => self.skip = true,
21982200

@@ -2208,15 +2210,18 @@ impl<'a, 'tcx> Visitor<'tcx> for MutableVarsVisitor<'a, 'tcx> {
22082210
}
22092211

22102212
struct MutVarsDelegate {
2211-
mut_spans: HashMap<NodeId, Option<Span>>,
2213+
used_mutably: HashMap<NodeId, bool>,
22122214
}
22132215

22142216
impl<'tcx> MutVarsDelegate {
22152217
fn update(&mut self, cat: &'tcx Categorization, sp: Span) {
2216-
if let Categorization::Local(id) = *cat {
2217-
if let Some(span) = self.mut_spans.get_mut(&id) {
2218-
*span = Some(sp)
2219-
}
2218+
match *cat {
2219+
Categorization::Local(id) =>
2220+
if let Some(used) = self.used_mutably.get_mut(&id) {
2221+
*used = true;
2222+
},
2223+
Categorization::Deref(ref cmt, _) => self.update(&cmt.cat, sp),
2224+
_ => {}
22202225
}
22212226
}
22222227
}
@@ -2236,7 +2241,7 @@ impl<'tcx> Delegate<'tcx> for MutVarsDelegate {
22362241
}
22372242

22382243
fn mutate(&mut self, _: NodeId, sp: Span, cmt: cmt<'tcx>, _: MutateMode) {
2239-
self.update(&cmt.cat, sp)
2244+
self.update(&cmt.cat, sp)
22402245
}
22412246

22422247
fn decl_without_init(&mut self, _: NodeId, _: Span) {}

tests/ui/infinite_loop.rs

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -124,9 +124,36 @@ fn internally_mutable() {
124124
}
125125
}
126126

127+
struct Counter {
128+
count: usize,
129+
}
130+
131+
impl Counter {
132+
fn inc(&mut self) {
133+
self.count += 1;
134+
}
135+
136+
fn inc_n(&mut self, n: usize) {
137+
while self.count < n {
138+
self.inc();
139+
}
140+
println!("OK - self borrowed mutably");
141+
}
142+
143+
fn print_n(&self, n: usize) {
144+
while self.count < n {
145+
println!("KO - {} is not mutated", self.count);
146+
}
147+
}
148+
}
149+
127150
fn main() {
128151
immutable_condition();
129152
unused_var();
130153
used_immutable();
131154
internally_mutable();
155+
156+
let mut c = Counter { count: 0 };
157+
c.inc_n(5);
158+
c.print_n(2);
132159
}

tests/ui/infinite_loop.stderr

Lines changed: 25 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -1,67 +1,58 @@
1-
error: all variables in condition are immutable. This either leads to an infinite or to a never running loop.
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.
22
--> $DIR/infinite_loop.rs:10:11
33
|
44
10 | while y < 10 {
55
| ^^^^^^
66
|
77
= note: `-D while-immutable-condition` implied by `-D warnings`
88

9-
error: all variables in condition are immutable. This either leads to an infinite or to a never running loop.
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.
1010
--> $DIR/infinite_loop.rs:15:11
1111
|
1212
15 | while y < 10 && x < 3 {
1313
| ^^^^^^^^^^^^^^^
1414

15-
error: all variables in condition are immutable. This either leads to an infinite or to a never running loop.
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.
1616
--> $DIR/infinite_loop.rs:22:11
1717
|
1818
22 | while !cond {
1919
| ^^^^^
2020

2121
error: Variable in the condition are not mutated in the loop body. This either leads to an infinite or to a never running loop.
22-
--> $DIR/infinite_loop.rs:52:5
22+
--> $DIR/infinite_loop.rs:52:11
2323
|
24-
52 | / while i < 3 {
25-
53 | | j = 3;
26-
54 | | println!("KO - i not mentionned");
27-
55 | | }
28-
| |_____^
24+
52 | while i < 3 {
25+
| ^^^^^
2926

3027
error: Variable in the condition are not mutated in the loop body. This either leads to an infinite or to a never running loop.
31-
--> $DIR/infinite_loop.rs:57:5
28+
--> $DIR/infinite_loop.rs:57:11
3229
|
33-
57 | / while i < 3 && j > 0 {
34-
58 | | println!("KO - i and j not mentionned");
35-
59 | | }
36-
| |_____^
30+
57 | while i < 3 && j > 0 {
31+
| ^^^^^^^^^^^^^^
3732

3833
error: Variable in the condition are not mutated in the loop body. This either leads to an infinite or to a never running loop.
39-
--> $DIR/infinite_loop.rs:61:5
34+
--> $DIR/infinite_loop.rs:61:11
4035
|
41-
61 | / while i < 3 {
42-
62 | | let mut i = 5;
43-
63 | | fn_mutref(&mut i);
44-
64 | | println!("KO - shadowed");
45-
65 | | }
46-
| |_____^
36+
61 | while i < 3 {
37+
| ^^^^^
4738

4839
error: Variable in the condition are not mutated in the loop body. This either leads to an infinite or to a never running loop.
49-
--> $DIR/infinite_loop.rs:76:5
40+
--> $DIR/infinite_loop.rs:76:11
5041
|
51-
76 | / while i < 3 {
52-
77 | | fn_constref(&i);
53-
78 | | println!("KO - const reference");
54-
79 | | }
55-
| |_____^
42+
76 | while i < 3 {
43+
| ^^^^^
5644

5745
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-
--> $DIR/infinite_loop.rs:81:5
46+
--> $DIR/infinite_loop.rs:81:11
5947
|
60-
81 | / while i < 3 {
61-
82 | | fn_val(i);
62-
83 | | println!("KO - passed by value");
63-
84 | | }
64-
| |_____^
48+
81 | while i < 3 {
49+
| ^^^^^
50+
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.
52+
--> $DIR/infinite_loop.rs:144:15
53+
|
54+
144 | while self.count < n {
55+
| ^^^^^^^^^^^^^^
6556

66-
error: aborting due to 8 previous errors
57+
error: aborting due to 9 previous errors
6758

0 commit comments

Comments
 (0)