@@ -5,9 +5,9 @@ use syntax::source_map::{self, BytePos, Pos, SourceMap, Span};
5
5
use syntax:: { ast, visit} ;
6
6
7
7
use crate :: attr:: * ;
8
- use crate :: comment:: { CodeCharKind , CommentCodeSlices } ;
9
- use crate :: config:: file_lines:: LineRange ;
8
+ use crate :: comment:: { rewrite_comment, CodeCharKind , CommentCodeSlices } ;
10
9
use crate :: config:: { BraceStyle , Config } ;
10
+ use crate :: coverage:: transform_missing_snippet;
11
11
use crate :: items:: {
12
12
format_impl, format_trait, format_trait_alias, is_mod_decl, is_use_item,
13
13
rewrite_associated_impl_type, rewrite_associated_type, rewrite_existential_impl_type,
@@ -22,8 +22,8 @@ use crate::source_map::{LineRangeUtils, SpanUtils};
22
22
use crate :: spanned:: Spanned ;
23
23
use crate :: stmt:: Stmt ;
24
24
use 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,
27
27
} ;
28
28
use crate :: { ErrorKind , FormatReport , FormattingError } ;
29
29
@@ -165,32 +165,6 @@ impl<'b, 'a: 'b> FmtVisitor<'a> {
165
165
}
166
166
}
167
167
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
-
194
168
pub ( crate ) fn visit_block (
195
169
& mut self ,
196
170
b : & ast:: Block ,
@@ -226,72 +200,99 @@ impl<'b, 'a: 'b> FmtVisitor<'a> {
226
200
}
227
201
}
228
202
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) ) ;
246
206
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) ) ;
247
211
}
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 ( ) ) ) ;
255
212
self . last_pos = source ! ( self , b. span) . hi ( ) ;
256
213
}
257
214
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 ;
278
217
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 ( ) ) ;
290
280
}
291
281
}
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 ) ;
293
288
}
294
289
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 ( )
295
296
}
296
297
297
298
// Note that this only gets called for function definitions. Required methods
@@ -806,9 +807,8 @@ impl<'b, 'a: 'b> FmtVisitor<'a> {
806
807
self . block_indent = self . block_indent . block_indent ( self . config ) ;
807
808
self . visit_attrs ( attrs, ast:: AttrStyle :: Inner ) ;
808
809
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 ) ;
812
812
}
813
813
self . last_pos = source ! ( self , m. inner) . hi ( ) ;
814
814
} else {
0 commit comments