diff --git a/src/parse/session.rs b/src/parse/session.rs index 05cf467167c..7684b6de8c1 100644 --- a/src/parse/session.rs +++ b/src/parse/session.rs @@ -1,3 +1,4 @@ +use std::ops::Range; use std::path::Path; use std::sync::atomic::{AtomicBool, Ordering}; @@ -237,6 +238,15 @@ impl ParseSess { } } + pub(crate) fn line_bounds(&self, pos: BytePos) -> Option> { + let line = self.raw_psess.source_map().lookup_line(pos).ok(); + + match line { + Some(line_info) => Some(line_info.sf.line_bounds(line_info.line)), + None => None, + } + } + pub(crate) fn line_of_byte_pos(&self, pos: BytePos) -> usize { self.raw_psess.source_map().lookup_char_pos(pos).line } diff --git a/src/visitor.rs b/src/visitor.rs index b08aa35f8f8..b57a49e502f 100644 --- a/src/visitor.rs +++ b/src/visitor.rs @@ -223,6 +223,41 @@ impl<'b, 'a: 'b> FmtVisitor<'a> { self.push_str("{"); self.trim_spaces_after_opening_brace(b, inner_attrs); + // Try to detect comments that refer to the block, not the first statement in the block. + if has_braces && self.config.style_edition() >= StyleEdition::Edition2024 { + let block_line_range = self.psess.lookup_line_range(b.span); + if block_line_range.lo != block_line_range.hi { + // Skipping if a single line block + // Make sure there is no code on the first line we have to worry about. + // That would also be ambiguous: what should `if { /* comment */ statement;` + // even do -- should the comment be attached to the `if` or the `statement`? + // The current logic answers this with "statement". + let first_line_contains_stmt = if let Some(first_stmt) = b.stmts.first() { + self.psess.lookup_line_range(first_stmt.span).lo == block_line_range.lo + } else { + false + }; + if !first_line_contains_stmt { + let first_line_bounds = self.psess.line_bounds(self.last_pos).unwrap(); + let first_line_snip = self + .snippet(mk_sp(self.last_pos, first_line_bounds.end)) + .trim(); + + if contains_comment(first_line_snip) { + if let Ok(comment) = + rewrite_comment(first_line_snip, false, self.shape(), self.config) + { + self.push_str(" "); + self.push_str(&comment); + // This line has no statements, so we can jump to the end of it + // (but *before* the newline). + self.last_pos = first_line_bounds.end - BytePos::from_usize(1); + } + } + } + } + } + // Format inner attributes if available. if let Some(attrs) = inner_attrs { self.visit_attrs(attrs, ast::AttrStyle::Inner); diff --git a/tests/source/issue-3255.rs b/tests/source/issue-3255.rs new file mode 100644 index 00000000000..fc54c0c5996 --- /dev/null +++ b/tests/source/issue-3255.rs @@ -0,0 +1,40 @@ +// rustfmt-style_edition: 2024 + +fn foo(){ + if true { // Sample comment + // second-line comment + 1 + } +} + + +fn foo(){ + if true { + // Sample comment + 1 + } +} + +fn foo(){ + if true { /* Sample comment */ + 1 + } +} + +fn foo(){ + if true { /* Sample + comment */ + 1 + } +} + +// This isn't ideal. +fn foo(){ + if true { /* Sample + * another line + * another line + * end + */ + 1 + } +} diff --git a/tests/target/issue-3255.rs b/tests/target/issue-3255.rs new file mode 100644 index 00000000000..1277a7f3751 --- /dev/null +++ b/tests/target/issue-3255.rs @@ -0,0 +1,39 @@ +// rustfmt-style_edition: 2024 + +fn foo() { + if true { // Sample comment + // second-line comment + 1 + } +} + +fn foo() { + if true { + // Sample comment + 1 + } +} + +fn foo() { + if true { /* Sample comment */ + 1 + } +} + +fn foo() { + if true { /* Sample + comment */ + 1 + } +} + +// This isn't ideal. +fn foo() { + if true { /* Sample + * another line + * another line + * end + */ + 1 + } +}