@@ -398,18 +398,37 @@ impl UnusedParens {
398398 }
399399 }
400400
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+
406425 let pattern_text = if let Ok ( snippet) = cx. sess ( ) . source_map ( )
407426 . span_to_snippet ( value. span ) {
408427 snippet
409428 } else {
410429 pprust:: pat_to_string ( value)
411430 } ;
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 ) ) ;
413432 }
414433 }
415434
@@ -474,6 +493,13 @@ impl EarlyLintPass for UnusedParens {
474493 fn check_expr ( & mut self , cx : & EarlyContext < ' _ > , e : & ast:: Expr ) {
475494 use syntax:: ast:: ExprKind :: * ;
476495 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+
477503 If ( ref cond, ref block, ..) => {
478504 let left = e. span . lo ( ) + syntax_pos:: BytePos ( 2 ) ;
479505 let right = block. span . lo ( ) ;
@@ -486,7 +512,8 @@ impl EarlyLintPass for UnusedParens {
486512 ( cond, "`while` condition" , true , Some ( left) , Some ( right) )
487513 } ,
488514
489- ForLoop ( _, ref cond, ref block, ..) => {
515+ ForLoop ( ref pat, ref cond, ref block, ..) => {
516+ self . check_unused_parens_pat ( cx, pat, false , false ) ;
490517 ( cond, "`for` head expression" , true , None , Some ( block. span . lo ( ) ) )
491518 }
492519
@@ -531,26 +558,46 @@ impl EarlyLintPass for UnusedParens {
531558 }
532559
533560 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 ) ,
544579 }
545580 }
546581
547582 fn check_stmt ( & mut self , cx : & EarlyContext < ' _ > , s : & ast:: Stmt ) {
548583 if let ast:: StmtKind :: Local ( ref local) = s. node {
584+ self . check_unused_parens_pat ( cx, & local. pat , false , false ) ;
585+
549586 if let Some ( ref value) = local. init {
550587 self . check_unused_parens_expr ( cx, & value, "assigned value" , false , None , None ) ;
551588 }
552589 }
553590 }
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+ }
554601}
555602
556603declare_lint ! {
0 commit comments