diff --git a/src/codemap.rs b/src/codemap.rs index f62bb16dfa22..efbe50bcf649 100644 --- a/src/codemap.rs +++ b/src/codemap.rs @@ -34,6 +34,7 @@ pub trait SpanUtils { fn span_after(&self, original: Span, needle: &str) -> BytePos; fn span_after_last(&self, original: Span, needle: &str) -> BytePos; fn span_before(&self, original: Span, needle: &str) -> BytePos; + fn opt_span_after(&self, original: Span, needle: &str) -> Option; } pub trait LineRangeUtils { @@ -70,6 +71,13 @@ impl SpanUtils for CodeMap { original.lo() + BytePos(offset as u32) } + + fn opt_span_after(&self, original: Span, needle: &str) -> Option { + let snippet = self.span_to_snippet(original).ok()?; + let offset = snippet.find_uncommented(needle)? + needle.len(); + + Some(original.lo() + BytePos(offset as u32)) + } } impl LineRangeUtils for CodeMap { diff --git a/src/lib.rs b/src/lib.rs index c042d9d79541..7b441c4de02a 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -321,6 +321,7 @@ where let filemap = visitor.codemap.lookup_char_pos(module.inner.lo()).file; // Format inner attributes if available. if !krate.attrs.is_empty() && path == main_file { + visitor.skip_empty_lines(filemap.end_pos); if visitor.visit_attrs(&krate.attrs, ast::AttrStyle::Inner) { visitor.push_rewrite(module.inner, None); } else { @@ -328,6 +329,7 @@ where } } else { visitor.last_pos = filemap.start_pos; + visitor.skip_empty_lines(filemap.end_pos); visitor.format_separate_mod(module, &*filemap); }; diff --git a/src/visitor.rs b/src/visitor.rs index c613b3b8a551..b69edfda0c62 100644 --- a/src/visitor.rs +++ b/src/visitor.rs @@ -510,6 +510,10 @@ impl<'a> FmtVisitor<'a> { } } + pub fn opt_snippet(&self, span: Span) -> Option { + self.codemap.span_to_snippet(span).ok() + } + pub fn snippet(&self, span: Span) -> String { match self.codemap.span_to_snippet(span) { Ok(s) => s, @@ -695,6 +699,20 @@ impl<'a> FmtVisitor<'a> { self.format_missing_with_indent(filemap.end_pos); } + pub fn skip_empty_lines(&mut self, end_pos: BytePos) { + while let Some(pos) = self.codemap + .opt_span_after(mk_sp(self.last_pos, end_pos), "\n") + { + if let Some(snippet) = self.opt_snippet(mk_sp(self.last_pos, pos)) { + if snippet.trim().is_empty() { + self.last_pos = pos; + } else { + return; + } + } + } + } + pub fn get_context(&self) -> RewriteContext { RewriteContext { parse_session: self.parse_session, diff --git a/tests/source/issue-2025.rs b/tests/source/issue-2025.rs new file mode 100644 index 000000000000..c6f61b4e3e19 --- /dev/null +++ b/tests/source/issue-2025.rs @@ -0,0 +1,8 @@ + + + + +// See if rustfmt removes empty lines on top of the file. +pub fn foo() { + println!("hello, world"); +} diff --git a/tests/target/issue-2025.rs b/tests/target/issue-2025.rs new file mode 100644 index 000000000000..38bf369bea32 --- /dev/null +++ b/tests/target/issue-2025.rs @@ -0,0 +1,4 @@ +// See if rustfmt removes empty lines on top of the file. +pub fn foo() { + println!("hello, world"); +} diff --git a/tests/target/loop.rs b/tests/target/loop.rs index e02d73dc5504..f669e7e2c584 100644 --- a/tests/target/loop.rs +++ b/tests/target/loop.rs @@ -1,4 +1,3 @@ - fn main() { loop { return some_val; diff --git a/tests/target/nestedmod/mod.rs b/tests/target/nestedmod/mod.rs index ead395b2384a..1df462931846 100644 --- a/tests/target/nestedmod/mod.rs +++ b/tests/target/nestedmod/mod.rs @@ -1,4 +1,3 @@ - mod mod2a; mod mod2b; diff --git a/tests/target/nestedmod/mod2b.rs b/tests/target/nestedmod/mod2b.rs index f06766f304fd..9b6ea844e65d 100644 --- a/tests/target/nestedmod/mod2b.rs +++ b/tests/target/nestedmod/mod2b.rs @@ -1,3 +1,2 @@ - #[path = "mod2a.rs"] mod c;