@@ -9,7 +9,7 @@ use clippy_utils::ty::is_copy;
99use clippy_utils:: visitors:: for_each_local_use_after_expr;
1010use clippy_utils:: { get_parent_expr, higher, is_trait_method} ;
1111use 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 } ;
1313use rustc_lint:: { LateContext , LateLintPass } ;
1414use rustc_middle:: ty;
1515use rustc_middle:: ty:: layout:: LayoutOf ;
@@ -52,35 +52,25 @@ declare_clippy_lint! {
5252
5353impl_lint_pass ! ( UselessVec => [ USELESS_VEC ] ) ;
5454
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-
7255impl < ' tcx > LateLintPass < ' tcx > for UselessVec {
7356 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 ) {
7562 // search for `let foo = vec![_]` expressions where all uses of `foo`
7663 // 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| {
8474 // allow indexing into a vec and some set of allowed method calls that exist on slices, too
8575 if let Some ( parent) = get_parent_expr ( cx, expr)
8676 && ( adjusts_to_slice ( cx, expr)
@@ -100,26 +90,22 @@ impl<'tcx> LateLintPass<'tcx> for UselessVec {
10090 } else {
10191 self . span_to_lint_map . insert ( span, None ) ;
10292 }
103- }
93+ } ,
10494 // 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 ( ) => {
10996 let span = expr. span . ctxt ( ) . outer_expn_data ( ) . call_site ;
11097 self . span_to_lint_map . insert ( span, None ) ;
111- }
98+ } ,
11299 // 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 ) =>
116102 {
117103 // report the error around the `vec!` not inside `<std macros>:`
118104 let span = expr. span . ctxt ( ) . outer_expn_data ( ) . call_site ;
119105 self . check_vec_macro ( cx, & vec_args, span, expr. hir_id , SuggestedType :: Array ) ;
120- }
106+ } ,
121107 // search for `&vec![_]` or `vec![_]` expressions where the adjusted type is `&[_]`
122- else {
108+ _ => {
123109 let ( suggest_slice, span) = if let ExprKind :: AddrOf ( BorrowKind :: Ref , mutability, _) = expr. kind {
124110 // `expr` is `&vec![_]`, so suggest `&[_]` (or `&mut[_]` resp.)
125111 ( SuggestedType :: SliceRef ( mutability) , expr. span )
@@ -134,20 +120,14 @@ impl<'tcx> LateLintPass<'tcx> for UselessVec {
134120 } else {
135121 self . span_to_lint_map . insert ( span, None ) ;
136122 }
137- }
123+ } ,
138124 }
139125 }
140126
141127 fn check_crate_post ( & mut self , cx : & LateContext < ' tcx > ) {
142128 for ( span, lint_opt) in & self . span_to_lint_map {
143129 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( ) , ) ;
151131 span_lint_hir_and_then ( cx, USELESS_VEC , * hir_id, * span, "useless use of `vec!`" , |diag| {
152132 diag. span_suggestion ( * span, help_msg, snippet, * applicability) ;
153133 } ) ;
@@ -158,14 +138,6 @@ impl<'tcx> LateLintPass<'tcx> for UselessVec {
158138 extract_msrv_attr ! ( LateContext ) ;
159139}
160140
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-
169141impl UselessVec {
170142 fn check_vec_macro < ' tcx > (
171143 & mut self ,
@@ -194,44 +166,21 @@ impl UselessVec {
194166 return ;
195167 }
196168
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)
205170 } else {
206171 return ;
207172 }
208173 } ,
209174 higher:: VecArgs :: Vec ( args) => {
210- if let Some ( last) = args. iter ( ) . last ( ) {
175+ let args_span = if let Some ( last) = args. iter ( ) . last ( ) {
211176 if args. len ( ) as u64 * size_of ( cx, last) > self . too_large_for_stack {
212177 return ;
213178 }
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 ( ) ) )
228180 } 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)
235184 } ,
236185 } ;
237186
@@ -241,7 +190,62 @@ impl UselessVec {
241190 }
242191}
243192
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+
244231fn size_of ( cx : & LateContext < ' _ > , expr : & Expr < ' _ > ) -> u64 {
245232 let ty = cx. typeck_results ( ) . expr_ty_adjusted ( expr) ;
246233 cx. layout_of ( ty) . map_or ( 0 , |l| l. size . bytes ( ) )
247234}
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