1- use clippy_utils:: diagnostics:: { span_lint , span_lint_and_then} ;
2- use clippy_utils:: source:: snippet ;
1+ use clippy_utils:: diagnostics:: span_lint_and_then;
2+ use clippy_utils:: source:: snippet_with_applicability ;
33use clippy_utils:: ty:: implements_trait;
44use clippy_utils:: { path_to_local_with_projections, sym} ;
55use rustc_ast:: { BindingMode , Mutability } ;
66use rustc_errors:: Applicability ;
7- use rustc_hir as hir ;
7+ use rustc_hir:: { Expr , Node , PatKind } ;
88use rustc_lint:: LateContext ;
99
1010use super :: FILTER_NEXT ;
1111
12- #[ derive( Copy , Clone ) ]
12+ #[ derive( Clone , Copy ) ]
1313pub ( super ) enum Direction {
1414 Forward ,
1515 Backward ,
1616}
1717
1818/// lint use of `filter().next()` for `Iterator` and `filter().next_back()` for
1919/// `DoubleEndedIterator`
20- pub ( super ) fn check < ' tcx > (
21- cx : & LateContext < ' tcx > ,
22- expr : & ' tcx hir :: Expr < ' _ > ,
23- recv : & ' tcx hir :: Expr < ' _ > ,
24- filter_arg : & ' tcx hir :: Expr < ' _ > ,
20+ pub ( super ) fn check (
21+ cx : & LateContext < ' _ > ,
22+ expr : & Expr < ' _ > ,
23+ recv : & Expr < ' _ > ,
24+ filter_arg : & Expr < ' _ > ,
2525 direction : Direction ,
2626) {
27- // lint if caller of `.filter().next()` is an Iterator or `.filter().next_back()` is a
28- // DoubleEndedIterator
2927 let ( required_trait, next_method, find_method) = match direction {
3028 Direction :: Forward => ( sym:: Iterator , "next" , "find" ) ,
3129 Direction :: Backward => ( sym:: DoubleEndedIterator , "next_back" , "rfind" ) ,
@@ -37,30 +35,31 @@ pub(super) fn check<'tcx>(
3735 {
3836 return ;
3937 }
40- let msg = format ! (
41- "called `filter(..).{next_method}()` on an `{}`. This is more succinctly expressed by calling \
42- `.{find_method}(..)` instead" ,
43- required_trait . as_str ( )
44- ) ;
45- let filter_snippet = snippet ( cx , filter_arg . span , ".." ) ;
46- if filter_snippet . lines ( ) . count ( ) <= 1 {
47- let iter_snippet = snippet ( cx, recv . span , ".." ) ;
48- // add note if not multi-line
49- span_lint_and_then ( cx , FILTER_NEXT , expr . span , msg , |diag| {
50- let ( applicability , pat) = if let Some ( id) = path_to_local_with_projections ( recv)
51- && let hir :: Node :: Pat ( pat) = cx. tcx . hir_node ( id)
52- && let hir :: PatKind :: Binding ( BindingMode ( _, Mutability :: Not ) , _, ident, _) = pat. kind
38+ span_lint_and_then (
39+ cx ,
40+ FILTER_NEXT ,
41+ expr . span ,
42+ format ! ( "called `filter(..).{next_method}()` on an `{required_trait}`" ) ,
43+ |diag| {
44+ let mut app = Applicability :: MachineApplicable ;
45+ let filter_snippet = snippet_with_applicability ( cx, filter_arg . span , ".." , & mut app ) ;
46+ let iter_snippet = snippet_with_applicability ( cx , recv . span , ".." , & mut app ) ;
47+
48+ let pat = if let Some ( id) = path_to_local_with_projections ( recv)
49+ && let Node :: Pat ( pat) = cx. tcx . hir_node ( id)
50+ && let PatKind :: Binding ( BindingMode ( _, Mutability :: Not ) , _, ident, _) = pat. kind
5351 {
54- ( Applicability :: Unspecified , Some ( ( pat. span , ident) ) )
52+ app = Applicability :: Unspecified ;
53+ Some ( ( pat. span , ident) )
5554 } else {
56- ( Applicability :: MachineApplicable , None )
55+ None
5756 } ;
5857
59- diag. span_suggestion (
58+ diag. span_suggestion_verbose (
6059 expr. span ,
61- "try" ,
60+ format ! ( "use `.{find_method}(..)` instead" ) ,
6261 format ! ( "{iter_snippet}.{find_method}({filter_snippet})" ) ,
63- applicability ,
62+ app ,
6463 ) ;
6564
6665 if let Some ( ( pat_span, ident) ) = pat {
@@ -69,8 +68,6 @@ pub(super) fn check<'tcx>(
6968 format ! ( "you will also need to make `{ident}` mutable, because `{find_method}` takes `&mut self`" ) ,
7069 ) ;
7170 }
72- } ) ;
73- } else {
74- span_lint ( cx, FILTER_NEXT , expr. span , msg) ;
75- }
71+ } ,
72+ ) ;
7673}
0 commit comments