mirror of
https://github.com/astral-sh/ruff.git
synced 2025-07-24 05:25:17 +00:00
100 lines
2.9 KiB
Rust
100 lines
2.9 KiB
Rust
use crate::comments::Comments;
|
|
use crate::trivia::{first_non_trivia_token, first_non_trivia_token_rev, Token, TokenKind};
|
|
use ruff_python_ast::node::AnyNodeRef;
|
|
use rustpython_parser::ast::Ranged;
|
|
|
|
pub(crate) trait NeedsParentheses {
|
|
fn needs_parentheses(
|
|
&self,
|
|
parenthesize: Parenthesize,
|
|
source: &str,
|
|
comments: &Comments,
|
|
) -> Parentheses;
|
|
}
|
|
|
|
pub(super) fn default_expression_needs_parentheses(
|
|
node: AnyNodeRef,
|
|
parenthesize: Parenthesize,
|
|
source: &str,
|
|
comments: &Comments,
|
|
) -> Parentheses {
|
|
debug_assert!(
|
|
node.is_expression(),
|
|
"Should only be called for expressions"
|
|
);
|
|
|
|
// `Optional` or `Preserve` and expression has parentheses in source code.
|
|
if !parenthesize.is_if_breaks() && is_expression_parenthesized(node, source) {
|
|
Parentheses::Always
|
|
}
|
|
// `Optional` or `IfBreaks`: Add parentheses if the expression doesn't fit on a line but enforce
|
|
// parentheses if the expression has leading comments
|
|
else if !parenthesize.is_preserve() {
|
|
if comments.has_leading_comments(node) {
|
|
Parentheses::Always
|
|
} else {
|
|
Parentheses::Optional
|
|
}
|
|
} else {
|
|
//`Preserve` and expression has no parentheses in the source code
|
|
Parentheses::Never
|
|
}
|
|
}
|
|
|
|
/// Configures if the expression should be parenthesized.
|
|
#[derive(Copy, Clone, Debug, Default)]
|
|
pub enum Parenthesize {
|
|
/// Parenthesize the expression if it has parenthesis in the source.
|
|
#[default]
|
|
Preserve,
|
|
|
|
/// Parenthesizes the expression if it doesn't fit on a line OR if the expression is parenthesized in the source code.
|
|
Optional,
|
|
|
|
/// Parenthesizes the expression only if it doesn't fit on a line.
|
|
IfBreaks,
|
|
}
|
|
|
|
impl Parenthesize {
|
|
const fn is_if_breaks(self) -> bool {
|
|
matches!(self, Parenthesize::IfBreaks)
|
|
}
|
|
|
|
const fn is_preserve(self) -> bool {
|
|
matches!(self, Parenthesize::Preserve)
|
|
}
|
|
}
|
|
|
|
/// Whether it is necessary to add parentheses around an expression.
|
|
/// This is different from [`Parenthesize`] in that it is the resolved representation: It takes into account
|
|
/// whether there are parentheses in the source code or not.
|
|
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
|
|
pub enum Parentheses {
|
|
/// Always create parentheses
|
|
Always,
|
|
|
|
/// Only add parentheses when necessary because the expression breaks over multiple lines.
|
|
Optional,
|
|
|
|
/// Custom handling by the node's formatter implementation
|
|
Custom,
|
|
|
|
/// Never add parentheses
|
|
Never,
|
|
}
|
|
|
|
fn is_expression_parenthesized(expr: AnyNodeRef, contents: &str) -> bool {
|
|
matches!(
|
|
first_non_trivia_token(expr.end(), contents),
|
|
Some(Token {
|
|
kind: TokenKind::RParen,
|
|
..
|
|
})
|
|
) && matches!(
|
|
first_non_trivia_token_rev(expr.start(), contents),
|
|
Some(Token {
|
|
kind: TokenKind::LParen,
|
|
..
|
|
})
|
|
)
|
|
}
|