@@ -17,32 +17,25 @@ pub(super) fn check(cx: &LateContext<'_>, method_name: &str, expr: &Expr<'_>, se
1717 }
1818
1919 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) {
2126 Some ( x) => x,
2227 None => return ,
2328 } ;
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- } ;
2929
3030 let mut app = Applicability :: MachineApplicable ;
3131 let self_snip = snippet_with_context ( cx, self_arg. span , ctxt, ".." , & mut app) . 0 ;
3232 let pat_snip = snippet_with_context ( cx, pat_arg. span , ctxt, ".." , & mut app) . 0 ;
3333
34- match usage. kind {
34+ let sugg = match usage. kind {
3535 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)
4537 } ,
38+ IterUsageKind :: RNextTuple => format ! ( "{}.{}({}).map(|(x, y)| (y, x))" , self_snip, method_name, pat_snip) ,
4639 IterUsageKind :: Next => {
4740 let self_deref = {
4841 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
5851 "*" . repeat ( adjust. len ( ) - 2 )
5952 }
6053 } ;
61- let sugg = if usage. unwrap_kind . is_some ( ) {
54+ if usage. unwrap_kind . is_some ( ) {
6255 format ! (
6356 "{}.{}({}).map_or({}{}, |x| x.0)" ,
6457 & 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
6861 "Some({}.{}({}).map_or({}{}, |x| x.0))" ,
6962 & self_snip, method_name, pat_snip, self_deref, & self_snip
7063 )
71- } ;
72-
73- span_lint_and_sugg ( cx, MANUAL_SPLIT_ONCE , usage. span , msg, "try this" , sugg, app) ;
64+ }
7465 } ,
7566 IterUsageKind :: Second => {
7667 let access_str = match usage. unwrap_kind {
7768 Some ( UnwrapKind :: Unwrap ) => ".unwrap().1" ,
7869 Some ( UnwrapKind :: QuestionMark ) => "?.1" ,
7970 None => ".map(|x| x.1)" ,
8071 } ;
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)
9073 } ,
91- }
74+ } ;
75+
76+ span_lint_and_sugg ( cx, MANUAL_SPLIT_ONCE , usage. span , msg, "try this" , sugg, app) ;
9277}
9378
9479enum IterUsageKind {
9580 Next ,
9681 Second ,
9782 NextTuple ,
83+ RNextTuple ,
9884}
9985
10086enum UnwrapKind {
@@ -108,10 +94,12 @@ struct IterUsage {
10894 span : Span ,
10995}
11096
97+ #[ allow( clippy:: too_many_lines) ]
11198fn parse_iter_usage (
11299 cx : & LateContext < ' tcx > ,
113100 ctxt : SyntaxContext ,
114101 mut iter : impl Iterator < Item = ( HirId , Node < ' tcx > ) > ,
102+ reverse : bool ,
115103) -> Option < IterUsage > {
116104 let ( kind, span) = match iter. next ( ) {
117105 Some ( ( _, Node :: Expr ( e) ) ) if e. span . ctxt ( ) == ctxt => {
@@ -124,20 +112,30 @@ fn parse_iter_usage(
124112 let iter_id = cx. tcx . get_diagnostic_item ( sym:: Iterator ) ?;
125113
126114 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+ } ,
128122 ( "next_tuple" , [ ] ) => {
129- if_chain ! {
123+ return if_chain ! {
130124 if match_def_path( cx, did, & paths:: ITERTOOLS_NEXT_TUPLE ) ;
131125 if let ty:: Adt ( adt_def, subs) = cx. typeck_results( ) . expr_ty( e) . kind( ) ;
132126 if cx. tcx. is_diagnostic_item( sym:: option_type, adt_def. did) ;
133127 if let ty:: Tuple ( subs) = subs. type_at( 0 ) . kind( ) ;
134128 if subs. len( ) == 2 ;
135129 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+ } )
137135 } else {
138- return None ;
136+ None
139137 }
140- }
138+ } ;
141139 } ,
142140 ( "nth" | "skip" , [ idx_expr] ) if cx. tcx . trait_of_item ( did) == Some ( iter_id) => {
143141 if let Some ( ( Constant :: Int ( idx) , _) ) = constant ( cx, cx. typeck_results ( ) , idx_expr) {
@@ -158,7 +156,7 @@ fn parse_iter_usage(
158156 }
159157 }
160158 } ;
161- match idx {
159+ match if reverse { idx ^ 1 } else { idx } {
162160 0 => ( IterUsageKind :: Next , span) ,
163161 1 => ( IterUsageKind :: Second , span) ,
164162 _ => return None ,
0 commit comments