]> git.lizzy.rs Git - rust.git/blob - clippy_lints/src/vec.rs
Merge branch 'master' into allow-pass-by-ref-on-ref-return
[rust.git] / clippy_lints / src / vec.rs
1 use rustc::hir::*;
2 use rustc::lint::*;
3 use rustc::{declare_lint, lint_array};
4 use if_chain::if_chain;
5 use rustc::ty::{self, Ty};
6 use syntax::codemap::Span;
7 use crate::utils::{higher, is_copy, snippet, span_lint_and_sugg};
8 use crate::consts::constant;
9
10 /// **What it does:** Checks for usage of `&vec![..]` when using `&[..]` would
11 /// be possible.
12 ///
13 /// **Why is this bad?** This is less efficient.
14 ///
15 /// **Known problems:** None.
16 ///
17 /// **Example:**
18 /// ```rust,ignore
19 /// foo(&vec![1, 2])
20 /// ```
21 declare_clippy_lint! {
22     pub USELESS_VEC,
23     perf,
24     "useless `vec!`"
25 }
26
27 #[derive(Copy, Clone, Debug)]
28 pub struct Pass;
29
30 impl LintPass for Pass {
31     fn get_lints(&self) -> LintArray {
32         lint_array!(USELESS_VEC)
33     }
34 }
35
36 impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass {
37     fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr) {
38         // search for `&vec![_]` expressions where the adjusted type is `&[_]`
39         if_chain! {
40             if let ty::TyRef(_, ty, _) = cx.tables.expr_ty_adjusted(expr).sty;
41             if let ty::TySlice(..) = ty.sty;
42             if let ExprKind::AddrOf(_, ref addressee) = expr.node;
43             if let Some(vec_args) = higher::vec_macro(cx, addressee);
44             then {
45                 check_vec_macro(cx, &vec_args, expr.span);
46             }
47         }
48
49         // search for `for _ in vec![…]`
50         if_chain! {
51             if let Some((_, arg, _)) = higher::for_loop(expr);
52             if let Some(vec_args) = higher::vec_macro(cx, arg);
53             if is_copy(cx, vec_type(cx.tables.expr_ty_adjusted(arg)));
54             then {
55                 // report the error around the `vec!` not inside `<std macros>:`
56                 let span = arg.span
57                     .ctxt()
58                     .outer()
59                     .expn_info()
60                     .map(|info| info.call_site)
61                     .expect("unable to get call_site");
62                 check_vec_macro(cx, &vec_args, span);
63             }
64         }
65     }
66 }
67
68 fn check_vec_macro<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, vec_args: &higher::VecArgs<'tcx>, span: Span) {
69     let snippet = match *vec_args {
70         higher::VecArgs::Repeat(elem, len) => {
71             if constant(cx, cx.tables, len).is_some() {
72                 format!("&[{}; {}]", snippet(cx, elem.span, "elem"), snippet(cx, len.span, "len"))
73             } else {
74                 return;
75             }
76         },
77         higher::VecArgs::Vec(args) => if let Some(last) = args.iter().last() {
78             let span = args[0].span.to(last.span);
79
80             format!("&[{}]", snippet(cx, span, ".."))
81         } else {
82             "&[]".into()
83         },
84     };
85
86     span_lint_and_sugg(
87         cx,
88         USELESS_VEC,
89         span,
90         "useless use of `vec!`",
91         "you can use a slice directly",
92         snippet,
93     );
94 }
95
96 /// Return the item type of the vector (ie. the `T` in `Vec<T>`).
97 fn vec_type(ty: Ty<'_>) -> Ty<'_> {
98     if let ty::TyAdt(_, substs) = ty.sty {
99         substs.type_at(0)
100     } else {
101         panic!("The type of `vec!` is a not a struct?");
102     }
103 }