@@ -112,7 +112,7 @@ impl<'b, 'a: 'b> FmtVisitor<'a> {
112112 mk_sp ( self . last_pos , hi)
113113 }
114114
115- fn visit_stmt ( & mut self , stmt : & Stmt < ' _ > ) {
115+ fn visit_stmt ( & mut self , stmt : & Stmt < ' _ > , include_empty_semi : bool ) {
116116 debug ! (
117117 "visit_stmt: {}" ,
118118 self . parse_sess. span_to_debug_info( stmt. span( ) )
@@ -127,22 +127,31 @@ impl<'b, 'a: 'b> FmtVisitor<'a> {
127127 . map_or ( false , |i| starts_with_newline ( & snippet[ i..] ) ) ;
128128 let snippet = snippet. trim ( ) ;
129129 if !snippet. is_empty ( ) {
130- if original_starts_with_newline {
131- self . push_str ( "\n " ) ;
130+ // FIXME(calebcartwright 2021-01-03) - This exists strictly to maintain legacy
131+ // formatting where rustfmt would preserve redundant semicolons on Items in a
132+ // statement position.
133+ // See comment within `walk_stmts` for more info
134+ if include_empty_semi {
135+ self . format_missing ( stmt. span ( ) . hi ( ) ) ;
136+ } else {
137+ if original_starts_with_newline {
138+ self . push_str ( "\n " ) ;
139+ }
140+
141+ self . push_str ( & self . block_indent . to_string ( self . config ) ) ;
142+ self . push_str ( snippet) ;
132143 }
133- self . push_str ( & self . block_indent . to_string ( self . config ) ) ;
134- self . push_str ( snippet ) ;
144+ } else if include_empty_semi {
145+ self . push_str ( ";" ) ;
135146 }
136-
137147 self . last_pos = stmt. span ( ) . hi ( ) ;
138148 return ;
139149 }
140150
141151 match stmt. as_ast_node ( ) . kind {
142152 ast:: StmtKind :: Item ( ref item) => {
143153 self . visit_item ( item) ;
144- // Handle potential `;` after the item.
145- self . format_missing ( stmt. span ( ) . hi ( ) ) ;
154+ self . last_pos = stmt. span ( ) . hi ( ) ;
146155 }
147156 ast:: StmtKind :: Local ( ..) | ast:: StmtKind :: Expr ( ..) | ast:: StmtKind :: Semi ( ..) => {
148157 let attrs = get_attrs_from_stmt ( stmt. as_ast_node ( ) ) ;
@@ -899,7 +908,7 @@ impl<'b, 'a: 'b> FmtVisitor<'a> {
899908 self . visit_items_with_reordering ( & ptr_vec_to_ref_vec ( & m. items ) ) ;
900909 }
901910
902- fn walk_stmts ( & mut self , stmts : & [ Stmt < ' _ > ] ) {
911+ fn walk_stmts ( & mut self , stmts : & [ Stmt < ' _ > ] , include_current_empty_semi : bool ) {
903912 if stmts. is_empty ( ) {
904913 return ;
905914 }
@@ -912,16 +921,38 @@ impl<'b, 'a: 'b> FmtVisitor<'a> {
912921 . collect ( ) ;
913922
914923 if items. is_empty ( ) {
915- self . visit_stmt ( & stmts[ 0 ] ) ;
916- self . walk_stmts ( & stmts[ 1 ..] ) ;
924+ self . visit_stmt ( & stmts[ 0 ] , include_current_empty_semi) ;
925+
926+ // FIXME(calebcartwright 2021-01-03) - This exists strictly to maintain legacy
927+ // formatting where rustfmt would preserve redundant semicolons on Items in a
928+ // statement position.
929+ //
930+ // Starting in rustc-ap-* v692 (~2020-12-01) the rustc parser now parses this as
931+ // two separate statements (Item and Empty kinds), whereas before it was parsed as
932+ // a single statement with the statement's span including the redundant semicolon.
933+ //
934+ // rustfmt typically tosses unnecessary/redundant semicolons, and eventually we
935+ // should toss these as well, but doing so at this time would
936+ // break the Stability Guarantee
937+ // N.B. This could be updated to utilize the version gates.
938+ let include_next_empty = if stmts. len ( ) > 1 {
939+ match ( & stmts[ 0 ] . as_ast_node ( ) . kind , & stmts[ 1 ] . as_ast_node ( ) . kind ) {
940+ ( ast:: StmtKind :: Item ( _) , ast:: StmtKind :: Empty ) => true ,
941+ _ => false ,
942+ }
943+ } else {
944+ false
945+ } ;
946+
947+ self . walk_stmts ( & stmts[ 1 ..] , include_next_empty) ;
917948 } else {
918949 self . visit_items_with_reordering ( & items) ;
919- self . walk_stmts ( & stmts[ items. len ( ) ..] ) ;
950+ self . walk_stmts ( & stmts[ items. len ( ) ..] , false ) ;
920951 }
921952 }
922953
923954 fn walk_block_stmts ( & mut self , b : & ast:: Block ) {
924- self . walk_stmts ( & Stmt :: from_ast_nodes ( b. stmts . iter ( ) ) )
955+ self . walk_stmts ( & Stmt :: from_ast_nodes ( b. stmts . iter ( ) ) , false )
925956 }
926957
927958 fn format_mod (
0 commit comments