[pylint] - add fix for unary expressions in PLC2801#9587
[pylint] - add fix for unary expressions in PLC2801#9587MichaReiser merged 7 commits intoastral-sh:mainfrom
pylint] - add fix for unary expressions in PLC2801#9587Conversation
38ee7ae to
5a85f1d
Compare
|
| code | total | + violation | - violation | + fix | - fix |
|---|---|---|---|---|---|
| PLC2801 | 96 | 48 | 0 | 0 | 48 |
5a85f1d to
c1782ce
Compare
|
I see now that the |
|
@diceroll123 - Feel free to change, I won't get to this until tomorrow. |
CodSpeed Performance ReportMerging #9587 will not alter performanceComparing Summary
|
a825cc4 to
c49171c
Compare
MichaReiser
left a comment
There was a problem hiding this comment.
Would it be possible to generalize the fix to correctly handle operator precedence in general. There are some more cases mentioned on the linked Issue that this PR doesn't address.
| if let Some(fixed) = fixed { | ||
| diagnostic.set_fix(Fix::safe_edit(Edit::range_replacement(fixed, call.range()))); | ||
| if let Some(mut fixed) = fixed { | ||
| let is_in_unary = checker |
There was a problem hiding this comment.
The section here could use a comment explaining on why we're doing what we're doing below because it's not immediately obvious what it is about.
| let rparen = | ||
| SimpleTokenizer::starts_at(value.as_ref().end(), checker.locator().contents()) | ||
| .find(|token| { | ||
| token.kind == SimpleTokenKind::RParen && token.start() < call.end() | ||
| }); | ||
|
|
There was a problem hiding this comment.
What happens if we have a.__sub__(((((b)))))?
You can use call.arguments.start (or end) to get the parentheses offsets of the call expression and retain those.
|
|
||
| if let Some(fixed) = fixed { | ||
| diagnostic.set_fix(Fix::safe_edit(Edit::range_replacement(fixed, call.range()))); | ||
| if let Some(mut fixed) = fixed { |
There was a problem hiding this comment.
I wonder if the fix produces invalid code if you have
4.__sub__(
3
+
4
)What i understand is that we fix this to
a -
3
+
4which Python doesn't like very much
| if is_in_unary { | ||
| // find the first ")" before our dunder method | ||
| let rparen = | ||
| SimpleTokenizer::starts_at(value.as_ref().end(), checker.locator().contents()) |
There was a problem hiding this comment.
Can we start after the attribute to reduce the text that need to be searched?
There was a problem hiding this comment.
Can't start after the value in this case.
We're looking for this,
(-a).__sub__(1)
###^
and the difference between
(-a).__sub__(1) and -a.__sub__(1)
It could possibly be optimized another way though, perhaps by checking the tokens between value and the first Dot 🤔
874ef9b to
7f3f81d
Compare
|
Made some tweaks! First and foremost: the fix is marked as unsafe. This could be conditional with more type logic in a future iteration, for sure. The arguments within the dunder method call will now stay in parentheses if it's anything more complex than a literal/name/attribute. I'm sure that logic may be fine to expand into other expression types. So, this example: print(a.__sub__(
3
+
4
))now turns into print(a - (3
+
4
))And since you explicitly asked, print(a.__sub__(((((2 - 1))))))is now reduced to print(a - (2 - 1)) # PLC2801Semantically it's the same, regardless of extra parens. Looking forward to opinions on improving it further! 😄 |
9875f6a to
525ea07
Compare
| let value_slice = checker.locator().slice(value.as_ref()); | ||
| let arg_slice = checker.locator().slice(arg); | ||
|
|
||
| if arg.is_attribute_expr() || arg.is_name_expr() || arg.is_literal_expr() { |
There was a problem hiding this comment.
I think we can exclude some more expressions here
- Calls
- Unary expressions
- Lambda
- If expressions (I think)?
- Dict / Set / List / Tuple and all comprehension variants (everything with parentheses)
- Generators
- Subscripts
- Starred (I think)
- Slices?
There was a problem hiding this comment.
Reworked it, added all of the above except Unary (because that's what got us this PR in the first place hah)
MichaReiser
left a comment
There was a problem hiding this comment.
Sorry for the late review. The uv release took a lot of attention recently.
This is an excellent improvement. I think there are a few more situations where adding the parentheses isn't strictly necessary. You might want to move the logic into its own function to avoid coding it twice.
c73f701 to
c1ffe3f
Compare
c1ffe3f to
b223783
Compare
b223783 to
1a14221
Compare
## Summary Closes astral-sh#9572 Don't go easy on this review! ## Test Plan `cargo test`
Summary
Closes #9572
Don't go easy on this review!
Test Plan
cargo test