@@ -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 , GenericArg , GenericArgs , HirId , PatKind , StmtKind , Ty } ;
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" ;
@@ -88,24 +88,23 @@ fn check_needless_collect_indirect_usage<'tcx>(expr: &'tcx Expr<'_>, cx: &LateCo
88
88
if let ExprKind :: Block ( block, _) = expr. kind {
89
89
for stmt in block. stmts {
90
90
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;
91
+ if let StmtKind :: Local ( local) = stmt. kind;
92
+ if let PatKind :: Binding ( _, id, ..) = local. pat. kind;
93
+ if let Some ( init_expr) = local. init;
95
94
if let ExprKind :: MethodCall ( method_name, collect_span, & [ ref iter_source] , ..) = init_expr. kind;
96
95
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) ;
96
+ if let Some ( hir_id) = get_hir_id( local . ty, method_name. args) ;
98
97
if let Some ( ty) = cx. typeck_results( ) . node_type_opt( hir_id) ;
99
98
if is_type_diagnostic_item( cx, ty, sym:: vec_type) ||
100
99
is_type_diagnostic_item( cx, ty, sym:: vecdeque_type) ||
101
100
is_type_diagnostic_item( cx, ty, sym:: BinaryHeap ) ||
102
101
is_type_diagnostic_item( cx, ty, sym:: LinkedList ) ;
103
- if let Some ( iter_calls) = detect_iter_and_into_iters( block, * ident ) ;
102
+ if let Some ( iter_calls) = detect_iter_and_into_iters( block, id ) ;
104
103
if let [ iter_call] = & * iter_calls;
105
104
then {
106
105
let mut used_count_visitor = UsedCountVisitor {
107
106
cx,
108
- id: * pat_id ,
107
+ id,
109
108
count: 0 ,
110
109
} ;
111
110
walk_block( & mut used_count_visitor, block) ;
@@ -187,48 +186,40 @@ enum IterFunctionKind {
187
186
struct IterFunctionVisitor {
188
187
uses : Vec < IterFunction > ,
189
188
seen_other : bool ,
190
- target : Ident ,
189
+ target : HirId ,
191
190
}
192
191
impl < ' tcx > Visitor < ' tcx > for IterFunctionVisitor {
193
192
fn visit_expr ( & mut self , expr : & ' tcx Expr < ' tcx > ) {
194
193
// 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
- ) ,
194
+ if let ExprKind :: MethodCall ( method_name, _, [ recv, args @ ..] , _) = & expr. kind {
195
+ if path_to_local_id ( recv, self . target ) {
196
+ match & * method_name. ident . name . as_str ( ) {
197
+ "into_iter" => self . uses . push ( IterFunction {
198
+ func : IterFunctionKind :: IntoIter ,
199
+ span : expr. span ,
200
+ } ) ,
201
+ "len" => self . uses . push ( IterFunction {
202
+ func : IterFunctionKind :: Len ,
203
+ span : expr. span ,
204
+ } ) ,
205
+ "is_empty" => self . uses . push ( IterFunction {
206
+ func : IterFunctionKind :: IsEmpty ,
207
+ span : expr. span ,
208
+ } ) ,
209
+ "contains" => self . uses . push ( IterFunction {
210
+ func : IterFunctionKind :: Contains ( args[ 0 ] . span ) ,
211
+ span : expr. span ,
212
+ } ) ,
217
213
_ => self . seen_other = true ,
218
214
}
219
- return
215
+ return ;
220
216
}
221
217
}
222
218
// 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
- }
219
+ if path_to_local_id ( expr, self . target ) {
220
+ self . seen_other = true ;
221
+ } else {
222
+ walk_expr ( self , expr) ;
232
223
}
233
224
}
234
225
@@ -262,10 +253,10 @@ impl<'a, 'tcx> Visitor<'tcx> for UsedCountVisitor<'a, 'tcx> {
262
253
263
254
/// Detect the occurrences of calls to `iter` or `into_iter` for the
264
255
/// given identifier
265
- fn detect_iter_and_into_iters < ' tcx > ( block : & ' tcx Block < ' tcx > , identifier : Ident ) -> Option < Vec < IterFunction > > {
256
+ fn detect_iter_and_into_iters < ' tcx > ( block : & ' tcx Block < ' tcx > , id : HirId ) -> Option < Vec < IterFunction > > {
266
257
let mut visitor = IterFunctionVisitor {
267
258
uses : Vec :: new ( ) ,
268
- target : identifier ,
259
+ target : id ,
269
260
seen_other : false ,
270
261
} ;
271
262
visitor. visit_block ( block) ;
0 commit comments