@@ -10,51 +10,68 @@ use rustc_span::sym;
10
10
11
11
use super :: FILTER_NEXT ;
12
12
13
- /// lint use of `filter().next()` for `Iterators`
13
+ #[ derive( Copy , Clone ) ]
14
+ pub ( super ) enum Direction {
15
+ Forward ,
16
+ Backward ,
17
+ }
18
+
19
+ /// lint use of `filter().next()` for `Iterator` and `filter().next_back()` for
20
+ /// `DoubleEndedIterator`
14
21
pub ( super ) fn check < ' tcx > (
15
22
cx : & LateContext < ' tcx > ,
16
23
expr : & ' tcx hir:: Expr < ' _ > ,
17
24
recv : & ' tcx hir:: Expr < ' _ > ,
18
25
filter_arg : & ' tcx hir:: Expr < ' _ > ,
26
+ direction : Direction ,
19
27
) {
20
- // lint if caller of `.filter().next()` is an Iterator
21
- let recv_impls_iterator = cx
28
+ // lint if caller of `.filter().next()` is an Iterator or `.filter().next_back()` is a
29
+ // DoubleEndedIterator
30
+ let ( required_trait, next_method, find_method) = match direction {
31
+ Direction :: Forward => ( sym:: Iterator , "next" , "find" ) ,
32
+ Direction :: Backward => ( sym:: DoubleEndedIterator , "next_back" , "rfind" ) ,
33
+ } ;
34
+ if !cx
22
35
. tcx
23
- . get_diagnostic_item ( sym:: Iterator )
24
- . is_some_and ( |id| implements_trait ( cx, cx. typeck_results ( ) . expr_ty ( recv) , id, & [ ] ) ) ;
25
- if recv_impls_iterator {
26
- let msg = "called `filter(..).next()` on an `Iterator`. This is more succinctly expressed by calling \
27
- `.find(..)` instead";
28
- let filter_snippet = snippet ( cx, filter_arg. span , ".." ) ;
29
- if filter_snippet. lines ( ) . count ( ) <= 1 {
30
- let iter_snippet = snippet ( cx, recv. span , ".." ) ;
31
- // add note if not multi-line
32
- span_lint_and_then ( cx, FILTER_NEXT , expr. span , msg, |diag| {
33
- let ( applicability, pat) = if let Some ( id) = path_to_local_with_projections ( recv)
34
- && let hir:: Node :: Pat ( pat) = cx. tcx . hir_node ( id)
35
- && let hir:: PatKind :: Binding ( BindingMode ( _, Mutability :: Not ) , _, ident, _) = pat. kind
36
- {
37
- ( Applicability :: Unspecified , Some ( ( pat. span , ident) ) )
38
- } else {
39
- ( Applicability :: MachineApplicable , None )
40
- } ;
36
+ . get_diagnostic_item ( required_trait)
37
+ . is_some_and ( |id| implements_trait ( cx, cx. typeck_results ( ) . expr_ty ( recv) , id, & [ ] ) )
38
+ {
39
+ return ;
40
+ }
41
+ let msg = format ! (
42
+ "called `filter(..).{next_method}()` on an `{}`. This is more succinctly expressed by calling \
43
+ `.{find_method}(..)` instead",
44
+ required_trait. as_str( )
45
+ ) ;
46
+ let filter_snippet = snippet ( cx, filter_arg. span , ".." ) ;
47
+ if filter_snippet. lines ( ) . count ( ) <= 1 {
48
+ let iter_snippet = snippet ( cx, recv. span , ".." ) ;
49
+ // add note if not multi-line
50
+ span_lint_and_then ( cx, FILTER_NEXT , expr. span , msg, |diag| {
51
+ let ( applicability, pat) = if let Some ( id) = path_to_local_with_projections ( recv)
52
+ && let hir:: Node :: Pat ( pat) = cx. tcx . hir_node ( id)
53
+ && let hir:: PatKind :: Binding ( BindingMode ( _, Mutability :: Not ) , _, ident, _) = pat. kind
54
+ {
55
+ ( Applicability :: Unspecified , Some ( ( pat. span , ident) ) )
56
+ } else {
57
+ ( Applicability :: MachineApplicable , None )
58
+ } ;
41
59
42
- diag. span_suggestion (
43
- expr. span ,
44
- "try" ,
45
- format ! ( "{iter_snippet}.find ({filter_snippet})" ) ,
46
- applicability,
47
- ) ;
60
+ diag. span_suggestion (
61
+ expr. span ,
62
+ "try" ,
63
+ format ! ( "{iter_snippet}.{find_method} ({filter_snippet})" ) ,
64
+ applicability,
65
+ ) ;
48
66
49
- if let Some ( ( pat_span, ident) ) = pat {
50
- diag. span_help (
51
- pat_span,
52
- format ! ( "you will also need to make `{ident}` mutable, because `find` takes `&mut self`" ) ,
53
- ) ;
54
- }
55
- } ) ;
56
- } else {
57
- span_lint ( cx, FILTER_NEXT , expr. span , msg) ;
58
- }
67
+ if let Some ( ( pat_span, ident) ) = pat {
68
+ diag. span_help (
69
+ pat_span,
70
+ format ! ( "you will also need to make `{ident}` mutable, because `{find_method}` takes `&mut self`" ) ,
71
+ ) ;
72
+ }
73
+ } ) ;
74
+ } else {
75
+ span_lint ( cx, FILTER_NEXT , expr. span , msg) ;
59
76
}
60
77
}
0 commit comments