@@ -398,18 +398,37 @@ impl UnusedParens {
398
398
}
399
399
}
400
400
401
- fn check_unused_parens_pat ( & self ,
402
- cx : & EarlyContext < ' _ > ,
403
- value : & ast:: Pat ,
404
- msg : & str ) {
405
- if let ast:: PatKind :: Paren ( _) = value. node {
401
+ fn check_unused_parens_pat (
402
+ & self ,
403
+ cx : & EarlyContext < ' _ > ,
404
+ value : & ast:: Pat ,
405
+ avoid_or : bool ,
406
+ avoid_mut : bool ,
407
+ ) {
408
+ use ast:: { PatKind , BindingMode :: ByValue , Mutability :: Mutable } ;
409
+
410
+ if let PatKind :: Paren ( inner) = & value. node {
411
+ match inner. node {
412
+ // The lint visitor will visit each subpattern of `p`. We do not want to lint
413
+ // any range pattern no matter where it occurs in the pattern. For something like
414
+ // `&(a..=b)`, there is a recursive `check_pat` on `a` and `b`, but we will assume
415
+ // that if there are unnecessary parens they serve a purpose of readability.
416
+ PatKind :: Range ( ..) => return ,
417
+ // Avoid `p0 | .. | pn` if we should.
418
+ PatKind :: Or ( ..) if avoid_or => return ,
419
+ // Avoid `mut x` and `mut x @ p` if we should:
420
+ PatKind :: Ident ( ByValue ( Mutable ) , ..) if avoid_mut => return ,
421
+ // Otherwise proceed with linting.
422
+ _ => { }
423
+ }
424
+
406
425
let pattern_text = if let Ok ( snippet) = cx. sess ( ) . source_map ( )
407
426
. span_to_snippet ( value. span ) {
408
427
snippet
409
428
} else {
410
429
pprust:: pat_to_string ( value)
411
430
} ;
412
- Self :: remove_outer_parens ( cx, value. span , & pattern_text, msg , ( false , false ) ) ;
431
+ Self :: remove_outer_parens ( cx, value. span , & pattern_text, "pattern" , ( false , false ) ) ;
413
432
}
414
433
}
415
434
@@ -474,6 +493,13 @@ impl EarlyLintPass for UnusedParens {
474
493
fn check_expr ( & mut self , cx : & EarlyContext < ' _ > , e : & ast:: Expr ) {
475
494
use syntax:: ast:: ExprKind :: * ;
476
495
let ( value, msg, followed_by_block, left_pos, right_pos) = match e. node {
496
+ Let ( ref pats, ..) => {
497
+ for p in pats {
498
+ self . check_unused_parens_pat ( cx, p, false , false ) ;
499
+ }
500
+ return ;
501
+ }
502
+
477
503
If ( ref cond, ref block, ..) => {
478
504
let left = e. span . lo ( ) + syntax_pos:: BytePos ( 2 ) ;
479
505
let right = block. span . lo ( ) ;
@@ -486,7 +512,8 @@ impl EarlyLintPass for UnusedParens {
486
512
( cond, "`while` condition" , true , Some ( left) , Some ( right) )
487
513
} ,
488
514
489
- ForLoop ( _, ref cond, ref block, ..) => {
515
+ ForLoop ( ref pat, ref cond, ref block, ..) => {
516
+ self . check_unused_parens_pat ( cx, pat, false , false ) ;
490
517
( cond, "`for` head expression" , true , None , Some ( block. span . lo ( ) ) )
491
518
}
492
519
@@ -531,26 +558,46 @@ impl EarlyLintPass for UnusedParens {
531
558
}
532
559
533
560
fn check_pat ( & mut self , cx : & EarlyContext < ' _ > , p : & ast:: Pat ) {
534
- use ast:: PatKind :: { Paren , Range } ;
535
- // The lint visitor will visit each subpattern of `p`. We do not want to lint any range
536
- // pattern no matter where it occurs in the pattern. For something like `&(a..=b)`, there
537
- // is a recursive `check_pat` on `a` and `b`, but we will assume that if there are
538
- // unnecessary parens they serve a purpose of readability.
539
- if let Paren ( ref pat) = p. node {
540
- match pat. node {
541
- Range ( ..) => { }
542
- _ => self . check_unused_parens_pat ( cx, & p, "pattern" )
543
- }
561
+ use ast:: { PatKind :: * , Mutability } ;
562
+ match & p. node {
563
+ // Do not lint on `(..)` as that will result in the other arms being useless.
564
+ Paren ( _)
565
+ // The other cases do not contain sub-patterns.
566
+ | Wild | Rest | Lit ( ..) | Mac ( ..) | Range ( ..) | Ident ( .., None ) | Path ( ..) => return ,
567
+ // These are list-like patterns; parens can always be removed.
568
+ TupleStruct ( _, ps) | Tuple ( ps) | Slice ( ps) | Or ( ps) => for p in ps {
569
+ self . check_unused_parens_pat ( cx, p, false , false ) ;
570
+ } ,
571
+ Struct ( _, fps, _) => for f in fps {
572
+ self . check_unused_parens_pat ( cx, & f. pat , false , false ) ;
573
+ } ,
574
+ // Avoid linting on `i @ (p0 | .. | pn)` and `box (p0 | .. | pn)`, #64106.
575
+ Ident ( .., Some ( p) ) | Box ( p) => self . check_unused_parens_pat ( cx, p, true , false ) ,
576
+ // Avoid linting on `&(mut x)` as `&mut x` has a different meaning, #55342.
577
+ // Also avoid linting on `& mut? (p0 | .. | pn)`, #64106.
578
+ Ref ( p, m) => self . check_unused_parens_pat ( cx, p, true , * m == Mutability :: Immutable ) ,
544
579
}
545
580
}
546
581
547
582
fn check_stmt ( & mut self , cx : & EarlyContext < ' _ > , s : & ast:: Stmt ) {
548
583
if let ast:: StmtKind :: Local ( ref local) = s. node {
584
+ self . check_unused_parens_pat ( cx, & local. pat , false , false ) ;
585
+
549
586
if let Some ( ref value) = local. init {
550
587
self . check_unused_parens_expr ( cx, & value, "assigned value" , false , None , None ) ;
551
588
}
552
589
}
553
590
}
591
+
592
+ fn check_param ( & mut self , cx : & EarlyContext < ' _ > , param : & ast:: Param ) {
593
+ self . check_unused_parens_pat ( cx, & param. pat , true , false ) ;
594
+ }
595
+
596
+ fn check_arm ( & mut self , cx : & EarlyContext < ' _ > , arm : & ast:: Arm ) {
597
+ for p in & arm. pats {
598
+ self . check_unused_parens_pat ( cx, p, false , false ) ;
599
+ }
600
+ }
554
601
}
555
602
556
603
declare_lint ! {
0 commit comments