1+ use std:: collections:: BTreeMap ;
12use std:: ops:: ControlFlow ;
23
34use clippy_config:: msrvs:: { self , Msrv } ;
45use clippy_utils:: consts:: { constant, Constant } ;
5- use clippy_utils:: diagnostics:: span_lint_and_sugg ;
6+ use clippy_utils:: diagnostics:: span_lint_hir_and_then ;
67use clippy_utils:: source:: snippet_with_applicability;
78use clippy_utils:: ty:: is_copy;
89use clippy_utils:: visitors:: for_each_local_use_after_expr;
910use clippy_utils:: { get_parent_expr, higher, is_trait_method} ;
1011use rustc_errors:: Applicability ;
11- use rustc_hir:: { BorrowKind , Expr , ExprKind , Mutability , Node , PatKind } ;
12+ use rustc_hir:: { BorrowKind , Expr , ExprKind , HirId , Mutability , Node , PatKind } ;
1213use rustc_lint:: { LateContext , LateLintPass } ;
1314use rustc_middle:: ty:: layout:: LayoutOf ;
1415use rustc_middle:: ty:: { self , Ty } ;
1516use rustc_session:: impl_lint_pass;
16- use rustc_span:: { sym, Span } ;
17+ use rustc_span:: { sym, DesugaringKind , Span } ;
1718
1819#[ expect( clippy:: module_name_repetitions) ]
1920#[ derive( Clone ) ]
2021pub struct UselessVec {
2122 pub too_large_for_stack : u64 ,
2223 pub msrv : Msrv ,
24+ pub span_to_lint_map : BTreeMap < Span , Option < ( HirId , SuggestedType , String , Applicability ) > > ,
2325}
2426
2527declare_clippy_lint ! {
@@ -69,72 +71,96 @@ pub fn is_allowed_vec_method(cx: &LateContext<'_>, e: &Expr<'_>) -> bool {
6971
7072impl < ' tcx > LateLintPass < ' tcx > for UselessVec {
7173 fn check_expr ( & mut self , cx : & LateContext < ' tcx > , expr : & ' tcx Expr < ' _ > ) {
72- // search for `&vec![_]` or `vec![_]` expressions where the adjusted type is `&[_]`
73- if adjusts_to_slice ( cx, expr)
74- && let Some ( vec_args) = higher:: VecArgs :: hir ( cx, expr. peel_borrows ( ) )
75- {
76- let ( suggest_slice, span) = if let ExprKind :: AddrOf ( BorrowKind :: Ref , mutability, _) = expr. kind {
77- // `expr` is `&vec![_]`, so suggest `&[_]` (or `&mut[_]` resp.)
78- ( SuggestedType :: SliceRef ( mutability) , expr. span )
79- } else {
80- // `expr` is the `vec![_]` expansion, so suggest `[_]`
81- // and also use the span of the actual `vec![_]` expression
82- ( SuggestedType :: Array , expr. span . ctxt ( ) . outer_expn_data ( ) . call_site )
83- } ;
84-
85- self . check_vec_macro ( cx, & vec_args, span, suggest_slice) ;
86- }
74+ if let Some ( vec_args) = higher:: VecArgs :: hir ( cx, expr. peel_borrows ( ) ) {
75+ // search for `let foo = vec![_]` expressions where all uses of `foo`
76+ // adjust to slices or call a method that exist on slices (e.g. len)
77+ if let Node :: Local ( local) = cx. tcx . hir ( ) . get_parent ( 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+ && is_copy ( cx, vec_type ( cx. typeck_results ( ) . expr_ty_adjusted ( expr. peel_borrows ( ) ) ) )
83+ {
84+ let only_slice_uses = for_each_local_use_after_expr ( cx, id, expr. hir_id , |expr| {
85+ // allow indexing into a vec and some set of allowed method calls that exist on slices, too
86+ if let Some ( parent) = get_parent_expr ( cx, expr)
87+ && ( adjusts_to_slice ( cx, expr)
88+ || matches ! ( parent. kind, ExprKind :: Index ( ..) )
89+ || is_allowed_vec_method ( cx, parent) )
90+ {
91+ ControlFlow :: Continue ( ( ) )
92+ } else {
93+ ControlFlow :: Break ( ( ) )
94+ }
95+ } )
96+ . is_continue ( ) ;
8797
88- // search for `let foo = vec![_]` expressions where all uses of `foo`
89- // adjust to slices or call a method that exist on slices (e.g. len)
90- if let Some ( vec_args) = higher:: VecArgs :: hir ( cx, expr)
91- && let Node :: Local ( local) = cx. tcx . hir ( ) . get_parent ( expr. hir_id )
92- // for now ignore locals with type annotations.
93- // this is to avoid compile errors when doing the suggestion here: let _: Vec<_> = vec![..];
94- && local. ty . is_none ( )
95- && let PatKind :: Binding ( _, id, ..) = local. pat . kind
96- && is_copy ( cx, vec_type ( cx. typeck_results ( ) . expr_ty_adjusted ( expr) ) )
97- {
98- let only_slice_uses = for_each_local_use_after_expr ( cx, id, expr. hir_id , |expr| {
99- // allow indexing into a vec and some set of allowed method calls that exist on slices, too
100- if let Some ( parent) = get_parent_expr ( cx, expr)
101- && ( adjusts_to_slice ( cx, expr)
102- || matches ! ( parent. kind, ExprKind :: Index ( ..) )
103- || is_allowed_vec_method ( cx, parent) )
104- {
105- ControlFlow :: Continue ( ( ) )
98+ let span = expr. span . ctxt ( ) . outer_expn_data ( ) . call_site ;
99+ if only_slice_uses {
100+ self . check_vec_macro ( cx, & vec_args, span, expr. hir_id , SuggestedType :: Array ) ;
106101 } else {
107- ControlFlow :: Break ( ( ) )
102+ self . span_to_lint_map . insert ( span, None ) ;
103+ }
104+ }
105+ // if the local pattern has a specified type, do not lint.
106+ else if let Some ( _) = higher:: VecArgs :: hir ( cx, expr)
107+ && let Node :: Local ( local) = cx. tcx . hir ( ) . get_parent ( expr. hir_id )
108+ && local. ty . is_some ( )
109+ {
110+ let span = expr. span . ctxt ( ) . outer_expn_data ( ) . call_site ;
111+ self . span_to_lint_map . insert ( span, None ) ;
112+ }
113+ // search for `for _ in vec![...]`
114+ else if let Some ( parent) = get_parent_expr ( cx, expr)
115+ && parent. span . is_desugaring ( DesugaringKind :: ForLoop )
116+ && self . msrv . meets ( msrvs:: ARRAY_INTO_ITERATOR )
117+ {
118+ // report the error around the `vec!` not inside `<std macros>:`
119+ let span = expr. span . ctxt ( ) . outer_expn_data ( ) . call_site ;
120+ self . check_vec_macro ( cx, & vec_args, span, expr. hir_id , SuggestedType :: Array ) ;
121+ }
122+ // search for `&vec![_]` or `vec![_]` expressions where the adjusted type is `&[_]`
123+ else {
124+ let ( suggest_slice, span) = if let ExprKind :: AddrOf ( BorrowKind :: Ref , mutability, _) = expr. kind {
125+ // `expr` is `&vec![_]`, so suggest `&[_]` (or `&mut[_]` resp.)
126+ ( SuggestedType :: SliceRef ( mutability) , expr. span )
127+ } else {
128+ // `expr` is the `vec![_]` expansion, so suggest `[_]`
129+ // and also use the span of the actual `vec![_]` expression
130+ ( SuggestedType :: Array , expr. span . ctxt ( ) . outer_expn_data ( ) . call_site )
131+ } ;
132+
133+ if adjusts_to_slice ( cx, expr) {
134+ self . check_vec_macro ( cx, & vec_args, span, expr. hir_id , suggest_slice) ;
135+ } else {
136+ self . span_to_lint_map . insert ( span, None ) ;
108137 }
109- } )
110- . is_continue ( ) ;
111-
112- if only_slice_uses {
113- self . check_vec_macro (
114- cx,
115- & vec_args,
116- expr. span . ctxt ( ) . outer_expn_data ( ) . call_site ,
117- SuggestedType :: Array ,
118- ) ;
119138 }
120139 }
140+ }
121141
122- // search for `for _ in vec![…]`
123- if let Some ( higher:: ForLoop { arg, .. } ) = higher:: ForLoop :: hir ( expr)
124- && let Some ( vec_args) = higher:: VecArgs :: hir ( cx, arg)
125- && self . msrv . meets ( msrvs:: ARRAY_INTO_ITERATOR )
126- {
127- // report the error around the `vec!` not inside `<std macros>:`
128- let span = arg. span . ctxt ( ) . outer_expn_data ( ) . call_site ;
129- self . check_vec_macro ( cx, & vec_args, span, SuggestedType :: Array ) ;
142+ fn check_crate_post ( & mut self , cx : & LateContext < ' tcx > ) {
143+ for ( span, lint_opt) in & self . span_to_lint_map {
144+ if let Some ( ( hir_id, suggest_slice, snippet, applicability) ) = lint_opt {
145+ let help_msg = format ! (
146+ "you can use {} directly" ,
147+ match suggest_slice {
148+ SuggestedType :: SliceRef ( _) => "a slice" ,
149+ SuggestedType :: Array => "an array" ,
150+ }
151+ ) ;
152+ span_lint_hir_and_then ( cx, USELESS_VEC , * hir_id, * span, "useless use of `vec!`" , |diag| {
153+ diag. span_suggestion ( * span, help_msg, snippet, * applicability) ;
154+ } ) ;
155+ }
130156 }
131157 }
132158
133159 extract_msrv_attr ! ( LateContext ) ;
134160}
135161
136162#[ derive( Copy , Clone ) ]
137- enum SuggestedType {
163+ pub ( crate ) enum SuggestedType {
138164 /// Suggest using a slice `&[..]` / `&mut [..]`
139165 SliceRef ( Mutability ) ,
140166 /// Suggest using an array: `[..]`
@@ -147,6 +173,7 @@ impl UselessVec {
147173 cx : & LateContext < ' tcx > ,
148174 vec_args : & higher:: VecArgs < ' tcx > ,
149175 span : Span ,
176+ hir_id : HirId ,
150177 suggest_slice : SuggestedType ,
151178 ) {
152179 if span. from_expansion ( ) {
@@ -204,21 +231,9 @@ impl UselessVec {
204231 } ,
205232 } ;
206233
207- span_lint_and_sugg (
208- cx,
209- USELESS_VEC ,
210- span,
211- "useless use of `vec!`" ,
212- & format ! (
213- "you can use {} directly" ,
214- match suggest_slice {
215- SuggestedType :: SliceRef ( _) => "a slice" ,
216- SuggestedType :: Array => "an array" ,
217- }
218- ) ,
219- snippet,
220- applicability,
221- ) ;
234+ self . span_to_lint_map
235+ . entry ( span)
236+ . or_insert ( Some ( ( hir_id, suggest_slice, snippet, applicability) ) ) ;
222237 }
223238}
224239
0 commit comments