@@ -7,10 +7,10 @@ use clippy_utils::{is_trait_method, path_to_local_id};
77use if_chain:: if_chain;
88use rustc_errors:: Applicability ;
99use 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 } ;
1111use rustc_lint:: LateContext ;
1212use rustc_middle:: hir:: map:: Map ;
13- use rustc_span:: symbol :: { sym, Ident } ;
13+ use rustc_span:: sym;
1414use rustc_span:: { MultiSpan , Span } ;
1515
1616const 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
8888 if let ExprKind :: Block ( block, _) = expr. kind {
8989 for stmt in block. stmts {
9090 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;
9594 if let ExprKind :: MethodCall ( method_name, collect_span, & [ ref iter_source] , ..) = init_expr. kind;
9695 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) ;
9897 if let Some ( ty) = cx. typeck_results( ) . node_type_opt( hir_id) ;
9998 if is_type_diagnostic_item( cx, ty, sym:: vec_type) ||
10099 is_type_diagnostic_item( cx, ty, sym:: vecdeque_type) ||
101100 is_type_diagnostic_item( cx, ty, sym:: BinaryHeap ) ||
102101 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 ) ;
104103 if let [ iter_call] = & * iter_calls;
105104 then {
106105 let mut used_count_visitor = UsedCountVisitor {
107106 cx,
108- id: * pat_id ,
107+ id,
109108 count: 0 ,
110109 } ;
111110 walk_block( & mut used_count_visitor, block) ;
@@ -187,48 +186,40 @@ enum IterFunctionKind {
187186struct IterFunctionVisitor {
188187 uses : Vec < IterFunction > ,
189188 seen_other : bool ,
190- target : Ident ,
189+ target : HirId ,
191190}
192191impl < ' tcx > Visitor < ' tcx > for IterFunctionVisitor {
193192 fn visit_expr ( & mut self , expr : & ' tcx Expr < ' tcx > ) {
194193 // 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+ } ) ,
217213 _ => self . seen_other = true ,
218214 }
219- return
215+ return ;
220216 }
221217 }
222218 // 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) ;
232223 }
233224 }
234225
@@ -262,10 +253,10 @@ impl<'a, 'tcx> Visitor<'tcx> for UsedCountVisitor<'a, 'tcx> {
262253
263254/// Detect the occurrences of calls to `iter` or `into_iter` for the
264255/// 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 > > {
266257 let mut visitor = IterFunctionVisitor {
267258 uses : Vec :: new ( ) ,
268- target : identifier ,
259+ target : id ,
269260 seen_other : false ,
270261 } ;
271262 visitor. visit_block ( block) ;
0 commit comments