-
Notifications
You must be signed in to change notification settings - Fork 1.3k
[refurb
] Unsafe fixes in FURB161
#17240
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for looking into this. Could you update the rule's documentation with a ## Fif safety
header and explain when the fix is safe (or isn't)? This will also make reviewing easier
This PR doesn’t fully fix #16457. The point of that issue is that FURB161 should be unsafe by default, with a few exceptions. This PR keeps it safe by default, the only exception being string literals. |
Thanks for the explanation. I approved the modification to make the rule unsafe if we can not determine if the argument of the |
Using |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for working on this! Overall I think this is good, but we can simplify things a bit by using a fix Applicability
, and then I think we can do a better job with type inference with ResolvedPythonType::from
, specifically for Expr::BinOp
(cases like 1 + 2
) and for Expr::UnOp
(cases like -1
).
If we extend the safe handling to bool
, we may also be able to resolve expressions like True or False
.
/// ## Fix safety | ||
/// This rule's fix is marked as unsafe, as the `bit_count()` method can be used when the argument | ||
/// to the `bin()` is an instance of a type that implements the `__index__` and `bit_count` methods. | ||
/// |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We also want to say explicitly when it is safe, since it's not always unsafe. Maybe something like this?
/// ## Fix safety | |
/// This rule's fix is marked as unsafe, as the `bit_count()` method can be used when the argument | |
/// to the `bin()` is an instance of a type that implements the `__index__` and `bit_count` methods. | |
/// | |
/// ## Fix safety | |
/// This rule's fix is marked as unsafe unless the argument to `bin` can be inferred as | |
/// an instance of a type that implements the `__index__` and `bit_count` methods. | |
/// |
I think we could also possibly drop the mention of __index__
since we're always just calling bit_count
right? Based on my reading of the __index__
docs, it's actually a requirement for calling bin
itself rather than a requirement to call bit_count
as seems more relevant here.
// it. | ||
let parenthesize = match arg { | ||
// it. Moreover, we check if the fix is safe. | ||
let (parenthesize, fix_is_safe): (bool, bool) = match arg { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think instead of returning a second bool
here, you can just return an Applicability
and use that with Fix::applicable_edit
instead of branching on fix_is_safe
down below.
@@ -160,7 +166,7 @@ pub(crate) fn bit_count(checker: &Checker, call: &ExprCall) { | |||
| Expr::NoneLiteral(_) | |||
| Expr::EllipsisLiteral(_) | |||
| Expr::Attribute(_) | |||
| Expr::Subscript(_) => false, | |||
| Expr::Subscript(_) => (false, false), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I can't highlight the line directly, but I think Expr::BooleanLiteral
should also allow a safe edit, at least that's what it sounds like from the issue.
@@ -12,7 +12,7 @@ FURB161.py:6:9: FURB161 [*] Use of `bin(x).count('1')` | |||
| | |||
= help: Replace with `(x).bit_count()` | |||
|
|||
ℹ Safe fix | |||
ℹ Unsafe fix |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is a separate issue from the changes here, but I don't think Expr::Name
s need to be parenthesized. Let's not modify this here, but I'm surprised to see (x).bit_count
instead of x.bit_count
.
@@ -116,7 +116,7 @@ FURB161.py:11:9: FURB161 [*] Use of `bin(0x10 + 0x1000).count('1')` | |||
| | |||
= help: Replace with `(0x10 + 0x1000).bit_count()` | |||
|
|||
ℹ Safe fix | |||
ℹ Unsafe fix |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This one is also a bit unfortunate because this is obviously an integer. I think this would be helped by ResolvedPythonType::from
as @dscorbett suggested.
The PR fixes #16457 .
Specifically,
FURB161
is marked safe, but the rule generates safe fixes only in specific cases. Therefore, we attempt to mark the fix as unsafe when we are not in one of these cases.For instances, the fix is marked as aunsafe just in case of strings (as pointed out in the issue). Let me know if I should change something.