Add API to chain comment placement operations (#6319)

## Summary

This PR adds an API for chaining comment placement methods based on the
[`then_with`](https://doc.rust-lang.org/std/cmp/enum.Ordering.html#method.then_with)
from `Ordering` in the standard library.

For example, you can now do:

```rust
try_some_case(comment).then_with(|comment| try_some_other_case_if_still_default(comment))
```

This lets us avoid this kind of pattern, which I've seen in
`placement.rs` and used myself before:

```rust
let comment = match handle_own_line_comment_between_branches(comment, preceding, locator) {
    CommentPlacement::Default(comment) => comment,
    placement => return placement,
};
```
This commit is contained in:
Charlie Marsh 2023-08-03 21:08:50 -04:00 committed by GitHub
parent 9ae498595c
commit d3aa8b4ee0
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 27 additions and 30 deletions

View file

@ -25,24 +25,14 @@ pub(super) fn place_comment<'a>(
) -> CommentPlacement<'a> {
// Handle comments before and after bodies such as the different branches of an if statement.
let comment = if comment.line_position().is_own_line() {
match handle_own_line_comment_around_body(comment, locator) {
CommentPlacement::Default(comment) => comment,
placement => {
return placement;
}
}
handle_own_line_comment_around_body(comment, locator)
} else {
match handle_end_of_line_comment_around_body(comment, locator) {
CommentPlacement::Default(comment) => comment,
placement => {
return placement;
}
}
handle_end_of_line_comment_around_body(comment, locator)
};
// Change comment placement depending on the node type. These can be seen as node-specific
// fixups.
match comment.enclosing_node() {
comment.then_with(|comment| match comment.enclosing_node() {
AnyNodeRef::Parameters(arguments) => {
handle_parameters_separator_comment(comment, arguments, locator)
}
@ -88,7 +78,7 @@ pub(super) fn place_comment<'a>(
}
AnyNodeRef::StmtImportFrom(import_from) => handle_import_from_comment(comment, import_from),
_ => CommentPlacement::Default(comment),
}
})
}
fn handle_end_of_line_comment_around_body<'a>(
@ -275,22 +265,18 @@ fn handle_own_line_comment_around_body<'a>(
}
// Check if we're between bodies and should attach to the following body.
let comment = match handle_own_line_comment_between_branches(comment, preceding, locator) {
CommentPlacement::Default(comment) => comment,
placement => return placement,
};
// Otherwise, there's no following branch or the indentation is too deep, so attach to the
// recursively last statement in the preceding body with the matching indentation.
let comment = match handle_own_line_comment_after_branch(comment, preceding, locator) {
CommentPlacement::Default(comment) => comment,
placement => return placement,
};
// If the following node is the first in its body, and there's a non-trivia token between the
// comment and the following node (like a parenthesis), then it means the comment is trailing
// the preceding node, not leading the following one.
handle_own_line_comment_in_clause(comment, preceding, locator)
handle_own_line_comment_between_branches(comment, preceding, locator)
.then_with(|comment| {
// Otherwise, there's no following branch or the indentation is too deep, so attach to the
// recursively last statement in the preceding body with the matching indentation.
handle_own_line_comment_after_branch(comment, preceding, locator)
})
.then_with(|comment| {
// If the following node is the first in its body, and there's a non-trivia token between the
// comment and the following node (like a parenthesis), then it means the comment is trailing
// the preceding node, not leading the following one.
handle_own_line_comment_in_clause(comment, preceding, locator)
})
}
/// Handles own line comments between two branches of a node.

View file

@ -658,6 +658,17 @@ impl<'a> CommentPlacement<'a> {
comment: comment.into(),
}
}
/// Chains the placement with the given function.
///
/// Returns `self` when the placement is non-[`CommentPlacement::Default`]. Otherwise, calls the
/// function with the comment and returns the result.
pub(super) fn then_with<F: FnOnce(DecoratedComment<'a>) -> Self>(self, f: F) -> Self {
match self {
Self::Default(comment) => f(comment),
_ => self,
}
}
}
#[derive(Copy, Clone, Eq, PartialEq, Debug)]