Fix dangling module comments (#7456)
This commit is contained in:
4
crates/ruff_python_formatter/resources/test/fixtures/ruff/statement/module_comment.py
vendored
Normal file
4
crates/ruff_python_formatter/resources/test/fixtures/ruff/statement/module_comment.py
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
|
||||
|
||||
|
||||
# hehehe >:)a
|
||||
@@ -2,7 +2,7 @@ use std::cmp::Ordering;
|
||||
|
||||
use ruff_python_ast::node::AnyNodeRef;
|
||||
use ruff_python_ast::whitespace::indentation;
|
||||
use ruff_python_ast::{self as ast, Comprehension, Expr, MatchCase, Parameters};
|
||||
use ruff_python_ast::{self as ast, Comprehension, Expr, MatchCase, ModModule, Parameters};
|
||||
use ruff_python_trivia::{
|
||||
find_only_token_in_range, indentation_at_offset, BackwardsTokenizer, CommentRanges,
|
||||
SimpleToken, SimpleTokenKind, SimpleTokenizer,
|
||||
@@ -229,8 +229,12 @@ fn handle_enclosed_comment<'a>(
|
||||
CommentPlacement::Default(comment)
|
||||
}
|
||||
}
|
||||
AnyNodeRef::ModModule(_) => {
|
||||
handle_module_level_own_line_comment_before_class_or_function_comment(comment, locator)
|
||||
AnyNodeRef::ModModule(module) => {
|
||||
handle_trailing_module_comment(module, comment).or_else(|comment| {
|
||||
handle_module_level_own_line_comment_before_class_or_function_comment(
|
||||
comment, locator,
|
||||
)
|
||||
})
|
||||
}
|
||||
AnyNodeRef::WithItem(_) => handle_with_item_comment(comment, locator),
|
||||
AnyNodeRef::PatternMatchSequence(pattern_match_sequence) => {
|
||||
@@ -882,6 +886,35 @@ fn handle_trailing_binary_like_comment<'a>(
|
||||
}
|
||||
}
|
||||
|
||||
/// Handles trailing comments after the last statement in a module.
|
||||
/// Ruff's parser sets the module range to exclude trailing comments and the result is that
|
||||
/// [`CommentPlacement::Default`] makes these comments dangling comments.
|
||||
///
|
||||
/// This method overrides the handling to make these comments trailing comments of the last
|
||||
/// statement instead.
|
||||
///
|
||||
/// ```python
|
||||
/// a
|
||||
///
|
||||
/// # trailing comment
|
||||
/// ```
|
||||
///
|
||||
/// Comments of an all empty module are leading module comments
|
||||
fn handle_trailing_module_comment<'a>(
|
||||
module: &'a ModModule,
|
||||
comment: DecoratedComment<'a>,
|
||||
) -> CommentPlacement<'a> {
|
||||
if comment.preceding_node().is_none() && comment.following_node().is_none() {
|
||||
if let Some(last_statement) = module.body.last() {
|
||||
CommentPlacement::trailing(last_statement, comment)
|
||||
} else {
|
||||
CommentPlacement::leading(comment.enclosing_node(), comment)
|
||||
}
|
||||
} else {
|
||||
CommentPlacement::Default(comment)
|
||||
}
|
||||
}
|
||||
|
||||
/// Handles own line comments on the module level before a class or function statement.
|
||||
/// A comment only becomes the leading comment of a class or function if it isn't separated by an empty
|
||||
/// line from the class. Comments that are separated by at least one empty line from the header of the
|
||||
|
||||
@@ -8,8 +8,7 @@ expression: comments.debug(test_case.source_code)
|
||||
range: 0..0,
|
||||
source: ``,
|
||||
}: {
|
||||
"leading": [],
|
||||
"dangling": [
|
||||
"leading": [
|
||||
SourceComment {
|
||||
text: "# Some comment",
|
||||
position: OwnLine,
|
||||
@@ -21,6 +20,7 @@ expression: comments.debug(test_case.source_code)
|
||||
formatted: false,
|
||||
},
|
||||
],
|
||||
"dangling": [],
|
||||
"trailing": [],
|
||||
},
|
||||
}
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
use ruff_formatter::prelude::hard_line_break;
|
||||
use ruff_formatter::{Buffer, FormatResult};
|
||||
use ruff_formatter::write;
|
||||
use ruff_python_ast::ModModule;
|
||||
|
||||
use crate::comments::{trailing_comments, SourceComment};
|
||||
use crate::comments::SourceComment;
|
||||
use crate::prelude::*;
|
||||
use crate::statement::suite::SuiteKind;
|
||||
use crate::{write, AsFormat, FormatNodeRule, PyFormatter};
|
||||
use crate::FormatNodeRule;
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct FormatModModule;
|
||||
@@ -12,13 +12,11 @@ pub struct FormatModModule;
|
||||
impl FormatNodeRule<ModModule> for FormatModModule {
|
||||
fn fmt_fields(&self, item: &ModModule, f: &mut PyFormatter) -> FormatResult<()> {
|
||||
let ModModule { range: _, body } = item;
|
||||
let comments = f.context().comments().clone();
|
||||
|
||||
write!(
|
||||
f,
|
||||
[
|
||||
body.format().with_options(SuiteKind::TopLevel),
|
||||
trailing_comments(comments.dangling(item)),
|
||||
// Trailing newline at the end of the file
|
||||
hard_line_break()
|
||||
]
|
||||
|
||||
@@ -17,6 +17,7 @@ magic-trailing-comma = Respect
|
||||
```
|
||||
|
||||
```py
|
||||
|
||||
```
|
||||
|
||||
|
||||
@@ -30,6 +31,7 @@ magic-trailing-comma = Respect
|
||||
```
|
||||
|
||||
```py
|
||||
|
||||
```
|
||||
|
||||
|
||||
@@ -43,6 +45,7 @@ magic-trailing-comma = Respect
|
||||
```
|
||||
|
||||
```py
|
||||
|
||||
```
|
||||
|
||||
|
||||
|
||||
@@ -1,31 +1,19 @@
|
||||
---
|
||||
source: crates/ruff_python_formatter/tests/fixtures.rs
|
||||
input_file: crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/whitespace.py
|
||||
input_file: crates/ruff_python_formatter/resources/test/fixtures/ruff/statement/module_comment.py
|
||||
---
|
||||
## Input
|
||||
|
||||
```py
|
||||
|
||||
|
||||
|
||||
# hehehe >:)a
|
||||
```
|
||||
|
||||
## Black Differences
|
||||
|
||||
```diff
|
||||
--- Black
|
||||
+++ Ruff
|
||||
@@ -1 +0,0 @@
|
||||
-
|
||||
```
|
||||
|
||||
## Ruff Output
|
||||
|
||||
## Output
|
||||
```py
|
||||
```
|
||||
|
||||
## Black Output
|
||||
|
||||
```py
|
||||
|
||||
# hehehe >:)a
|
||||
```
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user