From b039e3a8c31a1357c13034c7d1fc00cd2686fc37 Mon Sep 17 00:00:00 2001
From: Marcus Klaas <mail@marcusklaas.nl>
Date: Wed, 14 Oct 2015 22:28:17 +0200
Subject: [PATCH] Force semicolons after break/continue/return. Remove after
 blocks.

---
 src/expr.rs           |  2 +-
 src/visitor.rs        | 45 ++++++++++++++++++++++++++++++++++++-------
 tests/source/expr.rs  |  8 +++++++-
 tests/target/expr.rs  |  8 +++++++-
 tests/target/match.rs |  2 +-
 5 files changed, 54 insertions(+), 11 deletions(-)

diff --git a/src/expr.rs b/src/expr.rs
index 6be572f847b..7d2ce3ea3af 100644
--- a/src/expr.rs
+++ b/src/expr.rs
@@ -1322,7 +1322,7 @@ fn rewrite_struct_lit<'a>(context: &RewriteContext,
 
         if prelim_tactic == ListTactic::HorizontalVertical && fields.len() > 1 {
             prelim_tactic = ListTactic::LimitedHorizontalVertical(context.config.struct_lit_width);
-        };
+        }
 
         definitive_tactic(&item_vec, prelim_tactic, h_budget)
     };
diff --git a/src/visitor.rs b/src/visitor.rs
index 4827f68dafa..5f287ab5ee9 100644
--- a/src/visitor.rs
+++ b/src/visitor.rs
@@ -59,13 +59,11 @@ impl<'a, 'v> visit::Visitor<'v> for FmtVisitor<'a> {
             }
             ast::Stmt_::StmtExpr(ref ex, _) | ast::Stmt_::StmtSemi(ref ex, _) => {
                 self.format_missing_with_indent(stmt.span.lo);
-                let suffix = if let ast::Stmt_::StmtExpr(..) = stmt.node {
-                    ""
-                } else {
+                let suffix = if semicolon_for_stmt(stmt) {
                     ";"
+                } else {
+                    ""
                 };
-
-                // 1 = trailing semicolon;
                 let rewrite = ex.rewrite(&self.get_context(),
                                          self.config.max_width - self.block_indent.width() -
                                          suffix.len(),
@@ -110,6 +108,10 @@ impl<'a, 'v> visit::Visitor<'v> for FmtVisitor<'a> {
             Some(ref e) => {
                 self.format_missing_with_indent(e.span.lo);
                 self.visit_expr(e);
+
+                if semicolon_for_expr(e) {
+                    self.buffer.push_str(";");
+                }
             }
             None => {}
         }
@@ -215,7 +217,7 @@ impl<'a, 'v> visit::Visitor<'v> for FmtVisitor<'a> {
             }
             ast::Item_::ItemMac(..) => {
                 self.format_missing_with_indent(item.span.lo);
-                // TODO: we cannot format these yet, because of a bad span.
+                // FIXME: we cannot format these yet, because of a bad span.
                 // See rust lang issue #28424.
                 // visit::walk_item(self, item);
             }
@@ -245,7 +247,7 @@ impl<'a, 'v> visit::Visitor<'v> for FmtVisitor<'a> {
                 self.last_pos = ti.span.hi;
             }
         }
-        // TODO: format trait types.
+        // TODO(#78): format trait types.
 
         visit::walk_trait_item(self, ti)
     }
@@ -399,6 +401,35 @@ impl<'a> FmtVisitor<'a> {
     }
 }
 
+fn semicolon_for_stmt(stmt: &ast::Stmt) -> bool {
+    match stmt.node {
+        ast::Stmt_::StmtSemi(ref expr, _) => {
+            match expr.node {
+                ast::Expr_::ExprWhile(..) |
+                ast::Expr_::ExprWhileLet(..) |
+                ast::Expr_::ExprIf(..) |
+                ast::Expr_::ExprIfLet(..) |
+                ast::Expr_::ExprBlock(..) |
+                ast::Expr_::ExprLoop(..) |
+                ast::Expr_::ExprForLoop(..) |
+                ast::Expr_::ExprMatch(..) => false,
+                _ => true,
+            }
+        }
+        ast::Stmt_::StmtExpr(..) => false,
+        _ => true,
+    }
+}
+
+fn semicolon_for_expr(expr: &ast::Expr) -> bool {
+    match expr.node {
+        ast::Expr_::ExprRet(..) |
+        ast::Expr_::ExprAgain(..) |
+        ast::Expr_::ExprBreak(..) => true,
+        _ => false,
+    }
+}
+
 impl<'a> Rewrite for [ast::Attribute] {
     fn rewrite(&self, context: &RewriteContext, _: usize, offset: Indent) -> Option<String> {
         let mut result = String::new();
diff --git a/tests/source/expr.rs b/tests/source/expr.rs
index 689b2b22c32..b5a22479058 100644
--- a/tests/source/expr.rs
+++ b/tests/source/expr.rs
@@ -70,7 +70,7 @@ fn bar() {
     let bar = 5 ;
     let nonsense = (10 .. 0)..(0..10);
 
-    loop{if true {break;}}
+    loop{if true {break}}
 
     let x = (aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa &&
              aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa,
@@ -226,3 +226,9 @@ fn repeats() {
     let x = [aaaaaaaaaaaaaaaaaaaaaaaaaaaa+bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb+cccccccccccccccc; x + y + z ];
     let y = [aaaaaaaaaaaaaaaaaaaaaaaaaaaa + bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb + cccccccccccccccc; xxxxx + yyyyy + zzzzz ];
 }
+
+fn blocks() {
+    if 1 + 1 == 2 {
+        println!("yay arithmetix!");
+    };
+}
diff --git a/tests/target/expr.rs b/tests/target/expr.rs
index 4c12e6642cb..ed842289439 100644
--- a/tests/target/expr.rs
+++ b/tests/target/expr.rs
@@ -40,7 +40,7 @@ fn foo() -> bool {
         result
     } else {
         4
-    };
+    }
 
     if let Some(x) = aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa {
         // Nothing
@@ -248,3 +248,9 @@ fn repeats() {
     let y = [aaaaaaaaaaaaaaaaaaaaaaaaaaaa + bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb +
              cccccccccccccccc; xxxxx + yyyyy + zzzzz];
 }
+
+fn blocks() {
+    if 1 + 1 == 2 {
+        println!("yay arithmetix!");
+    }
+}
diff --git a/tests/target/match.rs b/tests/target/match.rs
index e6b0b4099d3..e758cdd6f71 100644
--- a/tests/target/match.rs
+++ b/tests/target/match.rs
@@ -215,5 +215,5 @@ fn issue383() {
     match resolution.last_private {
         LastImport{..} => false,
         _ => true,
-    };
+    }
 }