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