1
1
use clippy_utils:: diagnostics:: span_lint_and_sugg;
2
2
use clippy_utils:: higher:: { get_vec_init_kind, VecInitKind } ;
3
+ use clippy_utils:: path_to_local_id;
3
4
use clippy_utils:: source:: snippet;
4
- use clippy_utils:: visitors:: for_each_local_use_after_expr;
5
- use clippy_utils:: { get_parent_expr, path_to_local_id} ;
6
- use core:: ops:: ControlFlow ;
7
- use rustc_ast:: LitKind ;
5
+ //use rustc_ast::LitKind;
8
6
use rustc_errors:: Applicability ;
9
7
use rustc_hir:: def:: Res ;
10
- use rustc_hir:: {
11
- BindingAnnotation , Block , Expr , ExprKind , HirId , Local , Mutability , PatKind , QPath , Stmt , StmtKind , UnOp ,
12
- } ;
8
+ use rustc_hir:: { BindingAnnotation , Block , Expr , ExprKind , HirId , Local , PatKind , QPath , Stmt , StmtKind } ;
13
9
use rustc_lint:: { LateContext , LateLintPass , LintContext } ;
14
10
use rustc_middle:: lint:: in_external_macro;
15
11
use rustc_session:: { declare_tool_lint, impl_lint_pass} ;
16
- use rustc_span:: { Span , Symbol } ;
12
+ use rustc_span:: Span ;
17
13
18
14
declare_clippy_lint ! {
19
15
/// ### What it does
@@ -45,89 +41,17 @@ pub struct ReserveAfterInitialization {
45
41
46
42
struct VecReserveSearcher {
47
43
local_id : HirId ,
48
- lhs_is_let : bool ,
49
- let_ty_span : Option < Span > ,
50
- name : Symbol ,
51
44
err_span : Span ,
52
- last_reserve_expr : HirId ,
53
- space_hint : Option < usize > ,
45
+ init_part : String ,
46
+ space_hint : String ,
54
47
}
55
48
impl VecReserveSearcher {
56
49
fn display_err ( & self , cx : & LateContext < ' _ > ) {
57
- if self . space_hint == Some ( 0 ) {
50
+ if self . space_hint . is_empty ( ) {
58
51
return ;
59
52
}
60
53
61
- let mut needs_mut = false ;
62
- let _res = for_each_local_use_after_expr ( cx, self . local_id , self . last_reserve_expr , |e| {
63
- let Some ( parent) = get_parent_expr ( cx, e) else {
64
- return ControlFlow :: Continue ( ( ) ) ;
65
- } ;
66
- let adjusted_ty = cx. typeck_results ( ) . expr_ty_adjusted ( e) ;
67
- let adjusted_mut = adjusted_ty. ref_mutability ( ) . unwrap_or ( Mutability :: Not ) ;
68
- needs_mut |= adjusted_mut == Mutability :: Mut ;
69
- match parent. kind {
70
- ExprKind :: AddrOf ( _, Mutability :: Mut , _) => {
71
- needs_mut = true ;
72
- return ControlFlow :: Break ( true ) ;
73
- } ,
74
- ExprKind :: Unary ( UnOp :: Deref , _) | ExprKind :: Index ( ..) if !needs_mut => {
75
- let mut last_place = parent;
76
- while let Some ( parent) = get_parent_expr ( cx, last_place) {
77
- if matches ! ( parent. kind, ExprKind :: Unary ( UnOp :: Deref , _) | ExprKind :: Field ( ..) )
78
- || matches ! ( parent. kind, ExprKind :: Index ( e, _, _) if e. hir_id == last_place. hir_id)
79
- {
80
- last_place = parent;
81
- } else {
82
- break ;
83
- }
84
- }
85
- needs_mut |= cx. typeck_results ( ) . expr_ty_adjusted ( last_place) . ref_mutability ( )
86
- == Some ( Mutability :: Mut )
87
- || get_parent_expr ( cx, last_place)
88
- . map_or ( false , |e| matches ! ( e. kind, ExprKind :: AddrOf ( _, Mutability :: Mut , _) ) ) ;
89
- } ,
90
- ExprKind :: MethodCall ( _, recv, ..)
91
- if recv. hir_id == e. hir_id
92
- && adjusted_mut == Mutability :: Mut
93
- && !adjusted_ty. peel_refs ( ) . is_slice ( ) =>
94
- {
95
- // No need to set `needs_mut` to true. The receiver will be either explicitly borrowed, or it will
96
- // be implicitly borrowed via an adjustment. Both of these cases are already handled by this point.
97
- return ControlFlow :: Break ( true ) ;
98
- } ,
99
- ExprKind :: Assign ( lhs, ..) if e. hir_id == lhs. hir_id => {
100
- needs_mut = true ;
101
- return ControlFlow :: Break ( false ) ;
102
- } ,
103
- _ => ( ) ,
104
- }
105
- ControlFlow :: Continue ( ( ) )
106
- } ) ;
107
-
108
- let mut s = if self . lhs_is_let {
109
- String :: from ( "let " )
110
- } else {
111
- String :: new ( )
112
- } ;
113
- if needs_mut {
114
- s. push_str ( "mut " ) ;
115
- }
116
- s. push_str ( self . name . as_str ( ) ) ;
117
- if let Some ( span) = self . let_ty_span {
118
- s. push_str ( ": " ) ;
119
- s. push_str ( & snippet ( cx, span, "_" ) ) ;
120
- }
121
- s. push_str (
122
- format ! (
123
- " = Vec::with_capacity({});" ,
124
- match self . space_hint {
125
- None => ".." . to_string( ) ,
126
- Some ( hint) => hint. to_string( ) ,
127
- }
128
- )
129
- . as_str ( ) ,
130
- ) ;
54
+ let s = format ! ( "{} = Vec::with_capacity({});" , self . init_part, self . space_hint) ;
131
55
132
56
span_lint_and_sugg (
133
57
cx,
@@ -148,19 +72,22 @@ impl<'tcx> LateLintPass<'tcx> for ReserveAfterInitialization {
148
72
149
73
fn check_local ( & mut self , cx : & LateContext < ' tcx > , local : & ' tcx Local < ' tcx > ) {
150
74
if let Some ( init_expr) = local. init
151
- && let PatKind :: Binding ( BindingAnnotation :: MUT , id, name , None ) = local. pat . kind
75
+ && let PatKind :: Binding ( BindingAnnotation :: MUT , id, _name , None ) = local. pat . kind
152
76
&& !in_external_macro ( cx. sess ( ) , local. span )
153
77
&& let Some ( init) = get_vec_init_kind ( cx, init_expr)
154
78
&& !matches ! ( init, VecInitKind :: WithExprCapacity ( _) )
79
+ && !matches ! ( init, VecInitKind :: WithConstCapacity ( _) )
155
80
{
156
81
self . searcher = Some ( VecReserveSearcher {
157
82
local_id : id,
158
- lhs_is_let : true ,
159
- name : name. name ,
160
- let_ty_span : local. ty . map ( |ty| ty. span ) ,
161
83
err_span : local. span ,
162
- last_reserve_expr : init_expr. hir_id ,
163
- space_hint : Some ( 0 )
84
+ init_part : format ! ( "let {}: {}" ,
85
+ snippet( cx, local. pat. span, "" ) ,
86
+ match local. ty {
87
+ Some ( type_inference) => snippet( cx, type_inference. span, "" ) . to_string( ) ,
88
+ None => String :: new( )
89
+ } ) ,
90
+ space_hint : String :: new ( )
164
91
} ) ;
165
92
}
166
93
}
@@ -169,20 +96,18 @@ impl<'tcx> LateLintPass<'tcx> for ReserveAfterInitialization {
169
96
if self . searcher . is_none ( )
170
97
&& let ExprKind :: Assign ( left, right, _) = expr. kind
171
98
&& let ExprKind :: Path ( QPath :: Resolved ( None , path) ) = left. kind
172
- && let [ name ] = & path. segments
99
+ && let [ _name ] = & path. segments
173
100
&& let Res :: Local ( id) = path. res
174
101
&& !in_external_macro ( cx. sess ( ) , expr. span )
175
102
&& let Some ( init) = get_vec_init_kind ( cx, right)
176
103
&& !matches ! ( init, VecInitKind :: WithExprCapacity ( _) )
104
+ && !matches ! ( init, VecInitKind :: WithConstCapacity ( _) )
177
105
{
178
106
self . searcher = Some ( VecReserveSearcher {
179
107
local_id : id,
180
- lhs_is_let : false ,
181
- let_ty_span : None ,
182
- name : name. ident . name ,
183
108
err_span : expr. span ,
184
- last_reserve_expr : expr . hir_id ,
185
- space_hint : Some ( 0 )
109
+ init_part : snippet ( cx , left . span , "" ) . to_string ( ) ,
110
+ space_hint : String :: new ( )
186
111
} ) ;
187
112
}
188
113
}
@@ -195,22 +120,11 @@ impl<'tcx> LateLintPass<'tcx> for ReserveAfterInitialization {
195
120
&& path_to_local_id ( self_arg, searcher. local_id )
196
121
&& name. ident . as_str ( ) == "reserve"
197
122
{
198
- if let ExprKind :: Lit ( lit) = other_args[ 0 ] . kind
199
- && let LitKind :: Int ( space_hint, _) = lit. node {
200
- self . searcher = Some ( VecReserveSearcher {
201
- err_span : searcher. err_span . to ( stmt. span ) ,
202
- last_reserve_expr : expr. hir_id ,
203
- space_hint : Some ( space_hint as usize ) , // the expression is an int, so we'll display the good amount as a hint
204
- .. searcher
205
- } ) ;
206
- } else {
207
- self . searcher = Some ( VecReserveSearcher {
208
- err_span : searcher. err_span . to ( stmt. span ) ,
209
- last_reserve_expr : expr. hir_id ,
210
- space_hint : None , // the expression isn't an int, so we'll display ".." as hint
211
- .. searcher
212
- } ) ;
213
- }
123
+ self . searcher = Some ( VecReserveSearcher {
124
+ err_span : searcher. err_span . to ( stmt. span ) ,
125
+ space_hint : snippet ( cx, other_args[ 0 ] . span , "" ) . to_string ( ) ,
126
+ .. searcher
127
+ } ) ;
214
128
} else {
215
129
searcher. display_err ( cx) ;
216
130
}
0 commit comments