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;
15 #[expect(clippy::module_name_repetitions)]
16 #[derive(Copy, Clone)]
17 pub struct UselessVec {
18 pub too_large_for_stack: u64,
21 declare_clippy_lint! {
23 /// Checks for usage of `&vec![..]` when using `&[..]` would
26 /// ### Why is this bad?
27 /// This is less efficient.
31 /// fn foo(_x: &[u8]) {}
38 /// # fn foo(_x: &[u8]) {}
41 #[clippy::version = "pre 1.29.0"]
47 impl_lint_pass!(UselessVec => [USELESS_VEC]);
49 impl<'tcx> LateLintPass<'tcx> for UselessVec {
50 fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
51 // search for `&vec![_]` expressions where the adjusted type is `&[_]`
53 if let ty::Ref(_, ty, _) = cx.typeck_results().expr_ty_adjusted(expr).kind();
54 if let ty::Slice(..) = ty.kind();
55 if let ExprKind::AddrOf(BorrowKind::Ref, mutability, addressee) = expr.kind;
56 if let Some(vec_args) = higher::VecArgs::hir(cx, addressee);
58 self.check_vec_macro(cx, &vec_args, mutability, expr.span);
62 // search for `for _ in vec![…]`
64 if let Some(higher::ForLoop { arg, .. }) = higher::ForLoop::hir(expr);
65 if let Some(vec_args) = higher::VecArgs::hir(cx, arg);
66 if is_copy(cx, vec_type(cx.typeck_results().expr_ty_adjusted(arg)));
68 // report the error around the `vec!` not inside `<std macros>:`
69 let span = arg.span.ctxt().outer_expn_data().call_site;
70 self.check_vec_macro(cx, &vec_args, Mutability::Not, span);
77 fn check_vec_macro<'tcx>(
79 cx: &LateContext<'tcx>,
80 vec_args: &higher::VecArgs<'tcx>,
81 mutability: Mutability,
84 let mut applicability = Applicability::MachineApplicable;
85 let snippet = match *vec_args {
86 higher::VecArgs::Repeat(elem, len) => {
87 if let Some((Constant::Int(len_constant), _)) = constant(cx, cx.typeck_results(), len) {
88 #[expect(clippy::cast_possible_truncation)]
89 if len_constant as u64 * size_of(cx, elem) > self.too_large_for_stack {
97 snippet_with_applicability(cx, elem.span, "elem", &mut applicability),
98 snippet_with_applicability(cx, len.span, "len", &mut applicability)
104 snippet_with_applicability(cx, elem.span, "elem", &mut applicability),
105 snippet_with_applicability(cx, len.span, "len", &mut applicability)
113 higher::VecArgs::Vec(args) => {
114 if let Some(last) = args.iter().last() {
115 if args.len() as u64 * size_of(cx, last) > self.too_large_for_stack {
118 let span = args[0].span.to(last.span);
124 snippet_with_applicability(cx, span, "..", &mut applicability)
128 format!("&[{}]", snippet_with_applicability(cx, span, "..", &mut applicability))
133 Mutability::Mut => "&mut []".into(),
134 Mutability::Not => "&[]".into(),
144 "useless use of `vec!`",
145 "you can use a slice directly",
152 fn size_of(cx: &LateContext<'_>, expr: &Expr<'_>) -> u64 {
153 let ty = cx.typeck_results().expr_ty_adjusted(expr);
154 cx.layout_of(ty).map_or(0, |l| l.size.bytes())
157 /// Returns the item type of the vector (i.e., the `T` in `Vec<T>`).
158 fn vec_type(ty: Ty<'_>) -> Ty<'_> {
159 if let ty::Adt(_, substs) = ty.kind() {
162 panic!("The type of `vec!` is a not a struct?");