mirror of
https://github.com/astral-sh/ruff.git
synced 2025-09-27 20:42:10 +00:00
Format Attribute Expression (#5259)
This commit is contained in:
parent
341b12d918
commit
ccf34aae8c
20 changed files with 394 additions and 329 deletions
|
@ -1,9 +1,9 @@
|
|||
use crate::comments::Comments;
|
||||
use crate::comments::{leading_comments, trailing_comments, Comments};
|
||||
use crate::expression::parentheses::{
|
||||
default_expression_needs_parentheses, NeedsParentheses, Parentheses, Parenthesize,
|
||||
};
|
||||
use crate::prelude::*;
|
||||
use crate::{not_yet_implemented_custom_text, FormatNodeRule};
|
||||
use crate::FormatNodeRule;
|
||||
use ruff_formatter::write;
|
||||
use rustpython_parser::ast::{Constant, Expr, ExprAttribute, ExprConstant};
|
||||
|
||||
|
@ -15,11 +15,11 @@ impl FormatNodeRule<ExprAttribute> for FormatExprAttribute {
|
|||
let ExprAttribute {
|
||||
value,
|
||||
range: _,
|
||||
attr: _,
|
||||
attr,
|
||||
ctx: _,
|
||||
} = item;
|
||||
|
||||
let requires_space = matches!(
|
||||
let needs_parentheses = matches!(
|
||||
value.as_ref(),
|
||||
Expr::Constant(ExprConstant {
|
||||
value: Constant::Int(_) | Constant::Float(_),
|
||||
|
@ -27,16 +27,45 @@ impl FormatNodeRule<ExprAttribute> for FormatExprAttribute {
|
|||
})
|
||||
);
|
||||
|
||||
if needs_parentheses {
|
||||
value.format().with_options(Parenthesize::Always).fmt(f)?;
|
||||
} else {
|
||||
value.format().fmt(f)?;
|
||||
}
|
||||
|
||||
let comments = f.context().comments().clone();
|
||||
|
||||
if comments.has_trailing_own_line_comments(value.as_ref()) {
|
||||
hard_line_break().fmt(f)?;
|
||||
}
|
||||
|
||||
let dangling_comments = comments.dangling_comments(item);
|
||||
|
||||
let leading_attribute_comments_start =
|
||||
dangling_comments.partition_point(|comment| comment.line_position().is_end_of_line());
|
||||
let (trailing_dot_comments, leading_attribute_comments) =
|
||||
dangling_comments.split_at(leading_attribute_comments_start);
|
||||
|
||||
write!(
|
||||
f,
|
||||
[
|
||||
item.value.format(),
|
||||
requires_space.then_some(space()),
|
||||
text("."),
|
||||
not_yet_implemented_custom_text("NOT_IMPLEMENTED_attr")
|
||||
trailing_comments(trailing_dot_comments),
|
||||
(!leading_attribute_comments.is_empty()).then_some(hard_line_break()),
|
||||
leading_comments(leading_attribute_comments),
|
||||
attr.format()
|
||||
]
|
||||
)
|
||||
}
|
||||
|
||||
fn fmt_dangling_comments(
|
||||
&self,
|
||||
_node: &ExprAttribute,
|
||||
_f: &mut PyFormatter,
|
||||
) -> FormatResult<()> {
|
||||
// handle in `fmt_fields`
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl NeedsParentheses for ExprAttribute {
|
||||
|
@ -46,6 +75,9 @@ impl NeedsParentheses for ExprAttribute {
|
|||
source: &str,
|
||||
comments: &Comments,
|
||||
) -> Parentheses {
|
||||
default_expression_needs_parentheses(self.into(), parenthesize, source, comments)
|
||||
match default_expression_needs_parentheses(self.into(), parenthesize, source, comments) {
|
||||
Parentheses::Optional => Parentheses::Never,
|
||||
parentheses => parentheses,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -23,8 +23,12 @@ pub(super) fn default_expression_needs_parentheses(
|
|||
"Should only be called for expressions"
|
||||
);
|
||||
|
||||
#[allow(clippy::if_same_then_else)]
|
||||
if parenthesize.is_always() {
|
||||
Parentheses::Always
|
||||
}
|
||||
// `Optional` or `Preserve` and expression has parentheses in source code.
|
||||
if !parenthesize.is_if_breaks() && is_expression_parenthesized(node, source) {
|
||||
else 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
|
||||
|
@ -53,9 +57,15 @@ pub enum Parenthesize {
|
|||
|
||||
/// Parenthesizes the expression only if it doesn't fit on a line.
|
||||
IfBreaks,
|
||||
|
||||
Always,
|
||||
}
|
||||
|
||||
impl Parenthesize {
|
||||
pub(crate) const fn is_always(self) -> bool {
|
||||
matches!(self, Parenthesize::Always)
|
||||
}
|
||||
|
||||
pub(crate) const fn is_if_breaks(self) -> bool {
|
||||
matches!(self, Parenthesize::IfBreaks)
|
||||
}
|
||||
|
@ -70,7 +80,8 @@ impl Parenthesize {
|
|||
/// whether there are parentheses in the source code or not.
|
||||
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
|
||||
pub enum Parentheses {
|
||||
/// Always create parentheses
|
||||
/// Always set parentheses regardless if the expression breaks or if they were
|
||||
/// present in the source.
|
||||
Always,
|
||||
|
||||
/// Only add parentheses when necessary because the expression breaks over multiple lines.
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue