1
1
use crate :: { LateContext , LateLintPass , LintContext } ;
2
2
3
3
use hir:: { Expr , Pat } ;
4
+ use rustc_errors:: Applicability ;
4
5
use rustc_hir as hir;
5
6
use rustc_middle:: ty;
6
7
use rustc_span:: sym;
@@ -65,18 +66,24 @@ impl<'tcx> LateLintPass<'tcx> for ForLoopOverFallibles {
65
66
_ => return ,
66
67
} ;
67
68
68
- let Ok ( pat_snip) = cx. sess ( ) . source_map ( ) . span_to_snippet ( pat. span ) else { return } ;
69
69
let Ok ( arg_snip) = cx. sess ( ) . source_map ( ) . span_to_snippet ( arg. span ) else { return } ;
70
70
71
- let help_string = format ! (
72
- "consider replacing `for {pat_snip} in {arg_snip}` with `if let {var}({pat_snip}) = {arg_snip}`"
73
- ) ;
74
71
let msg = format ! (
75
72
"for loop over `{arg_snip}`, which is {article} `{ty}`. This is more readably written as an `if let` statement" ,
76
73
) ;
77
74
78
75
cx. struct_span_lint ( FOR_LOOP_OVER_FALLIBLES , arg. span , |diag| {
79
- diag. build ( msg) . help ( help_string) . emit ( )
76
+ diag. build ( msg)
77
+ . multipart_suggestion_verbose (
78
+ "consider using `if let` to clear intent" ,
79
+ vec ! [
80
+ // NB can't use `until` here because `expr.span` and `pat.span` have different syntax contexts
81
+ ( expr. span. with_hi( pat. span. lo( ) ) , format!( "if let {var}(" ) ) ,
82
+ ( pat. span. between( arg. span) , format!( ") = " ) ) ,
83
+ ] ,
84
+ Applicability :: MachineApplicable ,
85
+ )
86
+ . emit ( )
80
87
} )
81
88
}
82
89
}
@@ -89,11 +96,10 @@ fn extract_for_loop<'tcx>(expr: &Expr<'tcx>) -> Option<(&'tcx Pat<'tcx>, &'tcx E
89
96
&& let [ stmt] = block. stmts
90
97
&& let hir:: StmtKind :: Expr ( e) = stmt. kind
91
98
&& let hir:: ExprKind :: Match ( _, [ _, some_arm] , _) = e. kind
92
- && let hir:: PatKind :: Struct ( _, [ field] , _) = some_arm. pat . kind
99
+ && let hir:: PatKind :: Struct ( _, [ field] , _) = some_arm. pat . kind
93
100
{
94
101
Some ( ( field. pat , arg) )
95
102
} else {
96
103
None
97
104
}
98
-
99
- }
105
+ }
0 commit comments