]> git.lizzy.rs Git - rust.git/blobdiff - clippy_lints/src/vec.rs
Merge branch 'macro-use' into HEAD
[rust.git] / clippy_lints / src / vec.rs
index cc9d5a5f224b042e0f7256d972ed11077c3058b2..a58d73f86daa067d5d14e2a84d0f493844a4060f 100644 (file)
@@ -1,12 +1,14 @@
 use rustc::hir::*;
 use rustc::lint::*;
-use rustc::ty;
-use rustc_const_eval::EvalHint::ExprTypeChecked;
-use rustc_const_eval::eval_const_expr_partial;
+use rustc::{declare_lint, lint_array};
+use if_chain::if_chain;
+use rustc::ty::{self, Ty};
 use syntax::codemap::Span;
-use utils::{higher, is_copy, snippet, span_lint_and_then};
+use crate::utils::{higher, is_copy, snippet, span_lint_and_sugg};
+use crate::consts::constant;
 
-/// **What it does:** This lint warns about using `&vec![..]` when using `&[..]` would be possible.
+/// **What it does:** Checks for usage of `&vec![..]` when using `&[..]` would
+/// be possible.
 ///
 /// **Why is this bad?** This is less efficient.
 ///
@@ -16,9 +18,9 @@
 /// ```rust,ignore
 /// foo(&vec![1, 2])
 /// ```
-declare_lint! {
+declare_clippy_lint! {
     pub USELESS_VEC,
-    Warn,
+    perf,
     "useless `vec!`"
 }
 
@@ -31,64 +33,70 @@ fn get_lints(&self) -> LintArray {
     }
 }
 
-impl LateLintPass for Pass {
-    fn check_expr(&mut self, cx: &LateContext, expr: &Expr) {
+impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass {
+    fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr) {
         // search for `&vec![_]` expressions where the adjusted type is `&[_]`
-        if_let_chain!{[
-            let ty::TypeVariants::TyRef(_, ref ty) = cx.tcx.expr_ty_adjusted(expr).sty,
-            let ty::TypeVariants::TySlice(..) = ty.ty.sty,
-            let ExprAddrOf(_, ref addressee) = expr.node,
-            let Some(vec_args) = higher::vec_macro(cx, addressee),
-        ], {
-            check_vec_macro(cx, &vec_args, expr.span);
-        }}
+        if_chain! {
+            if let ty::TyRef(_, ty, _) = cx.tables.expr_ty_adjusted(expr).sty;
+            if let ty::TySlice(..) = ty.sty;
+            if let ExprKind::AddrOf(_, ref addressee) = expr.node;
+            if let Some(vec_args) = higher::vec_macro(cx, addressee);
+            then {
+                check_vec_macro(cx, &vec_args, expr.span);
+            }
+        }
 
         // search for `for _ in vec![…]`
-        if_let_chain!{[
-            let Some((_, arg, _)) = higher::for_loop(expr),
-            let Some(vec_args) = higher::vec_macro(cx, arg),
-            is_copy(cx, vec_type(cx.tcx.expr_ty_adjusted(arg)), cx.tcx.map.get_parent(expr.id)),
-        ], {
-            // report the error around the `vec!` not inside `<std macros>:`
-            let span = cx.sess().codemap().source_callsite(arg.span);
-            check_vec_macro(cx, &vec_args, span);
-        }}
+        if_chain! {
+            if let Some((_, arg, _)) = higher::for_loop(expr);
+            if let Some(vec_args) = higher::vec_macro(cx, arg);
+            if is_copy(cx, vec_type(cx.tables.expr_ty_adjusted(arg)));
+            then {
+                // report the error around the `vec!` not inside `<std macros>:`
+                let span = arg.span
+                    .ctxt()
+                    .outer()
+                    .expn_info()
+                    .map(|info| info.call_site)
+                    .expect("unable to get call_site");
+                check_vec_macro(cx, &vec_args, span);
+            }
+        }
     }
 }
 
-fn check_vec_macro(cx: &LateContext, vec_args: &higher::VecArgs, span: Span) {
+fn check_vec_macro<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, vec_args: &higher::VecArgs<'tcx>, span: Span) {
     let snippet = match *vec_args {
         higher::VecArgs::Repeat(elem, len) => {
-            if eval_const_expr_partial(cx.tcx, len, ExprTypeChecked, None).is_ok() {
-                format!("&[{}; {}]", snippet(cx, elem.span, "elem"), snippet(cx, len.span, "len")).into()
+            if constant(cx, cx.tables, len).is_some() {
+                format!("&[{}; {}]", snippet(cx, elem.span, "elem"), snippet(cx, len.span, "len"))
             } else {
                 return;
             }
-        }
-        higher::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,
-                };
+        },
+        higher::VecArgs::Vec(args) => if let Some(last) = args.iter().last() {
+            let span = args[0].span.to(last.span);
 
-                format!("&[{}]", snippet(cx, span, "..")).into()
-            } else {
-                "&[]".into()
-            }
-        }
+            format!("&[{}]", snippet(cx, span, ".."))
+        } else {
+            "&[]".into()
+        },
     };
 
-    span_lint_and_then(cx, USELESS_VEC, span, "useless use of `vec!`", |db| {
-        db.span_suggestion(span, "you can use a slice directly", snippet);
-    });
+    span_lint_and_sugg(
+        cx,
+        USELESS_VEC,
+        span,
+        "useless use of `vec!`",
+        "you can use a slice directly",
+        snippet,
+    );
 }
 
 /// Return the item type of the vector (ie. the `T` in `Vec<T>`).
-fn vec_type(ty: ty::Ty) -> ty::Ty {
-    if let ty::TyStruct(_, substs) = ty.sty {
-        substs.types.get(ty::subst::ParamSpace::TypeSpace, 0)
+fn vec_type(ty: Ty) -> Ty {
+    if let ty::TyAdt(_, substs) = ty.sty {
+        substs.type_at(0)
     } else {
         panic!("The type of `vec!` is a not a struct?");
     }