Skip to content

Commit

Permalink
prevent unnecessary indent when formatting doc comment code snippets
Browse files Browse the repository at this point in the history
Fixes 5623

When formatting code snippets in doc comments, we start by wrapping the
content of the code block in an `fn main(){}` and add indentation. We do
this because we're about to create an internal rustfmt `Session` that
will try to parse the input snippet as a crate. In order for that
operation to succeed the snippet can only contain top level items like
function definitions.

To illustrate the transformation, assume we're starting with the following
doc comment:

```rust
//! ```rust
//! let x =       "hello world!";
//! ```
```

After the transformation rustfmt will actually try to format this:

```rust
fn main() {
    let x =       "hello world!";
}
```

It turns out that during the transformation described above, we sometimes
add indentation to empty lines. This normally isn't an issue because
rustfmt removes the redundant indentation while reformatting, but in the
event a user adds an inner `#![rustfmt::skip]` attribute to their doc
comment snippet the inner attribute will be applied to the `fn main(){}`
and we'll leave the erroneous indentation in place.

So this is what rustfmt will try to reformat:

```rust
fn main() {
    #![rustfmt::skip]
    // ... the rest of the doc comment snippet
}
```

To prevent this issue entirely we won't add indentation to any line
that is empty or only contains whitespace.
  • Loading branch information
ytmimi committed Jan 29, 2024
1 parent 7bedb9f commit 649f69c
Show file tree
Hide file tree
Showing 2 changed files with 15 additions and 2 deletions.
8 changes: 6 additions & 2 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -352,10 +352,14 @@ fn format_code_block(
result.push_str(FN_MAIN_PREFIX);
let mut need_indent = true;
for (kind, line) in LineClasses::new(s) {
if need_indent {
let not_empty = !line.trim().is_empty();
// Only add indentation if the current line isn't empty
if need_indent && not_empty {
result.push_str(&indent.to_string(config));
}
result.push_str(&line);
if not_empty {
result.push_str(&line);
}
result.push('\n');
need_indent = indent_next_line(kind, &line, config);
}
Expand Down
9 changes: 9 additions & 0 deletions tests/target/issue_5623.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
// rustfmt-format_code_in_doc_comments: true

/// ```
/// #![rustfmt::skip]
/// use core::primitive;
///
/// let y = 0;
/// ```
fn main() {}

0 comments on commit 649f69c

Please sign in to comment.