Skip to content

Commit b309875

Browse files
committed
[useless_vec]: detect unnecessary vec![_]
1 parent f93df98 commit b309875

File tree

1 file changed

+42
-55
lines changed

1 file changed

+42
-55
lines changed

clippy_lints/src/vec.rs

Lines changed: 42 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@ use clippy_utils::ty::is_copy;
88
use clippy_utils::visitors::for_each_local_use_after_expr;
99
use clippy_utils::{get_parent_expr, higher, is_trait_method};
1010
use if_chain::if_chain;
11-
use rustc_ast::BindingAnnotation;
1211
use rustc_errors::Applicability;
1312
use rustc_hir::{BorrowKind, Expr, ExprKind, Mutability, Node, PatKind};
1413
use rustc_lint::{LateContext, LateLintPass};
@@ -54,11 +53,7 @@ declare_clippy_lint! {
5453
impl_lint_pass!(UselessVec => [USELESS_VEC]);
5554

5655
fn adjusts_to_slice(cx: &LateContext<'_>, e: &Expr<'_>) -> bool {
57-
if let ty::Ref(_, ty, _) = cx.typeck_results().expr_ty_adjusted(e).kind() {
58-
ty.is_slice()
59-
} else {
60-
false
61-
}
56+
matches!(cx.typeck_results().expr_ty_adjusted(e).kind(), ty::Ref(_, ty, _) if ty.is_slice())
6257
}
6358

6459
/// Checks if the given expression is a method call to a `Vec` method
@@ -76,13 +71,21 @@ fn is_allowed_vec_method(cx: &LateContext<'_>, e: &Expr<'_>) -> bool {
7671

7772
impl<'tcx> LateLintPass<'tcx> for UselessVec {
7873
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
79-
// search for `&vec![_]` expressions where the adjusted type is `&[_]`
74+
// search for `&vec![_]` or `vec![_]` expressions where the adjusted type is `&[_]`
8075
if_chain! {
8176
if adjusts_to_slice(cx, expr);
82-
if let ExprKind::AddrOf(BorrowKind::Ref, mutability, addressee) = expr.kind;
83-
if let Some(vec_args) = higher::VecArgs::hir(cx, addressee);
77+
if let Some(vec_args) = higher::VecArgs::hir(cx, expr.peel_borrows());
8478
then {
85-
self.check_vec_macro(cx, &vec_args, mutability, expr.span, SuggestSlice::Yes);
79+
let (suggest_slice, span) = if let ExprKind::AddrOf(BorrowKind::Ref, mutability, _) = expr.kind {
80+
// `expr` is `&vec![_]`, so suggest `&[_]` (or `&mut[_]` resp.)
81+
(SuggestedType::SliceRef(mutability), expr.span)
82+
} else {
83+
// `expr` is the `vec![_]` expansion, so suggest `[_]`
84+
// and also use the span of the actual `vec![_]` expression
85+
(SuggestedType::Array, expr.span.ctxt().outer_expn_data().call_site)
86+
};
87+
88+
self.check_vec_macro(cx, &vec_args, span, suggest_slice);
8689
}
8790
}
8891

@@ -93,7 +96,7 @@ impl<'tcx> LateLintPass<'tcx> for UselessVec {
9396
// for now ignore locals with type annotations.
9497
// this is to avoid compile errors when doing the suggestion here: let _: Vec<_> = vec![..];
9598
&& local.ty.is_none()
96-
&& let PatKind::Binding(BindingAnnotation(_, mutbl), id, ..) = local.pat.kind
99+
&& let PatKind::Binding(_, id, ..) = local.pat.kind
97100
&& is_copy(cx, vec_type(cx.typeck_results().expr_ty_adjusted(expr)))
98101
{
99102
let only_slice_uses = for_each_local_use_after_expr(cx, id, expr.hir_id, |expr| {
@@ -113,9 +116,8 @@ impl<'tcx> LateLintPass<'tcx> for UselessVec {
113116
self.check_vec_macro(
114117
cx,
115118
&vec_args,
116-
mutbl,
117119
expr.span.ctxt().outer_expn_data().call_site,
118-
SuggestSlice::No
120+
SuggestedType::Array
119121
);
120122
}
121123
}
@@ -128,7 +130,7 @@ impl<'tcx> LateLintPass<'tcx> for UselessVec {
128130
then {
129131
// report the error around the `vec!` not inside `<std macros>:`
130132
let span = arg.span.ctxt().outer_expn_data().call_site;
131-
self.check_vec_macro(cx, &vec_args, Mutability::Not, span, SuggestSlice::No);
133+
self.check_vec_macro(cx, &vec_args, span, SuggestedType::Array);
132134
}
133135
}
134136
}
@@ -137,29 +139,23 @@ impl<'tcx> LateLintPass<'tcx> for UselessVec {
137139
}
138140

139141
#[derive(Copy, Clone)]
140-
enum SuggestSlice {
142+
enum SuggestedType {
141143
/// Suggest using a slice `&[..]` / `&mut [..]`
142-
Yes,
144+
SliceRef(Mutability),
143145
/// Suggest using an array: `[..]`
144-
No,
146+
Array,
145147
}
146148

147149
impl UselessVec {
148150
fn check_vec_macro<'tcx>(
149151
&mut self,
150152
cx: &LateContext<'tcx>,
151153
vec_args: &higher::VecArgs<'tcx>,
152-
mutability: Mutability,
153154
span: Span,
154-
suggest_slice: SuggestSlice,
155+
suggest_slice: SuggestedType,
155156
) {
156157
let mut applicability = Applicability::MachineApplicable;
157158

158-
let (borrow_prefix_mut, borrow_prefix) = match suggest_slice {
159-
SuggestSlice::Yes => ("&mut ", "&"),
160-
SuggestSlice::No => ("", ""),
161-
};
162-
163159
let snippet = match *vec_args {
164160
higher::VecArgs::Repeat(elem, len) => {
165161
if let Some(Constant::Int(len_constant)) = constant(cx, cx.typeck_results(), len) {
@@ -168,21 +164,13 @@ impl UselessVec {
168164
return;
169165
}
170166

171-
match mutability {
172-
Mutability::Mut => {
173-
format!(
174-
"{borrow_prefix_mut}[{}; {}]",
175-
snippet_with_applicability(cx, elem.span, "elem", &mut applicability),
176-
snippet_with_applicability(cx, len.span, "len", &mut applicability)
177-
)
178-
},
179-
Mutability::Not => {
180-
format!(
181-
"{borrow_prefix}[{}; {}]",
182-
snippet_with_applicability(cx, elem.span, "elem", &mut applicability),
183-
snippet_with_applicability(cx, len.span, "len", &mut applicability)
184-
)
185-
},
167+
let elem = snippet_with_applicability(cx, elem.span, "elem", &mut applicability);
168+
let len = snippet_with_applicability(cx, len.span, "len", &mut applicability);
169+
170+
match suggest_slice {
171+
SuggestedType::SliceRef(Mutability::Mut) => format!("&mut [{elem}; {len}]"),
172+
SuggestedType::SliceRef(Mutability::Not) => format!("&[{elem}; {len}]"),
173+
SuggestedType::Array => format!("[{elem}; {len}]"),
186174
}
187175
} else {
188176
return;
@@ -194,25 +182,24 @@ impl UselessVec {
194182
return;
195183
}
196184
let span = args[0].span.to(last.span);
185+
let args = snippet_with_applicability(cx, span, "..", &mut applicability);
197186

198-
match mutability {
199-
Mutability::Mut => {
200-
format!(
201-
"{borrow_prefix_mut}[{}]",
202-
snippet_with_applicability(cx, span, "..", &mut applicability)
203-
)
187+
match suggest_slice {
188+
SuggestedType::SliceRef(Mutability::Mut) => {
189+
format!("&mut [{args}]")
190+
},
191+
SuggestedType::SliceRef(Mutability::Not) => {
192+
format!("&[{args}]")
204193
},
205-
Mutability::Not => {
206-
format!(
207-
"{borrow_prefix}[{}]",
208-
snippet_with_applicability(cx, span, "..", &mut applicability)
209-
)
194+
SuggestedType::Array => {
195+
format!("[{args}]")
210196
},
211197
}
212198
} else {
213-
match mutability {
214-
Mutability::Mut => format!("{borrow_prefix_mut}[]"),
215-
Mutability::Not => format!("{borrow_prefix}[]"),
199+
match suggest_slice {
200+
SuggestedType::SliceRef(Mutability::Mut) => "&mut []".to_owned(),
201+
SuggestedType::SliceRef(Mutability::Not) => "&[]".to_owned(),
202+
SuggestedType::Array => "[]".to_owned(),
216203
}
217204
}
218205
},
@@ -226,8 +213,8 @@ impl UselessVec {
226213
&format!(
227214
"you can use {} directly",
228215
match suggest_slice {
229-
SuggestSlice::Yes => "a slice",
230-
SuggestSlice::No => "an array",
216+
SuggestedType::SliceRef(_) => "a slice",
217+
SuggestedType::Array => "an array",
231218
}
232219
),
233220
snippet,

0 commit comments

Comments
 (0)