@@ -5,9 +5,9 @@ use syntax::source_map::{self, BytePos, Pos, SourceMap, Span};
55use syntax:: { ast, visit} ;
66
77use crate :: attr:: * ;
8- use crate :: comment:: { CodeCharKind , CommentCodeSlices } ;
9- use crate :: config:: file_lines:: LineRange ;
8+ use crate :: comment:: { rewrite_comment, CodeCharKind , CommentCodeSlices } ;
109use crate :: config:: { BraceStyle , Config } ;
10+ use crate :: coverage:: transform_missing_snippet;
1111use crate :: items:: {
1212 format_impl, format_trait, format_trait_alias, is_mod_decl, is_use_item,
1313 rewrite_associated_impl_type, rewrite_associated_type, rewrite_existential_impl_type,
@@ -22,8 +22,8 @@ use crate::source_map::{LineRangeUtils, SpanUtils};
2222use crate :: spanned:: Spanned ;
2323use crate :: stmt:: Stmt ;
2424use crate :: utils:: {
25- self , contains_skip, count_newlines, depr_skip_annotation, inner_attributes, mk_sp ,
26- ptr_vec_to_ref_vec, rewrite_ident, stmt_expr,
25+ self , contains_skip, count_newlines, depr_skip_annotation, inner_attributes, last_line_width ,
26+ mk_sp , ptr_vec_to_ref_vec, rewrite_ident, stmt_expr,
2727} ;
2828use crate :: { ErrorKind , FormatReport , FormattingError } ;
2929
@@ -165,32 +165,6 @@ impl<'b, 'a: 'b> FmtVisitor<'a> {
165165 }
166166 }
167167
168- /// Returns the total length of the spaces which should be trimmed between the last statement
169- /// and the closing brace of the block.
170- fn trimmed_spaces_width_before_closing_brace (
171- & mut self ,
172- b : & ast:: Block ,
173- brace_compensation : BytePos ,
174- ) -> usize {
175- match b. stmts . last ( ) {
176- None => 0 ,
177- Some ( ..) => {
178- let span_after_last_stmt = self . next_span ( b. span . hi ( ) - brace_compensation) ;
179- let missing_snippet = self . snippet ( span_after_last_stmt) ;
180- CommentCodeSlices :: new ( missing_snippet)
181- . last ( )
182- . and_then ( |( kind, _, s) | {
183- if kind == CodeCharKind :: Normal && s. trim ( ) . is_empty ( ) {
184- Some ( s. len ( ) )
185- } else {
186- None
187- }
188- } )
189- . unwrap_or ( 0 )
190- }
191- }
192- }
193-
194168 pub ( crate ) fn visit_block (
195169 & mut self ,
196170 b : & ast:: Block ,
@@ -226,72 +200,99 @@ impl<'b, 'a: 'b> FmtVisitor<'a> {
226200 }
227201 }
228202
229- let missing_span = self . next_span ( b. span . hi ( ) ) ;
230- if out_of_file_lines_range ! ( self , missing_span) {
231- self . push_str ( self . snippet ( missing_span) ) ;
232- self . block_indent = self . block_indent . block_unindent ( self . config ) ;
233- self . last_pos = source ! ( self , b. span) . hi ( ) ;
234- return ;
235- }
236-
237- let remove_len = BytePos :: from_usize (
238- self . trimmed_spaces_width_before_closing_brace ( b, brace_compensation) ,
239- ) ;
240- let unindent_comment = self . is_if_else_block && !b. stmts . is_empty ( ) && {
241- let end_pos = source ! ( self , b. span) . hi ( ) - brace_compensation - remove_len;
242- let snippet = self . snippet ( mk_sp ( self . last_pos , end_pos) ) ;
243- snippet. contains ( "//" ) || snippet. contains ( "/*" )
244- } ;
245- if unindent_comment {
203+ let rest_span = self . next_span ( b. span . hi ( ) ) ;
204+ if out_of_file_lines_range ! ( self , rest_span) {
205+ self . push_str ( self . snippet ( rest_span) ) ;
246206 self . block_indent = self . block_indent . block_unindent ( self . config ) ;
207+ } else {
208+ // Ignore the closing brace.
209+ let missing_span = self . next_span ( b. span . hi ( ) - brace_compensation) ;
210+ self . close_block ( missing_span, self . unindent_comment_on_closing_brace ( b) ) ;
247211 }
248- self . format_missing_with_indent (
249- source ! ( self , b. span) . hi ( ) - brace_compensation - remove_len,
250- ) ;
251- if unindent_comment {
252- self . block_indent = self . block_indent . block_indent ( self . config ) ;
253- }
254- self . close_block ( unindent_comment, self . next_span ( b. span . hi ( ) ) ) ;
255212 self . last_pos = source ! ( self , b. span) . hi ( ) ;
256213 }
257214
258- // FIXME: this is a terrible hack to indent the comments between the last
259- // item in the block and the closing brace to the block's level.
260- // The closing brace itself, however, should be indented at a shallower
261- // level.
262- fn close_block ( & mut self , unindent_comment : bool , span : Span ) {
263- let skip_this_line = !self
264- . config
265- . file_lines ( )
266- . contains ( & LineRange :: from_span ( self . source_map , span) ) ;
267- if skip_this_line {
268- self . push_str ( self . snippet ( span) ) ;
269- } else {
270- let total_len = self . buffer . len ( ) ;
271- let chars_too_many = if unindent_comment {
272- 0
273- } else if self . config . hard_tabs ( ) {
274- 1
275- } else {
276- self . config . tab_spaces ( )
277- } ;
215+ fn close_block ( & mut self , span : Span , unindent_comment : bool ) {
216+ let config = self . config ;
278217
279- // FIXME this is a temporaly fix
280- // should be remove truncate logic in close_block
281- // avoid not to truncate necessary chars
282- let truncate_start = total_len - chars_too_many;
283- let target_str = & self . buffer [ truncate_start..total_len] ;
284- let truncate_length = target_str. len ( ) - target_str. trim ( ) . len ( ) ;
285-
286- if let Some ( last_char) = target_str. chars ( ) . last ( ) {
287- self . buffer . truncate ( total_len - truncate_length) ;
288- if last_char == '\n' {
289- self . buffer . push_str ( "\n " ) ;
218+ let mut last_hi = span. lo ( ) ;
219+ let mut unindented = false ;
220+ let mut prev_ends_with_newline = false ;
221+ let mut extra_newline = false ;
222+
223+ let skip_normal = |s : & str | {
224+ let trimmed = s. trim ( ) ;
225+ trimmed. is_empty ( ) || trimmed. chars ( ) . all ( |c| c == ';' )
226+ } ;
227+
228+ for ( kind, offset, sub_slice) in CommentCodeSlices :: new ( self . snippet ( span) ) {
229+ let sub_slice = transform_missing_snippet ( config, sub_slice) ;
230+
231+ debug ! ( "close_block: {:?} {:?} {:?}" , kind, offset, sub_slice) ;
232+
233+ match kind {
234+ CodeCharKind :: Comment => {
235+ if !unindented && unindent_comment {
236+ unindented = true ;
237+ self . block_indent = self . block_indent . block_unindent ( config) ;
238+ }
239+ let span_in_between = mk_sp ( last_hi, span. lo ( ) + BytePos :: from_usize ( offset) ) ;
240+ let snippet_in_between = self . snippet ( span_in_between) ;
241+ let mut comment_on_same_line = !snippet_in_between. contains ( "\n " ) ;
242+
243+ let mut comment_shape =
244+ Shape :: indented ( self . block_indent , config) . comment ( config) ;
245+ if comment_on_same_line {
246+ // 1 = a space before `//`
247+ let offset_len = 1 + last_line_width ( & self . buffer )
248+ . saturating_sub ( self . block_indent . width ( ) ) ;
249+ match comment_shape
250+ . visual_indent ( offset_len)
251+ . sub_width ( offset_len)
252+ {
253+ Some ( shp) => comment_shape = shp,
254+ None => comment_on_same_line = false ,
255+ }
256+ } ;
257+
258+ if comment_on_same_line {
259+ self . push_str ( " " ) ;
260+ } else {
261+ if count_newlines ( snippet_in_between) >= 2 || extra_newline {
262+ self . push_str ( "\n " ) ;
263+ }
264+ self . push_str ( & self . block_indent . to_string_with_newline ( config) ) ;
265+ }
266+
267+ let comment_str = rewrite_comment ( & sub_slice, false , comment_shape, config) ;
268+ match comment_str {
269+ Some ( ref s) => self . push_str ( s) ,
270+ None => self . push_str ( & sub_slice) ,
271+ }
272+ }
273+ CodeCharKind :: Normal if skip_normal ( & sub_slice) => {
274+ extra_newline = prev_ends_with_newline && sub_slice. contains ( '\n' ) ;
275+ continue ;
276+ }
277+ CodeCharKind :: Normal => {
278+ self . push_str ( & self . block_indent . to_string_with_newline ( config) ) ;
279+ self . push_str ( sub_slice. trim ( ) ) ;
290280 }
291281 }
292- self . push_str ( "}" ) ;
282+ prev_ends_with_newline = sub_slice. ends_with ( '\n' ) ;
283+ extra_newline = false ;
284+ last_hi = span. lo ( ) + BytePos :: from_usize ( offset + sub_slice. len ( ) ) ;
285+ }
286+ if unindented {
287+ self . block_indent = self . block_indent . block_indent ( self . config ) ;
293288 }
294289 self . block_indent = self . block_indent . block_unindent ( self . config ) ;
290+ self . push_str ( & self . block_indent . to_string_with_newline ( config) ) ;
291+ self . push_str ( "}" ) ;
292+ }
293+
294+ fn unindent_comment_on_closing_brace ( & self , b : & ast:: Block ) -> bool {
295+ self . is_if_else_block && !b. stmts . is_empty ( )
295296 }
296297
297298 // Note that this only gets called for function definitions. Required methods
@@ -806,9 +807,8 @@ impl<'b, 'a: 'b> FmtVisitor<'a> {
806807 self . block_indent = self . block_indent . block_indent ( self . config ) ;
807808 self . visit_attrs ( attrs, ast:: AttrStyle :: Inner ) ;
808809 self . walk_mod_items ( m) ;
809- let missing_span = mk_sp ( source ! ( self , m. inner) . hi ( ) - BytePos ( 1 ) , m. inner . hi ( ) ) ;
810- self . format_missing_with_indent ( missing_span. lo ( ) ) ;
811- self . close_block ( false , missing_span) ;
810+ let missing_span = self . next_span ( m. inner . hi ( ) - BytePos ( 1 ) ) ;
811+ self . close_block ( missing_span, false ) ;
812812 }
813813 self . last_pos = source ! ( self , m. inner) . hi ( ) ;
814814 } else {
0 commit comments