Skip to content

Commit dd80808

Browse files
committed
use the lists module for formatting the generic bounds
Fix how to extract post comments in a list with separators at the front. Fix extraction of a comment between the type bounds and the opening curly bracket. Support explicit padding passed through the separator when writing a list.
1 parent a49e474 commit dd80808

File tree

7 files changed

+290
-76
lines changed

7 files changed

+290
-76
lines changed

src/comment.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1789,7 +1789,7 @@ mod test {
17891789
* test3
17901790
*/"#,
17911791
false,
1792-
Shape::legacy(100, Indent::new(0, 0)),
1792+
Shape::legacy(100, Indent::empty()),
17931793
&wrap_normalize_config).unwrap();
17941794
assert_eq!("/// test1\n/// test2\n// test3", comment);
17951795

@@ -1798,7 +1798,7 @@ mod test {
17981798
17991799
// test2"#,
18001800
false,
1801-
Shape::legacy(100, Indent::new(0, 0)),
1801+
Shape::legacy(100, Indent::empty()),
18021802
&wrap_normalize_config).unwrap();
18031803
assert_eq!("// test1\n\n// test2", comment);
18041804

@@ -1807,7 +1807,7 @@ mod test {
18071807
18081808
//@ test2"#,
18091809
false,
1810-
Shape::legacy(100, Indent::new(0, 0)),
1810+
Shape::legacy(100, Indent::empty()),
18111811
&wrap_normalize_config).unwrap();
18121812
assert_eq!("//@ test1\n\n//@ test2", comment);
18131813

@@ -1819,7 +1819,7 @@ mod test {
18191819
another bare line!
18201820
*/"#,
18211821
false,
1822-
Shape::legacy(100, Indent::new(0, 0)),
1822+
Shape::legacy(100, Indent::empty()),
18231823
&wrap_config).unwrap();
18241824
assert_eq!("// test1\n/*\n a bare line!\n\n another bare line!\n*/", comment);
18251825
}

src/items.rs

Lines changed: 16 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -994,20 +994,20 @@ pub(crate) fn format_trait(
994994
rewrite_generics(context, rewrite_ident(context, item.ident), generics, shape)?;
995995
result.push_str(&generics_str);
996996

997-
// FIXME(#2055): rustfmt fails to format when there are comments between trait bounds.
998997
if !generic_bounds.is_empty() {
999-
let ident_hi = context
1000-
.snippet_provider
1001-
.span_after(item.span, &item.ident.as_str());
1002-
let bound_hi = generic_bounds.last().unwrap().span().hi();
1003-
let snippet = context.snippet(mk_sp(ident_hi, bound_hi));
1004-
if contains_comment(snippet) {
1005-
return None;
1006-
}
1007-
998+
let comment_span = mk_sp(generics.span.hi(), generic_bounds[0].span().lo());
999+
let after_colon = context.snippet_provider.span_after(comment_span, ":");
1000+
let comment = recover_missing_comment_in_span(
1001+
mk_sp(after_colon, comment_span.hi()),
1002+
shape,
1003+
context,
1004+
// 1 = ":"
1005+
last_line_width(&result) + 1,
1006+
)
1007+
.unwrap_or_default();
10081008
result = rewrite_assign_rhs_with(
10091009
context,
1010-
result + ":",
1010+
format!("{}:{}", result, comment),
10111011
generic_bounds,
10121012
shape,
10131013
RhsTactics::ForceNextLineWithoutIndent,
@@ -1052,7 +1052,11 @@ pub(crate) fn format_trait(
10521052
if let Some(lo) = item_snippet.find('/') {
10531053
// 1 = `{`
10541054
let comment_hi = body_lo - BytePos(1);
1055-
let comment_lo = item.span.lo() + BytePos(lo as u32);
1055+
let comment_lo = if generic_bounds.is_empty() {
1056+
item.span.lo() + BytePos(lo as u32)
1057+
} else {
1058+
generic_bounds[generic_bounds.len() - 1].span().hi()
1059+
};
10561060
if comment_lo < comment_hi {
10571061
match recover_missing_comment_in_span(
10581062
mk_sp(comment_lo, comment_hi),

src/lists.rs

Lines changed: 113 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ use std::iter::Peekable;
55

66
use syntax::source_map::BytePos;
77

8-
use crate::comment::{find_comment_end, rewrite_comment, FindUncommented};
8+
use crate::comment::{find_comment_end, is_last_comment_block, rewrite_comment, FindUncommented};
99
use crate::config::lists::*;
1010
use crate::config::{Config, IndentStyle};
1111
use crate::rewrite::RewriteContext;
@@ -32,6 +32,8 @@ pub(crate) struct ListFormatting<'a> {
3232
// Whether comments should be visually aligned.
3333
align_comments: bool,
3434
config: &'a Config,
35+
item_on_newline: Vec<bool>,
36+
padding: bool,
3537
}
3638

3739
impl<'a> ListFormatting<'a> {
@@ -47,9 +49,21 @@ impl<'a> ListFormatting<'a> {
4749
nested: false,
4850
align_comments: true,
4951
config,
52+
item_on_newline: Vec::new(),
53+
padding: true,
5054
}
5155
}
5256

57+
pub(crate) fn padding(mut self, padding: bool) -> Self {
58+
self.padding = padding;
59+
self
60+
}
61+
62+
pub(crate) fn item_on_newline(mut self, item_on_newline: Vec<bool>) -> Self {
63+
self.item_on_newline = item_on_newline;
64+
self
65+
}
66+
5367
pub(crate) fn tactic(mut self, tactic: DefinitiveListTactic) -> Self {
5468
self.tactic = tactic;
5569
self
@@ -281,6 +295,7 @@ where
281295
let mut prev_item_is_nested_import = false;
282296

283297
let mut line_len = 0;
298+
let mut first_item_on_line = true;
284299
let indent_str = &formatting.shape.indent.to_string(formatting.config);
285300
while let Some((i, item)) = iter.next() {
286301
let item = item.as_ref();
@@ -310,7 +325,7 @@ where
310325
}
311326

312327
match tactic {
313-
DefinitiveListTactic::Horizontal if !first => {
328+
DefinitiveListTactic::Horizontal if !first && formatting.padding => {
314329
result.push(' ');
315330
}
316331
DefinitiveListTactic::SpecialMacro(num_args_before) => {
@@ -328,25 +343,30 @@ where
328343
DefinitiveListTactic::Vertical
329344
if !first && !inner_item.is_empty() && !result.is_empty() =>
330345
{
346+
first_item_on_line = true;
331347
result.push('\n');
332348
result.push_str(indent_str);
333349
}
334350
DefinitiveListTactic::Mixed => {
335351
let total_width = total_item_width(item) + item_sep_len;
336352

337353
// 1 is space between separator and item.
338-
if (line_len > 0 && line_len + 1 + total_width > formatting.shape.width)
339-
|| prev_item_had_post_comment
340-
|| (formatting.nested
341-
&& (prev_item_is_nested_import || (!first && inner_item.contains("::"))))
354+
if (!formatting.item_on_newline.is_empty() && formatting.item_on_newline[i])
355+
|| formatting.item_on_newline.is_empty()
356+
&& ((line_len > 0 && line_len + 1 + total_width > formatting.shape.width)
357+
|| prev_item_had_post_comment
358+
|| (formatting.nested
359+
&& (prev_item_is_nested_import
360+
|| (!first && inner_item.contains("::")))))
342361
{
343362
result.push('\n');
344363
result.push_str(indent_str);
345364
line_len = 0;
365+
first_item_on_line = true;
346366
if formatting.ends_with_newline {
347367
trailing_separator = true;
348368
}
349-
} else if line_len > 0 {
369+
} else if formatting.padding && line_len > 0 {
350370
result.push(' ');
351371
line_len += 1;
352372
}
@@ -399,8 +419,14 @@ where
399419
}
400420

401421
if separate && sep_place.is_front() && !first {
402-
result.push_str(formatting.separator.trim());
403-
result.push(' ');
422+
if formatting.padding {
423+
result.push_str(formatting.separator.trim());
424+
result.push(' ');
425+
} else if first_item_on_line {
426+
result.push_str(formatting.separator.trim_start());
427+
} else {
428+
result.push_str(formatting.separator);
429+
}
404430
}
405431
result.push_str(inner_item);
406432

@@ -414,7 +440,12 @@ where
414440
formatting.config,
415441
)?;
416442

417-
result.push(' ');
443+
if is_last_comment_block(&formatted_comment) {
444+
result.push(' ');
445+
} else {
446+
result.push('\n');
447+
result.push_str(indent_str);
448+
}
418449
result.push_str(&formatted_comment);
419450
}
420451

@@ -512,6 +543,7 @@ where
512543
result.push('\n');
513544
}
514545

546+
first_item_on_line = false;
515547
prev_item_had_post_comment = item.post_comment.is_some();
516548
prev_item_is_nested_import = inner_item.contains("::");
517549
}
@@ -599,25 +631,20 @@ pub(crate) fn extract_pre_comment(pre_snippet: &str) -> (Option<String>, ListIte
599631
}
600632
}
601633

602-
pub(crate) fn extract_post_comment(
603-
post_snippet: &str,
604-
comment_end: usize,
605-
separator: &str,
606-
) -> Option<String> {
634+
fn extract_post_comment(post_snippet: &str, comment_end: usize, separator: &str) -> Option<String> {
607635
let white_space: &[_] = &[' ', '\t'];
608636

609637
// Cleanup post-comment: strip separators and whitespace.
610638
let post_snippet = post_snippet[..comment_end].trim();
611639
let post_snippet_trimmed = if post_snippet.starts_with(|c| c == ',' || c == ':') {
612640
post_snippet[1..].trim_matches(white_space)
641+
} else if post_snippet.ends_with(separator) {
642+
// the separator is in front of the next item
643+
post_snippet[..post_snippet.len() - separator.len()].trim_matches(white_space)
613644
} else if post_snippet.starts_with(separator) {
614645
post_snippet[separator.len()..].trim_matches(white_space)
615-
}
616-
// not comment or over two lines
617-
else if post_snippet.ends_with(',')
618-
&& (!post_snippet.trim().starts_with("//") || post_snippet.trim().contains('\n'))
619-
{
620-
post_snippet[..(post_snippet.len() - 1)].trim_matches(white_space)
646+
} else if post_snippet.ends_with(',') && !post_snippet.trim_start().starts_with("//") {
647+
post_snippet[..post_snippet.len() - 1].trim_matches(white_space)
621648
} else {
622649
post_snippet
623650
};
@@ -633,12 +660,7 @@ pub(crate) fn extract_post_comment(
633660
}
634661
}
635662

636-
pub(crate) fn get_comment_end(
637-
post_snippet: &str,
638-
separator: &str,
639-
terminator: &str,
640-
is_last: bool,
641-
) -> usize {
663+
fn get_comment_end(post_snippet: &str, separator: &str, terminator: &str, is_last: bool) -> usize {
642664
if is_last {
643665
return post_snippet
644666
.find_uncommented(terminator)
@@ -686,7 +708,7 @@ pub(crate) fn get_comment_end(
686708

687709
// Account for extra whitespace between items. This is fiddly
688710
// because of the way we divide pre- and post- comments.
689-
pub(crate) fn has_extra_newline(post_snippet: &str, comment_end: usize) -> bool {
711+
fn has_extra_newline(post_snippet: &str, comment_end: usize) -> bool {
690712
if post_snippet.is_empty() || comment_end == 0 {
691713
return false;
692714
}
@@ -767,7 +789,17 @@ where
767789
}
768790

769791
#[allow(clippy::too_many_arguments)]
770-
// Creates an iterator over a list's items with associated comments.
792+
/// Creates an iterator over a list's items with associated comments.
793+
///
794+
/// - inner is the iterator over items
795+
/// - terminator is a string that closes the list, used to get comments after the last item
796+
/// - separator is a string that separates the items
797+
/// - get_lo is a closure to get the lower bound of an item's span
798+
/// - get_hi is a closure to get the upper bound of an item's span
799+
/// - get_item_string is a closure to get the rewritten item as a string
800+
/// - prev_span_end is the BytePos before the first item
801+
/// - next_span_start is the BytePos after the last item
802+
/// - leave_last is a boolean whether or not to rewrite the last item
771803
pub(crate) fn itemize_list<'a, T, I, F1, F2, F3>(
772804
snippet_provider: &'a SnippetProvider<'_>,
773805
inner: I,
@@ -918,5 +950,57 @@ pub(crate) fn struct_lit_formatting<'a>(
918950
nested: false,
919951
align_comments: true,
920952
config: context.config,
953+
item_on_newline: Vec::new(),
954+
padding: true,
955+
}
956+
}
957+
958+
#[cfg(test)]
959+
mod test {
960+
use super::*;
961+
962+
#[test]
963+
fn test_extract_post_comment() {
964+
let data = [
965+
(
966+
", // a comment",
967+
", // a comment".len(),
968+
",",
969+
"// a comment",
970+
),
971+
(
972+
": // a comment",
973+
": // a comment".len(),
974+
":",
975+
"// a comment",
976+
),
977+
(
978+
"// a comment\n +",
979+
"// a comment\n +".len(),
980+
"+",
981+
"// a comment\n",
982+
),
983+
(
984+
"+ // a comment\n ",
985+
"+ // a comment\n ".len(),
986+
"+",
987+
"// a comment",
988+
),
989+
(
990+
"/* a comment */ ,",
991+
"/* a comment */ ,".len(),
992+
"+",
993+
"/* a comment */",
994+
),
995+
];
996+
997+
for (i, (post_snippet, comment_end, separator, expected)) in data.iter().enumerate() {
998+
assert_eq!(
999+
extract_post_comment(post_snippet, *comment_end, separator),
1000+
Some(expected.to_string()),
1001+
"Failed on input {}",
1002+
i
1003+
);
1004+
}
9211005
}
9221006
}

0 commit comments

Comments
 (0)