diff --git a/clippy_lints/src/operators/absurd_extreme_comparisons.rs b/clippy_lints/src/operators/absurd_extreme_comparisons.rs
index dbc9948eeedc..8172ccd78706 100644
--- a/clippy_lints/src/operators/absurd_extreme_comparisons.rs
+++ b/clippy_lints/src/operators/absurd_extreme_comparisons.rs
@@ -1,4 +1,4 @@
-use rustc_hir::{BinOpKind, Expr, ExprKind};
+use rustc_hir::{BinOpKind, Expr, ExprKind, QPath};
use rustc_lint::LateContext;
use rustc_middle::ty;
@@ -7,7 +7,7 @@ use clippy_utils::consts::{ConstEvalCtxt, Constant};
use clippy_utils::diagnostics::span_lint_and_help;
use clippy_utils::source::snippet;
use clippy_utils::ty::is_isize_or_usize;
-use clippy_utils::{clip, int_bits, unsext};
+use clippy_utils::{clip, int_bits, sym, unsext};
use super::ABSURD_EXTREME_COMPARISONS;
@@ -121,6 +121,78 @@ fn detect_absurd_comparison<'tcx>(
fn detect_extreme_expr<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> Option> {
let ty = cx.typeck_results().expr_ty(expr);
+ // Detect Duration zero values
+ if let ty::Adt(adt_def, _) = *ty.kind()
+ && cx.tcx.is_diagnostic_item(sym::Duration, adt_def.did())
+ {
+ if let ExprKind::Call(func, args) = &expr.kind {
+ if let ExprKind::Path(qpath) = &func.kind {
+ let method_name = match qpath {
+ QPath::Resolved(_, path) => path.segments.last().map(|seg| seg.ident.name.as_str()),
+ QPath::TypeRelative(_, seg) => Some(seg.ident.name.as_str()),
+ _ => None,
+ };
+
+ // Handle constructors like from_secs(0), from_millis(0), etc.
+ if args.len() == 1 {
+ let int_methods = ["from_secs", "from_millis", "from_micros", "from_nanos"];
+ if int_methods.iter().any(|&m| Some(m) == method_name) {
+ if let Some(Constant::Int(0)) = ConstEvalCtxt::new(cx).eval(&args[0]) {
+ return Some(ExtremeExpr {
+ which: ExtremeType::Minimum,
+ expr,
+ });
+ }
+ }
+
+ // Handle float constructors
+ let float_methods = ["from_secs_f32", "from_secs_f64"];
+ if float_methods.iter().any(|&m| Some(m) == method_name) {
+ if let ExprKind::Lit(lit) = &args[0].kind {
+ let lit_str = snippet(cx, lit.span, "");
+ if lit_str == "0.0" || lit_str == "0" {
+ return Some(ExtremeExpr {
+ which: ExtremeType::Minimum,
+ expr,
+ });
+ }
+ }
+ }
+ }
+ // Handle new(0, 0)
+ else if args.len() == 2 && method_name == Some("new") {
+ let first_arg_const = ConstEvalCtxt::new(cx).eval(&args[0]);
+ let second_arg_const = ConstEvalCtxt::new(cx).eval(&args[1]);
+
+ if let (Some(Constant::Int(0)), Some(Constant::Int(0))) = (first_arg_const, second_arg_const) {
+ return Some(ExtremeExpr {
+ which: ExtremeType::Minimum,
+ expr,
+ });
+ }
+
+ if let (ExprKind::Path(_), ExprKind::Path(_)) = (&args[0].kind, &args[1].kind) {
+ if snippet(cx, args[0].span, "").contains("zero")
+ && snippet(cx, args[1].span, "").contains("zero")
+ {
+ return Some(ExtremeExpr {
+ which: ExtremeType::Minimum,
+ expr,
+ });
+ }
+ }
+ }
+ // Handle constructor default()
+ else if args.is_empty() && method_name == Some("default") {
+ return Some(ExtremeExpr {
+ which: ExtremeType::Minimum,
+ expr,
+ });
+ }
+ }
+ }
+ }
+
let cv = ConstEvalCtxt::new(cx).eval(expr)?;
let which = match (ty.kind(), cv) {
diff --git a/tests/ui/absurd-extreme-comparisons.rs b/tests/ui/absurd-extreme-comparisons.rs
index 793961d30f0d..9f58060f559f 100644
--- a/tests/ui/absurd-extreme-comparisons.rs
+++ b/tests/ui/absurd-extreme-comparisons.rs
@@ -7,6 +7,8 @@
clippy::needless_pass_by_value
)]
+use std::time::Duration;
+
#[rustfmt::skip]
fn main() {
const Z: u32 = 0;
@@ -69,7 +71,68 @@ fn main() {
() < {};
//~^ unit_cmp
+ Duration::from_secs(0) > Duration::new(5, 0);
+ //~^ absurd_extreme_comparisons
+ Duration::new(5, 0) < Duration::from_secs(0);
+ //~^ absurd_extreme_comparisons
+ Duration::from_secs(0) < Duration::new(5, 0); // ok
+
+ let d = Duration::new(5, 0);
+ d < Duration::from_secs(0);
+ //~^ absurd_extreme_comparisons
+ Duration::from_secs(0) > d;
+ //~^ absurd_extreme_comparisons
+
+ d < Duration::from_millis(0);
+ //~^ absurd_extreme_comparisons
+ Duration::from_micros(0) > d;
+ //~^ absurd_extreme_comparisons
+
+ d <= Duration::from_nanos(0);
+ //~^ absurd_extreme_comparisons
+ Duration::from_nanos(0) >= d;
+ //~^ absurd_extreme_comparisons
+
+ d < Duration::default();
+ //~^ absurd_extreme_comparisons
+ Duration::default() > d;
+ //~^ absurd_extreme_comparisons
+
+ d < Duration::from_secs_f32(0.0);
+ //~^ absurd_extreme_comparisons
+ Duration::from_secs_f64(0.0) > d;
+ //~^ absurd_extreme_comparisons
+
+ let zero_secs: u64 = 0;
+ let zero_nanos: u32 = 0;
+ d < Duration::new(zero_secs, zero_nanos);
+ //~^ absurd_extreme_comparisons
+ Duration::new(zero_secs, zero_nanos) > d;
+ //~^ absurd_extreme_comparisons
+
+ d > Duration::from_secs(0); // OK
+ Duration::from_secs(0) < d; // OK
+ d == Duration::from_secs(0); // OK
+
+ let d = Duration::new(5, 0);
+ d < one_second_plus(0); // OK
+ one_second_plus(0) > d; // OK
+
+ let n = 0;
+ d < one_second_plus(n); // OK
+
+ d < Duration::from_secs(0);
+ //~^ absurd_extreme_comparisons
+ Duration::from_secs(0) > d;
+ //~^ absurd_extreme_comparisons
+
+
+ let d_zero = Duration::from_secs(0);
+ let d_one = one_second_plus(0);
+ d_zero < d_one; // OK
+ d_one > d_zero; // OK
+ d_zero < d_zero; // OK
}
use std::cmp::{Ordering, PartialEq, PartialOrd};
@@ -96,3 +159,7 @@ pub fn bar(len: u64) -> bool {
// This is OK as we are casting from target sized to fixed size
len >= usize::MAX as u64
}
+
+fn one_second_plus(n: u64) -> Duration {
+ Duration::from_secs(n + 1)
+}
diff --git a/tests/ui/absurd-extreme-comparisons.stderr b/tests/ui/absurd-extreme-comparisons.stderr
index 6df50c15e8cd..bb9ff06045d0 100644
--- a/tests/ui/absurd-extreme-comparisons.stderr
+++ b/tests/ui/absurd-extreme-comparisons.stderr
@@ -1,5 +1,5 @@
error: this comparison involving the minimum or maximum element for this type contains a case that is always true or always false
- --> tests/ui/absurd-extreme-comparisons.rs:14:5
+ --> tests/ui/absurd-extreme-comparisons.rs:16:5
|
LL | u <= 0;
| ^^^^^^
@@ -9,7 +9,7 @@ LL | u <= 0;
= help: to override `-D warnings` add `#[allow(clippy::absurd_extreme_comparisons)]`
error: this comparison involving the minimum or maximum element for this type contains a case that is always true or always false
- --> tests/ui/absurd-extreme-comparisons.rs:17:5
+ --> tests/ui/absurd-extreme-comparisons.rs:19:5
|
LL | u <= Z;
| ^^^^^^
@@ -17,7 +17,7 @@ LL | u <= Z;
= help: because `Z` is the minimum value for this type, the case where the two sides are not equal never occurs, consider using `u == Z` instead
error: this comparison involving the minimum or maximum element for this type contains a case that is always true or always false
- --> tests/ui/absurd-extreme-comparisons.rs:20:5
+ --> tests/ui/absurd-extreme-comparisons.rs:22:5
|
LL | u < Z;
| ^^^^^
@@ -25,7 +25,7 @@ LL | u < Z;
= help: because `Z` is the minimum value for this type, this comparison is always false
error: this comparison involving the minimum or maximum element for this type contains a case that is always true or always false
- --> tests/ui/absurd-extreme-comparisons.rs:23:5
+ --> tests/ui/absurd-extreme-comparisons.rs:25:5
|
LL | Z >= u;
| ^^^^^^
@@ -33,7 +33,7 @@ LL | Z >= u;
= help: because `Z` is the minimum value for this type, the case where the two sides are not equal never occurs, consider using `Z == u` instead
error: this comparison involving the minimum or maximum element for this type contains a case that is always true or always false
- --> tests/ui/absurd-extreme-comparisons.rs:26:5
+ --> tests/ui/absurd-extreme-comparisons.rs:28:5
|
LL | Z > u;
| ^^^^^
@@ -41,7 +41,7 @@ LL | Z > u;
= help: because `Z` is the minimum value for this type, this comparison is always false
error: this comparison involving the minimum or maximum element for this type contains a case that is always true or always false
- --> tests/ui/absurd-extreme-comparisons.rs:29:5
+ --> tests/ui/absurd-extreme-comparisons.rs:31:5
|
LL | u > u32::MAX;
| ^^^^^^^^^^^^
@@ -49,7 +49,7 @@ LL | u > u32::MAX;
= help: because `u32::MAX` is the maximum value for this type, this comparison is always false
error: this comparison involving the minimum or maximum element for this type contains a case that is always true or always false
- --> tests/ui/absurd-extreme-comparisons.rs:32:5
+ --> tests/ui/absurd-extreme-comparisons.rs:34:5
|
LL | u >= u32::MAX;
| ^^^^^^^^^^^^^
@@ -57,7 +57,7 @@ LL | u >= u32::MAX;
= help: because `u32::MAX` is the maximum value for this type, the case where the two sides are not equal never occurs, consider using `u == u32::MAX` instead
error: this comparison involving the minimum or maximum element for this type contains a case that is always true or always false
- --> tests/ui/absurd-extreme-comparisons.rs:35:5
+ --> tests/ui/absurd-extreme-comparisons.rs:37:5
|
LL | u32::MAX < u;
| ^^^^^^^^^^^^
@@ -65,7 +65,7 @@ LL | u32::MAX < u;
= help: because `u32::MAX` is the maximum value for this type, this comparison is always false
error: this comparison involving the minimum or maximum element for this type contains a case that is always true or always false
- --> tests/ui/absurd-extreme-comparisons.rs:38:5
+ --> tests/ui/absurd-extreme-comparisons.rs:40:5
|
LL | u32::MAX <= u;
| ^^^^^^^^^^^^^
@@ -73,7 +73,7 @@ LL | u32::MAX <= u;
= help: because `u32::MAX` is the maximum value for this type, the case where the two sides are not equal never occurs, consider using `u32::MAX == u` instead
error: this comparison involving the minimum or maximum element for this type contains a case that is always true or always false
- --> tests/ui/absurd-extreme-comparisons.rs:41:5
+ --> tests/ui/absurd-extreme-comparisons.rs:43:5
|
LL | 1-1 > u;
| ^^^^^^^
@@ -81,7 +81,7 @@ LL | 1-1 > u;
= help: because `1-1` is the minimum value for this type, this comparison is always false
error: this comparison involving the minimum or maximum element for this type contains a case that is always true or always false
- --> tests/ui/absurd-extreme-comparisons.rs:44:5
+ --> tests/ui/absurd-extreme-comparisons.rs:46:5
|
LL | u >= !0;
| ^^^^^^^
@@ -89,7 +89,7 @@ LL | u >= !0;
= help: because `!0` is the maximum value for this type, the case where the two sides are not equal never occurs, consider using `u == !0` instead
error: this comparison involving the minimum or maximum element for this type contains a case that is always true or always false
- --> tests/ui/absurd-extreme-comparisons.rs:47:5
+ --> tests/ui/absurd-extreme-comparisons.rs:49:5
|
LL | u <= 12 - 2*6;
| ^^^^^^^^^^^^^
@@ -97,7 +97,7 @@ LL | u <= 12 - 2*6;
= help: because `12 - 2*6` is the minimum value for this type, the case where the two sides are not equal never occurs, consider using `u == 12 - 2*6` instead
error: this comparison involving the minimum or maximum element for this type contains a case that is always true or always false
- --> tests/ui/absurd-extreme-comparisons.rs:51:5
+ --> tests/ui/absurd-extreme-comparisons.rs:53:5
|
LL | i < -127 - 1;
| ^^^^^^^^^^^^
@@ -105,7 +105,7 @@ LL | i < -127 - 1;
= help: because `-127 - 1` is the minimum value for this type, this comparison is always false
error: this comparison involving the minimum or maximum element for this type contains a case that is always true or always false
- --> tests/ui/absurd-extreme-comparisons.rs:54:5
+ --> tests/ui/absurd-extreme-comparisons.rs:56:5
|
LL | i8::MAX >= i;
| ^^^^^^^^^^^^
@@ -113,7 +113,7 @@ LL | i8::MAX >= i;
= help: because `i8::MAX` is the maximum value for this type, this comparison is always true
error: this comparison involving the minimum or maximum element for this type contains a case that is always true or always false
- --> tests/ui/absurd-extreme-comparisons.rs:57:5
+ --> tests/ui/absurd-extreme-comparisons.rs:59:5
|
LL | 3-7 < i32::MIN;
| ^^^^^^^^^^^^^^
@@ -121,7 +121,7 @@ LL | 3-7 < i32::MIN;
= help: because `i32::MIN` is the minimum value for this type, this comparison is always false
error: this comparison involving the minimum or maximum element for this type contains a case that is always true or always false
- --> tests/ui/absurd-extreme-comparisons.rs:61:5
+ --> tests/ui/absurd-extreme-comparisons.rs:63:5
|
LL | b >= true;
| ^^^^^^^^^
@@ -129,7 +129,7 @@ LL | b >= true;
= help: because `true` is the maximum value for this type, the case where the two sides are not equal never occurs, consider using `b == true` instead
error: this comparison involving the minimum or maximum element for this type contains a case that is always true or always false
- --> tests/ui/absurd-extreme-comparisons.rs:64:5
+ --> tests/ui/absurd-extreme-comparisons.rs:66:5
|
LL | false > b;
| ^^^^^^^^^
@@ -137,12 +137,140 @@ LL | false > b;
= help: because `false` is the minimum value for this type, this comparison is always false
error: <-comparison of unit values detected. This will always be false
- --> tests/ui/absurd-extreme-comparisons.rs:69:5
+ --> tests/ui/absurd-extreme-comparisons.rs:71:5
|
LL | () < {};
| ^^^^^^^
|
= note: `#[deny(clippy::unit_cmp)]` on by default
-error: aborting due to 18 previous errors
+error: this comparison involving the minimum or maximum element for this type contains a case that is always true or always false
+ --> tests/ui/absurd-extreme-comparisons.rs:74:5
+ |
+LL | Duration::from_secs(0) > Duration::new(5, 0);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = help: because `Duration::from_secs(0)` is the minimum value for this type, this comparison is always false
+
+error: this comparison involving the minimum or maximum element for this type contains a case that is always true or always false
+ --> tests/ui/absurd-extreme-comparisons.rs:76:5
+ |
+LL | Duration::new(5, 0) < Duration::from_secs(0);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = help: because `Duration::from_secs(0)` is the minimum value for this type, this comparison is always false
+
+error: this comparison involving the minimum or maximum element for this type contains a case that is always true or always false
+ --> tests/ui/absurd-extreme-comparisons.rs:82:5
+ |
+LL | d < Duration::from_secs(0);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = help: because `Duration::from_secs(0)` is the minimum value for this type, this comparison is always false
+
+error: this comparison involving the minimum or maximum element for this type contains a case that is always true or always false
+ --> tests/ui/absurd-extreme-comparisons.rs:84:5
+ |
+LL | Duration::from_secs(0) > d;
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = help: because `Duration::from_secs(0)` is the minimum value for this type, this comparison is always false
+
+error: this comparison involving the minimum or maximum element for this type contains a case that is always true or always false
+ --> tests/ui/absurd-extreme-comparisons.rs:87:5
+ |
+LL | d < Duration::from_millis(0);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = help: because `Duration::from_millis(0)` is the minimum value for this type, this comparison is always false
+
+error: this comparison involving the minimum or maximum element for this type contains a case that is always true or always false
+ --> tests/ui/absurd-extreme-comparisons.rs:89:5
+ |
+LL | Duration::from_micros(0) > d;
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = help: because `Duration::from_micros(0)` is the minimum value for this type, this comparison is always false
+
+error: this comparison involving the minimum or maximum element for this type contains a case that is always true or always false
+ --> tests/ui/absurd-extreme-comparisons.rs:92:5
+ |
+LL | d <= Duration::from_nanos(0);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = help: because `Duration::from_nanos(0)` is the minimum value for this type, the case where the two sides are not equal never occurs, consider using `d == Duration::from_nanos(0)` instead
+
+error: this comparison involving the minimum or maximum element for this type contains a case that is always true or always false
+ --> tests/ui/absurd-extreme-comparisons.rs:94:5
+ |
+LL | Duration::from_nanos(0) >= d;
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = help: because `Duration::from_nanos(0)` is the minimum value for this type, the case where the two sides are not equal never occurs, consider using `Duration::from_nanos(0) == d` instead
+
+error: this comparison involving the minimum or maximum element for this type contains a case that is always true or always false
+ --> tests/ui/absurd-extreme-comparisons.rs:97:5
+ |
+LL | d < Duration::default();
+ | ^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = help: because `Duration::default()` is the minimum value for this type, this comparison is always false
+
+error: this comparison involving the minimum or maximum element for this type contains a case that is always true or always false
+ --> tests/ui/absurd-extreme-comparisons.rs:99:5
+ |
+LL | Duration::default() > d;
+ | ^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = help: because `Duration::default()` is the minimum value for this type, this comparison is always false
+
+error: this comparison involving the minimum or maximum element for this type contains a case that is always true or always false
+ --> tests/ui/absurd-extreme-comparisons.rs:102:5
+ |
+LL | d < Duration::from_secs_f32(0.0);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = help: because `Duration::from_secs_f32(0.0)` is the minimum value for this type, this comparison is always false
+
+error: this comparison involving the minimum or maximum element for this type contains a case that is always true or always false
+ --> tests/ui/absurd-extreme-comparisons.rs:104:5
+ |
+LL | Duration::from_secs_f64(0.0) > d;
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = help: because `Duration::from_secs_f64(0.0)` is the minimum value for this type, this comparison is always false
+
+error: this comparison involving the minimum or maximum element for this type contains a case that is always true or always false
+ --> tests/ui/absurd-extreme-comparisons.rs:109:5
+ |
+LL | d < Duration::new(zero_secs, zero_nanos);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = help: because `Duration::new(zero_secs, zero_nanos)` is the minimum value for this type, this comparison is always false
+
+error: this comparison involving the minimum or maximum element for this type contains a case that is always true or always false
+ --> tests/ui/absurd-extreme-comparisons.rs:111:5
+ |
+LL | Duration::new(zero_secs, zero_nanos) > d;
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = help: because `Duration::new(zero_secs, zero_nanos)` is the minimum value for this type, this comparison is always false
+
+error: this comparison involving the minimum or maximum element for this type contains a case that is always true or always false
+ --> tests/ui/absurd-extreme-comparisons.rs:125:5
+ |
+LL | d < Duration::from_secs(0);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = help: because `Duration::from_secs(0)` is the minimum value for this type, this comparison is always false
+
+error: this comparison involving the minimum or maximum element for this type contains a case that is always true or always false
+ --> tests/ui/absurd-extreme-comparisons.rs:127:5
+ |
+LL | Duration::from_secs(0) > d;
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = help: because `Duration::from_secs(0)` is the minimum value for this type, this comparison is always false
+
+error: aborting due to 34 previous errors