1
1
use clippy_utils:: diagnostics:: span_lint_and_then;
2
2
use clippy_utils:: source:: snippet_with_applicability;
3
- use clippy_utils:: visitors:: for_each_expr;
3
+ use clippy_utils:: visitors:: { for_each_expr, is_local_used } ;
4
4
use rustc_errors:: Applicability ;
5
5
use rustc_hir:: def:: { DefKind , Res } ;
6
- use rustc_hir:: { Arm , BinOpKind , Expr , ExprKind , Guard , HirId , MatchSource , Node , Pat , PatField , PatKind } ;
6
+ use rustc_hir:: { Arm , BinOpKind , Expr , ExprKind , Guard , MatchSource , Node , Pat , PatField , PatKind } ;
7
7
use rustc_lint:: LateContext ;
8
8
use rustc_span:: symbol:: Ident ;
9
9
use rustc_span:: Span ;
10
10
use std:: borrow:: Cow ;
11
11
use std:: ops:: ControlFlow ;
12
12
13
- use super :: REDUNDANT_GUARD ;
13
+ use super :: REDUNDANT_GUARDS ;
14
14
15
- pub ( super ) fn check ( cx : & LateContext < ' _ > , arms : & [ Arm < ' _ > ] ) {
15
+ pub ( super ) fn check < ' tcx > ( cx : & LateContext < ' tcx > , arms : & ' tcx [ Arm < ' tcx > ] ) {
16
16
for outer_arm in arms {
17
17
let mut app = Applicability :: MaybeIncorrect ;
18
18
let Some ( guard) = outer_arm. guard else {
@@ -37,7 +37,7 @@ pub(super) fn check(cx: &LateContext<'_>, arms: &[Arm<'_>]) {
37
37
) = if_expr. kind
38
38
&& let Some ( ( pat_binding, field_name) ) = get_pat_binding ( cx, scrutinee, outer_arm)
39
39
{
40
- emit_redundant_guard (
40
+ emit_redundant_guards (
41
41
cx,
42
42
outer_arm,
43
43
if_expr. span ,
@@ -53,7 +53,7 @@ pub(super) fn check(cx: &LateContext<'_>, arms: &[Arm<'_>]) {
53
53
&& let pat = let_expr. pat
54
54
&& let Some ( ( pat_binding, field_name) ) = get_pat_binding ( cx, let_expr. init , outer_arm)
55
55
{
56
- emit_redundant_guard (
56
+ emit_redundant_guards (
57
57
cx,
58
58
outer_arm,
59
59
let_expr. span ,
@@ -78,7 +78,7 @@ pub(super) fn check(cx: &LateContext<'_>, arms: &[Arm<'_>]) {
78
78
// This isn't necessary in the other two checks, as they must be a pattern already.
79
79
&& cx. typeck_results ( ) . expr_ty ( local) == cx. typeck_results ( ) . expr_ty ( pat)
80
80
{
81
- emit_redundant_guard (
81
+ emit_redundant_guards (
82
82
cx,
83
83
outer_arm,
84
84
if_expr. span ,
@@ -103,21 +103,34 @@ fn remove_binding(
103
103
( pat_start, pat_end)
104
104
}
105
105
106
- fn get_pat_binding ( cx : & LateContext < ' _ > , guard_expr : & Expr < ' _ > , outer_arm : & Arm < ' _ > ) -> Option < ( Span , Option < Ident > ) > {
106
+ fn get_pat_binding < ' tcx > (
107
+ cx : & LateContext < ' tcx > ,
108
+ guard_expr : & Expr < ' _ > ,
109
+ outer_arm : & Arm < ' tcx > ,
110
+ ) -> Option < ( Span , Option < Ident > ) > {
107
111
if let ExprKind :: Path ( qpath) = guard_expr. kind
108
112
&& let res = cx. qpath_res ( & qpath, guard_expr. hir_id )
109
- && let Res :: Local ( hir_id ) = res
110
- && local_came_from_and_not_used ( cx, & res , outer_arm. pat . hir_id , outer_arm . body )
113
+ && let Res :: Local ( local ) = res
114
+ && ! is_local_used ( cx, outer_arm. body , local )
111
115
{
112
- return cx. tcx . hir ( ) . res_span ( res) . map ( |span| {
113
- (
114
- span,
115
- match cx. tcx . hir ( ) . get_parent ( hir_id) {
116
- Node :: PatField ( PatField { ident, .. } ) => Some ( * ident) ,
117
- _ => None ,
118
- } ,
119
- )
116
+ let mut is_from_pat = false ;
117
+ outer_arm. pat . each_binding ( |_, hir_id, _, _| {
118
+ if hir_id == local {
119
+ is_from_pat = true ;
120
+ }
120
121
} ) ;
122
+
123
+ if is_from_pat {
124
+ return cx. tcx . hir ( ) . res_span ( res) . map ( |span| {
125
+ (
126
+ span,
127
+ match cx. tcx . hir ( ) . get_parent ( local) {
128
+ Node :: PatField ( PatField { ident, .. } ) => Some ( * ident) ,
129
+ _ => None ,
130
+ } ,
131
+ )
132
+ } ) ;
133
+ }
121
134
}
122
135
123
136
None
@@ -140,29 +153,8 @@ fn get_guard(cx: &LateContext<'_>, guard: Option<Guard<'_>>, app: &mut Applicabi
140
153
)
141
154
}
142
155
143
- fn local_came_from_and_not_used ( cx : & LateContext < ' _ > , local : & Res , target : HirId , body : & Expr < ' _ > ) -> bool {
144
- if let Res :: Local ( local) = local
145
- && cx. tcx . hir ( ) . parent_iter ( * local) . any ( |( p, _) | p == target)
146
- && for_each_expr ( body, |expr| {
147
- if let ExprKind :: Path ( qpath) = expr. kind
148
- && let Res :: Local ( local_ref) = cx. qpath_res ( & qpath, expr. hir_id )
149
- && * local == local_ref
150
- {
151
- return ControlFlow :: Break ( ( ) ) ;
152
- }
153
-
154
- ControlFlow :: Continue ( ( ) )
155
- } )
156
- . is_none ( )
157
- {
158
- return true ;
159
- }
160
-
161
- false
162
- }
163
-
164
156
#[ expect( clippy:: too_many_arguments) ]
165
- fn emit_redundant_guard (
157
+ fn emit_redundant_guards (
166
158
cx : & LateContext < ' _ > ,
167
159
outer_arm : & Arm < ' _ > ,
168
160
guard_span : Span ,
@@ -177,18 +169,26 @@ fn emit_redundant_guard(
177
169
178
170
span_lint_and_then (
179
171
cx,
180
- REDUNDANT_GUARD ,
172
+ REDUNDANT_GUARDS ,
181
173
guard_span. source_callsite ( ) ,
182
174
"redundant guard" ,
183
175
|diag| {
184
- diag. span_suggestion (
185
- outer_arm. span . with_hi ( guard_span. source_callsite ( ) . hi ( ) ) ,
176
+ diag. multipart_suggestion_verbose (
186
177
"try" ,
187
- format ! (
188
- "{pat_start}{}{binding_replacement}{pat_end}{}" ,
189
- field_name. map_or_else( || Cow :: Borrowed ( "" ) , |i| format!( "{}: " , i. as_str( ) ) . into( ) ) ,
190
- get_guard( cx, inner_guard, app) ,
191
- ) ,
178
+ vec ! [
179
+ (
180
+ guard_span. source_callsite( ) . with_lo( outer_arm. pat. span. hi( ) ) ,
181
+ String :: new( ) ,
182
+ ) ,
183
+ (
184
+ outer_arm. pat. span,
185
+ format!(
186
+ "{pat_start}{}{binding_replacement}{pat_end}{}" ,
187
+ field_name. map_or_else( || Cow :: Borrowed ( "" ) , |i| format!( "{}: " , i. as_str( ) ) . into( ) ) ,
188
+ get_guard( cx, inner_guard, app) ,
189
+ ) ,
190
+ ) ,
191
+ ] ,
192
192
* app,
193
193
) ;
194
194
} ,
0 commit comments