1
- use std:: collections:: { BTreeMap , BTreeSet } ;
1
+ use std:: collections:: BTreeMap ;
2
2
use std:: ops:: ControlFlow ;
3
3
4
4
use clippy_config:: msrvs:: { self , Msrv } ;
@@ -14,15 +14,14 @@ use rustc_lint::{LateContext, LateLintPass};
14
14
use rustc_middle:: ty:: layout:: LayoutOf ;
15
15
use rustc_middle:: ty:: { self , Ty } ;
16
16
use rustc_session:: impl_lint_pass;
17
- use rustc_span:: { sym, Span } ;
17
+ use rustc_span:: { sym, DesugaringKind , Span } ;
18
18
19
19
#[ expect( clippy:: module_name_repetitions) ]
20
20
#[ derive( Clone ) ]
21
21
pub struct UselessVec {
22
22
pub too_large_for_stack : u64 ,
23
23
pub msrv : Msrv ,
24
24
pub span_to_lint_map : BTreeMap < Span , Option < ( HirId , SuggestedType , String , Applicability ) > > ,
25
- pub lintable_exprs : BTreeSet < HirId > ,
26
25
}
27
26
28
27
declare_clippy_lint ! {
@@ -72,61 +71,70 @@ pub fn is_allowed_vec_method(cx: &LateContext<'_>, e: &Expr<'_>) -> bool {
72
71
73
72
impl < ' tcx > LateLintPass < ' tcx > for UselessVec {
74
73
fn check_expr ( & mut self , cx : & LateContext < ' tcx > , expr : & ' tcx Expr < ' _ > ) {
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 Some ( vec_args) = higher:: VecArgs :: hir ( cx, expr)
78
- && let Node :: Local ( local) = cx. tcx . hir ( ) . get_parent ( expr. hir_id )
79
- // for now ignore locals with type annotations.
80
- // this is to avoid compile errors when doing the suggestion here: let _: Vec<_> = vec![..];
81
- && local. ty . is_none ( )
82
- && let PatKind :: Binding ( _, id, ..) = local. pat . kind
83
- && is_copy ( cx, vec_type ( cx. typeck_results ( ) . expr_ty_adjusted ( expr) ) )
84
- {
85
- let only_slice_uses = for_each_local_use_after_expr ( cx, id, expr. hir_id , |expr| {
86
- // allow indexing into a vec and some set of allowed method calls that exist on slices, too
87
- if let Some ( parent) = get_parent_expr ( cx, expr)
88
- && ( adjusts_to_slice ( cx, expr)
89
- || matches ! ( parent. kind, ExprKind :: Index ( ..) )
90
- || is_allowed_vec_method ( cx, parent) )
91
- {
92
- ControlFlow :: Continue ( ( ) )
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 ( ) ;
97
+
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 ) ;
93
101
} else {
94
- ControlFlow :: Break ( ( ) )
102
+ self . span_to_lint_map . insert ( span , None ) ;
95
103
}
96
- } )
97
- . is_continue ( ) ;
98
-
99
- if only_slice_uses {
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>:`
100
119
let span = expr. span . ctxt ( ) . outer_expn_data ( ) . call_site ;
101
- self . lintable_exprs . insert ( expr. hir_id ) ;
102
120
self . check_vec_macro ( cx, & vec_args, span, expr. hir_id , SuggestedType :: Array ) ;
103
121
}
104
- }
105
- // search for `for _ in vec![…]`
106
- else if let Some ( higher:: ForLoop { arg, .. } ) = higher:: ForLoop :: hir ( expr)
107
- && let Some ( vec_args) = higher:: VecArgs :: hir ( cx, arg)
108
- && self . msrv . meets ( msrvs:: ARRAY_INTO_ITERATOR )
109
- {
110
- // report the error around the `vec!` not inside `<std macros>:`
111
- let span = arg. span . ctxt ( ) . outer_expn_data ( ) . call_site ;
112
- self . lintable_exprs . insert ( arg. hir_id ) ;
113
- self . check_vec_macro ( cx, & vec_args, span, arg. hir_id , SuggestedType :: Array ) ;
114
- }
115
- // search for `&vec![_]` or `vec![_]` expressions where the adjusted type is `&[_]`
116
- else if let Some ( vec_args) = higher:: VecArgs :: hir ( cx, expr. peel_borrows ( ) ) {
117
- let ( suggest_slice, span) = if let ExprKind :: AddrOf ( BorrowKind :: Ref , mutability, _) = expr. kind {
118
- // `expr` is `&vec![_]`, so suggest `&[_]` (or `&mut[_]` resp.)
119
- ( SuggestedType :: SliceRef ( mutability) , expr. span )
120
- } else {
121
- // `expr` is the `vec![_]` expansion, so suggest `[_]`
122
- // and also use the span of the actual `vec![_]` expression
123
- ( SuggestedType :: Array , expr. span . ctxt ( ) . outer_expn_data ( ) . call_site )
124
- } ;
125
-
126
- if adjusts_to_slice ( cx, expr) {
127
- self . check_vec_macro ( cx, & vec_args, span, expr. hir_id , suggest_slice) ;
128
- } else if !self . lintable_exprs . contains ( & expr. hir_id ) {
129
- self . span_to_lint_map . insert ( span, None ) ;
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 ) ;
137
+ }
130
138
}
131
139
}
132
140
}
0 commit comments