1
1
#![ allow( clippy:: wildcard_imports, clippy:: enum_glob_use) ]
2
2
3
3
use clippy_config:: Conf ;
4
- use clippy_utils:: ast_utils :: { eq_field_pat , eq_maybe_qself , eq_pat , eq_path } ;
4
+ use clippy_utils:: ast :: EqCtxt ;
5
5
use clippy_utils:: diagnostics:: span_lint_and_then;
6
6
use clippy_utils:: msrvs:: { self , MsrvStack } ;
7
- use clippy_utils:: over;
8
7
use rustc_ast:: PatKind :: * ;
9
8
use rustc_ast:: mut_visit:: * ;
10
9
use rustc_ast:: { self as ast, DUMMY_NODE_ID , Mutability , Pat , PatKind } ;
@@ -50,12 +49,14 @@ declare_clippy_lint! {
50
49
51
50
pub struct UnnestedOrPatterns {
52
51
msrv : MsrvStack ,
52
+ eq_ctxt : EqCtxt ,
53
53
}
54
54
55
55
impl UnnestedOrPatterns {
56
56
pub fn new ( conf : & ' static Conf ) -> Self {
57
57
Self {
58
58
msrv : MsrvStack :: new ( conf. msrv ) ,
59
+ eq_ctxt : EqCtxt :: default ( ) ,
59
60
}
60
61
}
61
62
}
@@ -65,34 +66,34 @@ impl_lint_pass!(UnnestedOrPatterns => [UNNESTED_OR_PATTERNS]);
65
66
impl EarlyLintPass for UnnestedOrPatterns {
66
67
fn check_arm ( & mut self , cx : & EarlyContext < ' _ > , a : & ast:: Arm ) {
67
68
if self . msrv . meets ( msrvs:: OR_PATTERNS ) {
68
- lint_unnested_or_patterns ( cx, & a. pat ) ;
69
+ lint_unnested_or_patterns ( cx, & a. pat , & mut self . eq_ctxt ) ;
69
70
}
70
71
}
71
72
72
73
fn check_expr ( & mut self , cx : & EarlyContext < ' _ > , e : & ast:: Expr ) {
73
74
if self . msrv . meets ( msrvs:: OR_PATTERNS )
74
75
&& let ast:: ExprKind :: Let ( pat, _, _, _) = & e. kind
75
76
{
76
- lint_unnested_or_patterns ( cx, pat) ;
77
+ lint_unnested_or_patterns ( cx, pat, & mut self . eq_ctxt ) ;
77
78
}
78
79
}
79
80
80
81
fn check_param ( & mut self , cx : & EarlyContext < ' _ > , p : & ast:: Param ) {
81
82
if self . msrv . meets ( msrvs:: OR_PATTERNS ) {
82
- lint_unnested_or_patterns ( cx, & p. pat ) ;
83
+ lint_unnested_or_patterns ( cx, & p. pat , & mut self . eq_ctxt ) ;
83
84
}
84
85
}
85
86
86
87
fn check_local ( & mut self , cx : & EarlyContext < ' _ > , l : & ast:: Local ) {
87
88
if self . msrv . meets ( msrvs:: OR_PATTERNS ) {
88
- lint_unnested_or_patterns ( cx, & l. pat ) ;
89
+ lint_unnested_or_patterns ( cx, & l. pat , & mut self . eq_ctxt ) ;
89
90
}
90
91
}
91
92
92
93
extract_msrv_attr ! ( ) ;
93
94
}
94
95
95
- fn lint_unnested_or_patterns ( cx : & EarlyContext < ' _ > , pat : & Pat ) {
96
+ fn lint_unnested_or_patterns ( cx : & EarlyContext < ' _ > , pat : & Pat , eq_ctxt : & mut EqCtxt ) {
96
97
if let Ident ( .., None ) | Expr ( _) | Wild | Path ( ..) | Range ( ..) | Rest | MacCall ( _) = pat. kind {
97
98
// This is a leaf pattern, so cloning is unprofitable.
98
99
return ;
@@ -104,7 +105,7 @@ fn lint_unnested_or_patterns(cx: &EarlyContext<'_>, pat: &Pat) {
104
105
remove_all_parens ( & mut pat) ;
105
106
106
107
// Transform all unnested or-patterns into nested ones, and if there were none, quit.
107
- if !unnest_or_patterns ( & mut pat) {
108
+ if !unnest_or_patterns ( & mut pat, eq_ctxt ) {
108
109
return ;
109
110
}
110
111
@@ -163,11 +164,12 @@ fn insert_necessary_parens(pat: &mut Box<Pat>) {
163
164
164
165
/// Unnest or-patterns `p0 | ... | p1` in the pattern `pat`.
165
166
/// For example, this would transform `Some(0) | FOO | Some(2)` into `Some(0 | 2) | FOO`.
166
- fn unnest_or_patterns ( pat : & mut Box < Pat > ) -> bool {
167
- struct Visitor {
167
+ fn unnest_or_patterns ( pat : & mut Box < Pat > , eq_ctxt : & mut EqCtxt ) -> bool {
168
+ struct Visitor < ' a > {
168
169
changed : bool ,
170
+ eq_ctxt : & ' a mut EqCtxt ,
169
171
}
170
- impl MutVisitor for Visitor {
172
+ impl MutVisitor for Visitor < ' _ > {
171
173
fn visit_pat ( & mut self , p : & mut Pat ) {
172
174
// This is a bottom up transformation, so recurse first.
173
175
walk_pat ( self , p) ;
@@ -192,7 +194,7 @@ fn unnest_or_patterns(pat: &mut Box<Pat>) -> bool {
192
194
// Focus on `p_n` and then try to transform all `p_i` where `i > n`.
193
195
let mut focus_idx = 0 ;
194
196
while focus_idx < alternatives. len ( ) {
195
- this_level_changed |= transform_with_focus_on_idx ( alternatives, focus_idx) ;
197
+ this_level_changed |= transform_with_focus_on_idx ( alternatives, focus_idx, self . eq_ctxt ) ;
196
198
focus_idx += 1 ;
197
199
}
198
200
self . changed |= this_level_changed;
@@ -204,7 +206,10 @@ fn unnest_or_patterns(pat: &mut Box<Pat>) -> bool {
204
206
}
205
207
}
206
208
207
- let mut visitor = Visitor { changed : false } ;
209
+ let mut visitor = Visitor {
210
+ changed : false ,
211
+ eq_ctxt,
212
+ } ;
208
213
visitor. visit_pat ( pat) ;
209
214
visitor. changed
210
215
}
@@ -223,7 +228,7 @@ macro_rules! always_pat {
223
228
/// Focus on `focus_idx` in `alternatives`,
224
229
/// attempting to extend it with elements of the same constructor `C`
225
230
/// in `alternatives[focus_idx + 1..]`.
226
- fn transform_with_focus_on_idx ( alternatives : & mut ThinVec < Box < Pat > > , focus_idx : usize ) -> bool {
231
+ fn transform_with_focus_on_idx ( alternatives : & mut ThinVec < Box < Pat > > , focus_idx : usize , eq_cx : & mut EqCtxt ) -> bool {
227
232
// Extract the kind; we'll need to make some changes in it.
228
233
let mut focus_kind = mem:: replace ( & mut alternatives[ focus_idx] . kind , Wild ) ;
229
234
// We'll focus on `alternatives[focus_idx]`,
@@ -269,13 +274,13 @@ fn transform_with_focus_on_idx(alternatives: &mut ThinVec<Box<Pat>>, focus_idx:
269
274
// Transform `[pre, x, post] | ... | [pre, y, post]` into `[pre, x | y, post]`.
270
275
Slice ( ps1) => extend_with_matching_product (
271
276
ps1, start, alternatives,
272
- |k, ps1, idx| matches ! ( k, Slice ( ps2) if eq_pre_post( ps1, ps2, idx) ) ,
277
+ |k, ps1, idx| matches ! ( k, Slice ( ps2) if eq_pre_post( ps1, ps2, idx, eq_cx ) ) ,
273
278
|k| always_pat ! ( k, Slice ( ps) => ps) ,
274
279
) ,
275
280
// Transform `(pre, x, post) | ... | (pre, y, post)` into `(pre, x | y, post)`.
276
281
Tuple ( ps1) => extend_with_matching_product (
277
282
ps1, start, alternatives,
278
- |k, ps1, idx| matches ! ( k, Tuple ( ps2) if eq_pre_post( ps1, ps2, idx) ) ,
283
+ |k, ps1, idx| matches ! ( k, Tuple ( ps2) if eq_pre_post( ps1, ps2, idx, eq_cx ) ) ,
279
284
|k| always_pat ! ( k, Tuple ( ps) => ps) ,
280
285
) ,
281
286
// Transform `S(pre, x, post) | ... | S(pre, y, post)` into `S(pre, x | y, post)`.
@@ -284,14 +289,14 @@ fn transform_with_focus_on_idx(alternatives: &mut ThinVec<Box<Pat>>, focus_idx:
284
289
|k, ps1, idx| matches ! (
285
290
k,
286
291
TupleStruct ( qself2, path2, ps2)
287
- if eq_maybe_qself ( qself1 . as_deref ( ) , qself2. as_deref ( ) )
288
- && eq_path ( path1, path2) && eq_pre_post( ps1, ps2, idx)
292
+ if eq_cx . eq ( qself1 , qself2)
293
+ && eq_cx . eq ( path1, path2) && eq_pre_post( ps1, ps2, idx, eq_cx )
289
294
) ,
290
295
|k| always_pat ! ( k, TupleStruct ( _, _, ps) => ps) ,
291
296
) ,
292
297
// Transform a record pattern `S { fp_0, ..., fp_n }`.
293
298
Struct ( qself1, path1, fps1, rest1) => {
294
- extend_with_struct_pat ( qself1. as_deref ( ) , path1, fps1, * rest1, start, alternatives)
299
+ extend_with_struct_pat ( qself1. as_deref ( ) , path1, fps1, * rest1, start, alternatives, eq_cx )
295
300
} ,
296
301
} ;
297
302
@@ -310,6 +315,7 @@ fn extend_with_struct_pat(
310
315
rest1 : ast:: PatFieldsRest ,
311
316
start : usize ,
312
317
alternatives : & mut ThinVec < Box < Pat > > ,
318
+ eq_cx : & mut EqCtxt ,
313
319
) -> bool {
314
320
( 0 ..fps1. len ( ) ) . any ( |idx| {
315
321
let pos_in_2 = Cell :: new ( None ) ; // The element `k`.
@@ -319,8 +325,8 @@ fn extend_with_struct_pat(
319
325
|k| {
320
326
matches ! ( k, Struct ( qself2, path2, fps2, rest2)
321
327
if rest1 == * rest2 // If one struct pattern has `..` so must the other.
322
- && eq_maybe_qself ( qself1, qself2. as_deref( ) )
323
- && eq_path ( path1, path2)
328
+ && eq_cx . eq ( & qself1, & qself2. as_deref( ) )
329
+ && eq_cx . eq ( path1, path2)
324
330
&& fps1. len( ) == fps2. len( )
325
331
&& fps1. iter( ) . enumerate( ) . all( |( idx_1, fp1) | {
326
332
if idx_1 == idx {
@@ -334,7 +340,7 @@ fn extend_with_struct_pat(
334
340
pos_in_2. set( pos) ;
335
341
pos. is_some( )
336
342
} else {
337
- fps2. iter( ) . any( |fp2| eq_field_pat ( fp1, fp2) )
343
+ fps2. iter( ) . any( |fp2| eq_cx . eq ( fp1, fp2) )
338
344
}
339
345
} ) )
340
346
} ,
@@ -354,7 +360,7 @@ fn extend_with_matching_product(
354
360
targets : & mut [ Box < Pat > ] ,
355
361
start : usize ,
356
362
alternatives : & mut ThinVec < Box < Pat > > ,
357
- predicate : impl Fn ( & PatKind , & [ Box < Pat > ] , usize ) -> bool ,
363
+ mut predicate : impl FnMut ( & PatKind , & [ Box < Pat > ] , usize ) -> bool ,
358
364
extract : impl Fn ( PatKind ) -> ThinVec < Box < Pat > > ,
359
365
) -> bool {
360
366
( 0 ..targets. len ( ) ) . any ( |idx| {
@@ -409,7 +415,7 @@ fn extend_with_tail_or(target: &mut Pat, tail_or: ThinVec<Box<Pat>>) -> bool {
409
415
fn drain_matching (
410
416
start : usize ,
411
417
alternatives : & mut ThinVec < Box < Pat > > ,
412
- predicate : impl Fn ( & PatKind ) -> bool ,
418
+ mut predicate : impl FnMut ( & PatKind ) -> bool ,
413
419
extract : impl Fn ( PatKind ) -> Box < Pat > ,
414
420
) -> ThinVec < Box < Pat > > {
415
421
let mut tail_or = ThinVec :: new ( ) ;
@@ -451,9 +457,9 @@ fn extend_with_matching(
451
457
}
452
458
453
459
/// Are the patterns in `ps1` and `ps2` equal save for `ps1[idx]` compared to `ps2[idx]`?
454
- fn eq_pre_post ( ps1 : & [ Box < Pat > ] , ps2 : & [ Box < Pat > ] , idx : usize ) -> bool {
460
+ fn eq_pre_post ( ps1 : & [ Box < Pat > ] , ps2 : & [ Box < Pat > ] , idx : usize , eq_cx : & mut EqCtxt ) -> bool {
455
461
ps1. len ( ) == ps2. len ( )
456
462
&& ps1[ idx] . is_rest ( ) == ps2[ idx] . is_rest ( ) // Avoid `[x, ..] | [x, 0]` => `[x, .. | 0]`.
457
- && over ( & ps1[ ..idx] , & ps2[ ..idx] , |l , r| eq_pat ( l , r ) )
458
- && over ( & ps1[ idx + 1 ..] , & ps2[ idx + 1 ..] , |l , r| eq_pat ( l , r ) )
463
+ && eq_cx . eq ( & ps1[ ..idx] , & ps2[ ..idx] )
464
+ && eq_cx . eq ( & ps1[ idx + 1 ..] , & ps2[ idx + 1 ..] )
459
465
}
0 commit comments