Merge pull request #2576 from kimsnj/infinite_loop

while_immutable_condition: fix handling of self
This commit is contained in:
Oliver Schneider 2018-03-27 00:06:16 +02:00 committed by GitHub
commit b01b0083ba
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 86 additions and 63 deletions

View file

@ -2140,7 +2140,7 @@ fn check_infinite_loop<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, cond: &'tcx Expr, b
return;
}
let mut mut_var_visitor = MutableVarsVisitor {
let mut mut_var_visitor = VarCollectorVisitor {
cx,
ids: HashMap::new(),
skip: false,
@ -2150,49 +2150,51 @@ fn check_infinite_loop<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, cond: &'tcx Expr, b
return;
}
if mut_var_visitor.ids.is_empty() {
span_lint(
cx,
WHILE_IMMUTABLE_CONDITION,
cond.span,
"all variables in condition are immutable. This either leads to an infinite or to a never running loop.",
);
return;
}
let mut delegate = MutVarsDelegate {
mut_spans: mut_var_visitor.ids,
used_mutably: mut_var_visitor.ids,
};
let def_id = def_id::DefId::local(block.hir_id.owner);
let region_scope_tree = &cx.tcx.region_scope_tree(def_id);
ExprUseVisitor::new(&mut delegate, cx.tcx, cx.param_env, region_scope_tree, cx.tables, None).walk_expr(expr);
if !delegate.mut_spans.iter().any(|(_, v)| v.is_some()) {
if !delegate.used_mutably.iter().any(|(_, v)| *v) {
span_lint(
cx,
WHILE_IMMUTABLE_CONDITION,
expr.span,
cond.span,
"Variable in the condition are not mutated in the loop body. This either leads to an infinite or to a never running loop.",
);
}
}
/// Collects the set of mutable variable in an expression
/// Collects the set of variables in an expression
/// Stops analysis if a function call is found
struct MutableVarsVisitor<'a, 'tcx: 'a> {
/// Note: In some cases such as `self`, there are no mutable annotation,
/// All variables definition IDs are collected
struct VarCollectorVisitor<'a, 'tcx: 'a> {
cx: &'a LateContext<'a, 'tcx>,
ids: HashMap<NodeId, Option<Span>>,
ids: HashMap<NodeId, bool>,
skip: bool,
}
impl<'a, 'tcx> Visitor<'tcx> for MutableVarsVisitor<'a, 'tcx> {
impl<'a, 'tcx> VarCollectorVisitor<'a, 'tcx> {
fn insert_def_id(&mut self, ex: &'tcx Expr) {
if_chain! {
if let ExprPath(ref qpath) = ex.node;
if let QPath::Resolved(None, _) = *qpath;
let def = self.cx.tables.qpath_def(qpath, ex.hir_id);
if let Def::Local(node_id) = def;
then {
self.ids.insert(node_id, false);
}
}
}
}
impl<'a, 'tcx> Visitor<'tcx> for VarCollectorVisitor<'a, 'tcx> {
fn visit_expr(&mut self, ex: &'tcx Expr) {
match ex.node {
ExprPath(_) => if let Some(node_id) = check_for_mutability(self.cx, ex) {
self.ids.insert(node_id, None);
},
ExprPath(_) => self.insert_def_id(ex),
// If there is any fuction/method call… we just stop analysis
ExprCall(..) | ExprMethodCall(..) => self.skip = true,
@ -2208,15 +2210,18 @@ impl<'a, 'tcx> Visitor<'tcx> for MutableVarsVisitor<'a, 'tcx> {
}
struct MutVarsDelegate {
mut_spans: HashMap<NodeId, Option<Span>>,
used_mutably: HashMap<NodeId, bool>,
}
impl<'tcx> MutVarsDelegate {
fn update(&mut self, cat: &'tcx Categorization, sp: Span) {
if let Categorization::Local(id) = *cat {
if let Some(span) = self.mut_spans.get_mut(&id) {
*span = Some(sp)
}
match *cat {
Categorization::Local(id) =>
if let Some(used) = self.used_mutably.get_mut(&id) {
*used = true;
},
Categorization::Deref(ref cmt, _) => self.update(&cmt.cat, sp),
_ => {}
}
}
}

View file

@ -124,9 +124,36 @@ fn internally_mutable() {
}
}
struct Counter {
count: usize,
}
impl Counter {
fn inc(&mut self) {
self.count += 1;
}
fn inc_n(&mut self, n: usize) {
while self.count < n {
self.inc();
}
println!("OK - self borrowed mutably");
}
fn print_n(&self, n: usize) {
while self.count < n {
println!("KO - {} is not mutated", self.count);
}
}
}
fn main() {
immutable_condition();
unused_var();
used_immutable();
internally_mutable();
let mut c = Counter { count: 0 };
c.inc_n(5);
c.print_n(2);
}

View file

@ -1,4 +1,4 @@
error: all variables in condition are immutable. This either leads to an infinite or to a never running loop.
error: Variable in the condition are not mutated in the loop body. This either leads to an infinite or to a never running loop.
--> $DIR/infinite_loop.rs:10:11
|
10 | while y < 10 {
@ -6,62 +6,53 @@ error: all variables in condition are immutable. This either leads to an infinit
|
= note: `-D while-immutable-condition` implied by `-D warnings`
error: all variables in condition are immutable. This either leads to an infinite or to a never running loop.
error: Variable in the condition are not mutated in the loop body. This either leads to an infinite or to a never running loop.
--> $DIR/infinite_loop.rs:15:11
|
15 | while y < 10 && x < 3 {
| ^^^^^^^^^^^^^^^
error: all variables in condition are immutable. This either leads to an infinite or to a never running loop.
error: Variable in the condition are not mutated in the loop body. This either leads to an infinite or to a never running loop.
--> $DIR/infinite_loop.rs:22:11
|
22 | while !cond {
| ^^^^^
error: Variable in the condition are not mutated in the loop body. This either leads to an infinite or to a never running loop.
--> $DIR/infinite_loop.rs:52:5
--> $DIR/infinite_loop.rs:52:11
|
52 | / while i < 3 {
53 | | j = 3;
54 | | println!("KO - i not mentionned");
55 | | }
| |_____^
52 | while i < 3 {
| ^^^^^
error: Variable in the condition are not mutated in the loop body. This either leads to an infinite or to a never running loop.
--> $DIR/infinite_loop.rs:57:5
--> $DIR/infinite_loop.rs:57:11
|
57 | / while i < 3 && j > 0 {
58 | | println!("KO - i and j not mentionned");
59 | | }
| |_____^
57 | while i < 3 && j > 0 {
| ^^^^^^^^^^^^^^
error: Variable in the condition are not mutated in the loop body. This either leads to an infinite or to a never running loop.
--> $DIR/infinite_loop.rs:61:5
--> $DIR/infinite_loop.rs:61:11
|
61 | / while i < 3 {
62 | | let mut i = 5;
63 | | fn_mutref(&mut i);
64 | | println!("KO - shadowed");
65 | | }
| |_____^
61 | while i < 3 {
| ^^^^^
error: Variable in the condition are not mutated in the loop body. This either leads to an infinite or to a never running loop.
--> $DIR/infinite_loop.rs:76:5
--> $DIR/infinite_loop.rs:76:11
|
76 | / while i < 3 {
77 | | fn_constref(&i);
78 | | println!("KO - const reference");
79 | | }
| |_____^
76 | while i < 3 {
| ^^^^^
error: Variable in the condition are not mutated in the loop body. This either leads to an infinite or to a never running loop.
--> $DIR/infinite_loop.rs:81:5
--> $DIR/infinite_loop.rs:81:11
|
81 | / while i < 3 {
82 | | fn_val(i);
83 | | println!("KO - passed by value");
84 | | }
| |_____^
81 | while i < 3 {
| ^^^^^
error: aborting due to 8 previous errors
error: Variable in the condition are not mutated in the loop body. This either leads to an infinite or to a never running loop.
--> $DIR/infinite_loop.rs:144:15
|
144 | while self.count < n {
| ^^^^^^^^^^^^^^
error: aborting due to 9 previous errors