Rewrite placement logic (#6040)

## Summary
This is a rewrite of the main comment placement logic. `place_comment`
now has three parts:

- place own line comments
  - between branches
  - after a branch
- place end-of-line comments
  - after colon
  - after a branch
- place comments for specific nodes (that include module level comments)

The rewrite fixed three bugs: `class A: # trailing comment` comments now
stay end-of-line, `try: # comment` remains end-of-line and deeply
indented try-else-finally comments remain with the right nested
statement.

It will be much easier to give more alternative branches nodes since
this is abstracted away by `is_node_with_body` and the first/last child
helpers. Adding new node types can now be done by adding an entry to the
`place_comment` match. The code went from 1526 lines before #6033 to
1213 lines now.

It thinks it easier to just read the new `placement.rs` rather than
reviewing the diff.

## Test Plan

The existing fixtures staying the same or improving plus new ones for
the bug fixes.
This commit is contained in:
konsti 2023-07-26 18:21:23 +02:00 committed by GitHub
parent 2cf00fee96
commit 13f9a16e33
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
14 changed files with 541 additions and 673 deletions

File diff suppressed because it is too large Load diff

View file

@ -4,18 +4,18 @@ expression: comments.debug(test_case.source_code)
---
{
Node {
kind: StmtExpr,
range: 29..42,
source: `print("test")`,
kind: StmtPass,
range: 12..16,
source: `pass`,
}: {
"leading": [
"leading": [],
"dangling": [],
"trailing": [
SourceComment {
text: "# Test",
position: OwnLine,
formatted: false,
},
],
"dangling": [],
"trailing": [],
},
}

View file

@ -132,14 +132,12 @@ impl FormatNodeRule<ExprSlice> for FormatExprSlice {
let step_leading_comments = comments.leading_comments(step.as_ref());
leading_comments_spacing(f, step_leading_comments)?;
step.format().fmt(f)?;
} else {
if !dangling_step_comments.is_empty() {
// Put the colon and comments on their own lines
write!(
f,
[hard_line_break(), dangling_comments(dangling_step_comments)]
)?;
}
} else if !dangling_step_comments.is_empty() {
// Put the colon and comments on their own lines
write!(
f,
[hard_line_break(), dangling_comments(dangling_step_comments)]
)?;
}
} else {
debug_assert!(step.is_none(), "step can't exist without a second colon");

View file

@ -5,7 +5,6 @@ use crate::prelude::*;
use crate::{FormatNodeRule, PyFormatter};
use ruff_formatter::FormatRuleWithOptions;
use ruff_formatter::{write, Buffer, FormatResult};
use ruff_python_ast::node::AstNode;
use rustpython_ast::ExceptHandlerExceptHandler;
#[derive(Copy, Clone, Default)]
@ -45,7 +44,7 @@ impl FormatNodeRule<ExceptHandlerExceptHandler> for FormatExceptHandlerExceptHan
} = item;
let comments_info = f.context().comments().clone();
let dangling_comments = comments_info.dangling_comments(item.as_any_node_ref());
let dangling_comments = comments_info.dangling_comments(item);
write!(
f,
@ -75,7 +74,7 @@ impl FormatNodeRule<ExceptHandlerExceptHandler> for FormatExceptHandlerExceptHan
[
text(":"),
trailing_comments(dangling_comments),
block_indent(&body.format())
block_indent(&body.format()),
]
)
}

View file

@ -1,6 +1,6 @@
use crate::comments;
use crate::comments::leading_alternate_branch_comments;
use crate::comments::SourceComment;
use crate::comments::{leading_alternate_branch_comments, trailing_comments};
use crate::other::except_handler_except_handler::ExceptHandlerKind;
use crate::prelude::*;
use crate::statement::FormatRefWithRule;
@ -134,8 +134,7 @@ impl Format<PyFormatContext<'_>> for AnyStatementTry<'_> {
let orelse = self.orelse();
let finalbody = self.finalbody();
write!(f, [text("try:"), block_indent(&body.format())])?;
(_, dangling_comments) = format_case("try", body, None, dangling_comments, f)?;
let mut previous_node = body.last();
for handler in handlers {
@ -183,15 +182,18 @@ fn format_case<'a>(
let case_comments_start =
dangling_comments.partition_point(|comment| comment.slice().end() <= last.end());
let (case_comments, rest) = dangling_comments.split_at(case_comments_start);
let partition_point =
case_comments.partition_point(|comment| comment.line_position().is_own_line());
write!(
f,
[leading_alternate_branch_comments(
case_comments,
previous_node
)]
[
leading_alternate_branch_comments(&case_comments[..partition_point], previous_node),
text(name),
text(":"),
trailing_comments(&case_comments[partition_point..]),
block_indent(&body.format())
]
)?;
write!(f, [text(name), text(":"), block_indent(&body.format())])?;
(None, rest)
} else {
(None, dangling_comments)