Skip to content
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

Add lint to check for boolean comparison in assert macro calls #7083

Merged
merged 1 commit into from
Apr 21, 2021

Conversation

GuillaumeGomez
Copy link
Member

@GuillaumeGomez GuillaumeGomez commented Apr 15, 2021

This PR adds a lint to check if an assert macro is using a boolean as "comparison value". For example:

assert_eq!("a".is_empty(), false);

Could be rewritten as:

assert!(!"a".is_empty());

PS: The dev guidelines are amazing. Thanks a lot for writing them!

changelog: Add bool_assert_comparison lint

@rust-highfive
Copy link

r? @camsteffen

(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 15, 2021
@GuillaumeGomez GuillaumeGomez force-pushed the bool-assert-eq branch 2 times, most recently from 3375908 to 3f2c607 Compare April 15, 2021 14:00
@camsteffen
Copy link
Contributor

I'm pretty sure we are moving away from pre-expansion passes. Sorry that that means you need to re-work this to inspect expanded code. We have a util function extract_assert_macro_args to do this with the HIR. But it would be nice to implement this in an early pass (AST).

Tagging @rust-lang/clippy for input on this.

@GuillaumeGomez
Copy link
Member Author

Makes sense. I'll rewrite it then.

@GuillaumeGomez
Copy link
Member Author

Rewrite done. I'm very unhappy with the result though: if any of the macro gets updated, the lint will break. Also, the suggestion now is much worse since I can't simply show the macro arguments... Anyway, at least now it's fully running on early pass and doesn't require macro expansion anymore!

@Manishearth
Copy link
Member

Yeah, that's fine, we have a fair number of lints that do that kind of thing, which is why we have all these desugaring functions in utils. We catch breakages when they happen and update the code; this isn't a huge deal since clippy is shipped with rustc

@GuillaumeGomez GuillaumeGomez force-pushed the bool-assert-eq branch 3 times, most recently from 6b5312b to 1a43e15 Compare April 16, 2021 08:47
@GuillaumeGomez
Copy link
Member Author

CI finally passed! \o/

Copy link
Contributor

@camsteffen camsteffen left a comment

Choose a reason for hiding this comment

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

Not sure what the file /bool_assert_eq is. Probably need to remove.

clippy_lints/src/bool_assert_comparison.rs Outdated Show resolved Hide resolved
clippy_lints/src/bool_assert_comparison.rs Outdated Show resolved Hide resolved
Comment on lines 38 to 48
for mac in macros.iter().chain(inverted_macros.iter()) {
if is_direct_expn_of(e.span, mac).is_some() {
Copy link
Contributor

Choose a reason for hiding this comment

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

You can use the Span from on is_direct_expn_of to lint the entire macro invocation, not just the bool arg. This makes more sense because you are suggesting to use a different macro.

Copy link
Member Author

Choose a reason for hiding this comment

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

Right, now that I don't show the full result anymore, it doesn't make much sense anymore...

Copy link
Contributor

Choose a reason for hiding this comment

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

What do you mean by "the full result"?

Copy link
Member Author

Choose a reason for hiding this comment

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

My suggestion doesn't show anymore what the assert! call should look like since that the snippet span returns the macro "definition" and not the arguments anymore.

Copy link
Contributor

Choose a reason for hiding this comment

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

When you use snippet, you have to use spans that only include the arg passed to the macro. For example, assert_eq!(a, true) will expand to match (&a, &true) { .. }. From that, you need to get the span of just a.

Copy link
Member Author

Choose a reason for hiding this comment

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

It's still not good in case you have more than two arguments. Getting the arguments starting from the third is a nightmare... It was easy to do in the pre_expansion pass, but now it's just trying to go through the macro source code from a token tree.

clippy_lints/src/bool_assert_comparison.rs Show resolved Hide resolved
clippy_lints/src/bool_assert_comparison.rs Outdated Show resolved Hide resolved
clippy_lints/src/bool_assert_comparison.rs Outdated Show resolved Hide resolved
clippy_utils/src/ast_utils.rs Outdated Show resolved Hide resolved
clippy_utils/src/ast_utils.rs Outdated Show resolved Hide resolved
clippy_utils/src/ast_utils.rs Outdated Show resolved Hide resolved
clippy_lints/src/bool_assert_comparison.rs Outdated Show resolved Hide resolved
@GuillaumeGomez GuillaumeGomez force-pushed the bool-assert-eq branch 2 times, most recently from 66f5ecb to 7403737 Compare April 16, 2021 19:45
clippy_utils/src/ast_utils.rs Outdated Show resolved Hide resolved
Comment on lines 38 to 48
for mac in macros.iter().chain(inverted_macros.iter()) {
if is_direct_expn_of(e.span, mac).is_some() {
Copy link
Contributor

Choose a reason for hiding this comment

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

When you use snippet, you have to use spans that only include the arg passed to the macro. For example, assert_eq!(a, true) will expand to match (&a, &true) { .. }. From that, you need to get the span of just a.

clippy_lints/src/bool_assert_comparison.rs Outdated Show resolved Hide resolved
tests/ui/bool_assert_comparison.stderr Outdated Show resolved Hide resolved
clippy_lints/src/bool_assert_comparison.rs Show resolved Hide resolved
clippy_utils/src/ast_utils.rs Outdated Show resolved Hide resolved
@GuillaumeGomez GuillaumeGomez force-pushed the bool-assert-eq branch 3 times, most recently from 4f5e5bc to 6c8e925 Compare April 18, 2021 13:51
@GuillaumeGomez
Copy link
Member Author

Updated!

Copy link
Contributor

@camsteffen camsteffen left a comment

Choose a reason for hiding this comment

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

A couple minor changes and then LGTM! Please squash your commits.

clippy_utils/src/ast_utils.rs Outdated Show resolved Hide resolved
clippy_lints/src/bool_assert_comparison.rs Outdated Show resolved Hide resolved
@GuillaumeGomez
Copy link
Member Author

A couple minor changes and then LGTM! Please squash your commits.

I'd rather keep the first commit if you don't mind. It was more complete (in its suggestion) and it can be used for potential future migrations if anyone needs to do the same (I might haha).

@GuillaumeGomez GuillaumeGomez force-pushed the bool-assert-eq branch 2 times, most recently from aefee1a to 5a54c3f Compare April 19, 2021 12:21
@camsteffen
Copy link
Contributor

I'd rather keep the first commit if you don't mind.

No, I don't see how it would be useful. Pre-expansion passes are going away. Migrating to an early pass will always require re-thinking the implementation. I added a comment to hopefully stop people short of wring pre-exapnsion passes in the future.

@GuillaumeGomez
Copy link
Member Author

Makes me sad but ok. Just waiting for our last discussion to be resolved and then I'll squash.

@GuillaumeGomez
Copy link
Member Author

Removed the support of assert! in the function and squashed the commits.

@camsteffen
Copy link
Contributor

Sorry just thought of one more case that I think is missing: assert_eq!(a!(), expr). One arg is a macro. Should not lint.

@GuillaumeGomez
Copy link
Member Author

a()! isn't evaluated as true or false even if that's the only thing in it. I'll add a test case though. ;)

@GuillaumeGomez
Copy link
Member Author

Ah nevermind! It actually throws an error. Interesting...

@GuillaumeGomez
Copy link
Member Author

Updated!

@GuillaumeGomez
Copy link
Member Author

Is there anything else for me to do in here?

@camsteffen
Copy link
Contributor

Nope! Thanks!

@bors r+

@bors
Copy link
Contributor

bors commented Apr 21, 2021

📌 Commit e2e104b has been approved by camsteffen

@bors
Copy link
Contributor

bors commented Apr 21, 2021

⌛ Testing commit e2e104b with merge 37d2d26...

bors added a commit that referenced this pull request Apr 21, 2021
Add lint to check for boolean comparison in assert macro calls

This PR adds a lint to check if an assert macro is using a boolean as "comparison value". For example:

```rust
assert_eq!("a".is_empty(), false);
```

Could be rewritten as:

```rust
assert!(!"a".is_empty());
```

PS: The dev guidelines are amazing. Thanks a lot for writing them!
@bors
Copy link
Contributor

bors commented Apr 21, 2021

💔 Test failed - checks-action_test

@GuillaumeGomez
Copy link
Member Author

There is a failure because there is a missing "changelog" in the PR body but can't see anything about it in https://github.com/rust-lang/rust-clippy/blob/master/doc/adding_lints.md. If someone has a link or a tip on what I need to update? :)

@camsteffen
Copy link
Contributor

@bors retry

added a changelog line

@bors
Copy link
Contributor

bors commented Apr 21, 2021

⌛ Testing commit e2e104b with merge bbc22e2...

@GuillaumeGomez
Copy link
Member Author

added a changelog line

Thank you!

@bors
Copy link
Contributor

bors commented Apr 21, 2021

☀️ Test successful - checks-action_dev_test, checks-action_remark_test, checks-action_test
Approved by: camsteffen
Pushing bbc22e2 to master...

@bors bors merged commit bbc22e2 into rust-lang:master Apr 21, 2021
@GuillaumeGomez GuillaumeGomez deleted the bool-assert-eq branch April 21, 2021 14:15
@xFrednet
Copy link
Member

Hey, was there a reason why the lint suggestion doesn't snip the non literal expression into the suggested code change? 🙃

@GuillaumeGomez
Copy link
Member Author

If you have an improvement in mind, don't hesitate to send it or at least open an issue with your suggestion.

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.

6 participants