This commit is contained in:
Dylan 2025-11-16 22:49:15 +08:00 committed by GitHub
commit e880618c5c
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
9 changed files with 367 additions and 10 deletions

View file

@ -294,3 +294,39 @@ if parent_body:
# d
# e
#f
# Compare behavior with `while`/`else` comment placement
if True: pass
# comment
else:
pass
if True:
pass
# comment
else:
pass
if True: pass
# comment
else:
pass
if True: pass
# comment
else:
pass
def foo():
if True:
pass
# comment
else:
pass
if True:
first;second
# comment
else:
pass

View file

@ -28,3 +28,37 @@ while (
and anotherCondition or aThirdCondition # trailing third condition
): # comment
print("Do something")
while True: pass
# comment
else:
pass
while True:
pass
# comment
else:
pass
while True: pass
# comment
else:
pass
while True: pass
# comment
else:
pass
def foo():
while True:
pass
# comment
else:
pass
while True:
first;second
# comment
else:
pass

View file

@ -1042,4 +1042,33 @@ else: # trailing comment
assert_debug_snapshot!(comments.debug(test_case.source_code));
}
#[test]
fn while_else_indented_comment_between_branches() {
let source = r"while True: pass
# comment
else:
pass
";
let test_case = CommentsTestCase::from_code(source);
let comments = test_case.to_comments();
assert_debug_snapshot!(comments.debug(test_case.source_code));
}
#[test]
fn while_else_very_indented_comment_between_branches() {
let source = r"while True:
pass
# comment
else:
pass
";
let test_case = CommentsTestCase::from_code(source);
let comments = test_case.to_comments();
assert_debug_snapshot!(comments.debug(test_case.source_code));
}
}

View file

@ -8,7 +8,7 @@ use ruff_python_trivia::{
find_only_token_in_range, first_non_trivia_token, indentation_at_offset,
};
use ruff_source_file::LineRanges;
use ruff_text_size::{Ranged, TextLen, TextRange};
use ruff_text_size::{Ranged, TextLen, TextRange, TextSize};
use std::cmp::Ordering;
use crate::comments::visitor::{CommentPlacement, DecoratedComment};
@ -602,9 +602,35 @@ fn handle_own_line_comment_between_branches<'a>(
// following branch or if it a trailing comment of the previous body's last statement.
let comment_indentation = comment_indentation_after(preceding, comment.range(), source);
let preceding_indentation = indentation(source, &preceding)
.unwrap_or_default()
.text_len();
let preceding_indentation = indentation(source, &preceding).map_or_else(
// If `indentation` returns `None`, then there is leading
// content before the preceding node. In this case, we
// always treat the comment as being less-indented than the
// preceding. For example:
//
// ```python
// if True: pass
// # leading on `else`
// else:
// pass
// ```
// Note we even do this if the comment is very indented
// (which matches `black`'s behavior as of 2025.11.11)
//
// ```python
// if True: pass
// # leading on `else`
// else:
// pass
// ```
|| {
comment_indentation
// This can be any positive number - we just
// want to hit the `Less` branch below
+ TextSize::new(1)
},
ruff_text_size::TextLen::text_len,
);
// Compare to the last statement in the body
match comment_indentation.cmp(&preceding_indentation) {
@ -678,8 +704,49 @@ fn handle_own_line_comment_after_branch<'a>(
preceding: AnyNodeRef<'a>,
source: &str,
) -> CommentPlacement<'a> {
let Some(last_child) = preceding.last_child_in_body() else {
return CommentPlacement::Default(comment);
// If the preceding node has a body, we want the last child - e.g.
//
// ```python
// if True:
// def foo():
// something
// last_child
// # comment
// else:
// pass
// ```
//
// Otherwise, the preceding node may be the last statement in the body
// of the preceding branch, in which case we can take it as our
// `last_child` here - e.g.
//
// ```python
// if True:
// something
// last_child
// # comment
// else:
// pass
// ```
let last_child = match preceding.last_child_in_body() {
Some(last) => last,
None if matches!(
comment.enclosing_node(),
AnyNodeRef::StmtIf(_)
| AnyNodeRef::StmtWhile(_)
| AnyNodeRef::StmtFor(_)
| AnyNodeRef::StmtMatch(_)
| AnyNodeRef::ElifElseClause(_)
| AnyNodeRef::StmtTry(_)
| AnyNodeRef::MatchCase(_)
| AnyNodeRef::ExceptHandlerExceptHandler(_)
) =>
{
preceding
}
_ => {
return CommentPlacement::Default(comment);
}
};
// We only care about the length because indentations with mixed spaces and tabs are only valid if

View file

@ -0,0 +1,21 @@
---
source: crates/ruff_python_formatter/src/comments/mod.rs
expression: comments.debug(test_case.source_code)
---
{
Node {
kind: StmtWhile,
range: 0..45,
source: `while True: pass⏎`,
}: {
"leading": [],
"dangling": [
SourceComment {
text: "# comment",
position: OwnLine,
formatted: false,
},
],
"trailing": [],
},
}

View file

@ -0,0 +1,21 @@
---
source: crates/ruff_python_formatter/src/comments/mod.rs
expression: comments.debug(test_case.source_code)
---
{
Node {
kind: StmtPass,
range: 16..20,
source: `pass`,
}: {
"leading": [],
"dangling": [],
"trailing": [
SourceComment {
text: "# comment",
position: OwnLine,
formatted: false,
},
],
},
}

View file

@ -1,7 +1,6 @@
---
source: crates/ruff_python_formatter/tests/fixtures.rs
input_file: crates/ruff_python_formatter/resources/test/fixtures/ruff/form_feed.py
snapshot_kind: text
---
## Input
```python
@ -18,7 +17,7 @@ else:
# Regression test for: https://github.com/astral-sh/ruff/issues/7624
if symbol is not None:
request["market"] = market["id"]
# "remaining_volume": "0.0",
# "remaining_volume": "0.0",
else:
pass
```

View file

@ -1,7 +1,6 @@
---
source: crates/ruff_python_formatter/tests/fixtures.rs
input_file: crates/ruff_python_formatter/resources/test/fixtures/ruff/statement/if.py
snapshot_kind: text
---
## Input
```python
@ -301,6 +300,42 @@ if parent_body:
# d
# e
#f
# Compare behavior with `while`/`else` comment placement
if True: pass
# comment
else:
pass
if True:
pass
# comment
else:
pass
if True: pass
# comment
else:
pass
if True: pass
# comment
else:
pass
def foo():
if True:
pass
# comment
else:
pass
if True:
first;second
# comment
else:
pass
```
## Output
@ -607,6 +642,48 @@ if parent_body:
# d
# e
# f
# Compare behavior with `while`/`else` comment placement
if True:
pass
# comment
else:
pass
if True:
pass
# comment
else:
pass
if True:
pass
# comment
else:
pass
if True:
pass
# comment
else:
pass
def foo():
if True:
pass
# comment
else:
pass
if True:
first
second
# comment
else:
pass
```

View file

@ -1,7 +1,6 @@
---
source: crates/ruff_python_formatter/tests/fixtures.rs
input_file: crates/ruff_python_formatter/resources/test/fixtures/ruff/statement/while.py
snapshot_kind: text
---
## Input
```python
@ -35,6 +34,40 @@ while (
and anotherCondition or aThirdCondition # trailing third condition
): # comment
print("Do something")
while True: pass
# comment
else:
pass
while True:
pass
# comment
else:
pass
while True: pass
# comment
else:
pass
while True: pass
# comment
else:
pass
def foo():
while True:
pass
# comment
else:
pass
while True:
first;second
# comment
else:
pass
```
## Output
@ -70,4 +103,44 @@ while (
or aThirdCondition # trailing third condition
): # comment
print("Do something")
while True:
pass
# comment
else:
pass
while True:
pass
# comment
else:
pass
while True:
pass
# comment
else:
pass
while True:
pass
# comment
else:
pass
def foo():
while True:
pass
# comment
else:
pass
while True:
first
second
# comment
else:
pass
```