@@ -9,7 +9,7 @@ use clippy_utils::ty::is_copy;
9
9
use clippy_utils:: visitors:: for_each_local_use_after_expr;
10
10
use clippy_utils:: { get_parent_expr, higher, is_trait_method} ;
11
11
use rustc_errors:: Applicability ;
12
- use rustc_hir:: { BorrowKind , Expr , ExprKind , HirId , Mutability , Node , PatKind } ;
12
+ use rustc_hir:: { BorrowKind , Expr , ExprKind , HirId , Local , Mutability , Node , Pat , PatKind } ;
13
13
use rustc_lint:: { LateContext , LateLintPass } ;
14
14
use rustc_middle:: ty;
15
15
use rustc_middle:: ty:: layout:: LayoutOf ;
@@ -52,35 +52,25 @@ declare_clippy_lint! {
52
52
53
53
impl_lint_pass ! ( UselessVec => [ USELESS_VEC ] ) ;
54
54
55
- fn adjusts_to_slice ( cx : & LateContext < ' _ > , e : & Expr < ' _ > ) -> bool {
56
- matches ! ( cx. typeck_results( ) . expr_ty_adjusted( e) . kind( ) , ty:: Ref ( _, ty, _) if ty. is_slice( ) )
57
- }
58
-
59
- /// Checks if the given expression is a method call to a `Vec` method
60
- /// that also exists on slices. If this returns true, it means that
61
- /// this expression does not actually require a `Vec` and could just work with an array.
62
- pub fn is_allowed_vec_method ( cx : & LateContext < ' _ > , e : & Expr < ' _ > ) -> bool {
63
- const ALLOWED_METHOD_NAMES : & [ & str ] = & [ "len" , "as_ptr" , "is_empty" ] ;
64
-
65
- if let ExprKind :: MethodCall ( path, ..) = e. kind {
66
- ALLOWED_METHOD_NAMES . contains ( & path. ident . name . as_str ( ) )
67
- } else {
68
- is_trait_method ( cx, e, sym:: IntoIterator )
69
- }
70
- }
71
-
72
55
impl < ' tcx > LateLintPass < ' tcx > for UselessVec {
73
56
fn check_expr ( & mut self , cx : & LateContext < ' tcx > , expr : & ' tcx Expr < ' _ > ) {
74
- if let Some ( vec_args) = higher:: VecArgs :: hir ( cx, expr. peel_borrows ( ) ) {
57
+ let Some ( vec_args) = higher:: VecArgs :: hir ( cx, expr. peel_borrows ( ) ) else {
58
+ return ;
59
+ } ;
60
+
61
+ match cx. tcx . parent_hir_node ( expr. hir_id ) {
75
62
// search for `let foo = vec![_]` expressions where all uses of `foo`
76
63
// adjust to slices or call a method that exist on slices (e.g. len)
77
- if let Node :: Local ( local) = cx. tcx . parent_hir_node ( expr. hir_id )
78
- // for now ignore locals with type annotations.
79
- // this is to avoid compile errors when doing the suggestion here: let _: Vec<_> = vec![..];
80
- && local. ty . is_none ( )
81
- && let PatKind :: Binding ( _, id, ..) = local. pat . kind
82
- {
83
- let only_slice_uses = for_each_local_use_after_expr ( cx, id, expr. hir_id , |expr| {
64
+ Node :: Local ( Local {
65
+ ty : None ,
66
+ pat :
67
+ Pat {
68
+ kind : PatKind :: Binding ( _, id, ..) ,
69
+ ..
70
+ } ,
71
+ ..
72
+ } ) => {
73
+ let only_slice_uses = for_each_local_use_after_expr ( cx, * id, expr. hir_id , |expr| {
84
74
// allow indexing into a vec and some set of allowed method calls that exist on slices, too
85
75
if let Some ( parent) = get_parent_expr ( cx, expr)
86
76
&& ( adjusts_to_slice ( cx, expr)
@@ -100,26 +90,22 @@ impl<'tcx> LateLintPass<'tcx> for UselessVec {
100
90
} else {
101
91
self . span_to_lint_map . insert ( span, None ) ;
102
92
}
103
- }
93
+ } ,
104
94
// if the local pattern has a specified type, do not lint.
105
- else if let Some ( _) = higher:: VecArgs :: hir ( cx, expr)
106
- && let Node :: Local ( local) = cx. tcx . parent_hir_node ( expr. hir_id )
107
- && local. ty . is_some ( )
108
- {
95
+ Node :: Local ( Local { ty : Some ( _) , .. } ) if higher:: VecArgs :: hir ( cx, expr) . is_some ( ) => {
109
96
let span = expr. span . ctxt ( ) . outer_expn_data ( ) . call_site ;
110
97
self . span_to_lint_map . insert ( span, None ) ;
111
- }
98
+ } ,
112
99
// search for `for _ in vec![...]`
113
- else if let Some ( parent) = get_parent_expr ( cx, expr)
114
- && parent. span . is_desugaring ( DesugaringKind :: ForLoop )
115
- && self . msrv . meets ( msrvs:: ARRAY_INTO_ITERATOR )
100
+ Node :: Expr ( Expr { span, .. } )
101
+ if span. is_desugaring ( DesugaringKind :: ForLoop ) && self . msrv . meets ( msrvs:: ARRAY_INTO_ITERATOR ) =>
116
102
{
117
103
// report the error around the `vec!` not inside `<std macros>:`
118
104
let span = expr. span . ctxt ( ) . outer_expn_data ( ) . call_site ;
119
105
self . check_vec_macro ( cx, & vec_args, span, expr. hir_id , SuggestedType :: Array ) ;
120
- }
106
+ } ,
121
107
// search for `&vec![_]` or `vec![_]` expressions where the adjusted type is `&[_]`
122
- else {
108
+ _ => {
123
109
let ( suggest_slice, span) = if let ExprKind :: AddrOf ( BorrowKind :: Ref , mutability, _) = expr. kind {
124
110
// `expr` is `&vec![_]`, so suggest `&[_]` (or `&mut[_]` resp.)
125
111
( SuggestedType :: SliceRef ( mutability) , expr. span )
@@ -134,20 +120,14 @@ impl<'tcx> LateLintPass<'tcx> for UselessVec {
134
120
} else {
135
121
self . span_to_lint_map . insert ( span, None ) ;
136
122
}
137
- }
123
+ } ,
138
124
}
139
125
}
140
126
141
127
fn check_crate_post ( & mut self , cx : & LateContext < ' tcx > ) {
142
128
for ( span, lint_opt) in & self . span_to_lint_map {
143
129
if let Some ( ( hir_id, suggest_slice, snippet, applicability) ) = lint_opt {
144
- let help_msg = format ! (
145
- "you can use {} directly" ,
146
- match suggest_slice {
147
- SuggestedType :: SliceRef ( _) => "a slice" ,
148
- SuggestedType :: Array => "an array" ,
149
- }
150
- ) ;
130
+ let help_msg = format ! ( "you can use {} directly" , suggest_slice. desc( ) , ) ;
151
131
span_lint_hir_and_then ( cx, USELESS_VEC , * hir_id, * span, "useless use of `vec!`" , |diag| {
152
132
diag. span_suggestion ( * span, help_msg, snippet, * applicability) ;
153
133
} ) ;
@@ -158,14 +138,6 @@ impl<'tcx> LateLintPass<'tcx> for UselessVec {
158
138
extract_msrv_attr ! ( LateContext ) ;
159
139
}
160
140
161
- #[ derive( Copy , Clone ) ]
162
- pub ( crate ) enum SuggestedType {
163
- /// Suggest using a slice `&[..]` / `&mut [..]`
164
- SliceRef ( Mutability ) ,
165
- /// Suggest using an array: `[..]`
166
- Array ,
167
- }
168
-
169
141
impl UselessVec {
170
142
fn check_vec_macro < ' tcx > (
171
143
& mut self ,
@@ -194,44 +166,21 @@ impl UselessVec {
194
166
return ;
195
167
}
196
168
197
- let elem = snippet_with_applicability ( cx, elem. span , "elem" , & mut applicability) ;
198
- let len = snippet_with_applicability ( cx, len. span , "len" , & mut applicability) ;
199
-
200
- match suggest_slice {
201
- SuggestedType :: SliceRef ( Mutability :: Mut ) => format ! ( "&mut [{elem}; {len}]" ) ,
202
- SuggestedType :: SliceRef ( Mutability :: Not ) => format ! ( "&[{elem}; {len}]" ) ,
203
- SuggestedType :: Array => format ! ( "[{elem}; {len}]" ) ,
204
- }
169
+ suggest_slice. snippet ( cx, Some ( elem. span ) , Some ( len. span ) , & mut applicability)
205
170
} else {
206
171
return ;
207
172
}
208
173
} ,
209
174
higher:: VecArgs :: Vec ( args) => {
210
- if let Some ( last) = args. iter ( ) . last ( ) {
175
+ let args_span = if let Some ( last) = args. iter ( ) . last ( ) {
211
176
if args. len ( ) as u64 * size_of ( cx, last) > self . too_large_for_stack {
212
177
return ;
213
178
}
214
- let span = args[ 0 ] . span . source_callsite ( ) . to ( last. span . source_callsite ( ) ) ;
215
- let args = snippet_with_applicability ( cx, span, ".." , & mut applicability) ;
216
-
217
- match suggest_slice {
218
- SuggestedType :: SliceRef ( Mutability :: Mut ) => {
219
- format ! ( "&mut [{args}]" )
220
- } ,
221
- SuggestedType :: SliceRef ( Mutability :: Not ) => {
222
- format ! ( "&[{args}]" )
223
- } ,
224
- SuggestedType :: Array => {
225
- format ! ( "[{args}]" )
226
- } ,
227
- }
179
+ Some ( args[ 0 ] . span . source_callsite ( ) . to ( last. span . source_callsite ( ) ) )
228
180
} else {
229
- match suggest_slice {
230
- SuggestedType :: SliceRef ( Mutability :: Mut ) => "&mut []" . to_owned ( ) ,
231
- SuggestedType :: SliceRef ( Mutability :: Not ) => "&[]" . to_owned ( ) ,
232
- SuggestedType :: Array => "[]" . to_owned ( ) ,
233
- }
234
- }
181
+ None
182
+ } ;
183
+ suggest_slice. snippet ( cx, args_span, None , & mut applicability)
235
184
} ,
236
185
} ;
237
186
@@ -241,7 +190,62 @@ impl UselessVec {
241
190
}
242
191
}
243
192
193
+ #[ derive( Copy , Clone ) ]
194
+ pub ( crate ) enum SuggestedType {
195
+ /// Suggest using a slice `&[..]` / `&mut [..]`
196
+ SliceRef ( Mutability ) ,
197
+ /// Suggest using an array: `[..]`
198
+ Array ,
199
+ }
200
+
201
+ impl SuggestedType {
202
+ fn desc ( self ) -> & ' static str {
203
+ match self {
204
+ Self :: SliceRef ( _) => "a slice" ,
205
+ Self :: Array => "an array" ,
206
+ }
207
+ }
208
+
209
+ fn snippet (
210
+ self ,
211
+ cx : & LateContext < ' _ > ,
212
+ args_span : Option < Span > ,
213
+ len_span : Option < Span > ,
214
+ app : & mut Applicability ,
215
+ ) -> String {
216
+ let args = args_span
217
+ . map ( |sp| snippet_with_applicability ( cx, sp, ".." , app) )
218
+ . unwrap_or_default ( ) ;
219
+ let maybe_len = len_span
220
+ . map ( |sp| format ! ( "; {}" , snippet_with_applicability( cx, sp, "len" , app) ) )
221
+ . unwrap_or_default ( ) ;
222
+
223
+ match self {
224
+ Self :: SliceRef ( Mutability :: Mut ) => format ! ( "&mut [{args}{maybe_len}]" ) ,
225
+ Self :: SliceRef ( Mutability :: Not ) => format ! ( "&[{args}{maybe_len}]" ) ,
226
+ Self :: Array => format ! ( "[{args}{maybe_len}]" ) ,
227
+ }
228
+ }
229
+ }
230
+
244
231
fn size_of ( cx : & LateContext < ' _ > , expr : & Expr < ' _ > ) -> u64 {
245
232
let ty = cx. typeck_results ( ) . expr_ty_adjusted ( expr) ;
246
233
cx. layout_of ( ty) . map_or ( 0 , |l| l. size . bytes ( ) )
247
234
}
235
+
236
+ fn adjusts_to_slice ( cx : & LateContext < ' _ > , e : & Expr < ' _ > ) -> bool {
237
+ matches ! ( cx. typeck_results( ) . expr_ty_adjusted( e) . kind( ) , ty:: Ref ( _, ty, _) if ty. is_slice( ) )
238
+ }
239
+
240
+ /// Checks if the given expression is a method call to a `Vec` method
241
+ /// that also exists on slices. If this returns true, it means that
242
+ /// this expression does not actually require a `Vec` and could just work with an array.
243
+ pub fn is_allowed_vec_method ( cx : & LateContext < ' _ > , e : & Expr < ' _ > ) -> bool {
244
+ const ALLOWED_METHOD_NAMES : & [ & str ] = & [ "len" , "as_ptr" , "is_empty" ] ;
245
+
246
+ if let ExprKind :: MethodCall ( path, ..) = e. kind {
247
+ ALLOWED_METHOD_NAMES . contains ( & path. ident . name . as_str ( ) )
248
+ } else {
249
+ is_trait_method ( cx, e, sym:: IntoIterator )
250
+ }
251
+ }
0 commit comments