mirror of
https://github.com/astral-sh/ruff.git
synced 2025-07-23 21:15:19 +00:00
Fix comment formatting for yielded tuples (#6603)
## Summary Closes https://github.com/astral-sh/ruff/issues/6384, although I think the issue was fixed already on main, for the most part. The linked issue is around formatting expressions like: ```python def test(): ( yield #comment 1 * # comment 2 # comment 3 test # comment 4 ) ``` On main, prior to this PR, we now format like: ```python def test(): ( yield ( # comment 1 # comment 2 # comment 3 *test ) # comment 4 ) ``` Which strikes me as reasonable. (We can't test this, since it's a syntax error after for our parser, despite being a syntax error in both cases from CPython's perspective.) Meanwhile, Black does: ```python def test(): ( yield # comment 1 * # comment 2 # comment 3 test # comment 4 ) ``` So our formatting differs in that we move comments between the star and the expression above the star. As of this PR, we also support formatting this input, which is valid: ```python def test(): ( yield #comment 1 * # comment 2 # comment 3 test, # comment 4 1 ) ``` Like: ```python def test(): ( yield ( # comment 1 ( # comment 2 # comment 3 *test, # comment 4 1, ) ) ) ``` There were two fixes here: (1) marking starred comments as dangling and formatting them properly; and (2) supporting parenthesized comments for tuples that don't contain their own parentheses, as is often the case for yielded tuples (previously, we hit a debug assert). Note that this diff ## Test Plan cargo test
This commit is contained in:
parent
7ee2ae8395
commit
12f3c4c931
7 changed files with 88 additions and 21 deletions
|
@ -9,6 +9,7 @@ use ruff_text_size::{TextLen, TextRange};
|
|||
|
||||
use crate::comments::visitor::{CommentPlacement, DecoratedComment};
|
||||
use crate::expression::expr_slice::{assign_comment_in_slice, ExprSliceCommentSection};
|
||||
use crate::expression::expr_tuple::is_tuple_parenthesized;
|
||||
use crate::other::parameters::{
|
||||
assign_argument_separator_comment_placement, find_parameter_separators,
|
||||
};
|
||||
|
@ -185,7 +186,7 @@ fn handle_enclosed_comment<'a>(
|
|||
AnyNodeRef::ExprIfExp(expr_if) => handle_expr_if_comment(comment, expr_if, locator),
|
||||
AnyNodeRef::ExprSlice(expr_slice) => handle_slice_comments(comment, expr_slice, locator),
|
||||
AnyNodeRef::ExprStarred(starred) => {
|
||||
handle_trailing_expression_starred_star_end_of_line_comment(comment, starred)
|
||||
handle_trailing_expression_starred_star_end_of_line_comment(comment, starred, locator)
|
||||
}
|
||||
AnyNodeRef::ExprSubscript(expr_subscript) => {
|
||||
if let Expr::Slice(expr_slice) = expr_subscript.slice.as_ref() {
|
||||
|
@ -217,8 +218,10 @@ fn handle_enclosed_comment<'a>(
|
|||
| AnyNodeRef::ExprGeneratorExp(_)
|
||||
| AnyNodeRef::ExprListComp(_)
|
||||
| AnyNodeRef::ExprSetComp(_)
|
||||
| AnyNodeRef::ExprDictComp(_)
|
||||
| AnyNodeRef::ExprTuple(_) => handle_bracketed_end_of_line_comment(comment, locator),
|
||||
| AnyNodeRef::ExprDictComp(_) => handle_bracketed_end_of_line_comment(comment, locator),
|
||||
AnyNodeRef::ExprTuple(tuple) if is_tuple_parenthesized(tuple, locator.contents()) => {
|
||||
handle_bracketed_end_of_line_comment(comment, locator)
|
||||
}
|
||||
_ => CommentPlacement::Default(comment),
|
||||
}
|
||||
}
|
||||
|
@ -1060,27 +1063,37 @@ fn handle_expr_if_comment<'a>(
|
|||
CommentPlacement::Default(comment)
|
||||
}
|
||||
|
||||
/// Moving
|
||||
/// Handles trailing comments on between the `*` of a starred expression and the
|
||||
/// expression itself. For example, attaches the first two comments here as leading
|
||||
/// comments on the enclosing node, and the third to the `True` node.
|
||||
/// ``` python
|
||||
/// call(
|
||||
/// # Leading starred comment
|
||||
/// * # Trailing star comment
|
||||
/// []
|
||||
/// )
|
||||
/// ```
|
||||
/// to
|
||||
/// ``` python
|
||||
/// call(
|
||||
/// # Leading starred comment
|
||||
/// # Trailing star comment
|
||||
/// * []
|
||||
/// * # dangling end-of-line comment
|
||||
/// # dangling own line comment
|
||||
/// ( # leading comment on the expression
|
||||
/// True
|
||||
/// )
|
||||
/// )
|
||||
/// ```
|
||||
fn handle_trailing_expression_starred_star_end_of_line_comment<'a>(
|
||||
comment: DecoratedComment<'a>,
|
||||
starred: &'a ast::ExprStarred,
|
||||
locator: &Locator,
|
||||
) -> CommentPlacement<'a> {
|
||||
CommentPlacement::leading(starred, comment)
|
||||
if comment.following_node().is_some() {
|
||||
let tokenizer = SimpleTokenizer::new(
|
||||
locator.contents(),
|
||||
TextRange::new(starred.start(), comment.start()),
|
||||
);
|
||||
if !tokenizer
|
||||
.skip_trivia()
|
||||
.any(|token| token.kind() == SimpleTokenKind::LParen)
|
||||
{
|
||||
return CommentPlacement::leading(starred, comment);
|
||||
}
|
||||
}
|
||||
|
||||
CommentPlacement::Default(comment)
|
||||
}
|
||||
|
||||
/// Handles trailing own line comments before the `as` keyword of a with item and
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use ruff_python_ast::ExprStarred;
|
||||
|
||||
use crate::comments::SourceComment;
|
||||
use crate::comments::{dangling_comments, SourceComment};
|
||||
use ruff_formatter::write;
|
||||
use ruff_python_ast::node::AnyNodeRef;
|
||||
|
||||
|
@ -20,7 +20,10 @@ impl FormatNodeRule<ExprStarred> for FormatExprStarred {
|
|||
ctx: _,
|
||||
} = item;
|
||||
|
||||
write!(f, [text("*"), value.format()])
|
||||
let comments = f.context().comments().clone();
|
||||
let dangling = comments.dangling_comments(item);
|
||||
|
||||
write!(f, [text("*"), dangling_comments(dangling), value.format()])
|
||||
}
|
||||
|
||||
fn fmt_dangling_comments(
|
||||
|
|
|
@ -204,7 +204,7 @@ impl NeedsParentheses for ExprTuple {
|
|||
}
|
||||
|
||||
/// Check if a tuple has already had parentheses in the input
|
||||
fn is_tuple_parenthesized(tuple: &ExprTuple, source: &str) -> bool {
|
||||
pub(crate) fn is_tuple_parenthesized(tuple: &ExprTuple, source: &str) -> bool {
|
||||
let Some(elt) = tuple.elts.first() else {
|
||||
return false;
|
||||
};
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue