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