@@ -10,8 +10,8 @@ use rustc_hir::intravisit::{walk_block, walk_expr, NestedVisitorMap, Visitor};
10
10
use rustc_hir:: { Block , Expr , ExprKind , GenericArg , HirId , Local , Pat , PatKind , QPath , StmtKind } ;
11
11
use rustc_lint:: LateContext ;
12
12
use rustc_middle:: hir:: map:: Map ;
13
- use rustc_span:: source_map:: Span ;
14
13
use rustc_span:: symbol:: { sym, Ident } ;
14
+ use rustc_span:: { MultiSpan , Span } ;
15
15
16
16
const NEEDLESS_COLLECT_MSG : & str = "avoid using `collect()` when not needed" ;
17
17
@@ -22,7 +22,7 @@ pub(super) fn check<'tcx>(expr: &'tcx Expr<'_>, cx: &LateContext<'tcx>) {
22
22
fn check_needless_collect_direct_usage < ' tcx > ( expr : & ' tcx Expr < ' _ > , cx : & LateContext < ' tcx > ) {
23
23
if_chain ! {
24
24
if let ExprKind :: MethodCall ( ref method, _, ref args, _) = expr. kind;
25
- if let ExprKind :: MethodCall ( ref chain_method, _ , _, _) = args[ 0 ] . kind;
25
+ if let ExprKind :: MethodCall ( ref 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
27
if let Some ( ref generic_args) = chain_method. args;
28
28
if let Some ( GenericArg :: Type ( ref ty) ) = generic_args. args. get( 0 ) ;
@@ -31,55 +31,28 @@ fn check_needless_collect_direct_usage<'tcx>(expr: &'tcx Expr<'_>, cx: &LateCont
31
31
|| is_type_diagnostic_item( cx, ty, sym:: vecdeque_type)
32
32
|| match_type( cx, ty, & paths:: BTREEMAP )
33
33
|| is_type_diagnostic_item( cx, ty, sym:: hashmap_type) ;
34
- then {
35
- if method. ident. name == sym!( len) {
36
- let span = shorten_needless_collect_span( expr) ;
37
- span_lint_and_sugg(
38
- cx,
39
- NEEDLESS_COLLECT ,
40
- span,
41
- NEEDLESS_COLLECT_MSG ,
42
- "replace with" ,
43
- "count()" . to_string( ) ,
44
- Applicability :: MachineApplicable ,
45
- ) ;
46
- }
47
- if method. ident. name == sym!( is_empty) {
48
- let span = shorten_needless_collect_span( expr) ;
49
- span_lint_and_sugg(
50
- cx,
51
- NEEDLESS_COLLECT ,
52
- span,
53
- NEEDLESS_COLLECT_MSG ,
54
- "replace with" ,
55
- "next().is_none()" . to_string( ) ,
56
- Applicability :: MachineApplicable ,
57
- ) ;
58
- }
59
- if method. ident. name == sym!( contains) {
34
+ if let Some ( sugg) = match & * method. ident. name. as_str( ) {
35
+ "len" => Some ( "count()" . to_string( ) ) ,
36
+ "is_empty" => Some ( "next().is_none()" . to_string( ) ) ,
37
+ "contains" => {
60
38
let contains_arg = snippet( cx, args[ 1 ] . span, "??" ) ;
61
- let span = shorten_needless_collect_span( expr) ;
62
- span_lint_and_then(
63
- cx,
64
- NEEDLESS_COLLECT ,
65
- span,
66
- NEEDLESS_COLLECT_MSG ,
67
- |diag| {
68
- let ( arg, pred) = contains_arg
69
- . strip_prefix( '&' )
70
- . map_or( ( "&x" , & * contains_arg) , |s| ( "x" , s) ) ;
71
- diag. span_suggestion(
72
- span,
73
- "replace with" ,
74
- format!(
75
- "any(|{}| x == {})" ,
76
- arg, pred
77
- ) ,
78
- Applicability :: MachineApplicable ,
79
- ) ;
80
- }
81
- ) ;
39
+ let ( arg, pred) = contains_arg
40
+ . strip_prefix( '&' )
41
+ . map_or( ( "&x" , & * contains_arg) , |s| ( "x" , s) ) ;
42
+ Some ( format!( "any(|{}| x == {})" , arg, pred) )
82
43
}
44
+ _ => None ,
45
+ } ;
46
+ then {
47
+ span_lint_and_sugg(
48
+ cx,
49
+ NEEDLESS_COLLECT ,
50
+ method0_span. with_hi( expr. span. hi( ) ) ,
51
+ NEEDLESS_COLLECT_MSG ,
52
+ "replace with" ,
53
+ sugg,
54
+ Applicability :: MachineApplicable ,
55
+ ) ;
83
56
}
84
57
}
85
58
}
@@ -92,7 +65,7 @@ fn check_needless_collect_indirect_usage<'tcx>(expr: &'tcx Expr<'_>, cx: &LateCo
92
65
Local { pat: Pat { hir_id: pat_id, kind: PatKind :: Binding ( _, _, ident, .. ) , .. } ,
93
66
init: Some ( ref init_expr) , .. }
94
67
) = stmt. kind;
95
- if let ExprKind :: MethodCall ( ref method_name, _ , & [ ref iter_source] , ..) = init_expr. kind;
68
+ if let ExprKind :: MethodCall ( ref method_name, collect_span , & [ ref iter_source] , ..) = init_expr. kind;
96
69
if method_name. ident. name == sym!( collect) && is_trait_method( cx, & init_expr, sym:: Iterator ) ;
97
70
if let Some ( ref generic_args) = method_name. args;
98
71
if let Some ( GenericArg :: Type ( ref ty) ) = generic_args. args. get( 0 ) ;
@@ -101,7 +74,7 @@ fn check_needless_collect_indirect_usage<'tcx>(expr: &'tcx Expr<'_>, cx: &LateCo
101
74
is_type_diagnostic_item( cx, ty, sym:: vecdeque_type) ||
102
75
match_type( cx, ty, & paths:: LINKED_LIST ) ;
103
76
if let Some ( iter_calls) = detect_iter_and_into_iters( block, * ident) ;
104
- if iter_calls . len ( ) == 1 ;
77
+ if let [ iter_call ] = & * iter_calls ;
105
78
then {
106
79
let mut used_count_visitor = UsedCountVisitor {
107
80
cx,
@@ -114,11 +87,12 @@ fn check_needless_collect_indirect_usage<'tcx>(expr: &'tcx Expr<'_>, cx: &LateCo
114
87
}
115
88
116
89
// Suggest replacing iter_call with iter_replacement, and removing stmt
117
- let iter_call = & iter_calls[ 0 ] ;
90
+ let mut span = MultiSpan :: from_span( collect_span) ;
91
+ span. push_span_label( iter_call. span, "the iterator could be used here instead" . into( ) ) ;
118
92
span_lint_and_then(
119
93
cx,
120
94
super :: NEEDLESS_COLLECT ,
121
- stmt . span. until ( iter_call . span ) ,
95
+ span,
122
96
NEEDLESS_COLLECT_MSG ,
123
97
|diag| {
124
98
let iter_replacement = format!( "{}{}" , Sugg :: hir( cx, iter_source, ".." ) , iter_call. get_iter_method( cx) ) ;
@@ -129,7 +103,7 @@ fn check_needless_collect_indirect_usage<'tcx>(expr: &'tcx Expr<'_>, cx: &LateCo
129
103
( iter_call. span, iter_replacement)
130
104
] ,
131
105
Applicability :: MachineApplicable , // MaybeIncorrect,
132
- ) . emit ( ) ;
106
+ ) ;
133
107
} ,
134
108
) ;
135
109
}
@@ -269,14 +243,3 @@ fn detect_iter_and_into_iters<'tcx>(block: &'tcx Block<'tcx>, identifier: Ident)
269
243
visitor. visit_block ( block) ;
270
244
if visitor. seen_other { None } else { Some ( visitor. uses ) }
271
245
}
272
-
273
- fn shorten_needless_collect_span ( expr : & Expr < ' _ > ) -> Span {
274
- if_chain ! {
275
- if let ExprKind :: MethodCall ( .., args, _) = & expr. kind;
276
- if let ExprKind :: MethodCall ( _, span, ..) = & args[ 0 ] . kind;
277
- then {
278
- return expr. span. with_lo( span. lo( ) ) ;
279
- }
280
- }
281
- unreachable ! ( ) ;
282
- }
0 commit comments