X-Git-Url: https://git.lizzy.rs/?a=blobdiff_plain;f=src%2Floops.rs;h=614b561749f761f15c8f58eeb3fb1951bbfaa456;hb=840d87022e33ddd0a3e6ac40b26a4a4fc4fcb32c;hp=5c552d2ce4244df619e750a4fb9f61b88dc23ee7;hpb=b900e889106bd33b0b0ad84d6f8500ef958e0b18;p=rust.git diff --git a/src/loops.rs b/src/loops.rs index 5c552d2ce42..614b561749f 100644 --- a/src/loops.rs +++ b/src/loops.rs @@ -5,15 +5,13 @@ use rustc::middle::ty; use rustc::middle::def::DefLocal; use consts::{constant_simple, Constant}; -use rustc::front::map::Node::{NodeBlock}; +use rustc::front::map::Node::NodeBlock; use std::borrow::Cow; -use std::collections::{HashSet,HashMap}; -use syntax::ast::Lit_::*; +use std::collections::{HashSet, HashMap}; -use utils::{snippet, span_lint, get_parent_expr, match_trait_method, match_type, - in_external_macro, expr_block, span_help_and_lint, is_integer_literal, - get_enclosing_block}; -use utils::{VEC_PATH, LL_PATH}; +use utils::{snippet, span_lint, get_parent_expr, match_trait_method, match_type, in_external_macro, expr_block, + span_help_and_lint, is_integer_literal, get_enclosing_block}; +use utils::{HASHMAP_PATH, VEC_PATH, LL_PATH}; /// **What it does:** This lint checks for looping over the range of `0..len` of some collection just to get the values by index. It is `Warn` by default. /// @@ -50,7 +48,7 @@ declare_lint!{ pub ITER_NEXT_LOOP, Warn, "for-looping over `_.next()` which is probably not intended" } -/// **What it does:** This lint detects `loop + match` combinations that are easier written as a `while let` loop. +/// **What it does:** This lint detects `loop + match` combinations that are easier written as a `while let` loop. It is `Warn` by default. /// /// **Why is this bad?** The `while let` loop is usually shorter and more readable /// @@ -85,7 +83,7 @@ "`collect()`ing an iterator without using the result; this is usually better \ written as a for loop" } -/// **What it does:** This lint checks for loops over ranges `x..y` where both `x` and `y` are constant and `x` is greater or equal to `y`, unless the range is reversed or has a negative `.step_by(_)`. +/// **What it does:** This lint checks for loops over ranges `x..y` where both `x` and `y` are constant and `x` is greater or equal to `y`, unless the range is reversed or has a negative `.step_by(_)`. It is `Warn` by default. /// /// **Why is it bad?** Such loops will either be skipped or loop until wrap-around (in debug code, this may `panic!()`). Both options are probably not intended. /// @@ -128,9 +126,14 @@ impl LintPass for LoopsPass { fn get_lints(&self) -> LintArray { - lint_array!(NEEDLESS_RANGE_LOOP, EXPLICIT_ITER_LOOP, ITER_NEXT_LOOP, - WHILE_LET_LOOP, UNUSED_COLLECT, REVERSE_RANGE_LOOP, - EXPLICIT_COUNTER_LOOP, EMPTY_LOOP, + lint_array!(NEEDLESS_RANGE_LOOP, + EXPLICIT_ITER_LOOP, + ITER_NEXT_LOOP, + WHILE_LET_LOOP, + UNUSED_COLLECT, + REVERSE_RANGE_LOOP, + EXPLICIT_COUNTER_LOOP, + EMPTY_LOOP, WHILE_LET_ON_ITERATOR) } } @@ -146,10 +149,11 @@ fn check_expr(&mut self, cx: &LateContext, expr: &Expr) { if let ExprLoop(ref block, _) = expr.node { // also check for empty `loop {}` statements if block.stmts.is_empty() && block.expr.is_none() { - span_lint(cx, EMPTY_LOOP, expr.span, - "empty `loop {}` detected. You may want to either \ - use `panic!()` or add `std::thread::sleep(..);` to \ - the loop body."); + span_lint(cx, + EMPTY_LOOP, + expr.span, + "empty `loop {}` detected. You may want to either use `panic!()` or add \ + `std::thread::sleep(..);` to the loop body."); } // extract the expression from the first statement (if any) in a block @@ -159,11 +163,10 @@ fn check_expr(&mut self, cx: &LateContext, expr: &Expr) { if let ExprMatch(ref matchexpr, ref arms, ref source) = inner.node { // collect the remaining statements below the match let mut other_stuff = block.stmts - .iter() - .skip(1) - .map(|stmt| { - format!("{}", snippet(cx, stmt.span, "..")) - }).collect::>(); + .iter() + .skip(1) + .map(|stmt| format!("{}", snippet(cx, stmt.span, ".."))) + .collect::>(); if inner_stmt_expr.is_some() { // if we have a statement which has a match, if let Some(ref expr) = block.expr { @@ -174,29 +177,31 @@ fn check_expr(&mut self, cx: &LateContext, expr: &Expr) { // ensure "if let" compatible match structure match *source { - MatchSource::Normal | MatchSource::IfLetDesugar{..} => if - arms.len() == 2 && - arms[0].pats.len() == 1 && arms[0].guard.is_none() && - arms[1].pats.len() == 1 && arms[1].guard.is_none() && - // finally, check for "break" in the second clause - is_break_expr(&arms[1].body) - { - if in_external_macro(cx, expr.span) { return; } - let loop_body = if inner_stmt_expr.is_some() { - // FIXME: should probably be an ellipsis - // tabbing and newline is probably a bad idea, especially for large blocks - Cow::Owned(format!("{{\n {}\n}}", other_stuff.join("\n "))) - } else { - expr_block(cx, &arms[0].body, Some(other_stuff.join("\n ")), "..") - }; - span_help_and_lint(cx, WHILE_LET_LOOP, expr.span, - "this loop could be written as a `while let` loop", - &format!("try\nwhile let {} = {} {}", - snippet(cx, arms[0].pats[0].span, ".."), - snippet(cx, matchexpr.span, ".."), - loop_body)); - }, - _ => () + MatchSource::Normal | MatchSource::IfLetDesugar{..} => { + if arms.len() == 2 && arms[0].pats.len() == 1 && arms[0].guard.is_none() && + arms[1].pats.len() == 1 && arms[1].guard.is_none() && + is_break_expr(&arms[1].body) { + if in_external_macro(cx, expr.span) { + return; + } + let loop_body = if inner_stmt_expr.is_some() { + // FIXME: should probably be an ellipsis + // tabbing and newline is probably a bad idea, especially for large blocks + Cow::Owned(format!("{{\n {}\n}}", other_stuff.join("\n "))) + } else { + expr_block(cx, &arms[0].body, Some(other_stuff.join("\n ")), "..") + }; + span_help_and_lint(cx, + WHILE_LET_LOOP, + expr.span, + "this loop could be written as a `while let` loop", + &format!("try\nwhile let {} = {} {}", + snippet(cx, arms[0].pats[0].span, ".."), + snippet(cx, matchexpr.span, ".."), + loop_body)); + } + } + _ => (), } } } @@ -204,21 +209,20 @@ fn check_expr(&mut self, cx: &LateContext, expr: &Expr) { if let ExprMatch(ref match_expr, ref arms, MatchSource::WhileLetDesugar) = expr.node { let pat = &arms[0].pats[0].node; if let (&PatEnum(ref path, Some(ref pat_args)), - &ExprMethodCall(method_name, _, ref method_args)) = - (pat, &match_expr.node) { + &ExprMethodCall(method_name, _, ref method_args)) = (pat, &match_expr.node) { let iter_expr = &method_args[0]; if let Some(lhs_constructor) = path.segments.last() { if method_name.node.as_str() == "next" && - match_trait_method(cx, match_expr, &["core", "iter", "Iterator"]) && - lhs_constructor.identifier.name.as_str() == "Some" && - !is_iterator_used_after_while_let(cx, iter_expr) { + match_trait_method(cx, match_expr, &["core", "iter", "Iterator"]) && + lhs_constructor.identifier.name.as_str() == "Some" && + !is_iterator_used_after_while_let(cx, iter_expr) { let iterator = snippet(cx, method_args[0].span, "_"); let loop_var = snippet(cx, pat_args[0].span, "_"); - span_help_and_lint(cx, WHILE_LET_ON_ITERATOR, expr.span, + span_help_and_lint(cx, + WHILE_LET_ON_ITERATOR, + expr.span, "this loop could be written as a `for` loop", - &format!("try\nfor {} in {} {{...}}", - loop_var, - iterator)); + &format!("try\nfor {} in {} {{...}}", loop_var, iterator)); } } } @@ -229,10 +233,12 @@ fn check_stmt(&mut self, cx: &LateContext, stmt: &Stmt) { if let StmtSemi(ref expr, _) = stmt.node { if let ExprMethodCall(ref method, _, ref args) = expr.node { if args.len() == 1 && method.node.as_str() == "collect" && - match_trait_method(cx, expr, &["core", "iter", "Iterator"]) { - span_lint(cx, UNUSED_COLLECT, expr.span, &format!( - "you are collect()ing an iterator and throwing away the result. \ - Consider using an explicit for loop to exhaust the iterator")); + match_trait_method(cx, expr, &["core", "iter", "Iterator"]) { + span_lint(cx, + UNUSED_COLLECT, + expr.span, + &format!("you are collect()ing an iterator and throwing away the result. Consider \ + using an explicit for loop to exhaust the iterator")); } } } @@ -240,39 +246,102 @@ fn check_stmt(&mut self, cx: &LateContext, stmt: &Stmt) { } fn check_for_loop(cx: &LateContext, pat: &Pat, arg: &Expr, body: &Expr, expr: &Expr) { - // check for looping over a range and then indexing a sequence with it - // -> the iteratee must be a range literal - if let ExprRange(Some(ref l), _) = arg.node { - // Range should start with `0` - if let ExprLit(ref lit) = l.node { - if let LitInt(0, _) = lit.node { - - // the var must be a single name - if let PatIdent(_, ref ident, _) = pat.node { - let mut visitor = VarVisitor { cx: cx, var: ident.node.name, - indexed: HashSet::new(), nonindex: false }; - walk_expr(&mut visitor, body); - // linting condition: we only indexed one variable - if visitor.indexed.len() == 1 { - let indexed = visitor.indexed.into_iter().next().expect( - "Len was nonzero, but no contents found"); - if visitor.nonindex { - span_lint(cx, NEEDLESS_RANGE_LOOP, expr.span, &format!( - "the loop variable `{}` is used to index `{}`. Consider using \ - `for ({}, item) in {}.iter().enumerate()` or similar iterators", - ident.node.name, indexed, ident.node.name, indexed)); - } else { - span_lint(cx, NEEDLESS_RANGE_LOOP, expr.span, &format!( - "the loop variable `{}` is only used to index `{}`. \ - Consider using `for item in &{}` or similar iterators", - ident.node.name, indexed, indexed)); - } + check_for_loop_range(cx, pat, arg, body, expr); + check_for_loop_reverse_range(cx, arg, expr); + check_for_loop_explicit_iter(cx, arg, expr); + check_for_loop_explicit_counter(cx, arg, body, expr); +} + +/// Check for looping over a range and then indexing a sequence with it. +/// The iteratee must be a range literal. +fn check_for_loop_range(cx: &LateContext, pat: &Pat, arg: &Expr, body: &Expr, expr: &Expr) { + if let ExprRange(Some(ref l), ref r) = arg.node { + // the var must be a single name + if let PatIdent(_, ref ident, _) = pat.node { + let mut visitor = VarVisitor { + cx: cx, + var: ident.node.name, + indexed: HashSet::new(), + nonindex: false, + }; + walk_expr(&mut visitor, body); + // linting condition: we only indexed one variable + if visitor.indexed.len() == 1 { + let indexed = visitor.indexed + .into_iter() + .next() + .expect("Len was nonzero, but no contents found"); + + let starts_at_zero = is_integer_literal(l, 0); + + let skip: Cow<_> = if starts_at_zero { + "".into() + } + else { + format!(".skip({})", snippet(cx, l.span, "..")).into() + }; + + let take: Cow<_> = if let Some(ref r) = *r { + if !is_len_call(&r, &indexed) { + format!(".take({})", snippet(cx, r.span, "..")).into() + } + else { + "".into() } + } else { + "".into() + }; + + if visitor.nonindex { + span_lint(cx, + NEEDLESS_RANGE_LOOP, + expr.span, + &format!("the loop variable `{}` is used to index `{}`. \ + Consider using `for ({}, item) in {}.iter().enumerate(){}{}` or similar iterators", + ident.node.name, + indexed, + ident.node.name, + indexed, + take, + skip)); + } else { + let repl = if starts_at_zero && take.is_empty() { + format!("&{}", indexed) + } + else { + format!("{}.iter(){}{}", indexed, take, skip) + }; + + span_lint(cx, + NEEDLESS_RANGE_LOOP, + expr.span, + &format!("the loop variable `{}` is only used to index `{}`. \ + Consider using `for item in {}` or similar iterators", + ident.node.name, + indexed, + repl)); } } } } +} +fn is_len_call(expr: &Expr, var: &Name) -> bool { + if_let_chain! {[ + let ExprMethodCall(method, _, ref len_args) = expr.node, + len_args.len() == 1, + method.node.as_str() == "len", + let ExprPath(_, ref path) = len_args[0].node, + path.segments.len() == 1, + &path.segments[0].identifier.name == var + ], { + return true; + }} + + false +} + +fn check_for_loop_reverse_range(cx: &LateContext, arg: &Expr, expr: &Expr) { // if this for loop is iterating over a two-sided range... if let ExprRange(Some(ref start_expr), Some(ref stop_expr)) = arg.node { // ...and both sides are compile-time constant integers... @@ -283,20 +352,28 @@ fn check_for_loop(cx: &LateContext, pat: &Pat, arg: &Expr, body: &Expr, expr: &E // who think that this will iterate from the larger value to the // smaller value. if start_idx > stop_idx { - span_help_and_lint(cx, REVERSE_RANGE_LOOP, expr.span, - "this range is empty so this for loop will never run", - &format!("Consider using `({}..{}).rev()` if you are attempting to \ - iterate over this range in reverse", stop_idx, start_idx)); + span_help_and_lint(cx, + REVERSE_RANGE_LOOP, + expr.span, + "this range is empty so this for loop will never run", + &format!("Consider using `({}..{}).rev()` if you are attempting to iterate \ + over this range in reverse", + stop_idx, + start_idx)); } else if start_idx == stop_idx { // if they are equal, it's also problematic - this loop // will never run. - span_lint(cx, REVERSE_RANGE_LOOP, expr.span, - "this range is empty so this for loop will never run"); + span_lint(cx, + REVERSE_RANGE_LOOP, + expr.span, + "this range is empty so this for loop will never run"); } } } } +} +fn check_for_loop_explicit_iter(cx: &LateContext, arg: &Expr, expr: &Expr) { if let ExprMethodCall(ref method, _, ref args) = arg.node { // just the receiver, no arguments if args.len() == 1 { @@ -305,46 +382,68 @@ fn check_for_loop(cx: &LateContext, pat: &Pat, arg: &Expr, body: &Expr, expr: &E if method_name.as_str() == "iter" || method_name.as_str() == "iter_mut" { if is_ref_iterable_type(cx, &args[0]) { let object = snippet(cx, args[0].span, "_"); - span_lint(cx, EXPLICIT_ITER_LOOP, expr.span, &format!( - "it is more idiomatic to loop over `&{}{}` instead of `{}.{}()`", - if method_name.as_str() == "iter_mut" { "mut " } else { "" }, - object, object, method_name)); + span_lint(cx, + EXPLICIT_ITER_LOOP, + expr.span, + &format!("it is more idiomatic to loop over `&{}{}` instead of `{}.{}()`", + if method_name.as_str() == "iter_mut" { + "mut " + } else { + "" + }, + object, + object, + method_name)); } - } - // check for looping over Iterator::next() which is not what you want - else if method_name.as_str() == "next" && - match_trait_method(cx, arg, &["core", "iter", "Iterator"]) { - span_lint(cx, ITER_NEXT_LOOP, expr.span, - "you are iterating over `Iterator::next()` which is an Option; \ - this will compile but is probably not what you want"); + } else if method_name.as_str() == "next" && match_trait_method(cx, arg, &["core", "iter", "Iterator"]) { + span_lint(cx, + ITER_NEXT_LOOP, + expr.span, + "you are iterating over `Iterator::next()` which is an Option; this will compile but is \ + probably not what you want"); } } } +} + +fn check_for_loop_explicit_counter(cx: &LateContext, arg: &Expr, body: &Expr, expr: &Expr) { // Look for variables that are incremented once per loop iteration. - let mut visitor = IncrementVisitor { cx: cx, states: HashMap::new(), depth: 0, done: false }; + let mut visitor = IncrementVisitor { + cx: cx, + states: HashMap::new(), + depth: 0, + done: false, + }; walk_expr(&mut visitor, body); // For each candidate, check the parent block to see if // it's initialized to zero at the start of the loop. let map = &cx.tcx.map; - let parent_scope = map.get_enclosing_scope(expr.id).and_then(|id| map.get_enclosing_scope(id) ); + let parent_scope = map.get_enclosing_scope(expr.id).and_then(|id| map.get_enclosing_scope(id)); if let Some(parent_id) = parent_scope { if let NodeBlock(block) = map.get(parent_id) { - for (id, _) in visitor.states.iter().filter( |&(_,v)| *v == VarState::IncrOnce) { - let mut visitor2 = InitializeVisitor { cx: cx, end_expr: expr, var_id: id.clone(), - state: VarState::IncrOnce, name: None, - depth: 0, - past_loop: false }; + for (id, _) in visitor.states.iter().filter(|&(_, v)| *v == VarState::IncrOnce) { + let mut visitor2 = InitializeVisitor { + cx: cx, + end_expr: expr, + var_id: id.clone(), + state: VarState::IncrOnce, + name: None, + depth: 0, + past_loop: false, + }; walk_block(&mut visitor2, block); if visitor2.state == VarState::Warn { if let Some(name) = visitor2.name { - span_lint(cx, EXPLICIT_COUNTER_LOOP, expr.span, - &format!("the variable `{0}` is used as a loop counter. Consider \ - using `for ({0}, item) in {1}.enumerate()` \ - or similar iterators", - name, snippet(cx, arg.span, "_"))); + span_lint(cx, + EXPLICIT_COUNTER_LOOP, + expr.span, + &format!("the variable `{0}` is used as a loop counter. Consider using `for ({0}, \ + item) in {1}.enumerate()` or similar iterators", + name, + snippet(cx, arg.span, "_"))); } } } @@ -378,9 +477,9 @@ fn recover_for_loop(expr: &Expr) -> Option<(&Pat, &Expr, &Expr)> { struct VarVisitor<'v, 't: 'v> { cx: &'v LateContext<'v, 't>, // context reference - var: Name, // var name to look for as index - indexed: HashSet, // indexed variables - nonindex: bool, // has the var been used otherwise? + var: Name, // var name to look for as index + indexed: HashSet, // indexed variables + nonindex: bool, // has the var been used otherwise? } impl<'v, 't> Visitor<'v> for VarVisitor<'v, 't> { @@ -411,14 +510,14 @@ fn visit_expr(&mut self, expr: &'v Expr) { fn is_iterator_used_after_while_let(cx: &LateContext, iter_expr: &Expr) -> bool { let def_id = match var_def_id(cx, iter_expr) { Some(id) => id, - None => return false + None => return false, }; let mut visitor = VarUsedAfterLoopVisitor { cx: cx, def_id: def_id, iter_expr_id: iter_expr.id, past_while_let: false, - var_used_after_while_let: false + var_used_after_while_let: false, }; if let Some(enclosing_block) = get_enclosing_block(cx, def_id) { walk_block(&mut visitor, enclosing_block); @@ -431,10 +530,10 @@ struct VarUsedAfterLoopVisitor<'v, 't: 'v> { def_id: NodeId, iter_expr_id: NodeId, past_while_let: bool, - var_used_after_while_let: bool + var_used_after_while_let: bool, } -impl <'v, 't> Visitor<'v> for VarUsedAfterLoopVisitor<'v, 't> { +impl<'v, 't> Visitor<'v> for VarUsedAfterLoopVisitor<'v, 't> { fn visit_expr(&mut self, expr: &'v Expr) { if self.past_while_let { if Some(self.def_id) == var_def_id(self.cx, expr) { @@ -454,43 +553,52 @@ fn is_ref_iterable_type(cx: &LateContext, e: &Expr) -> bool { // no walk_ptrs_ty: calling iter() on a reference can make sense because it // will allow further borrows afterwards let ty = cx.tcx.expr_ty(e); - is_iterable_array(ty) || - match_type(cx, ty, &VEC_PATH) || - match_type(cx, ty, &LL_PATH) || - match_type(cx, ty, &["std", "collections", "hash", "map", "HashMap"]) || - match_type(cx, ty, &["std", "collections", "hash", "set", "HashSet"]) || - match_type(cx, ty, &["collections", "vec_deque", "VecDeque"]) || - match_type(cx, ty, &["collections", "binary_heap", "BinaryHeap"]) || - match_type(cx, ty, &["collections", "btree", "map", "BTreeMap"]) || - match_type(cx, ty, &["collections", "btree", "set", "BTreeSet"]) + is_iterable_array(ty) || match_type(cx, ty, &VEC_PATH) || match_type(cx, ty, &LL_PATH) || + match_type(cx, ty, &HASHMAP_PATH) || match_type(cx, ty, &["std", "collections", "hash", "set", "HashSet"]) || + match_type(cx, ty, &["collections", "vec_deque", "VecDeque"]) || + match_type(cx, ty, &["collections", "binary_heap", "BinaryHeap"]) || + match_type(cx, ty, &["collections", "btree", "map", "BTreeMap"]) || + match_type(cx, ty, &["collections", "btree", "set", "BTreeSet"]) } fn is_iterable_array(ty: ty::Ty) -> bool { // IntoIterator is currently only implemented for array sizes <= 32 in rustc match ty.sty { ty::TyArray(_, 0...32) => true, - _ => false + _ => false, } } /// If a block begins with a statement (possibly a `let` binding) and has an expression, return it. fn extract_expr_from_first_stmt(block: &Block) -> Option<&Expr> { - if block.stmts.is_empty() { return None; } + if block.stmts.is_empty() { + return None; + } if let StmtDecl(ref decl, _) = block.stmts[0].node { if let DeclLocal(ref local) = decl.node { - if let Some(ref expr) = local.init { Some(expr) } else { None } - } else { None } - } else { None } + if let Some(ref expr) = local.init { + Some(expr) + } else { + None + } + } else { + None + } + } else { + None + } } /// If a block begins with an expression (with or without semicolon), return it. fn extract_first_expr(block: &Block) -> Option<&Expr> { match block.expr { Some(ref expr) => Some(expr), - None if !block.stmts.is_empty() => match block.stmts[0].node { - StmtExpr(ref expr, _) | StmtSemi(ref expr, _) => Some(expr), - _ => None, - }, + None if !block.stmts.is_empty() => { + match block.stmts[0].node { + StmtExpr(ref expr, _) | StmtSemi(ref expr, _) => Some(expr), + _ => None, + } + } _ => None, } } @@ -500,10 +608,12 @@ fn is_break_expr(expr: &Expr) -> bool { match expr.node { ExprBreak(None) => true, // there won't be a `let = break` and so we can safely ignore the StmtDecl case - ExprBlock(ref b) => match extract_first_expr(b) { - Some(ref subexpr) => is_break_expr(subexpr), - None => false, - }, + ExprBlock(ref b) => { + match extract_first_expr(b) { + Some(ref subexpr) => is_break_expr(subexpr), + None => false, + } + } _ => false, } } @@ -513,19 +623,19 @@ fn is_break_expr(expr: &Expr) -> bool { // at the start of the loop. #[derive(PartialEq)] enum VarState { - Initial, // Not examined yet - IncrOnce, // Incremented exactly once, may be a loop counter - Declared, // Declared but not (yet) initialized to zero + Initial, // Not examined yet + IncrOnce, // Incremented exactly once, may be a loop counter + Declared, // Declared but not (yet) initialized to zero Warn, - DontWarn + DontWarn, } // Scan a for loop for variables that are incremented exactly once. struct IncrementVisitor<'v, 't: 'v> { - cx: &'v LateContext<'v, 't>, // context reference - states: HashMap, // incremented variables - depth: u32, // depth of conditional expressions - done: bool + cx: &'v LateContext<'v, 't>, // context reference + states: HashMap, // incremented variables + depth: u32, // depth of conditional expressions + done: bool, } impl<'v, 't> Visitor<'v> for IncrementVisitor<'v, 't> { @@ -540,33 +650,29 @@ fn visit_expr(&mut self, expr: &'v Expr) { let state = self.states.entry(def_id).or_insert(VarState::Initial); match parent.node { - ExprAssignOp(op, ref lhs, ref rhs) => + ExprAssignOp(op, ref lhs, ref rhs) => { if lhs.id == expr.id { if op.node == BiAdd && is_integer_literal(rhs, 1) { *state = match *state { VarState::Initial if self.depth == 0 => VarState::IncrOnce, - _ => VarState::DontWarn + _ => VarState::DontWarn, }; - } - else { + } else { // Assigned some other value *state = VarState::DontWarn; } - }, + } + } ExprAssign(ref lhs, _) if lhs.id == expr.id => *state = VarState::DontWarn, - ExprAddrOf(mutability,_) if mutability == MutMutable => *state = VarState::DontWarn, - _ => () + ExprAddrOf(mutability, _) if mutability == MutMutable => *state = VarState::DontWarn, + _ => (), } } - } - // Give up if there are nested loops - else if is_loop(expr) { + } else if is_loop(expr) { self.states.clear(); self.done = true; return; - } - // Keep track of whether we're inside a conditional expression - else if is_conditional(expr) { + } else if is_conditional(expr) { self.depth += 1; walk_expr(self, expr); self.depth -= 1; @@ -579,12 +685,12 @@ fn visit_expr(&mut self, expr: &'v Expr) { // Check whether a variable is initialized to zero at the start of a loop. struct InitializeVisitor<'v, 't: 'v> { cx: &'v LateContext<'v, 't>, // context reference - end_expr: &'v Expr, // the for loop. Stop scanning here. + end_expr: &'v Expr, // the for loop. Stop scanning here. var_id: NodeId, state: VarState, name: Option, - depth: u32, // depth of conditional expressions - past_loop: bool + depth: u32, // depth of conditional expressions + past_loop: bool, } impl<'v, 't> Visitor<'v> for InitializeVisitor<'v, 't> { @@ -601,8 +707,7 @@ fn visit_decl(&mut self, decl: &'v Decl) { } else { VarState::Declared } - } - else { + } else { VarState::Declared } } @@ -637,9 +742,10 @@ fn visit_expr(&mut self, expr: &'v Expr) { VarState::Warn } else { VarState::DontWarn - }} - ExprAddrOf(mutability,_) if mutability == MutMutable => self.state = VarState::DontWarn, - _ => () + } + } + ExprAddrOf(mutability, _) if mutability == MutMutable => self.state = VarState::DontWarn, + _ => (), } } @@ -647,14 +753,10 @@ fn visit_expr(&mut self, expr: &'v Expr) { self.state = VarState::DontWarn; return; } - } - // If there are other loops between the declaration and the target loop, give up - else if !self.past_loop && is_loop(expr) { + } else if !self.past_loop && is_loop(expr) { self.state = VarState::DontWarn; return; - } - // Keep track of whether we're inside a conditional expression - else if is_conditional(expr) { + } else if is_conditional(expr) { self.depth += 1; walk_expr(self, expr); self.depth -= 1; @@ -667,7 +769,7 @@ fn visit_expr(&mut self, expr: &'v Expr) { fn var_def_id(cx: &LateContext, expr: &Expr) -> Option { if let Some(path_res) = cx.tcx.def_map.borrow().get(&expr.id) { if let DefLocal(_, node_id) = path_res.base_def { - return Some(node_id) + return Some(node_id); } } None @@ -675,14 +777,14 @@ fn var_def_id(cx: &LateContext, expr: &Expr) -> Option { fn is_loop(expr: &Expr) -> bool { match expr.node { - ExprLoop(..) | ExprWhile(..) => true, - _ => false + ExprLoop(..) | ExprWhile(..) => true, + _ => false, } } fn is_conditional(expr: &Expr) -> bool { match expr.node { ExprIf(..) | ExprMatch(..) => true, - _ => false + _ => false, } }