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;
13 #[allow(clippy::module_name_repetitions)]
14 #[derive(Copy, Clone)]
15 pub struct UselessVec {
16 pub too_large_for_stack: u64,
19 declare_clippy_lint! {
20 /// **What it does:** Checks for usage of `&vec![..]` when using `&[..]` would
23 /// **Why is this bad?** This is less efficient.
25 /// **Known problems:** None.
29 /// # fn foo(my_vec: &[u8]) {}
42 impl_lint_pass!(UselessVec => [USELESS_VEC]);
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 `&[_]`
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);
53 self.check_vec_macro(cx, &vec_args, expr.span);
57 // search for `for _ in vec![…]`
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)));
63 // report the error around the `vec!` not inside `<std macros>:`
71 self.check_vec_macro(cx, &vec_args, span);
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 {
90 snippet_with_applicability(cx, elem.span, "elem", &mut applicability),
91 snippet_with_applicability(cx, len.span, "len", &mut applicability)
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 {
103 let span = args[0].span.to(last.span);
105 format!("&[{}]", snippet_with_applicability(cx, span, "..", &mut applicability))
116 "useless use of `vec!`",
117 "you can use a slice directly",
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())
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() {
134 panic!("The type of `vec!` is a not a struct?");