Skip to content

Conversation

tamaroning
Copy link
Contributor

@tamaroning tamaroning commented Apr 22, 2022

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 into if b { 1 } else { 2 } + 3 even in the case that the expression is in f(expr) or let x = expr; for now.

@rust-highfive
Copy link

r? @Manishearth

(rust-highfive has picked a reviewer for you, use r? to override)

@rust-highfive rust-highfive added the S-waiting-on-review Status: Awaiting review from the assignee but also interested parties label Apr 22, 2022
// See #8724
let a = 0;
let b = true;
0 + if b { 1 } else { 2 };
Copy link
Contributor

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 }
}

@tamaroning
Copy link
Contributor Author

tamaroning commented Apr 22, 2022

Hmm, uitest somehow fails.
Despite of attribute #[allow(clippy::identity_op)], the warning of identity_op occurs.

...
---- compile_test stdout ----
diff of stderr:

+error: the operation is ineffective. Consider reducing it to `i`
error: test failed, to rerun pass '--test compile-test'
+  --> $DIR/without_loop_counters.rs:104:13
+   |
+LL |         dst[i - 0] = src[i];
+   |             ^^^^^
+   |
+   = note: `-D clippy::identity-op` implied by `-D warnings`
+
...

#[allow(clippy::identity_op)]
for i in 0..5 {
dst[i - 0] = src[i];
}

4/23
Updated without_loop_counters test

@tamaroning tamaroning marked this pull request as ready for review April 22, 2022 16:17
Comment on lines 59 to 77
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.

@Manishearth
Copy link
Member

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)

Copy link
Member

@Alexendoo Alexendoo left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👋

Comment on lines 48 to 52
struct ExprVisitor<'a, 'tcx> {
cx: &'a LateContext<'tcx>,
leftmost: bool,
top_level_binop: bool,
}
Copy link
Member

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

Copy link
Contributor Author

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.

Copy link
Member

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

Copy link
Contributor Author

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.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed it.

@giraffate giraffate assigned giraffate and unassigned Manishearth Apr 27, 2022
Comment on lines 75 to 78
// 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
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit

Suggested change
// 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

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks. Fixed it.

Comment on lines +95 to +96
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 };
Copy link
Member

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

Copy link
Contributor Author

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?

Copy link
Member

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

Copy link
Contributor Author

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.

Copy link
Contributor Author

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)]
Copy link
Member

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

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed it.

// 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 {
Copy link
Member

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

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed it.

@Manishearth
Copy link
Member

@bors deletage=Alexendoo

@Manishearth
Copy link
Member

@bors delegate=Alexendoo

@bors
Copy link
Contributor

bors commented Apr 29, 2022

✌️ @Alexendoo can now approve this pull request

@Alexendoo
Copy link
Member

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
@Alexendoo
Copy link
Member

Thanks!

@bors r+

@bors
Copy link
Contributor

bors commented May 2, 2022

📌 Commit 6ad810f has been approved by Alexendoo

bors added a commit that referenced this pull request May 2, 2022
[FP] identity_op in front of if

fix #8724

changelog:
@bors
Copy link
Contributor

bors commented May 2, 2022

⌛ Testing commit 6ad810f with merge 59d7a90...

@bors
Copy link
Contributor

bors commented May 2, 2022

💔 Test failed - checks-action_test

@xFrednet
Copy link
Contributor

xFrednet commented May 2, 2022

Hey, the changelog entry from the PR description is still missing. Could you add one? Then all tests should pass 🙃

@tamaroning
Copy link
Contributor Author

@xFrednet Sorry, could you rerun the test?

@xFrednet
Copy link
Contributor

xFrednet commented May 3, 2022

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

@bors
Copy link
Contributor

bors commented May 3, 2022

⌛ Testing commit 6ad810f with merge 0ceacbe...

@bors
Copy link
Contributor

bors commented May 3, 2022

☀️ Test successful - checks-action_dev_test, checks-action_remark_test, checks-action_test
Approved by: Alexendoo
Pushing 0ceacbe to master...

@bors bors merged commit 0ceacbe into rust-lang:master May 3, 2022
bors added a commit that referenced this pull request May 24, 2022
…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
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
S-waiting-on-review Status: Awaiting review from the assignee but also interested parties
Projects
None yet
Development

Successfully merging this pull request may close these issues.

[FP] identity_op in front of if
8 participants