diff --git a/src/formatting/lists.rs b/src/formatting/lists.rs index 760c1f62946..1dcd7044d5d 100644 --- a/src/formatting/lists.rs +++ b/src/formatting/lists.rs @@ -8,7 +8,7 @@ use unicode_segmentation::UnicodeSegmentation; use crate::config::{lists::*, Config, IndentStyle}; use crate::formatting::{ - comment::{find_comment_end, rewrite_comment, FindUncommented}, + comment::{comment_style, find_comment_end, rewrite_comment, FindUncommented}, rewrite::RewriteContext, shape::{Indent, Shape}, utils::{ @@ -421,6 +421,33 @@ where result.push_str(formatting.separator); } + // Note about post-comments indentation: + // In the original code the the item separator may follow some comments that + // may span over some lines. E.g.: + // item1 /* 1st comment line 1 + // * line 2 */ + // /* 2nd comment */, + // item2, + // + // In this case, rustfmt moves the separator right after the item: + // item1, /* 1st comment line 1 + // * line 2 */ + // /* 2nd comment */ + // item2, + // + // In this code, only the 1st comment is regarded as post comment of item1. + // 2nd comment is regarded as pre-comment of item2, therefore the output + // of another round of formatting this code is: + // item1, /* 1st comment line 1 + // * line 2 */ + // /* 2nd comment */ + // item2, + // + // i.e. 2nd comment is now indented as pre-comment. + // + // This why in the code below a first multiline post-comment is indented + // differently then the other post-comments. + if tactic != DefinitiveListTactic::Horizontal && item.post_comment.is_some() { let comment = item.post_comment.as_ref().unwrap(); let overhead = last_line_width(&result) + first_line_width(comment.trim()); @@ -444,19 +471,88 @@ where }; let width = formatting.shape.width.checked_sub(overhead).unwrap_or(1); let offset = formatting.shape.indent + overhead; - let comment_shape = Shape::legacy(width, offset); - - // Use block-style only for the last item or multiline comments. - let block_style = !formatting.ends_with_newline && last - || comment.trim().contains('\n') - || comment.trim().len() > width; - - rewrite_comment( - comment.trim_start(), - block_style, - comment_shape, - formatting.config, - ) + let comment_start_trimmed = comment.trim_start(); + + // Find if first comment is single line and the end of the first comment + // when it is a multi-line block comment (since the first post-comment + // is added to the same line of the list item, its indentation is important + // only when it is a multiline comment). + let style = comment_style( + comment_start_trimmed, + formatting.config.normalize_comments(), + ); + let (first_comment_single_line, first_comment_end) = + if !formatting.config.normalize_comments() && style.is_line_comment() { + // Line comment (not normalizaed) + (true, None) + } else if style.is_block_comment() { + match find_comment_end(&comment_start_trimmed) { + Some(i) => { + if comment_start_trimmed[..i].contains('\n') { + // Multiline-comment (may be because of normalization) + (false, Some(i)) + } else { + // One line coment (Block or normalizaed Line) + (true, None) + } + } + _ => (false, None), // Unknow comment end + } + } else { + (false, None) // Unexpected case - non-block comment with normalization + }; + + // Closure for formatting post-comment with specific Shape + let rewrite_post_comment_with_shape = |cmt: &str, shape: Shape| { + // Use block-style only for the last item or multiline comments. + let block_style = !formatting.ends_with_newline && last + || cmt.trim().contains('\n') + || cmt.trim().len() > width; + rewrite_comment(&cmt, block_style, shape, formatting.config) + }; + + // Properly indent first and other comments + match (first_comment_single_line, first_comment_end) { + (_, None) => { + // First comment not multiline - same indentation for all comments + let comment_shape = + if first_comment_single_line && comment_start_trimmed.contains("\n") { + formatting.shape + } else { + Shape::legacy(width, offset) + }; + rewrite_post_comment_with_shape(comment_start_trimmed, comment_shape) + } + (false, Some(comment_end)) => { + // Separate indentation for first multi-line block comment + let formatted_first_comment = rewrite_comment( + &comment_start_trimmed[..comment_end], + true, + Shape::legacy(width, offset), + formatting.config, + )?; + let second_comment_start = comment_start_trimmed[comment_end..] + .find(|c: char| !c.is_whitespace()) + .map_or(None, |i| Some(i + comment_end)); + let formatted_all_comments = match second_comment_start { + Some(i) => { + let second_comment = comment_start_trimmed[i..].to_string(); + let formatted = rewrite_post_comment_with_shape( + &second_comment, + formatting.shape, + )?; + let indent = formatting + .shape + .indent + .to_string_with_newline(formatting.config); + format!("{}{}{}", formatted_first_comment, indent, formatted) + } + _ => formatted_first_comment, + }; + Some(formatted_all_comments) + } + (_, _) => unreachable!(), + } }; let mut formatted_comment = rewrite_post_comment(&mut item_max_width)?; @@ -699,6 +795,11 @@ pub(crate) fn get_comment_end( find_comment_end(&post_snippet[i..]).unwrap() + i, separator_index + 1, ), + // Comment is preceeded by new line and followed by a separator. + (Some(i), Some(_)) if separator_index > i => cmp::max( + find_comment_end(&post_snippet[i..]).unwrap() + i, + separator_index + 1, + ), // Potential *single* line comment. (_, Some(j)) if j > separator_index => j + 1, _ => post_snippet.len(), diff --git a/tests/source/issue-3847.rs b/tests/source/issue-3847.rs new file mode 100644 index 00000000000..e4440efa23a --- /dev/null +++ b/tests/source/issue-3847.rs @@ -0,0 +1,205 @@ +// Tests for multi one-line post-comments of list item +// (related cases when `normalize_comments` is set are already included in other test files). + +// Original cases from issue #3847 +type T1 = Result< + u32 // Lorem ipsum dolor sit amet, consectetur adipiscing elit. Etiam + // diam ac cursus. Aliquam condimentum in erat quis pretium. + // accumsan urna. Cras volutpat sit amet quam. + , + bool, +>; +type T2 = Result< + u32, // Lorem ipsum dolor sit amet, consectetur adipiscing elit. Etiam + // diam ac cursus. Aliquam condimentum in erat quis pretium. + // accumsan urna. Cras volutpat sit amet quam. + bool, +>; + +// Additional test cases with lists +fn main() { + let a = ["GOOD" // Comment1 + // Comment2 + , + ]; + let b = ["WASBAD" // Comment1 + // Comment2 + , + "CCC", + ]; +} + +// Tests with one multi-line block comment +type T3_good = Result< + u32 /* Lorem ipsum dolor sit amet, consectetur adipiscing elit. Etiam + * diam ac cursus. Aliquam condimentum in erat quis pretium. + * accumsan urna. Cras volutpat sit amet quam. */ + , + bool, +>; +type T4_good = Result< + u32, /* Lorem ipsum dolor sit amet, consectetur adipiscing elit. Etiam + * diam ac cursus. Aliquam condimentum in erat quis pretium. + * accumsan urna. Cras volutpat sit amet quam. */ + bool, +>; + +fn main() { + let a = ["WASGOOD1" /* Comment1 + * Comment2 */ + , + "WASGOOD2", /* Comment1 + * Comment2 */ + "CCC", + ]; +} + +// Tests with one-line block-comments +type T5_good = Result< + u32 /* Lorem ipsum dolor sit amet, consectetur adipiscing elit. Etiam */ + /* diam ac cursus. Aliquam condimentum in erat quis pretium. */ + /* accumsan urna. Cras volutpat sit amet quam. */ + , + bool, +>; +type T6_good = Result< + u32, /* Lorem ipsum dolor sit amet, consectetur adipiscing elit. Etiam */ + /* diam ac cursus. Aliquam condimentum in erat quis pretium. */ + /* accumsan urna. Cras volutpat sit amet quam. */ + bool, +>; + +// Tests with mix one-line and multi-linecomments - one-line is first +type T8_good = Result< + u32 // Lorem ipsum dolor sit amet, consectetur adipiscing elit. Etiam + /* Lorem ipsum dolor sit amet, consectetur adipiscing elit. Etiam + * diam ac cursus. Aliquam condimentum in erat quis pretium. + * accumsan urna. Cras volutpat sit amet quam. */, + bool, +>; +type T9_good = Result< + u32 /* Lorem ipsum dolor sit amet, consectetur adipiscing elit. Etiam */ + /* Lorem ipsum dolor sit amet, consectetur adipiscing elit. Etiam + * diam ac cursus. Aliquam condimentum in erat quis pretium. + * accumsan urna. Cras volutpat sit amet quam. */ + // Lorem ipsum dolor sit amet, consectetur adipiscing elit. Etiam + , + bool, +>; +type T9_good = Result< + u32 /* Lorem ipsum dolor sit amet, consectetur adipiscing elit. Etiam */ + /* Lorem ipsum dolor sit amet, consectetur adipiscing elit. Etiam + * diam ac cursus. Aliquam condimentum in erat quis pretium. + * accumsan urna. Cras volutpat sit amet quam. */, + // Lorem ipsum dolor sit amet, consectetur adipiscing elit. Etiam + bool, +>; + +// Tests with mix one-line and multi-linecomments - multi-line is first +type T10_good = Result< + u32 /* Lorem ipsum dolor sit amet, consectetur adipiscing elit. Etiam + * diam ac cursus. Aliquam condimentum in erat quis pretium. + * accumsan urna. Cras volutpat sit amet quam. */ + // Lorem ipsum dolor sit amet, consectetur adipiscing elit. Etiam + , + bool, +>; +type T11_good = Result< + u32 /* Lorem ipsum dolor sit amet, consectetur adipiscing elit. Etiam + * diam ac cursus. Aliquam condimentum in erat quis pretium. + * accumsan urna. Cras volutpat sit amet quam. */ + /* Lorem ipsum dolor sit amet, consectetur adipiscing elit. Etiam */, + // Lorem ipsum dolor sit amet, consectetur adipiscing elit. Etiam + bool, +>; +type T12_good = Result< + u32 /* Lorem ipsum dolor sit amet, consectetur adipiscing elit. Etiam + * diam ac cursus. Aliquam condimentum in erat quis pretium. + * accumsan urna. Cras volutpat sit amet quam. */ + /* Lorem ipsum dolor sit amet, consectetur adipiscing elit. Etiam */ + // Lorem ipsum dolor sit amet, consectetur adipiscing elit. Etiam + , + bool, +>; +type T12_good = Result< + u32 /* Lorem ipsum dolor sit amet, consectetur adipiscing elit. Etiam + * diam ac cursus. Aliquam condimentum in erat quis pretium. + * accumsan urna. Cras volutpat sit amet quam. */ + /* Lorem ipsum dolor sit amet, consectetur adipiscing elit. Etiam */, + // Lorem ipsum dolor sit amet, consectetur adipiscing elit. Etiam + bool, +>; +type T13_good = Result< + u32 /* Lorem ipsum dolor sit amet, consectetur adipiscing elit. Etiam + * diam ac cursus. Aliquam condimentum in erat quis pretium. + * accumsan urna. */ /*Cras volutpat sit amet quam. */ + /* Lorem ipsum dolor sit amet, consectetur adipiscing elit. Etiam */ + , + bool, +>; + +// Tests with mix one-line and multi-linecomments - +// multi-line is first with newline between comments +type T14_good = Result< + u32 /* Lorem ipsum dolor sit amet, consectetur adipiscing elit. Etiam + * diam ac cursus. Aliquam condimentum in erat quis pretium. + * accumsan urna. Cras volutpat sit amet quam. */ + + /* Lorem ipsum dolor sit amet, consectetur adipiscing elit. Etiam */, + // Lorem ipsum dolor sit amet, consectetur adipiscing elit. Etiam + bool, +>; +type T15_good = Result< + u32 /* Lorem ipsum dolor sit amet, consectetur adipiscing elit. Etiam + * diam ac cursus. Aliquam condimentum in erat quis pretium. + * accumsan urna. Cras volutpat sit amet quam. */ + + + /* Lorem ipsum dolor sit amet, consectetur adipiscing elit. Etiam */ + + // Lorem ipsum dolor sit amet, consectetur adipiscing elit. Etiam + , + bool, +>; + +// Tests with first comment is not in same line of item +type T16_good = Result< + u32 + /* Lorem ipsum dolor sit amet, consectetur adipiscing elit. Etiam */ + /* diam ac cursus. Aliquam condimentum in erat quis pretium. */ + /* accumsan urna. Cras volutpat sit amet quam. */, + bool, +>; +type T17_good = Result< +u32 +/* Lorem ipsum dolor sit amet, consectetur adipiscing elit. Etiam */ +/* diam ac cursus. Aliquam condimentum in erat quis pretium. */ +/* accumsan urna. Cras volutpat sit amet quam. */ +, +bool, +>; +type T18_good = Result< + u32 + /* Lorem ipsum dolor sit amet, consectetur adipiscing elit. Etiam */ + /* diam ac cursus. Aliquam condimentum in erat quis pretium. */, + /* accumsan urna. Cras volutpat sit amet quam. */ + bool, +>; +type T19_good = Result< + u32 + /* Lorem ipsum dolor sit amet, consectetur adipiscing elit. Etiam + * diam ac cursus. Aliquam condimentum in erat quis pretium. + * accumsan urna. Cras volutpat sit amet quam. */, + /* Lorem ipsum dolor sit amet, consectetur adipiscing elit. Etiam */ + // Lorem ipsum dolor sit amet, consectetur adipiscing elit. Etiam + bool, +>; +type T20_good = Result< + u32 + /* Lorem ipsum dolor sit amet, consectetur adipiscing elit. Etiam + * diam ac cursus. Aliquam condimentum in erat quis pretium. + * accumsan urna. Cras volutpat sit amet quam. */ + /* Lorem ipsum dolor sit amet, consectetur adipiscing elit. Etiam */, + // Lorem ipsum dolor sit amet, consectetur adipiscing elit. Etiam + bool, +>; diff --git a/tests/target/issue-3847.rs b/tests/target/issue-3847.rs new file mode 100644 index 00000000000..5a1b3618368 --- /dev/null +++ b/tests/target/issue-3847.rs @@ -0,0 +1,188 @@ +// Tests for multi one-line post-comments of list item +// (related cases when `normalize_comments` is set are already included in other test files). + +// Original cases from issue #3847 +type T1 = Result< + u32, // Lorem ipsum dolor sit amet, consectetur adipiscing elit. Etiam + // diam ac cursus. Aliquam condimentum in erat quis pretium. + // accumsan urna. Cras volutpat sit amet quam. + bool, +>; +type T2 = Result< + u32, // Lorem ipsum dolor sit amet, consectetur adipiscing elit. Etiam + // diam ac cursus. Aliquam condimentum in erat quis pretium. + // accumsan urna. Cras volutpat sit amet quam. + bool, +>; + +// Additional test cases with lists +fn main() { + let a = [ + "GOOD", // Comment1 + // Comment2 + ]; + let b = [ + "WASBAD", // Comment1 + // Comment2 + "CCC", + ]; +} + +// Tests with one multi-line block comment +type T3_good = Result< + u32, /* Lorem ipsum dolor sit amet, consectetur adipiscing elit. Etiam + * diam ac cursus. Aliquam condimentum in erat quis pretium. + * accumsan urna. Cras volutpat sit amet quam. */ + bool, +>; +type T4_good = Result< + u32, /* Lorem ipsum dolor sit amet, consectetur adipiscing elit. Etiam + * diam ac cursus. Aliquam condimentum in erat quis pretium. + * accumsan urna. Cras volutpat sit amet quam. */ + bool, +>; + +fn main() { + let a = [ + "WASGOOD1", /* Comment1 + * Comment2 */ + "WASGOOD2", /* Comment1 + * Comment2 */ + "CCC", + ]; +} + +// Tests with one-line block-comments +type T5_good = Result< + u32, /* Lorem ipsum dolor sit amet, consectetur adipiscing elit. Etiam */ + /* diam ac cursus. Aliquam condimentum in erat quis pretium. */ + /* accumsan urna. Cras volutpat sit amet quam. */ + bool, +>; +type T6_good = Result< + u32, /* Lorem ipsum dolor sit amet, consectetur adipiscing elit. Etiam */ + /* diam ac cursus. Aliquam condimentum in erat quis pretium. */ + /* accumsan urna. Cras volutpat sit amet quam. */ + bool, +>; + +// Tests with mix one-line and multi-linecomments - one-line is first +type T8_good = Result< + u32, // Lorem ipsum dolor sit amet, consectetur adipiscing elit. Etiam + /* Lorem ipsum dolor sit amet, consectetur adipiscing elit. Etiam + * diam ac cursus. Aliquam condimentum in erat quis pretium. + * accumsan urna. Cras volutpat sit amet quam. */ + bool, +>; +type T9_good = Result< + u32, /* Lorem ipsum dolor sit amet, consectetur adipiscing elit. Etiam */ + /* Lorem ipsum dolor sit amet, consectetur adipiscing elit. Etiam + * diam ac cursus. Aliquam condimentum in erat quis pretium. + * accumsan urna. Cras volutpat sit amet quam. */ + // Lorem ipsum dolor sit amet, consectetur adipiscing elit. Etiam + bool, +>; +type T9_good = Result< + u32, /* Lorem ipsum dolor sit amet, consectetur adipiscing elit. Etiam */ + /* Lorem ipsum dolor sit amet, consectetur adipiscing elit. Etiam + * diam ac cursus. Aliquam condimentum in erat quis pretium. + * accumsan urna. Cras volutpat sit amet quam. */ + // Lorem ipsum dolor sit amet, consectetur adipiscing elit. Etiam + bool, +>; + +// Tests with mix one-line and multi-linecomments - multi-line is first +type T10_good = Result< + u32, /* Lorem ipsum dolor sit amet, consectetur adipiscing elit. Etiam + * diam ac cursus. Aliquam condimentum in erat quis pretium. + * accumsan urna. Cras volutpat sit amet quam. */ + // Lorem ipsum dolor sit amet, consectetur adipiscing elit. Etiam + bool, +>; +type T11_good = Result< + u32, /* Lorem ipsum dolor sit amet, consectetur adipiscing elit. Etiam + * diam ac cursus. Aliquam condimentum in erat quis pretium. + * accumsan urna. Cras volutpat sit amet quam. */ + /* Lorem ipsum dolor sit amet, consectetur adipiscing elit. Etiam */ + // Lorem ipsum dolor sit amet, consectetur adipiscing elit. Etiam + bool, +>; +type T12_good = Result< + u32, /* Lorem ipsum dolor sit amet, consectetur adipiscing elit. Etiam + * diam ac cursus. Aliquam condimentum in erat quis pretium. + * accumsan urna. Cras volutpat sit amet quam. */ + /* Lorem ipsum dolor sit amet, consectetur adipiscing elit. Etiam */ + // Lorem ipsum dolor sit amet, consectetur adipiscing elit. Etiam + bool, +>; +type T12_good = Result< + u32, /* Lorem ipsum dolor sit amet, consectetur adipiscing elit. Etiam + * diam ac cursus. Aliquam condimentum in erat quis pretium. + * accumsan urna. Cras volutpat sit amet quam. */ + /* Lorem ipsum dolor sit amet, consectetur adipiscing elit. Etiam */ + // Lorem ipsum dolor sit amet, consectetur adipiscing elit. Etiam + bool, +>; +type T13_good = Result< + u32, /* Lorem ipsum dolor sit amet, consectetur adipiscing elit. Etiam + * diam ac cursus. Aliquam condimentum in erat quis pretium. + * accumsan urna. */ + /*Cras volutpat sit amet quam. */ + /* Lorem ipsum dolor sit amet, consectetur adipiscing elit. Etiam */ + bool, +>; + +// Tests with mix one-line and multi-linecomments - +// multi-line is first with newline between comments +type T14_good = Result< + u32, /* Lorem ipsum dolor sit amet, consectetur adipiscing elit. Etiam + * diam ac cursus. Aliquam condimentum in erat quis pretium. + * accumsan urna. Cras volutpat sit amet quam. */ + /* Lorem ipsum dolor sit amet, consectetur adipiscing elit. Etiam */ + // Lorem ipsum dolor sit amet, consectetur adipiscing elit. Etiam + bool, +>; +type T15_good = Result< + u32, /* Lorem ipsum dolor sit amet, consectetur adipiscing elit. Etiam + * diam ac cursus. Aliquam condimentum in erat quis pretium. + * accumsan urna. Cras volutpat sit amet quam. */ + /* Lorem ipsum dolor sit amet, consectetur adipiscing elit. Etiam */ + // Lorem ipsum dolor sit amet, consectetur adipiscing elit. Etiam + bool, +>; + +// Tests with first comment is not in same line of item +type T16_good = Result< + u32, /* Lorem ipsum dolor sit amet, consectetur adipiscing elit. Etiam */ + /* diam ac cursus. Aliquam condimentum in erat quis pretium. */ + /* accumsan urna. Cras volutpat sit amet quam. */ + bool, +>; +type T17_good = Result< + u32, /* Lorem ipsum dolor sit amet, consectetur adipiscing elit. Etiam */ + /* diam ac cursus. Aliquam condimentum in erat quis pretium. */ + /* accumsan urna. Cras volutpat sit amet quam. */ + bool, +>; +type T18_good = Result< + u32, /* Lorem ipsum dolor sit amet, consectetur adipiscing elit. Etiam */ + /* diam ac cursus. Aliquam condimentum in erat quis pretium. */ + /* accumsan urna. Cras volutpat sit amet quam. */ + bool, +>; +type T19_good = Result< + u32, /* Lorem ipsum dolor sit amet, consectetur adipiscing elit. Etiam + * diam ac cursus. Aliquam condimentum in erat quis pretium. + * accumsan urna. Cras volutpat sit amet quam. */ + /* Lorem ipsum dolor sit amet, consectetur adipiscing elit. Etiam */ + // Lorem ipsum dolor sit amet, consectetur adipiscing elit. Etiam + bool, +>; +type T20_good = Result< + u32, /* Lorem ipsum dolor sit amet, consectetur adipiscing elit. Etiam + * diam ac cursus. Aliquam condimentum in erat quis pretium. + * accumsan urna. Cras volutpat sit amet quam. */ + /* Lorem ipsum dolor sit amet, consectetur adipiscing elit. Etiam */ + // Lorem ipsum dolor sit amet, consectetur adipiscing elit. Etiam + bool, +>;