-
Notifications
You must be signed in to change notification settings - Fork 1.6k
Add new lint [manual_checked_sub
]
#14236
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: master
Are you sure you want to change the base?
Conversation
Thanks for the pull request, and welcome! The Rust team is excited to review your changes, and you should hear from @dswij (or someone else) some time within the next two weeks. Please see the contribution instructions for more information. Namely, in order to ensure the minimum review times lag, PR authors and assigned reviewers should ensure that the review label (
|
This comment has been minimized.
This comment has been minimized.
90bb498
to
98b1666
Compare
Manual checked sub
]manual_checked_sub
]
The following code will fail if the proposed fix is applied: if a >= b {
let _ = (a-b)+1;
} |
Thanks for the feedback, i think get what you mean.
which will try to do: |
This comment has been minimized.
This comment has been minimized.
9141494
to
414b39d
Compare
This comment has been minimized.
This comment has been minimized.
414b39d
to
5ef4f44
Compare
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.
Couple nits
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 don't know what to think about the result
name. It seems generic, and moreover it may exist. For example, the suggestion for this code will fail to compile:
let mut result = 0;
if a >= b {
result = a - b;
}
because it will suggest
if let Some(result) = a.checked_sub(b) {
result = result;
}
You should have a look at the output of lintcheck. Most of the suggestions are wrong because of |
Thanks for the comprehensive feedback, I will resolve them all and submit an update.
|
Hope you don't mind since you reviewed this and are now a part of the clippy team :). |
@rustbot author |
This reverts commit ae4d493.
fbaf8ad
to
b1f3340
Compare
There is #11789. It's still held up on other changes right now, but you should at least use the same lint name. |
Thanks for pointing this out, first time seeing this PR. Also I am not quite sure about changing the lint name, as that would significantly expand the scope of this PR that has undergone some initial reviews and iterations. @samueltardieu thoughts? |
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.
After you've handled the review comments, could you please rebase/squash your code into two commits?
- one commit with the new lint
- one commit with the fixes due to this lint in Clippy source code itself
Once the review is satisfactory, I will open a FCP thread on Zulip where we will also discuss the lint name/granularity as mentioned in #14236 (comment).
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 file should be removed
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 file should be removed
|
||
impl<'tcx> LateLintPass<'tcx> for ManualCheckedSub { | ||
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { | ||
if !self.msrv.meets(cx, msrvs::CHECKED_SUB) { |
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.
MSRV checking is more expensive than checking for the presence of an if
expression or the fact that there is an unsigned subtraction, so it should rather be moved at the end of the subsequent if let
check.
if (!matches!(lhs.kind, ExprKind::Lit(_)) && is_mutable(cx, lhs)) | ||
|| (!matches!(rhs.kind, ExprKind::Lit(_)) && is_mutable(cx, rhs)) | ||
{ | ||
return; | ||
} | ||
|
||
// Skip if either lhs or rhs is a macro call | ||
if lhs.span.from_expansion() || rhs.span.from_expansion() { | ||
return; | ||
} | ||
|
||
if let BinOpKind::Ge | BinOpKind::Gt | BinOpKind::Le | BinOpKind::Lt = op.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 checks can probably be merged into the earlier if let
test.
} | ||
|
||
impl SubExprVisitor<'_, '_> { | ||
fn emit_lint(&mut self) { |
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.
fn emit_lint(&mut self) { | |
fn emit_lint(&self) { |
fn is_unsigned_int<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'tcx>) -> bool { | ||
let expr_type = cx.typeck_results().expr_ty(expr).peel_refs(); | ||
if matches!(expr_type.kind(), ty::Uint(_)) { | ||
return true; | ||
} | ||
|
||
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.
You can use the shorter
fn is_unsigned_int<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'tcx>) -> bool { | |
let expr_type = cx.typeck_results().expr_ty(expr).peel_refs(); | |
if matches!(expr_type.kind(), ty::Uint(_)) { | |
return true; | |
} | |
false | |
} | |
fn is_unsigned_int(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { | |
matches!(cx.typeck_results().expr_ty(expr).peel_refs().kind(), ty::Uint(_)) | |
} |
Also, please add tests with references since you seem to need to peel them.
unused_assignments, | ||
unused_mut, | ||
clippy::assign_op_pattern, | ||
clippy::manual_checked_sub |
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'm not sure modifying this test file is needed, as implicit_saturating_sub
requires the modified variable to be mutable, which you filter out.
@@ -1,5 +1,5 @@ | |||
#![allow(clippy::manual_checked_sub)] |
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.
Why is this needed? You should not detect situations like
if a <= b { b - a } else { a - b }
in your lint, or at least you should make sure that it only triggers if manual_abs_diff
doesn't.
#![warn(clippy::manual_abs_diff)] | ||
|
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.
Gratuitous line removal
@@ -0,0 +1,150 @@ | |||
#![allow(clippy::collapsible_if)] | |||
// #![allow(clippy::manual_abs_diff)] |
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 commented out line should be removed
Having multiple lints is a downside on it's own and this case doesn't really gain anything by splitting them up. There are a large number of checked operations for integer types, all of which are clearer to use the For changing the name you don't have to implement all of them in this PR, just leave a note in the docs for which operations are currently handled. |
☔ The latest upstream changes (possibly 7bac114) made this pull request unmergeable. Please resolve the merge conflicts. |
Suggest using checked_sub() instead of manual implementation for basic cases.
Partially fixes #12894
changelog: new lint: [manual_checked_sub]