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.
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 unsexts with ity/uty.bit_width() instead of int_bits to exclude *size
There was a problem hiding this comment.
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.
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.
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.
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.
With that & squashed commits I think we're good to go
894ea82 to
961adc9
Compare
|
☔ The latest upstream changes (presumably #12631) made this pull request unmergeable. Please resolve the merge conflicts. |
5160ac7 to
d7d6b41
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.
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.
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.
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.
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.
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
|
☔ 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: |
Alexendoo
left a comment
There was a problem hiding this comment.
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.
If source is already Constant we wouldn't want to override it with CoreConstant
There was a problem hiding this comment.
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.
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
|
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,0changelog: added lint [
unnecessary_min_max]