@@ -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 , HirId , PatKind , StmtKind } ;
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" ;
@@ -24,10 +24,8 @@ fn check_needless_collect_direct_usage<'tcx>(expr: &'tcx Expr<'_>, cx: &LateCont
2424 if let ExprKind :: MethodCall ( method, _, args, _) = expr. kind;
2525 if let ExprKind :: MethodCall ( chain_method, method0_span, _, _) = args[ 0 ] . kind;
2626 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) ;
3027 then {
28+ let ty = cx. typeck_results( ) . expr_ty( & args[ 0 ] ) ;
3129 let mut applicability = Applicability :: MachineApplicable ;
3230 let is_empty_sugg = "next().is_none()" . to_string( ) ;
3331 let method_name = & * method. ident. name. as_str( ) ;
@@ -72,40 +70,25 @@ fn check_needless_collect_direct_usage<'tcx>(expr: &'tcx Expr<'_>, cx: &LateCont
7270}
7371
7472fn 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- }
8873 if let ExprKind :: Block ( block, _) = expr. kind {
8974 for stmt in block. stmts {
9075 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;
9579 if let ExprKind :: MethodCall ( method_name, collect_span, & [ ref iter_source] , ..) = init_expr. kind;
9680 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) ;
9982 if is_type_diagnostic_item( cx, ty, sym:: vec_type) ||
10083 is_type_diagnostic_item( cx, ty, sym:: vecdeque_type) ||
10184 is_type_diagnostic_item( cx, ty, sym:: BinaryHeap ) ||
10285 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 ) ;
10487 if let [ iter_call] = & * iter_calls;
10588 then {
10689 let mut used_count_visitor = UsedCountVisitor {
10790 cx,
108- id: * pat_id ,
91+ id,
10992 count: 0 ,
11093 } ;
11194 walk_block( & mut used_count_visitor, block) ;
@@ -187,48 +170,40 @@ enum IterFunctionKind {
187170struct IterFunctionVisitor {
188171 uses : Vec < IterFunction > ,
189172 seen_other : bool ,
190- target : Ident ,
173+ target : HirId ,
191174}
192175impl < ' tcx > Visitor < ' tcx > for IterFunctionVisitor {
193176 fn visit_expr ( & mut self , expr : & ' tcx Expr < ' tcx > ) {
194177 // 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+ } ) ,
217197 _ => self . seen_other = true ,
218198 }
219- return
199+ return ;
220200 }
221201 }
222202 // 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) ;
232207 }
233208 }
234209
@@ -262,10 +237,10 @@ impl<'a, 'tcx> Visitor<'tcx> for UsedCountVisitor<'a, 'tcx> {
262237
263238/// Detect the occurrences of calls to `iter` or `into_iter` for the
264239/// 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 > > {
266241 let mut visitor = IterFunctionVisitor {
267242 uses : Vec :: new ( ) ,
268- target : identifier ,
243+ target : id ,
269244 seen_other : false ,
270245 } ;
271246 visitor. visit_block ( block) ;
0 commit comments