1- use clippy_utils:: diagnostics:: { span_lint, span_lint_and_sugg } ;
1+ use clippy_utils:: diagnostics:: { span_lint, span_lint_and_then } ;
22use clippy_utils:: source:: snippet;
33use clippy_utils:: ty:: implements_trait;
4+ use rustc_ast:: { BindingAnnotation , Mutability } ;
45use rustc_errors:: Applicability ;
56use rustc_hir as hir;
67use rustc_lint:: LateContext ;
78use rustc_span:: sym;
89
910use super :: FILTER_NEXT ;
1011
12+ fn path_to_local ( expr : & hir:: Expr < ' _ > ) -> Option < hir:: HirId > {
13+ match expr. kind {
14+ hir:: ExprKind :: Field ( f, _) => path_to_local ( f) ,
15+ hir:: ExprKind :: Index ( recv, _) => path_to_local ( recv) ,
16+ hir:: ExprKind :: Path ( hir:: QPath :: Resolved (
17+ _,
18+ hir:: Path {
19+ res : rustc_hir:: def:: Res :: Local ( local) ,
20+ ..
21+ } ,
22+ ) ) => Some ( * local) ,
23+ _ => None ,
24+ }
25+ }
26+
1127/// lint use of `filter().next()` for `Iterators`
1228pub ( super ) fn check < ' tcx > (
1329 cx : & LateContext < ' tcx > ,
@@ -26,15 +42,30 @@ pub(super) fn check<'tcx>(
2642 if filter_snippet. lines ( ) . count ( ) <= 1 {
2743 let iter_snippet = snippet ( cx, recv. span , ".." ) ;
2844 // add note if not multi-line
29- span_lint_and_sugg (
30- cx,
31- FILTER_NEXT ,
32- expr. span ,
33- msg,
34- "try" ,
35- format ! ( "{iter_snippet}.find({filter_snippet})" ) ,
36- Applicability :: MachineApplicable ,
37- ) ;
45+ span_lint_and_then ( cx, FILTER_NEXT , expr. span , msg, |diag| {
46+ let ( applicability, pat) = if let Some ( id) = path_to_local ( recv)
47+ && let Some ( hir:: Node :: Pat ( pat) ) = cx. tcx . hir ( ) . find ( id)
48+ && let hir:: PatKind :: Binding ( BindingAnnotation ( _, Mutability :: Not ) , _, ident, _) = pat. kind
49+ {
50+ ( Applicability :: Unspecified , Some ( ( pat. span , ident) ) )
51+ } else {
52+ ( Applicability :: MachineApplicable , None )
53+ } ;
54+
55+ diag. span_suggestion (
56+ expr. span ,
57+ "try" ,
58+ format ! ( "{iter_snippet}.find({filter_snippet})" ) ,
59+ applicability,
60+ ) ;
61+
62+ if let Some ( ( pat_span, ident) ) = pat {
63+ diag. span_help (
64+ pat_span,
65+ format ! ( "you will also need to make `{ident}` mutable, because `find` takes `&mut self`" ) ,
66+ ) ;
67+ }
68+ } ) ;
3869 } else {
3970 span_lint ( cx, FILTER_NEXT , expr. span , msg) ;
4071 }
0 commit comments