Skip to content

Commit 02d81a9

Browse files
committed
Pass parent to NeedsParentheses
1 parent a4d6f9d commit 02d81a9

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

56 files changed

+554
-595
lines changed

crates/ruff/src/rules/ruff/rules/invalid_index_type.rs

+4-1
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,10 @@ pub(crate) fn invalid_index_type(checker: &mut Checker, expr: &ExprSubscript) {
7474

7575
// The value types supported by this rule should always be checkable
7676
let Some(value_type) = CheckableExprType::try_from(value) else {
77-
debug_assert!(false, "Index value must be a checkable type to generate a violation message.");
77+
debug_assert!(
78+
false,
79+
"Index value must be a checkable type to generate a violation message."
80+
);
7881
return;
7982
};
8083

crates/ruff_python_formatter/src/expression/expr_attribute.rs

+21-38
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
1-
use crate::comments::{leading_comments, trailing_comments, Comments};
2-
use crate::expression::parentheses::{
3-
default_expression_needs_parentheses, NeedsParentheses, Parentheses, Parenthesize,
4-
};
1+
use rustpython_parser::ast::{Constant, Expr, ExprAttribute, ExprConstant};
2+
3+
use ruff_formatter::write;
4+
use ruff_python_ast::node::AnyNodeRef;
5+
6+
use crate::comments::{leading_comments, trailing_comments};
7+
use crate::expression::parentheses::{NeedsParentheses, OptionalParentheses, Parentheses};
58
use crate::prelude::*;
69
use crate::FormatNodeRule;
7-
use ruff_formatter::write;
8-
use rustpython_parser::ast::{Constant, Expr, ExprAttribute, ExprConstant};
910

1011
#[derive(Default)]
1112
pub struct FormatExprAttribute;
@@ -35,7 +36,7 @@ impl FormatNodeRule<ExprAttribute> for FormatExprAttribute {
3536
dangling_comments.split_at(leading_attribute_comments_start);
3637

3738
if needs_parentheses {
38-
value.format().with_options(Parenthesize::Always).fmt(f)?;
39+
value.format().with_options(Parentheses::Always).fmt(f)?;
3940
} else if let Expr::Attribute(expr_attribute) = value.as_ref() {
4041
// We're in a attribute chain (`a.b.c`). The outermost node adds parentheses if
4142
// required, the inner ones don't need them so we skip the `Expr` formatting that
@@ -71,41 +72,23 @@ impl FormatNodeRule<ExprAttribute> for FormatExprAttribute {
7172
}
7273
}
7374

74-
/// Checks if there are any own line comments in an attribute chain (a.b.c). This method is
75-
/// recursive up to the innermost expression that the attribute chain starts behind.
76-
fn has_breaking_comments_attribute_chain(
77-
expr_attribute: &ExprAttribute,
78-
comments: &Comments,
79-
) -> bool {
80-
if comments
81-
.dangling_comments(expr_attribute)
82-
.iter()
83-
.any(|comment| comment.line_position().is_own_line())
84-
|| comments.has_trailing_own_line_comments(expr_attribute)
85-
{
86-
return true;
87-
}
88-
89-
if let Expr::Attribute(inner) = expr_attribute.value.as_ref() {
90-
return has_breaking_comments_attribute_chain(inner, comments);
91-
}
92-
93-
return comments.has_trailing_own_line_comments(expr_attribute.value.as_ref());
94-
}
95-
9675
impl NeedsParentheses for ExprAttribute {
9776
fn needs_parentheses(
9877
&self,
99-
parenthesize: Parenthesize,
78+
parent: AnyNodeRef,
10079
context: &PyFormatContext,
101-
) -> Parentheses {
102-
if has_breaking_comments_attribute_chain(self, context.comments()) {
103-
return Parentheses::Always;
104-
}
105-
106-
match default_expression_needs_parentheses(self.into(), parenthesize, context) {
107-
Parentheses::Optional => Parentheses::Never,
108-
parentheses => parentheses,
80+
) -> OptionalParentheses {
81+
// Checks if there are any own line comments in an attribute chain (a.b.c).
82+
if context
83+
.comments()
84+
.dangling_comments(self)
85+
.iter()
86+
.any(|comment| comment.line_position().is_own_line())
87+
|| context.comments().has_trailing_own_line_comments(self)
88+
{
89+
OptionalParentheses::Always
90+
} else {
91+
self.value.needs_parentheses(parent, context)
10992
}
11093
}
11194
}

crates/ruff_python_formatter/src/expression/expr_await.rs

+6-7
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,9 @@
11
use crate::context::PyFormatContext;
2-
use crate::expression::parentheses::{
3-
default_expression_needs_parentheses, NeedsParentheses, Parentheses, Parenthesize,
4-
};
2+
use crate::expression::parentheses::{NeedsParentheses, OptionalParentheses};
53
use crate::{AsFormat, FormatNodeRule, PyFormatter};
64
use ruff_formatter::prelude::{space, text};
75
use ruff_formatter::{write, Buffer, FormatResult};
6+
use ruff_python_ast::node::AnyNodeRef;
87
use rustpython_parser::ast::ExprAwait;
98

109
#[derive(Default)]
@@ -20,9 +19,9 @@ impl FormatNodeRule<ExprAwait> for FormatExprAwait {
2019
impl NeedsParentheses for ExprAwait {
2120
fn needs_parentheses(
2221
&self,
23-
parenthesize: Parenthesize,
24-
context: &PyFormatContext,
25-
) -> Parentheses {
26-
default_expression_needs_parentheses(self.into(), parenthesize, context)
22+
_parent: AnyNodeRef,
23+
_context: &PyFormatContext,
24+
) -> OptionalParentheses {
25+
OptionalParentheses::Multiline
2726
}
2827
}

crates/ruff_python_formatter/src/expression/expr_bin_op.rs

+6-7
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,12 @@
11
use crate::comments::{trailing_comments, trailing_node_comments};
22
use crate::expression::parentheses::{
3-
default_expression_needs_parentheses, in_parentheses_only_group, is_expression_parenthesized,
4-
NeedsParentheses, Parenthesize,
3+
in_parentheses_only_group, is_expression_parenthesized, NeedsParentheses, OptionalParentheses,
54
};
65
use crate::expression::Parentheses;
76
use crate::prelude::*;
87
use crate::FormatNodeRule;
98
use ruff_formatter::{write, FormatOwnedWithRule, FormatRefWithRule, FormatRuleWithOptions};
10-
use ruff_python_ast::node::AstNode;
9+
use ruff_python_ast::node::{AnyNodeRef, AstNode};
1110
use rustpython_parser::ast::{
1211
Constant, Expr, ExprAttribute, ExprBinOp, ExprConstant, ExprUnaryOp, Operator, UnaryOp,
1312
};
@@ -175,9 +174,9 @@ impl FormatRule<Operator, PyFormatContext<'_>> for FormatOperator {
175174
impl NeedsParentheses for ExprBinOp {
176175
fn needs_parentheses(
177176
&self,
178-
parenthesize: Parenthesize,
179-
context: &PyFormatContext,
180-
) -> Parentheses {
181-
default_expression_needs_parentheses(self.into(), parenthesize, context)
177+
_parent: AnyNodeRef,
178+
_context: &PyFormatContext,
179+
) -> OptionalParentheses {
180+
OptionalParentheses::Multiline
182181
}
183182
}

crates/ruff_python_formatter/src/expression/expr_bool_op.rs

+6-6
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
use crate::comments::leading_comments;
22
use crate::expression::parentheses::{
3-
default_expression_needs_parentheses, in_parentheses_only_group, NeedsParentheses, Parentheses,
4-
Parenthesize,
3+
in_parentheses_only_group, NeedsParentheses, OptionalParentheses, Parentheses,
54
};
65
use crate::prelude::*;
76
use ruff_formatter::{write, FormatOwnedWithRule, FormatRefWithRule, FormatRuleWithOptions};
7+
use ruff_python_ast::node::AnyNodeRef;
88
use rustpython_parser::ast::{BoolOp, ExprBoolOp};
99

1010
#[derive(Default)]
@@ -70,10 +70,10 @@ impl FormatNodeRule<ExprBoolOp> for FormatExprBoolOp {
7070
impl NeedsParentheses for ExprBoolOp {
7171
fn needs_parentheses(
7272
&self,
73-
parenthesize: Parenthesize,
74-
context: &PyFormatContext,
75-
) -> Parentheses {
76-
default_expression_needs_parentheses(self.into(), parenthesize, context)
73+
_parent: AnyNodeRef,
74+
_context: &PyFormatContext,
75+
) -> OptionalParentheses {
76+
OptionalParentheses::Multiline
7777
}
7878
}
7979

crates/ruff_python_formatter/src/expression/expr_call.rs

+23-18
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,17 @@
1-
use crate::builders::PyFormatterExtensions;
1+
use ruff_text_size::{TextRange, TextSize};
2+
use rustpython_parser::ast::{Expr, ExprCall, Ranged};
3+
4+
use ruff_formatter::write;
5+
use ruff_python_ast::node::AnyNodeRef;
6+
27
use crate::comments::dangling_comments;
3-
use crate::context::PyFormatContext;
8+
49
use crate::expression::parentheses::{
5-
default_expression_needs_parentheses, parenthesized, NeedsParentheses, Parentheses,
6-
Parenthesize,
10+
parenthesized, NeedsParentheses, OptionalParentheses, Parentheses,
711
};
12+
use crate::prelude::*;
813
use crate::trivia::{SimpleTokenizer, TokenKind};
9-
use crate::{AsFormat, FormatNodeRule, PyFormatter};
10-
use ruff_formatter::prelude::{format_with, group, text};
11-
use ruff_formatter::{write, Buffer, FormatResult};
12-
use ruff_text_size::{TextRange, TextSize};
13-
use rustpython_parser::ast::{Expr, ExprCall, Ranged};
14+
use crate::FormatNodeRule;
1415

1516
#[derive(Default)]
1617
pub struct FormatExprCall;
@@ -52,14 +53,21 @@ impl FormatNodeRule<ExprCall> for FormatExprCall {
5253
[argument] if keywords.is_empty() => {
5354
let parentheses =
5455
if is_single_argument_parenthesized(argument, item.end(), source) {
55-
Parenthesize::Always
56+
Parentheses::Always
5657
} else {
57-
Parenthesize::Never
58+
Parentheses::Never
5859
};
5960
joiner.entry(argument, &argument.format().with_options(parentheses));
6061
}
6162
arguments => {
62-
joiner.nodes(arguments).nodes(keywords.iter());
63+
joiner
64+
.entries(
65+
// We have the parentheses from the call so the arguments never need any
66+
arguments
67+
.iter()
68+
.map(|arg| (arg, arg.format().with_options(Parentheses::Preserve))),
69+
)
70+
.nodes(keywords.iter());
6371
}
6472
}
6573

@@ -100,13 +108,10 @@ impl FormatNodeRule<ExprCall> for FormatExprCall {
100108
impl NeedsParentheses for ExprCall {
101109
fn needs_parentheses(
102110
&self,
103-
parenthesize: Parenthesize,
111+
parent: AnyNodeRef,
104112
context: &PyFormatContext,
105-
) -> Parentheses {
106-
match default_expression_needs_parentheses(self.into(), parenthesize, context) {
107-
Parentheses::Optional => Parentheses::Never,
108-
parentheses => parentheses,
109-
}
113+
) -> OptionalParentheses {
114+
self.func.needs_parentheses(parent, context)
110115
}
111116
}
112117

crates/ruff_python_formatter/src/expression/expr_compare.rs

+6-6
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
use crate::comments::leading_comments;
22
use crate::expression::parentheses::{
3-
default_expression_needs_parentheses, in_parentheses_only_group, NeedsParentheses, Parentheses,
4-
Parenthesize,
3+
in_parentheses_only_group, NeedsParentheses, OptionalParentheses, Parentheses,
54
};
65
use crate::prelude::*;
76
use crate::FormatNodeRule;
87
use ruff_formatter::{write, FormatOwnedWithRule, FormatRefWithRule, FormatRuleWithOptions};
8+
use ruff_python_ast::node::AnyNodeRef;
99
use rustpython_parser::ast::{CmpOp, ExprCompare};
1010

1111
#[derive(Default)]
@@ -73,10 +73,10 @@ impl FormatNodeRule<ExprCompare> for FormatExprCompare {
7373
impl NeedsParentheses for ExprCompare {
7474
fn needs_parentheses(
7575
&self,
76-
parenthesize: Parenthesize,
77-
context: &PyFormatContext,
78-
) -> Parentheses {
79-
default_expression_needs_parentheses(self.into(), parenthesize, context)
76+
_parent: AnyNodeRef,
77+
_context: &PyFormatContext,
78+
) -> OptionalParentheses {
79+
OptionalParentheses::Multiline
8080
}
8181
}
8282

Original file line numberDiff line numberDiff line change
@@ -1,25 +1,17 @@
1-
use crate::expression::parentheses::{
2-
default_expression_needs_parentheses, NeedsParentheses, Parentheses, Parenthesize,
3-
};
4-
use crate::expression::string::{FormatString, StringLayout};
1+
use ruff_text_size::{TextLen, TextRange};
2+
use rustpython_parser::ast::{Constant, ExprConstant, Ranged};
3+
4+
use ruff_formatter::write;
5+
use ruff_python_ast::node::AnyNodeRef;
6+
use ruff_python_ast::str::is_implicit_concatenation;
7+
8+
use crate::expression::parentheses::{NeedsParentheses, OptionalParentheses};
9+
use crate::expression::string::{FormatString, StringPrefix, StringQuotes};
510
use crate::prelude::*;
611
use crate::{not_yet_implemented_custom_text, verbatim_text, FormatNodeRule};
7-
use ruff_formatter::{write, FormatRuleWithOptions};
8-
use rustpython_parser::ast::{Constant, ExprConstant};
912

1013
#[derive(Default)]
11-
pub struct FormatExprConstant {
12-
string_layout: StringLayout,
13-
}
14-
15-
impl FormatRuleWithOptions<ExprConstant, PyFormatContext<'_>> for FormatExprConstant {
16-
type Options = StringLayout;
17-
18-
fn with_options(mut self, options: Self::Options) -> Self {
19-
self.string_layout = options;
20-
self
21-
}
22-
}
14+
pub struct FormatExprConstant;
2315

2416
impl FormatNodeRule<ExprConstant> for FormatExprConstant {
2517
fn fmt_fields(&self, item: &ExprConstant, f: &mut PyFormatter) -> FormatResult<()> {
@@ -39,7 +31,7 @@ impl FormatNodeRule<ExprConstant> for FormatExprConstant {
3931
Constant::Int(_) | Constant::Float(_) | Constant::Complex { .. } => {
4032
write!(f, [verbatim_text(item)])
4133
}
42-
Constant::Str(_) => FormatString::new(item, self.string_layout).fmt(f),
34+
Constant::Str(_) => FormatString::new(item).fmt(f),
4335
Constant::Bytes(_) => {
4436
not_yet_implemented_custom_text(r#"b"NOT_YET_IMPLEMENTED_BYTE_STRING""#).fmt(f)
4537
}
@@ -61,20 +53,32 @@ impl FormatNodeRule<ExprConstant> for FormatExprConstant {
6153
impl NeedsParentheses for ExprConstant {
6254
fn needs_parentheses(
6355
&self,
64-
parenthesize: Parenthesize,
56+
_parent: AnyNodeRef,
6557
context: &PyFormatContext,
66-
) -> Parentheses {
67-
match default_expression_needs_parentheses(self.into(), parenthesize, context) {
68-
Parentheses::Optional if self.value.is_str() && parenthesize.is_if_breaks() => {
69-
// Custom handling that only adds parentheses for implicit concatenated strings.
70-
if parenthesize.is_if_breaks() {
71-
Parentheses::Custom
72-
} else {
73-
Parentheses::Optional
74-
}
58+
) -> OptionalParentheses {
59+
if self.value.is_str() {
60+
let contents = context.locator().slice(self.range());
61+
// Don't wrap triple quoted strings
62+
if is_multiline_string(self, context.source()) || !is_implicit_concatenation(contents) {
63+
OptionalParentheses::Never
64+
} else {
65+
OptionalParentheses::Multiline
7566
}
76-
Parentheses::Optional => Parentheses::Never,
77-
parentheses => parentheses,
67+
} else {
68+
OptionalParentheses::Never
7869
}
7970
}
8071
}
72+
73+
pub(super) fn is_multiline_string(constant: &ExprConstant, source: &str) -> bool {
74+
if constant.value.is_str() {
75+
let contents = &source[constant.range()];
76+
let prefix = StringPrefix::parse(contents);
77+
let quotes =
78+
StringQuotes::parse(&contents[TextRange::new(prefix.text_len(), contents.text_len())]);
79+
80+
quotes.map_or(false, StringQuotes::is_triple) && contents.contains(['\n', '\r'])
81+
} else {
82+
false
83+
}
84+
}

crates/ruff_python_formatter/src/expression/expr_dict.rs

+6-11
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,9 @@
11
use crate::comments::{dangling_node_comments, leading_comments};
2-
use crate::expression::parentheses::{
3-
default_expression_needs_parentheses, parenthesized, NeedsParentheses, Parentheses,
4-
Parenthesize,
5-
};
2+
use crate::expression::parentheses::{parenthesized, NeedsParentheses, OptionalParentheses};
63
use crate::prelude::*;
74
use crate::FormatNodeRule;
85
use ruff_formatter::{format_args, write};
6+
use ruff_python_ast::node::AnyNodeRef;
97
use ruff_text_size::TextRange;
108
use rustpython_parser::ast::Ranged;
119
use rustpython_parser::ast::{Expr, ExprDict};
@@ -99,12 +97,9 @@ impl FormatNodeRule<ExprDict> for FormatExprDict {
9997
impl NeedsParentheses for ExprDict {
10098
fn needs_parentheses(
10199
&self,
102-
parenthesize: Parenthesize,
103-
context: &PyFormatContext,
104-
) -> Parentheses {
105-
match default_expression_needs_parentheses(self.into(), parenthesize, context) {
106-
Parentheses::Optional => Parentheses::Never,
107-
parentheses => parentheses,
108-
}
100+
_parent: AnyNodeRef,
101+
_context: &PyFormatContext,
102+
) -> OptionalParentheses {
103+
OptionalParentheses::Never
109104
}
110105
}

0 commit comments

Comments
 (0)