-
Notifications
You must be signed in to change notification settings - Fork 1.5k
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
Modulo arithmetic #4867
Modulo arithmetic #4867
Conversation
Hi! I thought it would be good to add such lint in order to:
|
Hi! Do you want to lint a) modulo on a negative const value or b) modulo on signed integers? |
Well, I guess to lint on both. My first idea was to simply lint all modulo arithmetic, but from your question, I see that it can indeed be done in a more sophisticated way, i.e. no lint on positive const and/or unsigned integers. I'll see what I can do about it. |
An easy thing to do would be linting on |
I had issues with BTW: I see the build failing on the last commit with only changes in comments introduced. This is probably not related to this PR. Additionally, I would like this lint not to warn on const values when both sides are either positive or negative, such as Two more things:
|
There's a rustup in the queue, which means there's likely breakage and you may have to rebase after we merge it. |
You can use functions from the
This code should work: use rustc::ty;
if let ty::Int(_) = cx.tcx.expr_ty(..).kind {
// lint
} |
Thanks for you suggestions. I modified the code not to lint on consts that give predictable results (both operand of the same sign). This applies to both signed integral and floating point types. |
☔ The latest upstream changes (presumably #4889) made this pull request unmergeable. Please resolve the merge conflicts. |
After rebase and fine-tuning the build is finally green :) |
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.
LGTM now. Some nitpicking.
"you are using modulo operator on constants with different signs: `{} % {}`", lhs_negative.1.unwrap(), rhs_negative.1.unwrap() | ||
), | ||
expr.span, | ||
"double check for expected result especially when interoperating with different languages", |
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.
What are your thoughts on also suggesting usage of rem_euclid
or checked_rem_euclid
when the signs are different? Sometime that's what the user intended when performing modulo arithmetic on signed integers and they may not be aware that this method exists.
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.
Well, I myself was not aware that such functions exist :)
Let me check how they relate to the content of this PR.
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.
OK, so I see that wrapping_rem_euclid()
and checked_rem_euclid()
yield results that are consistent with what we can see in Python.
I will add info about these methods in the lint note later today.
Thanks!
BTW: Do I see correctly that these functions are available for integral types only?
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.
Yup these methods are only for integer types so we would only want to suggest these when operating on integers.
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.
Relevant changes are now pushed to the branch.
declare_clippy_lint! { | ||
/// **What it does:** Checks for modulo arithemtic. | ||
/// | ||
/// **Why is this bad?** The results of moudlo (%) operation migth differ |
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.
Hey you have some typos here: modulo
and might
.
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.
Good catch, thanks! Fixed in 6084c53
To be honest, I don't quite like the fragment below (too much repetition) and I would like to merge the match arms. What would be the best way to do it?
|
Regarding my previous comment, I reduced the code duplication by extracting the method, see 56f507b |
☔ The latest upstream changes (presumably #4930) made this pull request unmergeable. Please resolve the merge conflicts. |
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.
Looks great now. Only formatting and using another lint function.
lhs_operand.string_representation.unwrap(), | ||
rhs_operand.string_representation.unwrap() |
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: 1 indentation level too much
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.
Reduced by extracting helper functions: check_const_operands()
and check_non_const_operands()
expr.span, | ||
&format!( | ||
"double check for expected result especially when interoperating with different languages{}", | ||
if lhs_operand.is_integral {" or consider using `rem_euclid` or similar function"} else {""} |
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.
You should use the function
span_lint_and_then(
..,
|db| {
db.note("double check for expected result especially when interoperating with different languages");
if lhs_operand.is_integral {
db.note("or consider using `rem_euclid` or a similar function");
}
},
);
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.
OK, now using span_lint_and_then() and db.note() functions
Looks like I polluted the PR with rebase... I'll try to clean this up, but if that doesn't work I'll close the PR and create a fresh one with only the necessary changes. |
If you want, I can fix it for you real quick. Or you can do it with:
|
@flip1995 I'll be more than grateful if you can fix it if it's not too much hassle. I'm far from being a git wizard and copy&pasting your commands without a full understanding doesn't sound like a great idea. |
Yeah most of the time it isn't. Fixed it :) |
Hey since you have a huge number of commits consider squashing them into a single commit. Not sure what the squash policy of this repository is though so maybe one of the maintainers could chip in. |
tests/ui/modulo_arithmetic.rs
Outdated
@@ -26,7 +26,6 @@ fn main() { | |||
1i16 % -2i16; | |||
-1i32 % 2i32; | |||
1i32 % -2i32; | |||
-1i64 % 2i64; |
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.
Please don't remove test cases to satisfy the linter. You can move the test cases into separate files like so: modulo_arithmetic_integer.rs
and modulo_arithmetic_float.rs
to keep the file sizes within bounds. Having the modulo_arithmetic
prefix or any other prefix in your test case file name ensures that both files are tested by running TESTNAME=modulo_arithmetic cargo uitest
.
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 the hint, didn't know it works that way. I will reintroduce the removed tests.
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.
Done in 8d3efd6
This PR turned out to require many more commits than I initially anticipated. Even though my personal preference is to keep the commits small, let's wait for the maintainers' decision indeed. |
Thanks, LGTM now. We prefer to have less commits. I usually make 2 commits for fixing something: 1 for the fix and 1 for tests. For new lints I usually use 3-5 commits. 1 for the implementation, 1 for tests, 1 for running commands for updating lints, formatting, ... and a few additional commits to fix something if necessary. It would be great if you could squash your commits down to under 10 approximately. |
Due to my previous "messy" operation, there are currently duplicated commits in the PR, for example: How would you recommend progressing with the squash operation in such a scenario? My first idea was just to squash the duplicated commits respectively and create squashed duplicates (which I will further squash into single commit) , but maybe there is a better way... |
I'd recommend to just squash everything in one commit, then |
☔ The latest upstream changes (presumably #4885) made this pull request unmergeable. Please resolve the merge conflicts. |
Code rebased, commits squashed and cleaned-up. |
@bors r=flip1995 |
📌 Commit 5346954 has been approved by |
Modulo arithmetic changelog: Added modulo_arithmetic lint
💔 Test failed - checks-travis |
@bors retry |
Modulo arithmetic changelog: Added modulo_arithmetic lint
💔 Test failed - checks-travis |
You have to fix the warnings regarding |
For some reason, these warnings were reluctant to surface on my local build, but I finally managed to reproduce (and fix) them on the clean repo checkout. |
You probably had to update to the latest rustc master. Thanks! @bors r+ |
📌 Commit a208906 has been approved by |
Modulo arithmetic changelog: Added modulo_arithmetic lint
☀️ Test successful - checks-travis, status-appveyor |
Thank you, I've learned a lot here ;) |
changelog: Added modulo_arithmetic lint