mirror of https://github.com/astral-sh/ruff
factor out has_parenthesis_between, add some docs
This commit is contained in:
parent
e0b0b54b25
commit
ca5f4cc96f
|
|
@ -835,22 +835,9 @@ impl<'a> Operand<'a> {
|
||||||
Operand::Middle { expression } | Operand::Right { expression, .. } => {
|
Operand::Middle { expression } | Operand::Right { expression, .. } => {
|
||||||
let leading = comments.leading(*expression);
|
let leading = comments.leading(*expression);
|
||||||
if is_expression_parenthesized((*expression).into(), comments.ranges(), source) {
|
if is_expression_parenthesized((*expression).into(), comments.ranges(), source) {
|
||||||
leading.iter().any(|comment| {
|
leading
|
||||||
comment.end() <= expression.start()
|
.iter()
|
||||||
&& !comment.is_formatted()
|
.any(|comment| has_parenthesis_between(comment, expression, source))
|
||||||
&& matches!(
|
|
||||||
SimpleTokenizer::new(
|
|
||||||
source,
|
|
||||||
TextRange::new(comment.end(), expression.start()),
|
|
||||||
)
|
|
||||||
.skip_trivia()
|
|
||||||
.next(),
|
|
||||||
Some(SimpleToken {
|
|
||||||
kind: SimpleTokenKind::LParen,
|
|
||||||
..
|
|
||||||
})
|
|
||||||
)
|
|
||||||
})
|
|
||||||
} else {
|
} else {
|
||||||
!leading.is_empty()
|
!leading.is_empty()
|
||||||
}
|
}
|
||||||
|
|
@ -878,6 +865,53 @@ impl<'a> Operand<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns `true` if a left parenthesis is the first non-trivia token found between `comment` and
|
||||||
|
/// `expression`.
|
||||||
|
///
|
||||||
|
/// This can be used to detect unparenthesized leading comments, for example:
|
||||||
|
///
|
||||||
|
/// ```py
|
||||||
|
/// # leading comment
|
||||||
|
/// (
|
||||||
|
/// expression
|
||||||
|
/// )
|
||||||
|
/// ```
|
||||||
|
fn has_parenthesis_between(comment: &SourceComment, expression: &Expr, source: &str) -> bool {
|
||||||
|
// We adjust the comment placement for unary operators to avoid splitting the operator and its
|
||||||
|
// operand as in:
|
||||||
|
//
|
||||||
|
// ```py
|
||||||
|
// (
|
||||||
|
// not
|
||||||
|
// # comment
|
||||||
|
// True
|
||||||
|
// )
|
||||||
|
// ```
|
||||||
|
//
|
||||||
|
// but making these leading comments means that the comment range falls after the start of the
|
||||||
|
// expression.
|
||||||
|
//
|
||||||
|
// This case can only occur when the comment is after the operator, so it's safe to return
|
||||||
|
// `false` here. The comment will definitely be parenthesized if the the operator is.
|
||||||
|
//
|
||||||
|
// Unary operators are the only known case of this, so `debug_assert!` that it stays that way.
|
||||||
|
debug_assert!(
|
||||||
|
expression.is_unary_op_expr() || comment.end() <= expression.start(),
|
||||||
|
"Expected leading comment to come before its expression",
|
||||||
|
);
|
||||||
|
comment.end() <= expression.start()
|
||||||
|
&& !comment.is_formatted()
|
||||||
|
&& matches!(
|
||||||
|
SimpleTokenizer::new(source, TextRange::new(comment.end(), expression.start()),)
|
||||||
|
.skip_trivia()
|
||||||
|
.next(),
|
||||||
|
Some(SimpleToken {
|
||||||
|
kind: SimpleTokenKind::LParen,
|
||||||
|
..
|
||||||
|
})
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
impl Format<PyFormatContext<'_>> for Operand<'_> {
|
impl Format<PyFormatContext<'_>> for Operand<'_> {
|
||||||
fn fmt(&self, f: &mut Formatter<PyFormatContext<'_>>) -> FormatResult<()> {
|
fn fmt(&self, f: &mut Formatter<PyFormatContext<'_>>) -> FormatResult<()> {
|
||||||
let expression = self.expression();
|
let expression = self.expression();
|
||||||
|
|
@ -923,20 +957,7 @@ impl Format<PyFormatContext<'_>> for Operand<'_> {
|
||||||
let leading_before_parentheses_end = leading
|
let leading_before_parentheses_end = leading
|
||||||
.iter()
|
.iter()
|
||||||
.rposition(|comment| {
|
.rposition(|comment| {
|
||||||
comment.end() <= expression.start()
|
has_parenthesis_between(comment, expression, f.context().source())
|
||||||
&& comment.is_unformatted()
|
|
||||||
&& matches!(
|
|
||||||
SimpleTokenizer::new(
|
|
||||||
f.context().source(),
|
|
||||||
TextRange::new(comment.end(), expression.start()),
|
|
||||||
)
|
|
||||||
.skip_trivia()
|
|
||||||
.next(),
|
|
||||||
Some(SimpleToken {
|
|
||||||
kind: SimpleTokenKind::LParen,
|
|
||||||
..
|
|
||||||
})
|
|
||||||
)
|
|
||||||
})
|
})
|
||||||
.map_or(0, |position| position + 1);
|
.map_or(0, |position| position + 1);
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue