1
- use clippy_utils:: diagnostics:: { span_lint, span_lint_and_sugg } ;
1
+ use clippy_utils:: diagnostics:: { span_lint, span_lint_and_then } ;
2
2
use clippy_utils:: source:: snippet;
3
3
use clippy_utils:: ty:: implements_trait;
4
+ use rustc_ast:: { BindingAnnotation , Mutability } ;
4
5
use rustc_errors:: Applicability ;
5
6
use rustc_hir as hir;
6
7
use rustc_lint:: LateContext ;
7
8
use rustc_span:: sym;
8
9
9
10
use super :: FILTER_NEXT ;
10
11
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
+
11
27
/// lint use of `filter().next()` for `Iterators`
12
28
pub ( super ) fn check < ' tcx > (
13
29
cx : & LateContext < ' tcx > ,
@@ -26,15 +42,30 @@ pub(super) fn check<'tcx>(
26
42
if filter_snippet. lines ( ) . count ( ) <= 1 {
27
43
let iter_snippet = snippet ( cx, recv. span , ".." ) ;
28
44
// 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
+ } ) ;
38
69
} else {
39
70
span_lint ( cx, FILTER_NEXT , expr. span , msg) ;
40
71
}
0 commit comments