From e1344da2feb8c5ec12a0f830523bf9b30215d644 Mon Sep 17 00:00:00 2001 From: Ada Alakbarova Date: Sat, 15 Nov 2025 08:19:33 +0100 Subject: [PATCH 1/2] Handle the suggestion-less case inside `print_unchecked_duration_subtration_sugg` This doesn't change any functionality, but will make it easier to switch to a uniform message in the next commit. Also a nice simplification imo --- clippy_lints/src/time_subtraction.rs | 59 ++++++++++------------------ 1 file changed, 21 insertions(+), 38 deletions(-) diff --git a/clippy_lints/src/time_subtraction.rs b/clippy_lints/src/time_subtraction.rs index dbd4ec77fd5f..a48c6be4dc55 100644 --- a/clippy_lints/src/time_subtraction.rs +++ b/clippy_lints/src/time_subtraction.rs @@ -1,5 +1,5 @@ use clippy_config::Conf; -use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg}; +use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then}; use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::res::{MaybeDef, MaybeTypeckRes}; use clippy_utils::sugg::Sugg; @@ -109,36 +109,16 @@ impl LateLintPass<'_> for UncheckedTimeSubtraction { && !expr.span.from_expansion() && self.msrv.meets(cx, msrvs::TRY_FROM) { - // For chained subtraction like (instant - dur1) - dur2, avoid suggestions - if is_chained_time_subtraction(cx, lhs) { - span_lint( - cx, - UNCHECKED_TIME_SUBTRACTION, - expr.span, - "unchecked subtraction of a 'Duration' from an 'Instant'", - ); - } else { - // instant - duration - print_unchecked_duration_subtraction_sugg(cx, lhs, rhs, expr); - } + print_unchecked_duration_subtraction_sugg(cx, lhs, rhs, expr); } - } else if lhs_ty.is_diag_item(cx, sym::Duration) + } + // duration - duration + else if lhs_ty.is_diag_item(cx, sym::Duration) && rhs_ty.is_diag_item(cx, sym::Duration) && !expr.span.from_expansion() && self.msrv.meets(cx, msrvs::TRY_FROM) { - // For chained subtraction like (dur1 - dur2) - dur3, avoid suggestions - if is_chained_time_subtraction(cx, lhs) { - span_lint( - cx, - UNCHECKED_TIME_SUBTRACTION, - expr.span, - "unchecked subtraction between 'Duration' values", - ); - } else { - // duration - duration - print_unchecked_duration_subtraction_sugg(cx, lhs, rhs, expr); - } + print_unchecked_duration_subtraction_sugg(cx, lhs, rhs, expr); } } } @@ -200,17 +180,20 @@ fn print_unchecked_duration_subtraction_sugg( "unchecked subtraction between 'Duration' values" }; - let mut applicability = Applicability::MachineApplicable; - let left_sugg = Sugg::hir_with_applicability(cx, left_expr, "", &mut applicability); - let right_sugg = Sugg::hir_with_applicability(cx, right_expr, "", &mut applicability); + span_lint_and_then(cx, UNCHECKED_TIME_SUBTRACTION, expr.span, lint_msg, |diag| { + // For chained subtraction, like `(dur1 - dur2) - dur3` or `(instant - dur1) - dur2`, + // avoid suggestions + if !is_chained_time_subtraction(cx, left_expr) { + let mut applicability = Applicability::MachineApplicable; + let left_sugg = Sugg::hir_with_applicability(cx, left_expr, "", &mut applicability); + let right_sugg = Sugg::hir_with_applicability(cx, right_expr, "", &mut applicability); - span_lint_and_sugg( - cx, - UNCHECKED_TIME_SUBTRACTION, - expr.span, - lint_msg, - "try", - format!("{}.checked_sub({}).unwrap()", left_sugg.maybe_paren(), right_sugg), - applicability, - ); + diag.span_suggestion( + expr.span, + "try", + format!("{}.checked_sub({}).unwrap()", left_sugg.maybe_paren(), right_sugg), + applicability, + ); + } + }); } From 32f5ae101d68ce49980854995e51bf698eba3403 Mon Sep 17 00:00:00 2001 From: Ada Alakbarova Date: Sat, 15 Nov 2025 08:12:02 +0100 Subject: [PATCH 2/2] Give the same message for `Instant - Duration` and `Duration - Duration` Diff best seen with whitespace ignored --- clippy_lints/src/time_subtraction.rs | 45 +++++++++---------- tests/ui/unchecked_time_subtraction.stderr | 16 +++---- ...nchecked_time_subtraction_unfixable.stderr | 8 ++-- 3 files changed, 33 insertions(+), 36 deletions(-) diff --git a/clippy_lints/src/time_subtraction.rs b/clippy_lints/src/time_subtraction.rs index a48c6be4dc55..e0fdca97dbee 100644 --- a/clippy_lints/src/time_subtraction.rs +++ b/clippy_lints/src/time_subtraction.rs @@ -171,29 +171,26 @@ fn print_unchecked_duration_subtraction_sugg( right_expr: &Expr<'_>, expr: &Expr<'_>, ) { - let typeck = cx.typeck_results(); - let left_ty = typeck.expr_ty(left_expr); - - let lint_msg = if left_ty.is_diag_item(cx, sym::Instant) { - "unchecked subtraction of a 'Duration' from an 'Instant'" - } else { - "unchecked subtraction between 'Duration' values" - }; - - span_lint_and_then(cx, UNCHECKED_TIME_SUBTRACTION, expr.span, lint_msg, |diag| { - // For chained subtraction, like `(dur1 - dur2) - dur3` or `(instant - dur1) - dur2`, - // avoid suggestions - if !is_chained_time_subtraction(cx, left_expr) { - let mut applicability = Applicability::MachineApplicable; - let left_sugg = Sugg::hir_with_applicability(cx, left_expr, "", &mut applicability); - let right_sugg = Sugg::hir_with_applicability(cx, right_expr, "", &mut applicability); + span_lint_and_then( + cx, + UNCHECKED_TIME_SUBTRACTION, + expr.span, + "unchecked subtraction of a `Duration`", + |diag| { + // For chained subtraction, like `(dur1 - dur2) - dur3` or `(instant - dur1) - dur2`, + // avoid suggestions + if !is_chained_time_subtraction(cx, left_expr) { + let mut applicability = Applicability::MachineApplicable; + let left_sugg = Sugg::hir_with_applicability(cx, left_expr, "", &mut applicability); + let right_sugg = Sugg::hir_with_applicability(cx, right_expr, "", &mut applicability); - diag.span_suggestion( - expr.span, - "try", - format!("{}.checked_sub({}).unwrap()", left_sugg.maybe_paren(), right_sugg), - applicability, - ); - } - }); + diag.span_suggestion( + expr.span, + "try", + format!("{}.checked_sub({}).unwrap()", left_sugg.maybe_paren(), right_sugg), + applicability, + ); + } + }, + ); } diff --git a/tests/ui/unchecked_time_subtraction.stderr b/tests/ui/unchecked_time_subtraction.stderr index 7a39712269cf..c129497447fc 100644 --- a/tests/ui/unchecked_time_subtraction.stderr +++ b/tests/ui/unchecked_time_subtraction.stderr @@ -1,4 +1,4 @@ -error: unchecked subtraction of a 'Duration' from an 'Instant' +error: unchecked subtraction of a `Duration` --> tests/ui/unchecked_time_subtraction.rs:9:13 | LL | let _ = _first - second; @@ -7,43 +7,43 @@ LL | let _ = _first - second; = note: `-D clippy::unchecked-time-subtraction` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::unchecked_time_subtraction)]` -error: unchecked subtraction of a 'Duration' from an 'Instant' +error: unchecked subtraction of a `Duration` --> tests/ui/unchecked_time_subtraction.rs:12:13 | LL | let _ = Instant::now() - Duration::from_secs(5); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Instant::now().checked_sub(Duration::from_secs(5)).unwrap()` -error: unchecked subtraction of a 'Duration' from an 'Instant' +error: unchecked subtraction of a `Duration` --> tests/ui/unchecked_time_subtraction.rs:15:13 | LL | let _ = _first - Duration::from_secs(5); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `_first.checked_sub(Duration::from_secs(5)).unwrap()` -error: unchecked subtraction of a 'Duration' from an 'Instant' +error: unchecked subtraction of a `Duration` --> tests/ui/unchecked_time_subtraction.rs:18:13 | LL | let _ = Instant::now() - second; | ^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Instant::now().checked_sub(second).unwrap()` -error: unchecked subtraction between 'Duration' values +error: unchecked subtraction of a `Duration` --> tests/ui/unchecked_time_subtraction.rs:25:13 | LL | let _ = dur1 - dur2; | ^^^^^^^^^^^ help: try: `dur1.checked_sub(dur2).unwrap()` -error: unchecked subtraction between 'Duration' values +error: unchecked subtraction of a `Duration` --> tests/ui/unchecked_time_subtraction.rs:28:13 | LL | let _ = Duration::from_secs(10) - Duration::from_secs(5); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Duration::from_secs(10).checked_sub(Duration::from_secs(5)).unwrap()` -error: unchecked subtraction between 'Duration' values +error: unchecked subtraction of a `Duration` --> tests/ui/unchecked_time_subtraction.rs:31:13 | LL | let _ = second - dur1; | ^^^^^^^^^^^^^ help: try: `second.checked_sub(dur1).unwrap()` -error: unchecked subtraction between 'Duration' values +error: unchecked subtraction of a `Duration` --> tests/ui/unchecked_time_subtraction.rs:35:13 | LL | let _ = 2 * dur1 - dur2; diff --git a/tests/ui/unchecked_time_subtraction_unfixable.stderr b/tests/ui/unchecked_time_subtraction_unfixable.stderr index c25c112b06ce..017e5b1c7c11 100644 --- a/tests/ui/unchecked_time_subtraction_unfixable.stderr +++ b/tests/ui/unchecked_time_subtraction_unfixable.stderr @@ -1,4 +1,4 @@ -error: unchecked subtraction between 'Duration' values +error: unchecked subtraction of a `Duration` --> tests/ui/unchecked_time_subtraction_unfixable.rs:12:13 | LL | let _ = dur1 - dur2 - dur3; @@ -7,19 +7,19 @@ LL | let _ = dur1 - dur2 - dur3; = note: `-D clippy::unchecked-time-subtraction` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::unchecked_time_subtraction)]` -error: unchecked subtraction between 'Duration' values +error: unchecked subtraction of a `Duration` --> tests/ui/unchecked_time_subtraction_unfixable.rs:12:13 | LL | let _ = dur1 - dur2 - dur3; | ^^^^^^^^^^^ help: try: `dur1.checked_sub(dur2).unwrap()` -error: unchecked subtraction of a 'Duration' from an 'Instant' +error: unchecked subtraction of a `Duration` --> tests/ui/unchecked_time_subtraction_unfixable.rs:19:13 | LL | let _ = instant1 - dur2 - dur3; | ^^^^^^^^^^^^^^^^^^^^^^ -error: unchecked subtraction of a 'Duration' from an 'Instant' +error: unchecked subtraction of a `Duration` --> tests/ui/unchecked_time_subtraction_unfixable.rs:19:13 | LL | let _ = instant1 - dur2 - dur3;