]> git.lizzy.rs Git - rust.git/commitdiff
Add `for _ in vec![…]` to the `USELESS_VEC` lint
authormcarton <cartonmartin+git@gmail.com>
Mon, 28 Mar 2016 21:32:55 +0000 (23:32 +0200)
committermcarton <cartonmartin+git@gmail.com>
Mon, 28 Mar 2016 21:32:55 +0000 (23:32 +0200)
src/loops.rs
src/utils/mod.rs
src/vec.rs
tests/compile-fail/vec.rs

index 546f07a650751edc7face6e8288ae5579e127c45..10a8a76d7ae99159e9bf62dcb15b68854afe6ecb 100644 (file)
@@ -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
index 34404f4c2e9890e21413a2b0dc46a9bc88dcdfa0..300cb8df042dd29e0968aee69153317f95133d85 100644 (file)
@@ -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
+}
index 481c84079f25e44572680522bc1e84c516a91a3d..412ebf396dd3316a7fbe635b0b1b420ee6cdcdfc 100644 (file)
@@ -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,
-                        };
+            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()
-                    }
+                    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);
-            });
-        }}
+        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);
+        });
     }
 }
 
index b4f52ecadc521b0bff22a9433a5a10f7a8eb9dcf..eda75a2fe8a4f6bfc2edcb86a016f210269d5c9c 100644 (file)
@@ -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);
+    }
 }