@@ -17,32 +17,25 @@ pub(super) fn check(cx: &LateContext<'_>, method_name: &str, expr: &Expr<'_>, se
17
17
}
18
18
19
19
let ctxt = expr. span . ctxt ( ) ;
20
- let usage = match parse_iter_usage ( cx, ctxt, cx. tcx . hir ( ) . parent_iter ( expr. hir_id ) ) {
20
+ let ( method_name, msg, reverse) = if method_name == "splitn" {
21
+ ( "split_once" , "manual implementation of `split_once`" , false )
22
+ } else {
23
+ ( "rsplit_once" , "manual implementation of `rsplit_once`" , true )
24
+ } ;
25
+ let usage = match parse_iter_usage ( cx, ctxt, cx. tcx . hir ( ) . parent_iter ( expr. hir_id ) , reverse) {
21
26
Some ( x) => x,
22
27
None => return ,
23
28
} ;
24
- let ( method_name, msg) = if method_name == "splitn" {
25
- ( "split_once" , "manual implementation of `split_once`" )
26
- } else {
27
- ( "rsplit_once" , "manual implementation of `rsplit_once`" )
28
- } ;
29
29
30
30
let mut app = Applicability :: MachineApplicable ;
31
31
let self_snip = snippet_with_context ( cx, self_arg. span , ctxt, ".." , & mut app) . 0 ;
32
32
let pat_snip = snippet_with_context ( cx, pat_arg. span , ctxt, ".." , & mut app) . 0 ;
33
33
34
- match usage. kind {
34
+ let sugg = match usage. kind {
35
35
IterUsageKind :: NextTuple => {
36
- span_lint_and_sugg (
37
- cx,
38
- MANUAL_SPLIT_ONCE ,
39
- usage. span ,
40
- msg,
41
- "try this" ,
42
- format ! ( "{}.{}({})" , self_snip, method_name, pat_snip) ,
43
- app,
44
- ) ;
36
+ format ! ( "{}.{}({})" , self_snip, method_name, pat_snip)
45
37
} ,
38
+ IterUsageKind :: RNextTuple => format ! ( "{}.{}({}).map(|(x, y)| (y, x))" , self_snip, method_name, pat_snip) ,
46
39
IterUsageKind :: Next => {
47
40
let self_deref = {
48
41
let adjust = cx. typeck_results ( ) . expr_adjustments ( self_arg) ;
@@ -58,7 +51,7 @@ pub(super) fn check(cx: &LateContext<'_>, method_name: &str, expr: &Expr<'_>, se
58
51
"*" . repeat ( adjust. len ( ) - 2 )
59
52
}
60
53
} ;
61
- let sugg = if usage. unwrap_kind . is_some ( ) {
54
+ if usage. unwrap_kind . is_some ( ) {
62
55
format ! (
63
56
"{}.{}({}).map_or({}{}, |x| x.0)" ,
64
57
& self_snip, method_name, pat_snip, self_deref, & self_snip
@@ -68,33 +61,26 @@ pub(super) fn check(cx: &LateContext<'_>, method_name: &str, expr: &Expr<'_>, se
68
61
"Some({}.{}({}).map_or({}{}, |x| x.0))" ,
69
62
& self_snip, method_name, pat_snip, self_deref, & self_snip
70
63
)
71
- } ;
72
-
73
- span_lint_and_sugg ( cx, MANUAL_SPLIT_ONCE , usage. span , msg, "try this" , sugg, app) ;
64
+ }
74
65
} ,
75
66
IterUsageKind :: Second => {
76
67
let access_str = match usage. unwrap_kind {
77
68
Some ( UnwrapKind :: Unwrap ) => ".unwrap().1" ,
78
69
Some ( UnwrapKind :: QuestionMark ) => "?.1" ,
79
70
None => ".map(|x| x.1)" ,
80
71
} ;
81
- span_lint_and_sugg (
82
- cx,
83
- MANUAL_SPLIT_ONCE ,
84
- usage. span ,
85
- msg,
86
- "try this" ,
87
- format ! ( "{}.{}({}){}" , self_snip, method_name, pat_snip, access_str) ,
88
- app,
89
- ) ;
72
+ format ! ( "{}.{}({}){}" , self_snip, method_name, pat_snip, access_str)
90
73
} ,
91
- }
74
+ } ;
75
+
76
+ span_lint_and_sugg ( cx, MANUAL_SPLIT_ONCE , usage. span , msg, "try this" , sugg, app) ;
92
77
}
93
78
94
79
enum IterUsageKind {
95
80
Next ,
96
81
Second ,
97
82
NextTuple ,
83
+ RNextTuple ,
98
84
}
99
85
100
86
enum UnwrapKind {
@@ -108,10 +94,12 @@ struct IterUsage {
108
94
span : Span ,
109
95
}
110
96
97
+ #[ allow( clippy:: too_many_lines) ]
111
98
fn parse_iter_usage (
112
99
cx : & LateContext < ' tcx > ,
113
100
ctxt : SyntaxContext ,
114
101
mut iter : impl Iterator < Item = ( HirId , Node < ' tcx > ) > ,
102
+ reverse : bool ,
115
103
) -> Option < IterUsage > {
116
104
let ( kind, span) = match iter. next ( ) {
117
105
Some ( ( _, Node :: Expr ( e) ) ) if e. span . ctxt ( ) == ctxt => {
@@ -124,20 +112,30 @@ fn parse_iter_usage(
124
112
let iter_id = cx. tcx . get_diagnostic_item ( sym:: Iterator ) ?;
125
113
126
114
match ( & * name. ident . as_str ( ) , args) {
127
- ( "next" , [ ] ) if cx. tcx . trait_of_item ( did) == Some ( iter_id) => ( IterUsageKind :: Next , e. span ) ,
115
+ ( "next" , [ ] ) if cx. tcx . trait_of_item ( did) == Some ( iter_id) => {
116
+ if reverse {
117
+ ( IterUsageKind :: Second , e. span )
118
+ } else {
119
+ ( IterUsageKind :: Next , e. span )
120
+ }
121
+ } ,
128
122
( "next_tuple" , [ ] ) => {
129
- if_chain ! {
123
+ return if_chain ! {
130
124
if match_def_path( cx, did, & paths:: ITERTOOLS_NEXT_TUPLE ) ;
131
125
if let ty:: Adt ( adt_def, subs) = cx. typeck_results( ) . expr_ty( e) . kind( ) ;
132
126
if cx. tcx. is_diagnostic_item( sym:: option_type, adt_def. did) ;
133
127
if let ty:: Tuple ( subs) = subs. type_at( 0 ) . kind( ) ;
134
128
if subs. len( ) == 2 ;
135
129
then {
136
- return Some ( IterUsage { kind: IterUsageKind :: NextTuple , span: e. span, unwrap_kind: None } ) ;
130
+ Some ( IterUsage {
131
+ kind: if reverse { IterUsageKind :: RNextTuple } else { IterUsageKind :: NextTuple } ,
132
+ span: e. span,
133
+ unwrap_kind: None
134
+ } )
137
135
} else {
138
- return None ;
136
+ None
139
137
}
140
- }
138
+ } ;
141
139
} ,
142
140
( "nth" | "skip" , [ idx_expr] ) if cx. tcx . trait_of_item ( did) == Some ( iter_id) => {
143
141
if let Some ( ( Constant :: Int ( idx) , _) ) = constant ( cx, cx. typeck_results ( ) , idx_expr) {
@@ -158,7 +156,7 @@ fn parse_iter_usage(
158
156
}
159
157
}
160
158
} ;
161
- match idx {
159
+ match if reverse { idx ^ 1 } else { idx } {
162
160
0 => ( IterUsageKind :: Next , span) ,
163
161
1 => ( IterUsageKind :: Second , span) ,
164
162
_ => return None ,
0 commit comments