1 use crate::consts
::{constant, Constant}
;
2 use crate::rustc_target
::abi
::LayoutOf
;
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
;
15 #[allow(clippy::module_name_repetitions)]
16 #[derive(Copy, Clone)]
17 pub struct UselessVec
{
18 pub too_large_for_stack
: u64,
21 declare_clippy_lint
! {
22 /// **What it does:** Checks for usage of `&vec![..]` when using `&[..]` would
25 /// **Why is this bad?** This is less efficient.
27 /// **Known problems:** None.
31 /// # fn foo(my_vec: &[u8]) {}
44 impl_lint_pass
!(UselessVec
=> [USELESS_VEC
]);
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 `&[_]`
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
);
55 self.check_vec_macro(cx
, &vec_args
, mutability
, expr
.span
);
59 // search for `for _ in vec![…]`
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
)));
65 // report the error around the `vec!` not inside `<std macros>:`
73 self.check_vec_macro(cx
, &vec_args
, Mutability
::Not
, span
);
80 fn check_vec_macro
<'tcx
>(
82 cx
: &LateContext
<'tcx
>,
83 vec_args
: &higher
::VecArgs
<'tcx
>,
84 mutability
: Mutability
,
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
{
100 snippet_with_applicability(cx
, elem
.span
, "elem", &mut applicability
),
101 snippet_with_applicability(cx
, len
.span
, "len", &mut applicability
)
107 snippet_with_applicability(cx
, elem
.span
, "elem", &mut applicability
),
108 snippet_with_applicability(cx
, len
.span
, "len", &mut applicability
)
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
{
122 let span
= args
[0].span
.to(last
.span
);
128 snippet_with_applicability(cx
, span
, "..", &mut applicability
)
132 format
!("&[{}]", snippet_with_applicability(cx
, span
, "..", &mut applicability
))
137 Mutability
::Mut
=> "&mut []".into(),
138 Mutability
::Not
=> "&[]".into(),
148 "useless use of `vec!`",
149 "you can use a slice directly",
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())
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() {
166 panic
!("The type of `vec!` is a not a struct?");