]> git.lizzy.rs Git - rust.git/blob - clippy_lints/src/vec.rs
Auto merge of #6828 - mgacek8:issue_6758_enhance_wrong_self_convention, r=flip1995
[rust.git] / clippy_lints / src / vec.rs
1 use crate::consts::{constant, Constant};
2 use crate::rustc_target::abi::LayoutOf;
3 use crate::utils::{higher, snippet_with_applicability, span_lint_and_sugg};
4 use clippy_utils::ty::is_copy;
5 use if_chain::if_chain;
6 use rustc_errors::Applicability;
7 use rustc_hir::{BorrowKind, Expr, ExprKind};
8 use rustc_lint::{LateContext, LateLintPass};
9 use rustc_middle::ty::{self, Ty};
10 use rustc_session::{declare_tool_lint, impl_lint_pass};
11 use rustc_span::source_map::Span;
12
13 #[allow(clippy::module_name_repetitions)]
14 #[derive(Copy, Clone)]
15 pub struct UselessVec {
16     pub too_large_for_stack: u64,
17 }
18
19 declare_clippy_lint! {
20     /// **What it does:** Checks for usage of `&vec![..]` when using `&[..]` would
21     /// be possible.
22     ///
23     /// **Why is this bad?** This is less efficient.
24     ///
25     /// **Known problems:** None.
26     ///
27     /// **Example:**
28     /// ```rust
29     /// # fn foo(my_vec: &[u8]) {}
30     ///
31     /// // Bad
32     /// foo(&vec![1, 2]);
33     ///
34     /// // Good
35     /// foo(&[1, 2]);
36     /// ```
37     pub USELESS_VEC,
38     perf,
39     "useless `vec!`"
40 }
41
42 impl_lint_pass!(UselessVec => [USELESS_VEC]);
43
44 impl<'tcx> LateLintPass<'tcx> for UselessVec {
45     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
46         // search for `&vec![_]` expressions where the adjusted type is `&[_]`
47         if_chain! {
48             if let ty::Ref(_, ty, _) = cx.typeck_results().expr_ty_adjusted(expr).kind();
49             if let ty::Slice(..) = ty.kind();
50             if let ExprKind::AddrOf(BorrowKind::Ref, _, ref addressee) = expr.kind;
51             if let Some(vec_args) = higher::vec_macro(cx, addressee);
52             then {
53                 self.check_vec_macro(cx, &vec_args, expr.span);
54             }
55         }
56
57         // search for `for _ in vec![…]`
58         if_chain! {
59             if let Some((_, arg, _, _)) = higher::for_loop(expr);
60             if let Some(vec_args) = higher::vec_macro(cx, arg);
61             if is_copy(cx, vec_type(cx.typeck_results().expr_ty_adjusted(arg)));
62             then {
63                 // report the error around the `vec!` not inside `<std macros>:`
64                 let span = arg.span
65                     .ctxt()
66                     .outer_expn_data()
67                     .call_site
68                     .ctxt()
69                     .outer_expn_data()
70                     .call_site;
71                 self.check_vec_macro(cx, &vec_args, span);
72             }
73         }
74     }
75 }
76
77 impl UselessVec {
78     fn check_vec_macro<'tcx>(self, cx: &LateContext<'tcx>, vec_args: &higher::VecArgs<'tcx>, span: Span) {
79         let mut applicability = Applicability::MachineApplicable;
80         let snippet = match *vec_args {
81             higher::VecArgs::Repeat(elem, len) => {
82                 if let Some((Constant::Int(len_constant), _)) = constant(cx, cx.typeck_results(), len) {
83                     #[allow(clippy::cast_possible_truncation)]
84                     if len_constant as u64 * size_of(cx, elem) > self.too_large_for_stack {
85                         return;
86                     }
87
88                     format!(
89                         "&[{}; {}]",
90                         snippet_with_applicability(cx, elem.span, "elem", &mut applicability),
91                         snippet_with_applicability(cx, len.span, "len", &mut applicability)
92                     )
93                 } else {
94                     return;
95                 }
96             },
97             higher::VecArgs::Vec(args) => {
98                 if let Some(last) = args.iter().last() {
99                     #[allow(clippy::cast_possible_truncation)]
100                     if args.len() as u64 * size_of(cx, last) > self.too_large_for_stack {
101                         return;
102                     }
103                     let span = args[0].span.to(last.span);
104
105                     format!("&[{}]", snippet_with_applicability(cx, span, "..", &mut applicability))
106                 } else {
107                     "&[]".into()
108                 }
109             },
110         };
111
112         span_lint_and_sugg(
113             cx,
114             USELESS_VEC,
115             span,
116             "useless use of `vec!`",
117             "you can use a slice directly",
118             snippet,
119             applicability,
120         );
121     }
122 }
123
124 fn size_of(cx: &LateContext<'_>, expr: &Expr<'_>) -> u64 {
125     let ty = cx.typeck_results().expr_ty_adjusted(expr);
126     cx.layout_of(ty).map_or(0, |l| l.size.bytes())
127 }
128
129 /// Returns the item type of the vector (i.e., the `T` in `Vec<T>`).
130 fn vec_type(ty: Ty<'_>) -> Ty<'_> {
131     if let ty::Adt(_, substs) = ty.kind() {
132         substs.type_at(0)
133     } else {
134         panic!("The type of `vec!` is a not a struct?");
135     }
136 }