@@ -7,10 +7,10 @@ use clippy_utils::{is_trait_method, path_to_local_id};
7
7
use if_chain:: if_chain;
8
8
use rustc_errors:: Applicability ;
9
9
use rustc_hir:: intravisit:: { walk_block, walk_expr, NestedVisitorMap , Visitor } ;
10
- use rustc_hir:: { Block , Expr , ExprKind , GenericArg , GenericArgs , HirId , Local , Pat , PatKind , QPath , StmtKind , Ty } ;
10
+ use rustc_hir:: { Block , Expr , ExprKind , HirId , PatKind , StmtKind } ;
11
11
use rustc_lint:: LateContext ;
12
12
use rustc_middle:: hir:: map:: Map ;
13
- use rustc_span:: symbol :: { sym, Ident } ;
13
+ use rustc_span:: sym;
14
14
use rustc_span:: { MultiSpan , Span } ;
15
15
16
16
const NEEDLESS_COLLECT_MSG : & str = "avoid using `collect()` when not needed" ;
@@ -24,10 +24,8 @@ fn check_needless_collect_direct_usage<'tcx>(expr: &'tcx Expr<'_>, cx: &LateCont
24
24
if let ExprKind :: MethodCall ( method, _, args, _) = expr. kind;
25
25
if let ExprKind :: MethodCall ( chain_method, method0_span, _, _) = args[ 0 ] . kind;
26
26
if chain_method. ident. name == sym!( collect) && is_trait_method( cx, & args[ 0 ] , sym:: Iterator ) ;
27
- if let Some ( generic_args) = chain_method. args;
28
- if let Some ( GenericArg :: Type ( ref ty) ) = generic_args. args. get( 0 ) ;
29
- if let Some ( ty) = cx. typeck_results( ) . node_type_opt( ty. hir_id) ;
30
27
then {
28
+ let ty = cx. typeck_results( ) . expr_ty( & args[ 0 ] ) ;
31
29
let mut applicability = Applicability :: MachineApplicable ;
32
30
let is_empty_sugg = "next().is_none()" . to_string( ) ;
33
31
let method_name = & * method. ident. name. as_str( ) ;
@@ -72,40 +70,25 @@ fn check_needless_collect_direct_usage<'tcx>(expr: &'tcx Expr<'_>, cx: &LateCont
72
70
}
73
71
74
72
fn check_needless_collect_indirect_usage < ' tcx > ( expr : & ' tcx Expr < ' _ > , cx : & LateContext < ' tcx > ) {
75
- fn get_hir_id < ' tcx > ( ty : Option < & Ty < ' tcx > > , method_args : Option < & GenericArgs < ' tcx > > ) -> Option < HirId > {
76
- if let Some ( ty) = ty {
77
- return Some ( ty. hir_id ) ;
78
- }
79
-
80
- if let Some ( generic_args) = method_args {
81
- if let Some ( GenericArg :: Type ( ref ty) ) = generic_args. args . get ( 0 ) {
82
- return Some ( ty. hir_id ) ;
83
- }
84
- }
85
-
86
- None
87
- }
88
73
if let ExprKind :: Block ( block, _) = expr. kind {
89
74
for stmt in block. stmts {
90
75
if_chain ! {
91
- if let StmtKind :: Local (
92
- Local { pat: Pat { hir_id: pat_id, kind: PatKind :: Binding ( _, _, ident, .. ) , .. } ,
93
- init: Some ( init_expr) , ty, .. }
94
- ) = stmt. kind;
76
+ if let StmtKind :: Local ( local) = stmt. kind;
77
+ if let PatKind :: Binding ( _, id, ..) = local. pat. kind;
78
+ if let Some ( init_expr) = local. init;
95
79
if let ExprKind :: MethodCall ( method_name, collect_span, & [ ref iter_source] , ..) = init_expr. kind;
96
80
if method_name. ident. name == sym!( collect) && is_trait_method( cx, init_expr, sym:: Iterator ) ;
97
- if let Some ( hir_id) = get_hir_id( * ty, method_name. args) ;
98
- if let Some ( ty) = cx. typeck_results( ) . node_type_opt( hir_id) ;
81
+ let ty = cx. typeck_results( ) . expr_ty( init_expr) ;
99
82
if is_type_diagnostic_item( cx, ty, sym:: vec_type) ||
100
83
is_type_diagnostic_item( cx, ty, sym:: vecdeque_type) ||
101
84
is_type_diagnostic_item( cx, ty, sym:: BinaryHeap ) ||
102
85
is_type_diagnostic_item( cx, ty, sym:: LinkedList ) ;
103
- if let Some ( iter_calls) = detect_iter_and_into_iters( block, * ident ) ;
86
+ if let Some ( iter_calls) = detect_iter_and_into_iters( block, id ) ;
104
87
if let [ iter_call] = & * iter_calls;
105
88
then {
106
89
let mut used_count_visitor = UsedCountVisitor {
107
90
cx,
108
- id: * pat_id ,
91
+ id,
109
92
count: 0 ,
110
93
} ;
111
94
walk_block( & mut used_count_visitor, block) ;
@@ -187,48 +170,40 @@ enum IterFunctionKind {
187
170
struct IterFunctionVisitor {
188
171
uses : Vec < IterFunction > ,
189
172
seen_other : bool ,
190
- target : Ident ,
173
+ target : HirId ,
191
174
}
192
175
impl < ' tcx > Visitor < ' tcx > for IterFunctionVisitor {
193
176
fn visit_expr ( & mut self , expr : & ' tcx Expr < ' tcx > ) {
194
177
// Check function calls on our collection
195
- if_chain ! {
196
- if let ExprKind :: MethodCall ( method_name, _, args, _) = & expr. kind;
197
- if let Some ( Expr { kind: ExprKind :: Path ( QPath :: Resolved ( _, path) ) , .. } ) = args. get( 0 ) ;
198
- if let & [ name] = & path. segments;
199
- if name. ident == self . target;
200
- then {
201
- let len = sym!( len) ;
202
- let is_empty = sym!( is_empty) ;
203
- let contains = sym!( contains) ;
204
- match method_name. ident. name {
205
- sym:: into_iter => self . uses. push(
206
- IterFunction { func: IterFunctionKind :: IntoIter , span: expr. span }
207
- ) ,
208
- name if name == len => self . uses. push(
209
- IterFunction { func: IterFunctionKind :: Len , span: expr. span }
210
- ) ,
211
- name if name == is_empty => self . uses. push(
212
- IterFunction { func: IterFunctionKind :: IsEmpty , span: expr. span }
213
- ) ,
214
- name if name == contains => self . uses. push(
215
- IterFunction { func: IterFunctionKind :: Contains ( args[ 1 ] . span) , span: expr. span }
216
- ) ,
178
+ if let ExprKind :: MethodCall ( method_name, _, [ recv, args @ ..] , _) = & expr. kind {
179
+ if path_to_local_id ( recv, self . target ) {
180
+ match & * method_name. ident . name . as_str ( ) {
181
+ "into_iter" => self . uses . push ( IterFunction {
182
+ func : IterFunctionKind :: IntoIter ,
183
+ span : expr. span ,
184
+ } ) ,
185
+ "len" => self . uses . push ( IterFunction {
186
+ func : IterFunctionKind :: Len ,
187
+ span : expr. span ,
188
+ } ) ,
189
+ "is_empty" => self . uses . push ( IterFunction {
190
+ func : IterFunctionKind :: IsEmpty ,
191
+ span : expr. span ,
192
+ } ) ,
193
+ "contains" => self . uses . push ( IterFunction {
194
+ func : IterFunctionKind :: Contains ( args[ 0 ] . span ) ,
195
+ span : expr. span ,
196
+ } ) ,
217
197
_ => self . seen_other = true ,
218
198
}
219
- return
199
+ return ;
220
200
}
221
201
}
222
202
// Check if the collection is used for anything else
223
- if_chain ! {
224
- if let Expr { kind: ExprKind :: Path ( QPath :: Resolved ( _, path) ) , .. } = expr;
225
- if let & [ name] = & path. segments;
226
- if name. ident == self . target;
227
- then {
228
- self . seen_other = true ;
229
- } else {
230
- walk_expr( self , expr) ;
231
- }
203
+ if path_to_local_id ( expr, self . target ) {
204
+ self . seen_other = true ;
205
+ } else {
206
+ walk_expr ( self , expr) ;
232
207
}
233
208
}
234
209
@@ -262,10 +237,10 @@ impl<'a, 'tcx> Visitor<'tcx> for UsedCountVisitor<'a, 'tcx> {
262
237
263
238
/// Detect the occurrences of calls to `iter` or `into_iter` for the
264
239
/// given identifier
265
- fn detect_iter_and_into_iters < ' tcx > ( block : & ' tcx Block < ' tcx > , identifier : Ident ) -> Option < Vec < IterFunction > > {
240
+ fn detect_iter_and_into_iters < ' tcx > ( block : & ' tcx Block < ' tcx > , id : HirId ) -> Option < Vec < IterFunction > > {
266
241
let mut visitor = IterFunctionVisitor {
267
242
uses : Vec :: new ( ) ,
268
- target : identifier ,
243
+ target : id ,
269
244
seen_other : false ,
270
245
} ;
271
246
visitor. visit_block ( block) ;
0 commit comments