Skip to content
This repository was archived by the owner on May 28, 2025. It is now read-only.

Commit c0e616b

Browse files
authored
Implement closing-block procedure without relying on missed_span module (rust-lang#3691)
1 parent 76e2ba2 commit c0e616b

File tree

17 files changed

+115
-135
lines changed

17 files changed

+115
-135
lines changed

src/config/file_lines.rs

Lines changed: 1 addition & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ use std::{cmp, fmt, iter, str};
99
use serde::{ser, Deserialize, Deserializer, Serialize, Serializer};
1010
use serde_json as json;
1111

12-
use syntax::source_map::{self, SourceFile, SourceMap, Span};
12+
use syntax::source_map::{self, SourceFile};
1313

1414
/// A range of lines in a file, inclusive of both ends.
1515
pub struct LineRange {
@@ -78,17 +78,6 @@ impl LineRange {
7878
pub fn file_name(&self) -> FileName {
7979
self.file.name.clone().into()
8080
}
81-
82-
pub(crate) fn from_span(source_map: &SourceMap, span: Span) -> LineRange {
83-
let lo_char_pos = source_map.lookup_char_pos(span.lo());
84-
let hi_char_pos = source_map.lookup_char_pos(span.hi());
85-
debug_assert!(lo_char_pos.file.name == hi_char_pos.file.name);
86-
LineRange {
87-
file: lo_char_pos.file.clone(),
88-
lo: lo_char_pos.line,
89-
hi: hi_char_pos.line,
90-
}
91-
}
9281
}
9382

9483
/// A range that is inclusive of both ends.

src/coverage.rs

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
use crate::{Config, EmitMode};
2+
use std::borrow::Cow;
3+
4+
pub(crate) fn transform_missing_snippet<'a>(config: &Config, string: &'a str) -> Cow<'a, str> {
5+
match config.emit_mode() {
6+
EmitMode::Coverage => Cow::from(replace_chars(string)),
7+
_ => Cow::from(string),
8+
}
9+
}
10+
11+
fn replace_chars(s: &str) -> String {
12+
s.chars()
13+
.map(|ch| if ch.is_whitespace() { ch } else { 'X' })
14+
.collect()
15+
}

src/format-diff/main.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -292,5 +292,4 @@ mod cmd_line_tests {
292292
.is_err()
293293
);
294294
}
295-
296295
}

src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ mod chains;
4949
mod closures;
5050
mod comment;
5151
pub(crate) mod config;
52+
mod coverage;
5253
mod emitter;
5354
mod expr;
5455
mod format_report_formatter;

src/missed_spans.rs

Lines changed: 3 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,9 @@
1-
use std::borrow::Cow;
2-
31
use syntax::source_map::{BytePos, Pos, Span};
42

53
use crate::comment::{is_last_comment_block, rewrite_comment, CodeCharKind, CommentCodeSlices};
64
use crate::config::file_lines::FileLines;
7-
use crate::config::{EmitMode, FileName};
5+
use crate::config::FileName;
6+
use crate::coverage::transform_missing_snippet;
87
use crate::shape::{Indent, Shape};
98
use crate::source_map::LineRangeUtils;
109
use crate::utils::{count_lf_crlf, count_newlines, last_line_width, mk_sp};
@@ -171,10 +170,7 @@ impl<'a> FmtVisitor<'a> {
171170
let file_name = &char_pos.file.name.clone().into();
172171
let mut status = SnippetStatus::new(char_pos.line);
173172

174-
let snippet = &*match self.config.emit_mode() {
175-
EmitMode::Coverage => Cow::from(replace_chars(old_snippet)),
176-
_ => Cow::from(old_snippet),
177-
};
173+
let snippet = &*transform_missing_snippet(self.config, old_snippet);
178174

179175
let slice_within_file_lines_range =
180176
|file_lines: FileLines, cur_line, s| -> (usize, usize, bool) {
@@ -333,10 +329,3 @@ impl<'a> FmtVisitor<'a> {
333329
}
334330
}
335331
}
336-
337-
fn replace_chars(string: &str) -> String {
338-
string
339-
.chars()
340-
.map(|ch| if ch.is_whitespace() { ch } else { 'X' })
341-
.collect()
342-
}

src/visitor.rs

Lines changed: 89 additions & 89 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,9 @@ use syntax::source_map::{self, BytePos, Pos, SourceMap, Span};
55
use syntax::{ast, visit};
66

77
use crate::attr::*;
8-
use crate::comment::{CodeCharKind, CommentCodeSlices};
9-
use crate::config::file_lines::LineRange;
8+
use crate::comment::{rewrite_comment, CodeCharKind, CommentCodeSlices};
109
use crate::config::{BraceStyle, Config};
10+
use crate::coverage::transform_missing_snippet;
1111
use 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};
2222
use crate::spanned::Spanned;
2323
use crate::stmt::Stmt;
2424
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,
2727
};
2828
use 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 {

tests/source/configs/empty_item_single_line/false.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,5 +13,4 @@ fn lorem() {
1313
}
1414

1515
fn lorem() {
16-
1716
}

tests/source/configs/empty_item_single_line/true.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,5 +13,4 @@ fn lorem() {
1313
}
1414

1515
fn lorem() {
16-
1716
}

tests/source/issue-977.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
// rustfmt-normalize_comments: true
2-
// FIXME(#919)
32

43
trait NameC { /* comment */ }
54
struct FooC { /* comment */ }

tests/target/assignment.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ fn main() {
1717
single_lit_fit >>= 10;
1818

1919
// #2791
20-
let x = 2;;;;
20+
let x = 2;
2121
}
2222

2323
fn break_meee() {

tests/target/comment.rs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -59,8 +59,7 @@ fn issue_1086() {
5959

6060
// random comment
6161

62-
fn main() {
63-
// Test
62+
fn main() { // Test
6463
}
6564

6665
// #1643

tests/target/comments-fn.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@ where
1515
F: Foo, // COmment after where-clause
1616
G: Goo, // final comment
1717
{
18-
1918
}
2019

2120
fn bar<F /* comment on F */, G /* comment on G */>() {}

tests/target/configs/empty_item_single_line/false.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,5 +11,4 @@ fn lorem() {
1111
}
1212

1313
fn lorem() {
14-
1514
}

tests/target/fn.rs

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,6 @@ fn foo(
2121
where
2222
T: Blah,
2323
{
24-
2524
}
2625

2726
fn foo<U, T>(
@@ -32,7 +31,6 @@ where
3231
T: Blah,
3332
U: dsfasdfasdfasd,
3433
{
35-
3634
}
3735

3836
fn foo<U: Fn(A) -> B /* paren inside generics */>() {}

tests/target/issue-977.rs

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
// rustfmt-normalize_comments: true
2-
// FIXME(#919)
32

43
trait NameC {
54
// comment
@@ -10,8 +9,7 @@ struct FooC {
109
enum MooC {
1110
// comment
1211
}
13-
mod BarC {
14-
// comment
12+
mod BarC { // comment
1513
}
1614
extern "C" {
1715
// comment

0 commit comments

Comments
 (0)