@@ -656,6 +656,25 @@ trait UnusedDelimLint {
656656 is_kw : bool ,
657657 ) ;
658658
659+ #[ inline]
660+ fn impacts_followed_by_block ( e : & ast:: Expr ) -> bool {
661+ return match e. kind {
662+ ExprKind :: Block ( ..) | ExprKind :: Call ( ..) | ExprKind :: MethodCall ( ..) => true ,
663+ _ => Self :: is_followed_by_block ( e) ,
664+ } ;
665+ }
666+
667+ #[ inline]
668+ fn is_followed_by_block ( e : & ast:: Expr ) -> bool {
669+ return match e. kind {
670+ ExprKind :: If ( ref cond, ..) if !matches ! ( cond. kind, ExprKind :: Let ( ..) ) => true ,
671+ ExprKind :: While ( ref cond, ..) if !matches ! ( cond. kind, ExprKind :: Let ( ..) ) => true ,
672+ ExprKind :: ForLoop { .. } => true ,
673+ ExprKind :: Match ( _, _, ast:: MatchKind :: Prefix ) => true ,
674+ _ => false ,
675+ } ;
676+ }
677+
659678 fn is_expr_delims_necessary (
660679 inner : & ast:: Expr ,
661680 ctx : UnusedDelimsCtx ,
@@ -1475,7 +1494,15 @@ declare_lint! {
14751494 "unnecessary braces around an expression"
14761495}
14771496
1478- declare_lint_pass ! ( UnusedBraces => [ UNUSED_BRACES ] ) ;
1497+ #[ derive( Default ) ]
1498+ pub ( crate ) struct UnusedBraces {
1499+ // Used for tracking parent expressions that would immediately followed
1500+ // by block. Storing false here indicates that expression itself is Block
1501+ // expression. This is meant for to prevent report false positive cases.
1502+ followed_by_block : Vec < bool > ,
1503+ }
1504+
1505+ impl_lint_pass ! ( UnusedBraces => [ UNUSED_BRACES ] ) ;
14791506
14801507impl UnusedDelimLint for UnusedBraces {
14811508 const DELIM_STR : & ' static str = "braces" ;
@@ -1505,6 +1532,11 @@ impl UnusedDelimLint for UnusedBraces {
15051532 // - the block does not have a label
15061533 // - the block is not `unsafe`
15071534 // - the block contains exactly one expression (do not lint `{ expr; }`)
1535+ // - however, this does not lint if block is immediately followed by parent
1536+ // expression's block, e.g. `if` and `match`, which may cause false positive.
1537+ // ```
1538+ // if return { return } {} else {}
1539+ // ```
15081540 // - `followed_by_block` is true and the internal expr may contain a `{`
15091541 // - the block is not multiline (do not lint multiline match arms)
15101542 // ```
@@ -1524,9 +1556,18 @@ impl UnusedDelimLint for UnusedBraces {
15241556 // let _: A<{produces_literal!()}>;
15251557 // ```
15261558 // FIXME(const_generics): handle paths when #67075 is fixed.
1559+ // if ctx == UnusedDelimsCtx::FunctionArg {
1560+ // println!("{:?}", self.followed_by_block.last().copied().unwrap_or(false))
1561+ // }
15271562 if let [ stmt] = inner. stmts . as_slice ( )
15281563 && let ast:: StmtKind :: Expr ( ref expr) = stmt. kind
15291564 && !Self :: is_expr_delims_necessary ( expr, ctx, followed_by_block)
1565+ && ( ( ctx == UnusedDelimsCtx :: FunctionArg || ctx == UnusedDelimsCtx :: MethodArg )
1566+ || !Self :: is_expr_delims_necessary (
1567+ expr,
1568+ ctx,
1569+ self . followed_by_block . last ( ) . copied ( ) . unwrap_or ( false ) ,
1570+ ) )
15301571 && ( ctx != UnusedDelimsCtx :: AnonConst
15311572 || ( matches ! ( expr. kind, ast:: ExprKind :: Lit ( _) )
15321573 && !expr. span . from_expansion ( ) ) )
@@ -1564,6 +1605,10 @@ impl EarlyLintPass for UnusedBraces {
15641605 fn check_expr ( & mut self , cx : & EarlyContext < ' _ > , e : & ast:: Expr ) {
15651606 <Self as UnusedDelimLint >:: check_expr ( self , cx, e) ;
15661607
1608+ if <Self as UnusedDelimLint >:: impacts_followed_by_block ( e) {
1609+ self . followed_by_block . push ( <Self as UnusedDelimLint >:: is_followed_by_block ( e) ) ;
1610+ }
1611+
15671612 if let ExprKind :: Repeat ( _, ref anon_const) = e. kind {
15681613 self . check_unused_delims_expr (
15691614 cx,
@@ -1577,6 +1622,18 @@ impl EarlyLintPass for UnusedBraces {
15771622 }
15781623 }
15791624
1625+ fn check_expr_post ( & mut self , _cx : & EarlyContext < ' _ > , e : & ast:: Expr ) {
1626+ if <Self as UnusedDelimLint >:: impacts_followed_by_block ( e) {
1627+ let followed_by_block =
1628+ self . followed_by_block . pop ( ) . expect ( "check_expr and check_expr_post must balance" ) ;
1629+ assert_eq ! (
1630+ followed_by_block,
1631+ Self :: is_followed_by_block( e) ,
1632+ "check_expr, check_ty, and check_expr_post are called, in that order, by the visitor"
1633+ ) ;
1634+ }
1635+ }
1636+
15801637 fn check_generic_arg ( & mut self , cx : & EarlyContext < ' _ > , arg : & ast:: GenericArg ) {
15811638 if let ast:: GenericArg :: Const ( ct) = arg {
15821639 self . check_unused_delims_expr (
0 commit comments