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