Skip to content

Commit

Permalink
Treat comments on open parentheses in return annotations as dangling
Browse files Browse the repository at this point in the history
  • Loading branch information
charliermarsh committed Aug 8, 2023
1 parent 833c02b commit 8e4f85e
Show file tree
Hide file tree
Showing 4 changed files with 114 additions and 13 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -371,3 +371,15 @@ def f( # first
# third
):
...

# Handle comments on empty tuple return types.
def zrevrangebylex(self, name: _Key, max: _Value, min: _Value, start: int | None = None, num: int | None = None) -> ( # type: ignore[override]
): pass

def zrevrangebylex(self, name: _Key, max: _Value, min: _Value, start: int | None = None, num: int | None = None) -> ( # type: ignore[override]
# comment
): pass

def zrevrangebylex(self, name: _Key, max: _Value, min: _Value, start: int | None = None, num: int | None = None) -> ( # type: ignore[override]
1
): pass
39 changes: 38 additions & 1 deletion crates/ruff_python_formatter/src/comments/placement.rs
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,10 @@ pub(super) fn place_comment<'a>(
handle_module_level_own_line_comment_before_class_or_function_comment(comment, locator)
}
AnyNodeRef::WithItem(_) => handle_with_item_comment(comment, locator),
AnyNodeRef::StmtFunctionDef(_) => handle_leading_function_with_decorators_comment(comment),
AnyNodeRef::StmtFunctionDef(function_def) => {
handle_leading_function_with_decorators_comment(comment)
.or_else(|comment| handle_leading_returns_comment(comment, function_def))
}
AnyNodeRef::StmtClassDef(class_def) => {
handle_leading_class_with_decorators_comment(comment, class_def)
}
Expand Down Expand Up @@ -879,6 +882,40 @@ fn handle_leading_function_with_decorators_comment(comment: DecoratedComment) ->
}
}

/// Handles end-of-line comments between function parameters and the return type annotation,
/// attaching them as dangling comments to the function instead of making them trailing
/// parameter comments.
///
/// ```python
/// def double(a: int) -> ( # Hello
/// int
/// ):
/// return 2*a
/// ```
fn handle_leading_returns_comment<'a>(
comment: DecoratedComment<'a>,
function_def: &'a ast::StmtFunctionDef,
) -> CommentPlacement<'a> {
let parameters = function_def.parameters.as_ref();
let Some(returns) = function_def.returns.as_deref() else {
return CommentPlacement::Default(comment);
};

let is_preceding_parameters = comment
.preceding_node()
.is_some_and(|node| node == parameters.into());

let is_following_returns = comment
.following_node()
.is_some_and(|node| node == returns.into());

if comment.line_position().is_end_of_line() && is_preceding_parameters && is_following_returns {
CommentPlacement::dangling(comment.enclosing_node(), comment)
} else {
CommentPlacement::Default(comment)
}
}

/// Handle comments between decorators and the decorated node.
///
/// For example, given:
Expand Down
28 changes: 16 additions & 12 deletions crates/ruff_python_formatter/src/statement/stmt_function_def.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use ruff_formatter::write;
use ruff_python_ast::{Ranged, StmtFunctionDef};
use ruff_python_ast::{self as ast, Expr, Ranged, StmtFunctionDef};
use ruff_python_trivia::lines_after_ignoring_trivia;

use crate::comments::{leading_comments, trailing_comments};
Expand Down Expand Up @@ -61,17 +61,17 @@ impl FormatNodeRule<StmtFunctionDef> for FormatStmtFunctionDef {
write!(f, [item.parameters.format()])?;

if let Some(return_annotation) = item.returns.as_ref() {
write!(
f,
[
space(),
text("->"),
space(),
optional_parentheses(
&return_annotation.format().with_options(Parentheses::Never)
)
]
)?;
write!(f, [space(), text("->"), space()])?;
if is_empty_tuple(return_annotation) {
write!(f, [return_annotation.format()])?;
} else {
write!(
f,
[optional_parentheses(
&return_annotation.format().with_options(Parentheses::Never),
)]
)?;
}
}

write!(
Expand All @@ -93,3 +93,7 @@ impl FormatNodeRule<StmtFunctionDef> for FormatStmtFunctionDef {
Ok(())
}
}

fn is_empty_tuple(expr: &Expr) -> bool {
matches!(expr, Expr::Tuple(ast::ExprTuple { elts, .. }) if elts.is_empty())
}
Original file line number Diff line number Diff line change
Expand Up @@ -377,6 +377,18 @@ def f( # first
# third
):
...

# Handle comments on empty tuple return types.
def zrevrangebylex(self, name: _Key, max: _Value, min: _Value, start: int | None = None, num: int | None = None) -> ( # type: ignore[override]
): pass

def zrevrangebylex(self, name: _Key, max: _Value, min: _Value, start: int | None = None, num: int | None = None) -> ( # type: ignore[override]
# comment
): pass

def zrevrangebylex(self, name: _Key, max: _Value, min: _Value, start: int | None = None, num: int | None = None) -> ( # type: ignore[override]
1
): pass
```

## Output
Expand Down Expand Up @@ -902,6 +914,42 @@ def f( # first
/, # second
):
...


# Handle comments on empty tuple return types.
def zrevrangebylex(
self,
name: _Key,
max: _Value,
min: _Value,
start: int | None = None,
num: int | None = None,
) -> (): # type: ignore[override]
pass


def zrevrangebylex(
self,
name: _Key,
max: _Value,
min: _Value,
start: int | None = None,
num: int | None = None,
) -> ( # type: ignore[override]
# comment
):
pass


def zrevrangebylex(
self,
name: _Key,
max: _Value,
min: _Value,
start: int | None = None,
num: int | None = None,
) -> 1: # type: ignore[override]
pass
```


Expand Down

0 comments on commit 8e4f85e

Please sign in to comment.