diff --git a/src/loops.rs b/src/loops.rs index 546f07a6507..10a8a76d7ae 100644 --- a/src/loops.rs +++ b/src/loops.rs @@ -14,7 +14,7 @@ use utils::{snippet, span_lint, get_parent_expr, match_trait_method, match_type, in_external_macro, span_help_and_lint, is_integer_literal, get_enclosing_block, span_lint_and_then, - unsugar_range, walk_ptrs_ty}; + unsugar_range, walk_ptrs_ty, recover_for_loop}; use utils::{BTREEMAP_PATH, HASHMAP_PATH, LL_PATH, OPTION_PATH, RESULT_PATH, VEC_PATH}; use utils::UnsugaredRange; @@ -641,30 +641,6 @@ fn visit_expr(&mut self, expr: &Expr) { } } -/// Recover the essential nodes of a desugared for loop: -/// `for pat in arg { body }` becomes `(pat, arg, body)`. -fn recover_for_loop(expr: &Expr) -> Option<(&Pat, &Expr, &Expr)> { - if_let_chain! { - [ - let ExprMatch(ref iterexpr, ref arms, _) = expr.node, - let ExprCall(_, ref iterargs) = iterexpr.node, - iterargs.len() == 1 && arms.len() == 1 && arms[0].guard.is_none(), - let ExprLoop(ref block, _) = arms[0].body.node, - block.stmts.is_empty(), - let Some(ref loopexpr) = block.expr, - let ExprMatch(_, ref innerarms, MatchSource::ForLoopDesugar) = loopexpr.node, - innerarms.len() == 2 && innerarms[0].pats.len() == 1, - let PatKind::TupleStruct(_, Some(ref somepats)) = innerarms[0].pats[0].node, - somepats.len() == 1 - ], { - return Some((&somepats[0], - &iterargs[0], - &innerarms[0].body)); - } - } - None -} - struct VarVisitor<'v, 't: 'v> { cx: &'v LateContext<'v, 't>, // context reference var: Name, // var name to look for as index diff --git a/src/utils/mod.rs b/src/utils/mod.rs index 34404f4c2e9..300cb8df042 100644 --- a/src/utils/mod.rs +++ b/src/utils/mod.rs @@ -800,3 +800,27 @@ pub fn same_tys<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, a: ty::Ty<'tcx>, b: ty::Ty let new_b = b.subst(infcx.tcx, &infcx.parameter_environment.free_substs); infcx.can_equate(&new_a, &new_b).is_ok() } + +/// Recover the essential nodes of a desugared for loop: +/// `for pat in arg { body }` becomes `(pat, arg, body)`. +pub fn recover_for_loop(expr: &Expr) -> Option<(&Pat, &Expr, &Expr)> { + if_let_chain! { + [ + let ExprMatch(ref iterexpr, ref arms, _) = expr.node, + let ExprCall(_, ref iterargs) = iterexpr.node, + iterargs.len() == 1 && arms.len() == 1 && arms[0].guard.is_none(), + let ExprLoop(ref block, _) = arms[0].body.node, + block.stmts.is_empty(), + let Some(ref loopexpr) = block.expr, + let ExprMatch(_, ref innerarms, MatchSource::ForLoopDesugar) = loopexpr.node, + innerarms.len() == 2 && innerarms[0].pats.len() == 1, + let PatKind::TupleStruct(_, Some(ref somepats)) = innerarms[0].pats[0].node, + somepats.len() == 1 + ], { + return Some((&somepats[0], + &iterargs[0], + &innerarms[0].body)); + } + } + None +} diff --git a/src/vec.rs b/src/vec.rs index 481c84079f2..412ebf396dd 100644 --- a/src/vec.rs +++ b/src/vec.rs @@ -4,7 +4,7 @@ use syntax::codemap::Span; use syntax::ptr::P; use utils::VEC_FROM_ELEM_PATH; -use utils::{is_expn_of, match_path, snippet, span_lint_and_then}; +use utils::{is_expn_of, match_path, recover_for_loop, snippet, span_lint_and_then}; /// **What it does:** This lint warns about using `&vec![..]` when using `&[..]` would be possible. /// @@ -38,32 +38,42 @@ fn check_expr(&mut self, cx: &LateContext, expr: &Expr) { let TypeVariants::TyRef(_, ref ty) = cx.tcx.expr_ty_adjusted(expr).sty, let TypeVariants::TySlice(..) = ty.ty.sty, let ExprAddrOf(_, ref addressee) = expr.node, - let Some(vec_args) = unexpand_vec(cx, addressee) ], { - let snippet = match vec_args { - VecArgs::Repeat(elem, len) => { - format!("&[{}; {}]", snippet(cx, elem.span, "elem"), snippet(cx, len.span, "len")).into() - } - VecArgs::Vec(args) => { - if let Some(last) = args.iter().last() { - let span = Span { - lo: args[0].span.lo, - hi: last.span.hi, - expn_id: args[0].span.expn_id, - }; - - format!("&[{}]", snippet(cx, span, "..")).into() - } - else { - "&[]".into() - } - } - }; - - span_lint_and_then(cx, USELESS_VEC, expr.span, "useless use of `vec!`", |db| { - db.span_suggestion(expr.span, "you can use a slice directly", snippet); - }); + check_vec_macro(cx, expr, addressee); }} + + // search for `for _ in vec![…]` + if let Some((_, arg, _)) = recover_for_loop(expr) { + check_vec_macro(cx, arg, arg); + } + } +} + +fn check_vec_macro(cx: &LateContext, expr: &Expr, vec: &Expr) { + if let Some(vec_args) = unexpand_vec(cx, vec) { + let snippet = match vec_args { + VecArgs::Repeat(elem, len) => { + format!("&[{}; {}]", snippet(cx, elem.span, "elem"), snippet(cx, len.span, "len")).into() + } + VecArgs::Vec(args) => { + if let Some(last) = args.iter().last() { + let span = Span { + lo: args[0].span.lo, + hi: last.span.hi, + expn_id: args[0].span.expn_id, + }; + + format!("&[{}]", snippet(cx, span, "..")).into() + } + else { + "&[]".into() + } + } + }; + + span_lint_and_then(cx, USELESS_VEC, expr.span, "useless use of `vec!`", |db| { + db.span_suggestion(expr.span, "you can use a slice directly", snippet); + }); } } diff --git a/tests/compile-fail/vec.rs b/tests/compile-fail/vec.rs index b4f52ecadc5..eda75a2fe8a 100644 --- a/tests/compile-fail/vec.rs +++ b/tests/compile-fail/vec.rs @@ -41,4 +41,11 @@ fn main() { on_vec(&vec![]); on_vec(&vec![1, 2]); on_vec(&vec![1; 2]); + + for a in vec![1, 2, 3] { + //~^ ERROR useless use of `vec!` + //~| HELP you can use + //~| SUGGESTION for a in &[1, 2, 3] { + println!("{}", a); + } }