diff --git a/src/config/file_lines.rs b/src/config/file_lines.rs
index f58d3c16ac2..f0dc6c66597 100644
--- a/src/config/file_lines.rs
+++ b/src/config/file_lines.rs
@@ -9,7 +9,7 @@ use std::{cmp, fmt, iter, str};
use serde::{ser, Deserialize, Deserializer, Serialize, Serializer};
use serde_json as json;
-use syntax::source_map::{self, SourceFile, SourceMap, Span};
+use syntax::source_map::{self, SourceFile};
/// A range of lines in a file, inclusive of both ends.
pub struct LineRange {
@@ -78,17 +78,6 @@ impl LineRange {
pub fn file_name(&self) -> FileName {
self.file.name.clone().into()
}
-
- pub(crate) fn from_span(source_map: &SourceMap, span: Span) -> LineRange {
- let lo_char_pos = source_map.lookup_char_pos(span.lo());
- let hi_char_pos = source_map.lookup_char_pos(span.hi());
- debug_assert!(lo_char_pos.file.name == hi_char_pos.file.name);
- LineRange {
- file: lo_char_pos.file.clone(),
- lo: lo_char_pos.line,
- hi: hi_char_pos.line,
- }
- }
}
/// A range that is inclusive of both ends.
diff --git a/src/coverage.rs b/src/coverage.rs
new file mode 100644
index 00000000000..f5a04974251
--- /dev/null
+++ b/src/coverage.rs
@@ -0,0 +1,15 @@
+use crate::{Config, EmitMode};
+use std::borrow::Cow;
+
+pub(crate) fn transform_missing_snippet<'a>(config: &Config, string: &'a str) -> Cow<'a, str> {
+ match config.emit_mode() {
+ EmitMode::Coverage => Cow::from(replace_chars(string)),
+ _ => Cow::from(string),
+ }
+}
+
+fn replace_chars(s: &str) -> String {
+ s.chars()
+ .map(|ch| if ch.is_whitespace() { ch } else { 'X' })
+ .collect()
+}
diff --git a/src/format-diff/main.rs b/src/format-diff/main.rs
index 80815b5f1d9..5bfdcbd0420 100644
--- a/src/format-diff/main.rs
+++ b/src/format-diff/main.rs
@@ -292,5 +292,4 @@ mod cmd_line_tests {
.is_err()
);
}
-
}
diff --git a/src/lib.rs b/src/lib.rs
index a672e2cc8aa..e3e7f7f9244 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -49,6 +49,7 @@ mod chains;
mod closures;
mod comment;
pub(crate) mod config;
+mod coverage;
mod emitter;
mod expr;
mod format_report_formatter;
diff --git a/src/missed_spans.rs b/src/missed_spans.rs
index 8ac05457ec9..7bc81fdc844 100644
--- a/src/missed_spans.rs
+++ b/src/missed_spans.rs
@@ -1,10 +1,9 @@
-use std::borrow::Cow;
-
use syntax::source_map::{BytePos, Pos, Span};
use crate::comment::{is_last_comment_block, rewrite_comment, CodeCharKind, CommentCodeSlices};
use crate::config::file_lines::FileLines;
-use crate::config::{EmitMode, FileName};
+use crate::config::FileName;
+use crate::coverage::transform_missing_snippet;
use crate::shape::{Indent, Shape};
use crate::source_map::LineRangeUtils;
use crate::utils::{count_lf_crlf, count_newlines, last_line_width, mk_sp};
@@ -171,10 +170,7 @@ impl<'a> FmtVisitor<'a> {
let file_name = &char_pos.file.name.clone().into();
let mut status = SnippetStatus::new(char_pos.line);
- let snippet = &*match self.config.emit_mode() {
- EmitMode::Coverage => Cow::from(replace_chars(old_snippet)),
- _ => Cow::from(old_snippet),
- };
+ let snippet = &*transform_missing_snippet(self.config, old_snippet);
let slice_within_file_lines_range =
|file_lines: FileLines, cur_line, s| -> (usize, usize, bool) {
@@ -333,10 +329,3 @@ impl<'a> FmtVisitor<'a> {
}
}
}
-
-fn replace_chars(string: &str) -> String {
- string
- .chars()
- .map(|ch| if ch.is_whitespace() { ch } else { 'X' })
- .collect()
-}
diff --git a/src/visitor.rs b/src/visitor.rs
index 35291cecfb5..5526ed9e44d 100644
--- a/src/visitor.rs
+++ b/src/visitor.rs
@@ -5,9 +5,9 @@ use syntax::source_map::{self, BytePos, Pos, SourceMap, Span};
use syntax::{ast, visit};
use crate::attr::*;
-use crate::comment::{CodeCharKind, CommentCodeSlices};
-use crate::config::file_lines::LineRange;
+use crate::comment::{rewrite_comment, CodeCharKind, CommentCodeSlices};
use crate::config::{BraceStyle, Config};
+use crate::coverage::transform_missing_snippet;
use crate::items::{
format_impl, format_trait, format_trait_alias, is_mod_decl, is_use_item,
rewrite_associated_impl_type, rewrite_associated_type, rewrite_existential_impl_type,
@@ -22,8 +22,8 @@ use crate::source_map::{LineRangeUtils, SpanUtils};
use crate::spanned::Spanned;
use crate::stmt::Stmt;
use crate::utils::{
- self, contains_skip, count_newlines, depr_skip_annotation, inner_attributes, mk_sp,
- ptr_vec_to_ref_vec, rewrite_ident, stmt_expr,
+ self, contains_skip, count_newlines, depr_skip_annotation, inner_attributes, last_line_width,
+ mk_sp, ptr_vec_to_ref_vec, rewrite_ident, stmt_expr,
};
use crate::{ErrorKind, FormatReport, FormattingError};
@@ -165,32 +165,6 @@ impl<'b, 'a: 'b> FmtVisitor<'a> {
}
}
- /// Returns the total length of the spaces which should be trimmed between the last statement
- /// and the closing brace of the block.
- fn trimmed_spaces_width_before_closing_brace(
- &mut self,
- b: &ast::Block,
- brace_compensation: BytePos,
- ) -> usize {
- match b.stmts.last() {
- None => 0,
- Some(..) => {
- let span_after_last_stmt = self.next_span(b.span.hi() - brace_compensation);
- let missing_snippet = self.snippet(span_after_last_stmt);
- CommentCodeSlices::new(missing_snippet)
- .last()
- .and_then(|(kind, _, s)| {
- if kind == CodeCharKind::Normal && s.trim().is_empty() {
- Some(s.len())
- } else {
- None
- }
- })
- .unwrap_or(0)
- }
- }
- }
-
pub(crate) fn visit_block(
&mut self,
b: &ast::Block,
@@ -226,72 +200,99 @@ impl<'b, 'a: 'b> FmtVisitor<'a> {
}
}
- let missing_span = self.next_span(b.span.hi());
- if out_of_file_lines_range!(self, missing_span) {
- self.push_str(self.snippet(missing_span));
- self.block_indent = self.block_indent.block_unindent(self.config);
- self.last_pos = source!(self, b.span).hi();
- return;
- }
-
- let remove_len = BytePos::from_usize(
- self.trimmed_spaces_width_before_closing_brace(b, brace_compensation),
- );
- let unindent_comment = self.is_if_else_block && !b.stmts.is_empty() && {
- let end_pos = source!(self, b.span).hi() - brace_compensation - remove_len;
- let snippet = self.snippet(mk_sp(self.last_pos, end_pos));
- snippet.contains("//") || snippet.contains("/*")
- };
- if unindent_comment {
+ let rest_span = self.next_span(b.span.hi());
+ if out_of_file_lines_range!(self, rest_span) {
+ self.push_str(self.snippet(rest_span));
self.block_indent = self.block_indent.block_unindent(self.config);
+ } else {
+ // Ignore the closing brace.
+ let missing_span = self.next_span(b.span.hi() - brace_compensation);
+ self.close_block(missing_span, self.unindent_comment_on_closing_brace(b));
}
- self.format_missing_with_indent(
- source!(self, b.span).hi() - brace_compensation - remove_len,
- );
- if unindent_comment {
- self.block_indent = self.block_indent.block_indent(self.config);
- }
- self.close_block(unindent_comment, self.next_span(b.span.hi()));
self.last_pos = source!(self, b.span).hi();
}
- // FIXME: this is a terrible hack to indent the comments between the last
- // item in the block and the closing brace to the block's level.
- // The closing brace itself, however, should be indented at a shallower
- // level.
- fn close_block(&mut self, unindent_comment: bool, span: Span) {
- let skip_this_line = !self
- .config
- .file_lines()
- .contains(&LineRange::from_span(self.source_map, span));
- if skip_this_line {
- self.push_str(self.snippet(span));
- } else {
- let total_len = self.buffer.len();
- let chars_too_many = if unindent_comment {
- 0
- } else if self.config.hard_tabs() {
- 1
- } else {
- self.config.tab_spaces()
- };
+ fn close_block(&mut self, span: Span, unindent_comment: bool) {
+ let config = self.config;
- // FIXME this is a temporaly fix
- // should be remove truncate logic in close_block
- // avoid not to truncate necessary chars
- let truncate_start = total_len - chars_too_many;
- let target_str = &self.buffer[truncate_start..total_len];
- let truncate_length = target_str.len() - target_str.trim().len();
-
- if let Some(last_char) = target_str.chars().last() {
- self.buffer.truncate(total_len - truncate_length);
- if last_char == '\n' {
- self.buffer.push_str("\n");
+ let mut last_hi = span.lo();
+ let mut unindented = false;
+ let mut prev_ends_with_newline = false;
+ let mut extra_newline = false;
+
+ let skip_normal = |s: &str| {
+ let trimmed = s.trim();
+ trimmed.is_empty() || trimmed.chars().all(|c| c == ';')
+ };
+
+ for (kind, offset, sub_slice) in CommentCodeSlices::new(self.snippet(span)) {
+ let sub_slice = transform_missing_snippet(config, sub_slice);
+
+ debug!("close_block: {:?} {:?} {:?}", kind, offset, sub_slice);
+
+ match kind {
+ CodeCharKind::Comment => {
+ if !unindented && unindent_comment {
+ unindented = true;
+ self.block_indent = self.block_indent.block_unindent(config);
+ }
+ let span_in_between = mk_sp(last_hi, span.lo() + BytePos::from_usize(offset));
+ let snippet_in_between = self.snippet(span_in_between);
+ let mut comment_on_same_line = !snippet_in_between.contains("\n");
+
+ let mut comment_shape =
+ Shape::indented(self.block_indent, config).comment(config);
+ if comment_on_same_line {
+ // 1 = a space before `//`
+ let offset_len = 1 + last_line_width(&self.buffer)
+ .saturating_sub(self.block_indent.width());
+ match comment_shape
+ .visual_indent(offset_len)
+ .sub_width(offset_len)
+ {
+ Some(shp) => comment_shape = shp,
+ None => comment_on_same_line = false,
+ }
+ };
+
+ if comment_on_same_line {
+ self.push_str(" ");
+ } else {
+ if count_newlines(snippet_in_between) >= 2 || extra_newline {
+ self.push_str("\n");
+ }
+ self.push_str(&self.block_indent.to_string_with_newline(config));
+ }
+
+ let comment_str = rewrite_comment(&sub_slice, false, comment_shape, config);
+ match comment_str {
+ Some(ref s) => self.push_str(s),
+ None => self.push_str(&sub_slice),
+ }
+ }
+ CodeCharKind::Normal if skip_normal(&sub_slice) => {
+ extra_newline = prev_ends_with_newline && sub_slice.contains('\n');
+ continue;
+ }
+ CodeCharKind::Normal => {
+ self.push_str(&self.block_indent.to_string_with_newline(config));
+ self.push_str(sub_slice.trim());
}
}
- self.push_str("}");
+ prev_ends_with_newline = sub_slice.ends_with('\n');
+ extra_newline = false;
+ last_hi = span.lo() + BytePos::from_usize(offset + sub_slice.len());
+ }
+ if unindented {
+ self.block_indent = self.block_indent.block_indent(self.config);
}
self.block_indent = self.block_indent.block_unindent(self.config);
+ self.push_str(&self.block_indent.to_string_with_newline(config));
+ self.push_str("}");
+ }
+
+ fn unindent_comment_on_closing_brace(&self, b: &ast::Block) -> bool {
+ self.is_if_else_block && !b.stmts.is_empty()
}
// Note that this only gets called for function definitions. Required methods
@@ -806,9 +807,8 @@ impl<'b, 'a: 'b> FmtVisitor<'a> {
self.block_indent = self.block_indent.block_indent(self.config);
self.visit_attrs(attrs, ast::AttrStyle::Inner);
self.walk_mod_items(m);
- let missing_span = mk_sp(source!(self, m.inner).hi() - BytePos(1), m.inner.hi());
- self.format_missing_with_indent(missing_span.lo());
- self.close_block(false, missing_span);
+ let missing_span = self.next_span(m.inner.hi() - BytePos(1));
+ self.close_block(missing_span, false);
}
self.last_pos = source!(self, m.inner).hi();
} else {
diff --git a/tests/source/configs/empty_item_single_line/false.rs b/tests/source/configs/empty_item_single_line/false.rs
index 8fa74f28802..9bfb2b964ea 100644
--- a/tests/source/configs/empty_item_single_line/false.rs
+++ b/tests/source/configs/empty_item_single_line/false.rs
@@ -13,5 +13,4 @@ fn lorem() {
}
fn lorem() {
-
}
diff --git a/tests/source/configs/empty_item_single_line/true.rs b/tests/source/configs/empty_item_single_line/true.rs
index 02e703d1904..8af8b88ffff 100644
--- a/tests/source/configs/empty_item_single_line/true.rs
+++ b/tests/source/configs/empty_item_single_line/true.rs
@@ -13,5 +13,4 @@ fn lorem() {
}
fn lorem() {
-
}
diff --git a/tests/source/issue-977.rs b/tests/source/issue-977.rs
index b028b36a055..fe16387b7b2 100644
--- a/tests/source/issue-977.rs
+++ b/tests/source/issue-977.rs
@@ -1,5 +1,4 @@
// rustfmt-normalize_comments: true
-// FIXME(#919)
trait NameC { /* comment */ }
struct FooC { /* comment */ }
diff --git a/tests/target/assignment.rs b/tests/target/assignment.rs
index a33f3cb40ab..1a70d84813d 100644
--- a/tests/target/assignment.rs
+++ b/tests/target/assignment.rs
@@ -17,7 +17,7 @@ fn main() {
single_lit_fit >>= 10;
// #2791
- let x = 2;;;;
+ let x = 2;
}
fn break_meee() {
diff --git a/tests/target/comment.rs b/tests/target/comment.rs
index 4cccdab0e8b..b987c8a44f3 100644
--- a/tests/target/comment.rs
+++ b/tests/target/comment.rs
@@ -59,8 +59,7 @@ fn issue_1086() {
// random comment
-fn main() {
- // Test
+fn main() { // Test
}
// #1643
diff --git a/tests/target/comments-fn.rs b/tests/target/comments-fn.rs
index 5a17f03089c..1f43bd93bb0 100644
--- a/tests/target/comments-fn.rs
+++ b/tests/target/comments-fn.rs
@@ -15,7 +15,6 @@ where
F: Foo, // COmment after where-clause
G: Goo, // final comment
{
-
}
fn bar() {}
diff --git a/tests/target/configs/empty_item_single_line/false.rs b/tests/target/configs/empty_item_single_line/false.rs
index b7886df2aa8..174fe330a8d 100644
--- a/tests/target/configs/empty_item_single_line/false.rs
+++ b/tests/target/configs/empty_item_single_line/false.rs
@@ -11,5 +11,4 @@ fn lorem() {
}
fn lorem() {
-
}
diff --git a/tests/target/fn.rs b/tests/target/fn.rs
index 66a6e9082de..0ad775ee1dd 100644
--- a/tests/target/fn.rs
+++ b/tests/target/fn.rs
@@ -21,7 +21,6 @@ fn foo(
where
T: Blah,
{
-
}
fn foo(
@@ -32,7 +31,6 @@ where
T: Blah,
U: dsfasdfasdfasd,
{
-
}
fn foo B /* paren inside generics */>() {}
diff --git a/tests/target/issue-977.rs b/tests/target/issue-977.rs
index c4bc82d85d4..3784a387450 100644
--- a/tests/target/issue-977.rs
+++ b/tests/target/issue-977.rs
@@ -1,5 +1,4 @@
// rustfmt-normalize_comments: true
-// FIXME(#919)
trait NameC {
// comment
@@ -10,8 +9,7 @@ struct FooC {
enum MooC {
// comment
}
-mod BarC {
- // comment
+mod BarC { // comment
}
extern "C" {
// comment
diff --git a/tests/target/match.rs b/tests/target/match.rs
index f45574ee46c..78bcd2aa053 100644
--- a/tests/target/match.rs
+++ b/tests/target/match.rs
@@ -126,8 +126,7 @@ fn issue339() {
// collapsing here exceeds line length
ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffg => {
}
- h => {
- // comment above block
+ h => { // comment above block
}
i => {} // comment below block
j => {
@@ -148,8 +147,7 @@ fn issue339() {
m => {}
n => {}
o => {}
- p => {
- // Don't collapse me
+ p => { // Don't collapse me
}
q => {}
r => {}
diff --git a/tests/target/mod-1.rs b/tests/target/mod-1.rs
index a5d186c5df7..4118d123dd0 100644
--- a/tests/target/mod-1.rs
+++ b/tests/target/mod-1.rs
@@ -33,6 +33,5 @@ pub mod x {
}
}
-mod y {
- // sup boooooiiii
+mod y { // sup boooooiiii
}