-
Notifications
You must be signed in to change notification settings - Fork 1.6k
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
[FP] identity_op in front of if #8730
Conversation
r? @Manishearth (rust-highfive has picked a reviewer for you, use r? to override) |
// See #8724 | ||
let a = 0; | ||
let b = true; | ||
0 + if b { 1 } else { 2 }; |
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 would like to see a testcase like let _c = 0 + if b { 1 } else { 2 };
Maybe also a function like I wrote in #8724:
pub fn decide(a: bool, b: bool) -> u32 {
0 + if a { 1 } else { 2 } + if b { 3 } else { 5 }
}
Hmm, uitest somehow fails.
rust-clippy/tests/ui/manual_memcpy/without_loop_counters.rs Lines 102 to 105 in ed22428
4/23 |
clippy_lints/src/identity_op.rs
Outdated
fn reducible_to_right(&mut self, right: &'tcx Expr<'_>) -> bool { | ||
if self.top_level_binop { | ||
true | ||
} else { | ||
!if let ExprKind::If(..) | ExprKind::Match(..) = right.kind { | ||
self.leftmost | ||
} else { | ||
false | ||
} | ||
match cmp.node { | ||
BinOpKind::Add | BinOpKind::BitOr | BinOpKind::BitXor => { | ||
check(cx, left, 0, e.span, right.span); | ||
check(cx, right, 0, e.span, left.span); | ||
}, | ||
BinOpKind::Shl | BinOpKind::Shr | BinOpKind::Sub => check(cx, right, 0, e.span, left.span), | ||
BinOpKind::Mul => { | ||
check(cx, left, 1, e.span, right.span); | ||
check(cx, right, 1, e.span, left.span); | ||
}, | ||
BinOpKind::Div => check(cx, right, 1, e.span, left.span), | ||
BinOpKind::BitAnd => { | ||
check(cx, left, -1, e.span, right.span); | ||
check(cx, right, -1, e.span, left.span); | ||
}, | ||
BinOpKind::Rem => check_remainder(cx, left, right, e.span, left.span), | ||
_ => (), | ||
} | ||
} |
This comment was marked as outdated.
This comment was marked as outdated.
Sorry, something went wrong.
r? @Alexendoo (I'm travelling rn and might not be able to do full reviews, can rubber-stamp after you've had a look at it) |
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.
👋
clippy_lints/src/identity_op.rs
Outdated
struct ExprVisitor<'a, 'tcx> { | ||
cx: &'a LateContext<'tcx>, | ||
leftmost: bool, | ||
top_level_binop: bool, | ||
} |
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 a visitor is too confusing here, e.g. leftmost
is always true by the time it reaches the self.reducible_to_right
calls
A simpler alternative would be to go back to using check_expr
in the lint pass and checking if e
's parent expr is an ExprKind::Binary
to determine if it's top level or not
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 your review. I fixed it.
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 the visitor can be removed entirely, at least for all the test cases leftmost
is still always true in self.reducible_to_right
because the order statements are visited in are
a + b + c + d;
// 1 LLLLLLLLL R
// 2 LLLLL R
// 3 L R
I believe just checking the ExprKind
of right as you do in reducible_to_right
+ is_toplevel_binary
is enough
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.
Ohh I misunderstood what you meant. And it seems to work for test cases.
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.
Fixed it.
clippy_lints/src/identity_op.rs
Outdated
// Checks if `left op ..right` can be actually reduced to `right` | ||
// e.g. `0 + if b { 1 } + else { 2 } + if b { 3 } + else { 4 }` | ||
// cannot be reduced to `if b { 1 } + else { 2 } + if b { 3 } + else { 4 }` | ||
// See #8724 |
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.
nit
// Checks if `left op ..right` can be actually reduced to `right` | |
// e.g. `0 + if b { 1 } + else { 2 } + if b { 3 } + else { 4 }` | |
// cannot be reduced to `if b { 1 } + else { 2 } + if b { 3 } + else { 4 }` | |
// See #8724 | |
/// Checks if `left op ..right` can be actually reduced to `right` | |
/// e.g. `0 + if b { 1 } else { 2 } + if b { 3 } else { 4 }` | |
/// cannot be reduced to `if b { 1 } else { 2 } + if b { 3 } else { 4 }` | |
/// See #8724 |
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. Fixed it.
let _ = 0 + if 0 + 1 > 0 { 1 } else { 2 } + if 0 + 1 > 0 { 3 } else { 4 }; | ||
let _ = 0 + match 0 + 1 { 0 => 10, _ => 20 } + match 0 + 1 { 0 => 30, _ => 40 }; |
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.
There's a false negative in here, in contexts where it's unambiguously an expression it is fine to reduce these, e.g.
let b = true;
f(0 + if b { 1 } else { 2 } + 3);
let _ = 0 + if b { 1 } else { 2 } + 3;
const _: i32 = 0 + if b { 1 } else { 2 } + 3;
Perhaps instead of get_parent_expr
it should be a get_parent_node
, checking the node's variant
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.
But I think it seems to be enough to use get_parent_expr
.
Is there need to check node variants, using get_parent_node
?
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.
Those cases don't lint currently but they could do is what I mean, as in
// doesn't trigger the lint
f(0 + if b { 1 } else { 2 } + 3);
// but it could, as the following is valid
f(if b { 1 } else { 2 } + 3);
It'd be also fine to leave it as is and make a note of that under a Known problems
section in the lint description
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 didn't aware of this case. I will leave it as it is and add documents.
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.
Added documents
@@ -99,7 +100,6 @@ pub fn manual_copy(src: &[i32], dst: &mut [i32], dst2: &mut [i32]) { | |||
dst[i] = src[i - from]; | |||
} | |||
|
|||
#[allow(clippy::identity_op)] |
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.
nit: can move this back now
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.
Fixed it.
clippy_lints/src/identity_op.rs
Outdated
// cannot be reduced to `if b { 1 } + else { 2 } + if b { 3 } + else { 4 }` | ||
// See #8724 | ||
fn reducible_to_right(cx: &LateContext<'_>, binary: &Expr<'_>, right: &Expr<'_>) -> bool { | ||
if let ExprKind::If(..) | ExprKind::Match(..) = right.kind { |
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.
Can also include ExprKind::Block
and ExprKind::Loop
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.
Fixed it.
@bors deletage=Alexendoo |
@bors delegate=Alexendoo |
✌️ @Alexendoo can now approve this pull request |
Thanks @tamaroning! Changes look good, please could you squash your commits into one with a descriptive message and then it'll be good to go |
fix Update identity_op.rs ok update without_loop_counters test chore fix chore remove visitor and leftmost fix add document
Thanks! @bors r+ |
📌 Commit 6ad810f has been approved by |
[FP] identity_op in front of if fix #8724 changelog:
💔 Test failed - checks-action_test |
Hey, the changelog entry from the PR description is still missing. Could you add one? Then all tests should pass 🙃 |
@xFrednet Sorry, could you rerun the test? |
No problem @tamaroning, usually I would edit the changelog entry myself if it's the last thing, but here I wasn't sure anymore how it was exactly fixed. 🙃 Thank you for the changes 👍 @bors retry |
☀️ Test successful - checks-action_dev_test, checks-action_remark_test, checks-action_test |
…dnet `identity_op`: add parenthesis to suggestions where required changelog: [`identity_op`]: add parenthesis to suggestions where required Follow up to #8730, wraps the cases we can't lint as-is in parenthesis rather than ignoring them Catches a couple new FPs with mixed operator precedences and `as` casts ```rust // such as 0 + { a } * 2; 0 + a as usize; ``` The suggestions are now applied using `span_lint_and_sugg` rather than appearing in just the message and have a `run-rustfix` test
fix #8724
changelog: FP: [
identity_op
]: is now allowed in front of if statements, blocks and other expressions where the suggestion would be invalid.Resolved simular problems with blocks, mathces, and loops.
identity_op always does NOT suggest reducing
0 + if b { 1 } else { 2 } + 3
intoif b { 1 } else { 2 } + 3
even in the case that the expression is inf(expr)
orlet x = expr;
for now.