-
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
Unnecessary call to min/max method #12368
Conversation
Thanks for the pull request, and welcome! The Rust team is excited to review your changes, and you should hear from @Alexendoo (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 (
|
☔ The latest upstream changes (presumably #12508) made this pull request unmergeable. Please resolve the merge conflicts. |
match (ty.kind(), cv) { | ||
(&ty::Uint(_), Constant::Int(0)) => Some(Extrema::Minimum), | ||
(&ty::Int(ity), Constant::Int(i)) if i == unsext(cx.tcx, i128::MIN >> (128 - int_bits(cx.tcx, ity)), ity) => { | ||
Some(Extrema::Minimum) | ||
}, | ||
|
||
(&ty::Int(ity), Constant::Int(i)) if i == unsext(cx.tcx, i128::MAX >> (128 - int_bits(cx.tcx, ity)), ity) => { | ||
Some(Extrema::Maximum) | ||
}, | ||
(&ty::Uint(uty), Constant::Int(i)) if i == clip(cx.tcx, u128::MAX, uty) => Some(Extrema::Maximum), | ||
|
||
_ => None, | ||
} |
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.
unsext
/clip
/int_bits
handle usize
/isize
but for this lint we wouldn't want that (excluding 0usize
) to ensure x.min(i32::MAX as isize)
doesn't lint on 32 bit targets
cv.int_value(...)?
could replace the unsext
s with ity/uty.bit_width()
instead of int_bits
to exclude *size
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.
ensure x.min(i32::MAX as isize) doesn't lint on 32 bit targets
I don't really understand this. If x is of i32, it shouldn't be able to be compared to i32::MAX as isize
?
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.
In that example it would be that x
is an isize
, it wasn't a reference to the existing i32
x
in the test file
5d840b6
to
2a22b1c
Compare
tests/ui/unnecessary_min_max.fixed
Outdated
min = min.min(random_u32()); | ||
} | ||
|
||
let _ = (u32::MIN as isize).min(42); |
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.
An implementation detail of constant
but I don't think it handles as
casts, you'd need to either put these in a const
or inline the value as e.g. 2147483647isize
with a comment
} | ||
|
||
fn lint(cx: &LateContext<'_>, expr: &Expr<'_>, name: &str, lhs: Span, rhs: Span, order: Ordering) { | ||
let cmp_str = if (name == "min" && order.is_ge()) || (name == "max" && order.is_ge()) { |
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 believe this can be
let cmp_str = if (name == "min" && order.is_ge()) || (name == "max" && order.is_ge()) { | |
let cmp_str = if order.is_ge() { |
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.
With that & squashed commits I think we're good to go
894ea82
to
961adc9
Compare
882f85b
to
7a091b3
Compare
☔ The latest upstream changes (presumably #12631) made this pull request unmergeable. Please resolve the merge conflicts. |
5160ac7
to
d7d6b41
Compare
b4b77cd
to
2a688ad
Compare
fn is_external_const(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { | ||
let ExprKind::Path(ref qpath) = expr.kind else { | ||
return false; | ||
}; | ||
|
||
let Some(def_id) = cx.qpath_res(qpath, expr.hir_id()).opt_def_id() else { | ||
return false; | ||
}; | ||
!def_id.is_local() | ||
} |
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 won't catch some indirect usage, e.g. EXTERNAL_CONST + 1
. You can use constant_with_source
but it doesn't currently track if the constant is local or not. That's probably fine though as the same logic of it may only happen to be 0
applies to local constants equally
A good addition would be to have the const evaluation distinguish consts in core
, it would be a shame to lose those
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 agree. A significant purpose of this lint rule is to detect incorrect usage of i32::MIN. I will see what I can do here.
fc2d35c
to
f446e4e
Compare
clippy_utils/src/consts.rs
Outdated
/// Simple constant folding to determine if an expression depends on an external crate | ||
/// excluding crates listed in exceptions | ||
pub fn expr_is_external(&mut self, e: &Expr<'_>, exceptions: &[Symbol]) -> 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.
Let's add a new variant and check it in expr
/fetch_path_and_apply
rather than revisiting after the fact. It can be just specific to core
as that's all we're using it for currently. ConstantSource::CoreConstant
or similar
9d33968
to
31f5010
Compare
☔ The latest upstream changes (presumably #12567) made this pull request unmergeable. Please resolve the merge conflicts. |
clippy_utils/src/consts.rs
Outdated
/// The value is dependent on a constant defined in current crate of `core` crate. | ||
LocalOrCoreCrateConstant, |
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.
Let's keep it just core constants, local ones may have "arbitrary" values just as remote ones do while the ones in core are pretty straight forward
clippy_config/src/conf.rs
Outdated
/// Lint: UNNECESSARY_MIN_OR_MAX. | ||
/// | ||
/// Whether to also run the lints on external defined consts. | ||
(allowed_external_crates: bool = 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.
I think it would be fine to have no config, it seems like it would be very rare that an external crate would redefine a constant to be MIN/MAX in a way that the user wants to trigger the lint
31f5010
to
e0f3cfb
Compare
☔ The latest upstream changes (presumably #12815) made this pull request unmergeable. Please resolve the merge conflicts. |
There are merge commits (commits with multiple parents) in your changes. We have a no merge policy so these commits will need to be removed for this pull request to be merged. You can start a rebase with the following commands:
The following commits are merge commits: |
aa83de2
to
0bd0af2
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.
Sorry I forgot to press submit review and left this as pending 😅
clippy_utils/src/consts.rs
Outdated
this.source = if is_core_crate { | ||
ConstantSource::CoreConstant | ||
} else { | ||
ConstantSource::Constant | ||
}; |
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.
If source
is already Constant
we wouldn't want to override it with CoreConstant
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.
Sorry for taking so long to come back to this 🙇 I have pushed the new changes, could you give it another go?
☔ The latest upstream changes (presumably #12287) made this pull request unmergeable. Please resolve the merge conflicts. |
141c346
to
e9501b8
Compare
if let ( | ||
Some((left, ConstantSource::Local | ConstantSource::CoreConstant)), | ||
Some((right, ConstantSource::Local | ConstantSource::CoreConstant)), | ||
) = ( | ||
constant_with_source(cx, typeck_results, recv), | ||
constant_with_source(cx, typeck_results, arg), | ||
) { |
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.
Let's go with if let Some(..) == constant_with_source(..) && let Some(..) = constant_with_source(..)
so we don't have to evaluate arg
as a constant if recv
isn't one
e9501b8
to
2f9f204
Compare
Great, thanks! @bors r+ |
☀️ Test successful - checks-action_dev_test, checks-action_remark_test, checks-action_test |
Continuation of #12061
Fix #11901 and #11924
This implementation only deal with literal int, like
i32::MAX
,-6_i32
,0
changelog: added lint [
unnecessary_min_max
]