From 7fc181d11159bf16603bde3f383406e4223b1c8a Mon Sep 17 00:00:00 2001 From: Ruben Schmidmeister Date: Sat, 11 May 2019 15:03:59 +0200 Subject: [PATCH 1/7] Add regression test --- tests/config/normalize_multiline_doc_attribute.toml | 1 + tests/source/normalize_multiline_doc_attribute.rs | 4 ++++ tests/target/normalize_multiline_doc_attribute.rs | 4 ++++ 3 files changed, 9 insertions(+) create mode 100644 tests/config/normalize_multiline_doc_attribute.toml create mode 100644 tests/source/normalize_multiline_doc_attribute.rs create mode 100644 tests/target/normalize_multiline_doc_attribute.rs diff --git a/tests/config/normalize_multiline_doc_attribute.toml b/tests/config/normalize_multiline_doc_attribute.toml new file mode 100644 index 00000000000..e8bb3d9a050 --- /dev/null +++ b/tests/config/normalize_multiline_doc_attribute.toml @@ -0,0 +1 @@ +normalize_doc_attributes = true diff --git a/tests/source/normalize_multiline_doc_attribute.rs b/tests/source/normalize_multiline_doc_attribute.rs new file mode 100644 index 00000000000..9f6e6b52a16 --- /dev/null +++ b/tests/source/normalize_multiline_doc_attribute.rs @@ -0,0 +1,4 @@ +#[doc = "This comment +is split +on multiple lines"] +fn foo() {} diff --git a/tests/target/normalize_multiline_doc_attribute.rs b/tests/target/normalize_multiline_doc_attribute.rs new file mode 100644 index 00000000000..5368a18efc9 --- /dev/null +++ b/tests/target/normalize_multiline_doc_attribute.rs @@ -0,0 +1,4 @@ +///This comment +///is split +///on multiple lines +fn foo() {} From 47a0f78b3b7087550b82564f3bfe0b3701683c66 Mon Sep 17 00:00:00 2001 From: Ruben Schmidmeister Date: Sat, 11 May 2019 15:05:08 +0200 Subject: [PATCH 2/7] Fix normalisation of multi-line doc attributes --- src/attr.rs | 11 ++--- src/attr/doc_comment.rs | 92 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 98 insertions(+), 5 deletions(-) create mode 100644 src/attr/doc_comment.rs diff --git a/src/attr.rs b/src/attr.rs index 498d6e4d851..378c56b83a3 100644 --- a/src/attr.rs +++ b/src/attr.rs @@ -3,6 +3,7 @@ use syntax::ast; use syntax::source_map::{BytePos, Span, DUMMY_SP}; +use self::doc_comment::DocCommentFormatter; use crate::comment::{contains_comment, rewrite_doc_comment, CommentStyle}; use crate::config::lists::*; use crate::config::IndentStyle; @@ -14,6 +15,8 @@ use crate::shape::Shape; use crate::types::{rewrite_path, PathContext}; use crate::utils::{count_newlines, mk_sp}; +mod doc_comment; + /// Returns attributes on the given statement. pub(crate) fn get_attrs_from_stmt(stmt: &ast::Stmt) -> &[ast::Attribute] { match stmt.node { @@ -331,11 +334,9 @@ impl Rewrite for ast::Attribute { ast::AttrStyle::Outer => CommentStyle::TripleSlash, }; - // Remove possible whitespace from the `CommentStyle::opener()` so that - // the literal itself has control over the comment's leading spaces. - let opener = comment_style.opener().trim_end(); - - let doc_comment = format!("{}{}", opener, literal); + let doc_comment_formatter = + DocCommentFormatter::new(literal, comment_style); + let doc_comment = format!("{}", doc_comment_formatter); return rewrite_doc_comment( &doc_comment, shape.comment(context.config), diff --git a/src/attr/doc_comment.rs b/src/attr/doc_comment.rs new file mode 100644 index 00000000000..e687492fb89 --- /dev/null +++ b/src/attr/doc_comment.rs @@ -0,0 +1,92 @@ +use crate::comment::CommentStyle; +use std::fmt::{self, Display}; +use syntax_pos::symbol::Symbol; + +pub(super) struct DocCommentFormatter<'a> { + literal: &'a Symbol, + style: CommentStyle<'a>, +} + +impl<'a> DocCommentFormatter<'a> { + pub(super) fn new(literal: &'a Symbol, style: CommentStyle<'a>) -> Self { + Self { literal, style } + } +} + +impl Display for DocCommentFormatter<'_> { + fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { + let opener = self.style.opener().trim_end(); + + let literal_as_str = self.literal.as_str().get(); + let line_count = literal_as_str.lines().count(); + let last_line_index = line_count - 1; + let lines = literal_as_str.lines().enumerate(); + + for (index, line) in lines { + if index == last_line_index { + write!(formatter, "{}{}", opener, line)?; + } else { + writeln!(formatter, "{}{}", opener, line)?; + } + } + + Ok(()) + } +} + +#[cfg(test)] +mod tests { + use super::*; + use syntax_pos::{Globals, GLOBALS}; + + #[test] + fn literal_controls_leading_spaces() { + test_doc_comment_is_formatted_correctly( + " Lorem ipsum", + "/// Lorem ipsum", + CommentStyle::TripleSlash, + ); + } + + #[test] + fn single_line_doc_comment_is_formatted_correctly() { + test_doc_comment_is_formatted_correctly( + "Lorem ipsum", + "///Lorem ipsum", + CommentStyle::TripleSlash, + ); + } + + #[test] + fn multi_line_doc_comment_is_formatted_correctly() { + test_doc_comment_is_formatted_correctly( + "Lorem ipsum\nDolor sit amet", + "///Lorem ipsum\n///Dolor sit amet", + CommentStyle::TripleSlash, + ); + } + + #[test] + fn whitespace_within_lines_is_preserved() { + test_doc_comment_is_formatted_correctly( + " Lorem ipsum \n Dolor sit amet ", + "/// Lorem ipsum \n/// Dolor sit amet ", + CommentStyle::TripleSlash, + ); + } + + fn test_doc_comment_is_formatted_correctly( + literal: &str, + expected_comment: &str, + style: CommentStyle<'_>, + ) { + GLOBALS.set(&Globals::new(), || { + let literal = Symbol::gensym(literal); + + assert_eq!( + expected_comment, + format!("{}", DocCommentFormatter::new(&literal, style)) + ); + }); + } +} From 4ac0d35ebb8aeae27c8861850b59a747ac44f194 Mon Sep 17 00:00:00 2001 From: Ruben Schmidmeister Date: Sun, 12 May 2019 23:03:48 +0200 Subject: [PATCH 3/7] Only run test on nightly --- src/test/mod.rs | 27 ++++++++++++++----- .../normalize_multiline_doc_attribute.rs | 2 ++ .../normalize_multiline_doc_attribute.rs | 2 ++ 3 files changed, 25 insertions(+), 6 deletions(-) diff --git a/src/test/mod.rs b/src/test/mod.rs index 23f6a69b8d1..20c4bce5d81 100644 --- a/src/test/mod.rs +++ b/src/test/mod.rs @@ -259,9 +259,9 @@ fn assert_output(source: &Path, expected_filename: &Path) { #[test] fn idempotence_tests() { run_test_with(&TestSetting::default(), || { - match option_env!("CFG_RELEASE_CHANNEL") { - None | Some("nightly") => {} - _ => return, // these tests require nightly + // these tests require nightly + if !is_nightly() { + return; } // Get all files in the tests/target directory. let files = get_test_files(Path::new("tests/target"), true); @@ -277,9 +277,9 @@ fn idempotence_tests() { // no warnings are emitted. #[test] fn self_tests() { - match option_env!("CFG_RELEASE_CHANNEL") { - None | Some("nightly") => {} - _ => return, // Issue-3443: these tests require nightly + // Issue-3443: these tests require nightly + if !is_nightly() { + return; } let mut files = get_test_files(Path::new("tests"), false); let bin_directories = vec!["cargo-fmt", "git-rustfmt", "bin", "format-diff"]; @@ -313,6 +313,11 @@ fn self_tests() { ); } +fn is_nightly() -> bool { + let release_channel = option_env!("CFG_RELEASE_CHANNEL"); + release_channel.is_none() || release_channel == Some("nightly") +} + #[test] fn stdin_formatting_smoke_test() { let input = Input::Text("fn main () {}".to_owned()); @@ -426,6 +431,16 @@ fn check_files(files: Vec, opt_config: &Option) -> (Vec Date: Mon, 13 May 2019 09:40:16 +0200 Subject: [PATCH 4/7] Ignore unstable key when overriding config --- src/test/mod.rs | 2 +- tests/config/normalize_multiline_doc_attribute.toml | 1 - tests/source/normalize_multiline_doc_attribute.rs | 1 + tests/target/normalize_multiline_doc_attribute.rs | 1 + 4 files changed, 3 insertions(+), 2 deletions(-) delete mode 100644 tests/config/normalize_multiline_doc_attribute.toml diff --git a/src/test/mod.rs b/src/test/mod.rs index 20c4bce5d81..101a8c07fd9 100644 --- a/src/test/mod.rs +++ b/src/test/mod.rs @@ -500,7 +500,7 @@ fn read_config(filename: &Path) -> Config { }; for (key, val) in &sig_comments { - if key != "target" && key != "config" { + if key != "target" && key != "config" && key != "unstable" { config.override_value(key, val); if config.is_default(key) { warn!("Default value {} used explicitly for {}", val, key); diff --git a/tests/config/normalize_multiline_doc_attribute.toml b/tests/config/normalize_multiline_doc_attribute.toml deleted file mode 100644 index e8bb3d9a050..00000000000 --- a/tests/config/normalize_multiline_doc_attribute.toml +++ /dev/null @@ -1 +0,0 @@ -normalize_doc_attributes = true diff --git a/tests/source/normalize_multiline_doc_attribute.rs b/tests/source/normalize_multiline_doc_attribute.rs index fd4bf796c95..91d93091244 100644 --- a/tests/source/normalize_multiline_doc_attribute.rs +++ b/tests/source/normalize_multiline_doc_attribute.rs @@ -1,4 +1,5 @@ // rustfmt-unstable: true +// rustfmt-normalize_doc_attributes: true #[doc = "This comment is split diff --git a/tests/target/normalize_multiline_doc_attribute.rs b/tests/target/normalize_multiline_doc_attribute.rs index 8227317512a..3b30525cace 100644 --- a/tests/target/normalize_multiline_doc_attribute.rs +++ b/tests/target/normalize_multiline_doc_attribute.rs @@ -1,4 +1,5 @@ // rustfmt-unstable: true +// rustfmt-normalize_doc_attributes: true ///This comment ///is split From 8d4cb6e783c076829568bb82dcd5a0c888a09cb7 Mon Sep 17 00:00:00 2001 From: Ruben Schmidmeister Date: Sat, 18 May 2019 11:42:49 +0200 Subject: [PATCH 5/7] Use peek() instead of checking indexes --- src/attr/doc_comment.rs | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/src/attr/doc_comment.rs b/src/attr/doc_comment.rs index e687492fb89..1affc7bc910 100644 --- a/src/attr/doc_comment.rs +++ b/src/attr/doc_comment.rs @@ -16,14 +16,12 @@ impl<'a> DocCommentFormatter<'a> { impl Display for DocCommentFormatter<'_> { fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { let opener = self.style.opener().trim_end(); - let literal_as_str = self.literal.as_str().get(); - let line_count = literal_as_str.lines().count(); - let last_line_index = line_count - 1; - let lines = literal_as_str.lines().enumerate(); - for (index, line) in lines { - if index == last_line_index { + let mut lines = literal_as_str.lines().peekable(); + while let Some(line) = lines.next() { + let is_last_line = lines.peek().is_none(); + if is_last_line { write!(formatter, "{}{}", opener, line)?; } else { writeln!(formatter, "{}{}", opener, line)?; From 11a68d313ad351907acd68da3e4a683f7c30d94f Mon Sep 17 00:00:00 2001 From: Ruben Schmidmeister Date: Sat, 18 May 2019 11:47:54 +0200 Subject: [PATCH 6/7] Pass string instead of Symbol to DocCommentFormatter --- src/attr.rs | 2 +- src/attr/doc_comment.rs | 28 +++++++--------------------- 2 files changed, 8 insertions(+), 22 deletions(-) diff --git a/src/attr.rs b/src/attr.rs index 961b6031c93..1fb4ef407eb 100644 --- a/src/attr.rs +++ b/src/attr.rs @@ -334,7 +334,7 @@ impl Rewrite for ast::Attribute { }; let doc_comment_formatter = - DocCommentFormatter::new(literal, comment_style); + DocCommentFormatter::new(literal.as_str().get(), comment_style); let doc_comment = format!("{}", doc_comment_formatter); return rewrite_doc_comment( &doc_comment, diff --git a/src/attr/doc_comment.rs b/src/attr/doc_comment.rs index 1affc7bc910..c2ae16d1c91 100644 --- a/src/attr/doc_comment.rs +++ b/src/attr/doc_comment.rs @@ -1,24 +1,16 @@ use crate::comment::CommentStyle; use std::fmt::{self, Display}; -use syntax_pos::symbol::Symbol; +#[derive(new)] pub(super) struct DocCommentFormatter<'a> { - literal: &'a Symbol, + literal: &'a str, style: CommentStyle<'a>, } -impl<'a> DocCommentFormatter<'a> { - pub(super) fn new(literal: &'a Symbol, style: CommentStyle<'a>) -> Self { - Self { literal, style } - } -} - impl Display for DocCommentFormatter<'_> { fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { let opener = self.style.opener().trim_end(); - let literal_as_str = self.literal.as_str().get(); - - let mut lines = literal_as_str.lines().peekable(); + let mut lines = self.literal.lines().peekable(); while let Some(line) = lines.next() { let is_last_line = lines.peek().is_none(); if is_last_line { @@ -27,7 +19,6 @@ impl Display for DocCommentFormatter<'_> { writeln!(formatter, "{}{}", opener, line)?; } } - Ok(()) } } @@ -35,7 +26,6 @@ impl Display for DocCommentFormatter<'_> { #[cfg(test)] mod tests { use super::*; - use syntax_pos::{Globals, GLOBALS}; #[test] fn literal_controls_leading_spaces() { @@ -78,13 +68,9 @@ mod tests { expected_comment: &str, style: CommentStyle<'_>, ) { - GLOBALS.set(&Globals::new(), || { - let literal = Symbol::gensym(literal); - - assert_eq!( - expected_comment, - format!("{}", DocCommentFormatter::new(&literal, style)) - ); - }); + assert_eq!( + expected_comment, + format!("{}", DocCommentFormatter::new(&literal, style)) + ); } } From 1ba35fc9b52587f5ff01e188e7ae3d12e078765b Mon Sep 17 00:00:00 2001 From: Ruben Schmidmeister Date: Sat, 18 May 2019 11:50:09 +0200 Subject: [PATCH 7/7] Document DocCommentFormatter --- src/attr/doc_comment.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/attr/doc_comment.rs b/src/attr/doc_comment.rs index c2ae16d1c91..00185425d6a 100644 --- a/src/attr/doc_comment.rs +++ b/src/attr/doc_comment.rs @@ -1,6 +1,7 @@ use crate::comment::CommentStyle; use std::fmt::{self, Display}; +/// Formats a string as a doc comment using the given [`CommentStyle`]. #[derive(new)] pub(super) struct DocCommentFormatter<'a> { literal: &'a str,