From 708c2d95c14829e0acbe7f40d9bea39e7bb03450 Mon Sep 17 00:00:00 2001 From: Nadir Fejzic Date: Sat, 1 Oct 2022 15:58:10 +0200 Subject: [PATCH 01/16] feat: add and implement unchecked_duration_subtraction lint --- CHANGELOG.md | 1 + clippy_lints/src/lib.rs | 2 + .../src/unchecked_duration_subtraction.rs | 107 ++++++++++++++++++ clippy_lints/src/utils/conf.rs | 2 +- 4 files changed, 111 insertions(+), 1 deletion(-) create mode 100644 clippy_lints/src/unchecked_duration_subtraction.rs diff --git a/CHANGELOG.md b/CHANGELOG.md index 9bd67617f..eb4ca9801 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4428,6 +4428,7 @@ Released 2018-09-13 [`try_err`]: https://rust-lang.github.io/rust-clippy/master/index.html#try_err [`type_complexity`]: https://rust-lang.github.io/rust-clippy/master/index.html#type_complexity [`type_repetition_in_bounds`]: https://rust-lang.github.io/rust-clippy/master/index.html#type_repetition_in_bounds +[`unchecked_duration_subtraction`]: https://rust-lang.github.io/rust-clippy/master/index.html#unchecked_duration_subtraction [`undocumented_unsafe_blocks`]: https://rust-lang.github.io/rust-clippy/master/index.html#undocumented_unsafe_blocks [`undropped_manually_drops`]: https://rust-lang.github.io/rust-clippy/master/index.html#undropped_manually_drops [`unicode_not_nfc`]: https://rust-lang.github.io/rust-clippy/master/index.html#unicode_not_nfc diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index a4bacb780..a5407b65b 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -279,6 +279,7 @@ mod trailing_empty_array; mod trait_bounds; mod transmute; mod types; +mod unchecked_duration_subtraction; mod undocumented_unsafe_blocks; mod unicode; mod uninit_vec; @@ -921,6 +922,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_late_pass(|_| Box::new(from_raw_with_void_ptr::FromRawWithVoidPtr)); store.register_late_pass(|_| Box::new(suspicious_xor_used_as_pow::ConfusingXorAndPow)); store.register_late_pass(move |_| Box::new(manual_is_ascii_check::ManualIsAsciiCheck::new(msrv))); + store.register_late_pass(move || Box::new(unchecked_duration_subtraction::UncheckedDurationSubtraction::new(msrv))); // add lints here, do not remove this comment, it's used in `new_lint` } diff --git a/clippy_lints/src/unchecked_duration_subtraction.rs b/clippy_lints/src/unchecked_duration_subtraction.rs new file mode 100644 index 000000000..fb08067de --- /dev/null +++ b/clippy_lints/src/unchecked_duration_subtraction.rs @@ -0,0 +1,107 @@ +use clippy_utils::{diagnostics, meets_msrv, msrvs, source, ty}; +use rustc_errors::Applicability; +use rustc_hir::*; +use rustc_lint::{LateContext, LateLintPass}; +use rustc_semver::RustcVersion; +use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_span::symbol::sym; + +declare_clippy_lint! { + /// ### What it does + /// Finds patterns of unchecked subtraction of [`Duration`] from [`Instant::now()`]. + /// + /// ### Why is this bad? + /// Unchecked subtraction could cause underflow on certain platforms, leading to bugs and/or + /// unintentional panics. + /// + /// ### Example + /// ```rust + /// let time_passed = Instant::now() - Duration::from_secs(5); + /// ``` + /// + /// Use instead: + /// ```rust + /// let time_passed = Instant::now().checked_sub(Duration::from_secs(5)); + /// ``` + /// + /// [`Duration`]: std::time::Duration + /// [`Instant::now()`]: std::time::Instant::now; + #[clippy::version = "1.65.0"] + pub UNCHECKED_DURATION_SUBTRACTION, + suspicious, + "finds unchecked subtraction of a 'Duration' from an 'Instant'" +} + +pub struct UncheckedDurationSubtraction { + msrv: Option, +} + +impl UncheckedDurationSubtraction { + #[must_use] + pub fn new(msrv: Option) -> Self { + Self { msrv } + } +} + +impl_lint_pass!(UncheckedDurationSubtraction => [UNCHECKED_DURATION_SUBTRACTION]); + +impl<'tcx> LateLintPass<'tcx> for UncheckedDurationSubtraction { + fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) { + if expr.span.from_expansion() || !meets_msrv(self.msrv, msrvs::TRY_FROM) { + return; + } + + if_chain! { + if let ExprKind::Binary(op, lhs, rhs) = expr.kind; + + if let BinOpKind::Sub = op.node; + + // get types of left and right side + if is_an_instant(cx, lhs); + if is_a_duration(cx, rhs); + + then { + print_lint_and_sugg(cx, lhs, rhs, expr) + } + } + } +} + +fn is_an_instant(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { + let expr_ty = cx.typeck_results().expr_ty(expr); + + match expr_ty.kind() { + rustc_middle::ty::Adt(def, _) => { + clippy_utils::match_def_path(cx, dbg!(def).did(), &clippy_utils::paths::INSTANT) + }, + _ => false, + } +} + +fn is_a_duration(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { + let expr_ty = cx.typeck_results().expr_ty(expr); + ty::is_type_diagnostic_item(cx, expr_ty, sym::Duration) +} + +fn print_lint_and_sugg(cx: &LateContext<'_>, left_expr: &Expr<'_>, right_expr: &Expr<'_>, expr: &Expr<'_>) { + let mut applicability = Applicability::MachineApplicable; + + let left_expr = + source::snippet_with_applicability(cx, left_expr.span, "std::time::Instant::now()", &mut applicability); + let right_expr = source::snippet_with_applicability( + cx, + right_expr.span, + "std::time::Duration::from_secs(1)", + &mut applicability, + ); + + diagnostics::span_lint_and_sugg( + cx, + UNCHECKED_DURATION_SUBTRACTION, + expr.span, + "unchecked subtraction of a 'Duration' from an 'Instant'", + "try", + format!("{}.checked_sub({}).unwrap();", left_expr, right_expr), + applicability, + ); +} diff --git a/clippy_lints/src/utils/conf.rs b/clippy_lints/src/utils/conf.rs index 0cf49ca6d..ab58e9b8b 100644 --- a/clippy_lints/src/utils/conf.rs +++ b/clippy_lints/src/utils/conf.rs @@ -213,7 +213,7 @@ define_Conf! { /// /// Suppress lints whenever the suggested change would cause breakage for other crates. (avoid_breaking_exported_api: bool = true), - /// Lint: MANUAL_SPLIT_ONCE, MANUAL_STR_REPEAT, CLONED_INSTEAD_OF_COPIED, REDUNDANT_FIELD_NAMES, REDUNDANT_STATIC_LIFETIMES, FILTER_MAP_NEXT, CHECKED_CONVERSIONS, MANUAL_RANGE_CONTAINS, USE_SELF, MEM_REPLACE_WITH_DEFAULT, MANUAL_NON_EXHAUSTIVE, OPTION_AS_REF_DEREF, MAP_UNWRAP_OR, MATCH_LIKE_MATCHES_MACRO, MANUAL_STRIP, MISSING_CONST_FOR_FN, UNNESTED_OR_PATTERNS, FROM_OVER_INTO, PTR_AS_PTR, IF_THEN_SOME_ELSE_NONE, APPROX_CONSTANT, DEPRECATED_CFG_ATTR, INDEX_REFUTABLE_SLICE, MAP_CLONE, BORROW_AS_PTR, MANUAL_BITS, ERR_EXPECT, CAST_ABS_TO_UNSIGNED, UNINLINED_FORMAT_ARGS, MANUAL_CLAMP, MANUAL_LET_ELSE. + /// Lint: MANUAL_SPLIT_ONCE, MANUAL_STR_REPEAT, CLONED_INSTEAD_OF_COPIED, REDUNDANT_FIELD_NAMES, REDUNDANT_STATIC_LIFETIMES, FILTER_MAP_NEXT, CHECKED_CONVERSIONS, MANUAL_RANGE_CONTAINS, USE_SELF, MEM_REPLACE_WITH_DEFAULT, MANUAL_NON_EXHAUSTIVE, OPTION_AS_REF_DEREF, MAP_UNWRAP_OR, MATCH_LIKE_MATCHES_MACRO, MANUAL_STRIP, MISSING_CONST_FOR_FN, UNNESTED_OR_PATTERNS, FROM_OVER_INTO, PTR_AS_PTR, IF_THEN_SOME_ELSE_NONE, APPROX_CONSTANT, DEPRECATED_CFG_ATTR, INDEX_REFUTABLE_SLICE, MAP_CLONE, BORROW_AS_PTR, MANUAL_BITS, ERR_EXPECT, CAST_ABS_TO_UNSIGNED, UNINLINED_FORMAT_ARGS, MANUAL_CLAMP, MANUAL_LET_ELSE, UNCHECKED_DURATION_SUBTRACTION. /// /// The minimum rust version that the project supports (msrv: Option = None), From 3b4e42b91b0df11c43983c6fe67bb971f472aa3f Mon Sep 17 00:00:00 2001 From: Nadir Fejzic Date: Sat, 1 Oct 2022 16:02:57 +0200 Subject: [PATCH 02/16] test: add tests for 'unchecked_duration_subtraction' lint --- tests/ui/unchecked_duration_subtraction.rs | 16 ++++++++++ .../ui/unchecked_duration_subtraction.stderr | 32 +++++++++++++++++++ 2 files changed, 48 insertions(+) create mode 100644 tests/ui/unchecked_duration_subtraction.rs create mode 100644 tests/ui/unchecked_duration_subtraction.stderr diff --git a/tests/ui/unchecked_duration_subtraction.rs b/tests/ui/unchecked_duration_subtraction.rs new file mode 100644 index 000000000..fff1d1372 --- /dev/null +++ b/tests/ui/unchecked_duration_subtraction.rs @@ -0,0 +1,16 @@ +#![warn(clippy::unchecked_duration_subtraction)] + +use std::time::{Duration, Instant}; + +fn main() { + let _first = Instant::now(); + let second = Duration::from_secs(3); + + let _ = _first - second; + + let _ = Instant::now() - Duration::from_secs(5); + + let _ = _first - Duration::from_secs(5); + + let _ = Instant::now() - second; +} diff --git a/tests/ui/unchecked_duration_subtraction.stderr b/tests/ui/unchecked_duration_subtraction.stderr new file mode 100644 index 000000000..827b18a5a --- /dev/null +++ b/tests/ui/unchecked_duration_subtraction.stderr @@ -0,0 +1,32 @@ +[clippy_lints/src/unchecked_duration_subtraction.rs:75] def = std::time::Instant +error: unchecked subtraction of a 'Duration' from an 'Instant' + --> $DIR/unchecked_duration_subtraction.rs:9:13 + | +LL | let _ = _first - second; + | ^^^^^^^^^^^^^^^ help: try: `_first.checked_sub(second).unwrap();` + | + = note: `-D clippy::unchecked-duration-subtraction` implied by `-D warnings` + +[clippy_lints/src/unchecked_duration_subtraction.rs:75] def = std::time::Instant +error: unchecked subtraction of a 'Duration' from an 'Instant' + --> $DIR/unchecked_duration_subtraction.rs:11:13 + | +LL | let _ = Instant::now() - Duration::from_secs(5); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Instant::now().checked_sub(Duration::from_secs(5)).unwrap();` + +[clippy_lints/src/unchecked_duration_subtraction.rs:75] def = std::time::Instant +error: unchecked subtraction of a 'Duration' from an 'Instant' + --> $DIR/unchecked_duration_subtraction.rs:13:13 + | +LL | let _ = _first - Duration::from_secs(5); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `_first.checked_sub(Duration::from_secs(5)).unwrap();` + +[clippy_lints/src/unchecked_duration_subtraction.rs:75] def = std::time::Instant +error: unchecked subtraction of a 'Duration' from an 'Instant' + --> $DIR/unchecked_duration_subtraction.rs:15:13 + | +LL | let _ = Instant::now() - second; + | ^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Instant::now().checked_sub(second).unwrap();` + +error: aborting due to 4 previous errors + From b280dbe5f73286a3f2a02e93c6c3e42181ec8aca Mon Sep 17 00:00:00 2001 From: Nadir Fejzic Date: Sat, 1 Oct 2022 16:50:45 +0200 Subject: [PATCH 03/16] docs: add docs for `unchecked_duration_subtraction` lint --- src/docs/unchecked_duration_subtraction.txt | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) create mode 100644 src/docs/unchecked_duration_subtraction.txt diff --git a/src/docs/unchecked_duration_subtraction.txt b/src/docs/unchecked_duration_subtraction.txt new file mode 100644 index 000000000..6b9c9308c --- /dev/null +++ b/src/docs/unchecked_duration_subtraction.txt @@ -0,0 +1,19 @@ +### What it does +Finds patterns of unchecked subtraction of [`Duration`] from [`Instant::now()`]. + +### Why is this bad? +Unchecked subtraction could cause underflow on certain platforms, leading to bugs and/or +unintentional panics. + +### Example +``` +let time_passed = Instant::now() - Duration::from_secs(5); +``` + +Use instead: +``` +let time_passed = Instant::now().checked_sub(Duration::from_secs(5)); +``` + +[`Duration`]: std::time::Duration +[`Instant::now()`]: std::time::Instant::now; \ No newline at end of file From b485832b16a388dbcfd3c42030356959e7662a3d Mon Sep 17 00:00:00 2001 From: Nadir Fejzic Date: Sat, 1 Oct 2022 16:50:56 +0200 Subject: [PATCH 04/16] style: remove `dbg!` call --- clippy_lints/src/unchecked_duration_subtraction.rs | 4 +--- tests/ui/unchecked_duration_subtraction.stderr | 4 ---- 2 files changed, 1 insertion(+), 7 deletions(-) diff --git a/clippy_lints/src/unchecked_duration_subtraction.rs b/clippy_lints/src/unchecked_duration_subtraction.rs index fb08067de..ae7960006 100644 --- a/clippy_lints/src/unchecked_duration_subtraction.rs +++ b/clippy_lints/src/unchecked_duration_subtraction.rs @@ -71,9 +71,7 @@ fn is_an_instant(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { let expr_ty = cx.typeck_results().expr_ty(expr); match expr_ty.kind() { - rustc_middle::ty::Adt(def, _) => { - clippy_utils::match_def_path(cx, dbg!(def).did(), &clippy_utils::paths::INSTANT) - }, + rustc_middle::ty::Adt(def, _) => clippy_utils::match_def_path(cx, def.did(), &clippy_utils::paths::INSTANT), _ => false, } } diff --git a/tests/ui/unchecked_duration_subtraction.stderr b/tests/ui/unchecked_duration_subtraction.stderr index 827b18a5a..6b297a01c 100644 --- a/tests/ui/unchecked_duration_subtraction.stderr +++ b/tests/ui/unchecked_duration_subtraction.stderr @@ -1,4 +1,3 @@ -[clippy_lints/src/unchecked_duration_subtraction.rs:75] def = std::time::Instant error: unchecked subtraction of a 'Duration' from an 'Instant' --> $DIR/unchecked_duration_subtraction.rs:9:13 | @@ -7,21 +6,18 @@ LL | let _ = _first - second; | = note: `-D clippy::unchecked-duration-subtraction` implied by `-D warnings` -[clippy_lints/src/unchecked_duration_subtraction.rs:75] def = std::time::Instant error: unchecked subtraction of a 'Duration' from an 'Instant' --> $DIR/unchecked_duration_subtraction.rs:11:13 | LL | let _ = Instant::now() - Duration::from_secs(5); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Instant::now().checked_sub(Duration::from_secs(5)).unwrap();` -[clippy_lints/src/unchecked_duration_subtraction.rs:75] def = std::time::Instant error: unchecked subtraction of a 'Duration' from an 'Instant' --> $DIR/unchecked_duration_subtraction.rs:13:13 | LL | let _ = _first - Duration::from_secs(5); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `_first.checked_sub(Duration::from_secs(5)).unwrap();` -[clippy_lints/src/unchecked_duration_subtraction.rs:75] def = std::time::Instant error: unchecked subtraction of a 'Duration' from an 'Instant' --> $DIR/unchecked_duration_subtraction.rs:15:13 | From 2f2eb2e4baace68868af2f4ac3ec7aed073139ad Mon Sep 17 00:00:00 2001 From: Nadir Fejzic Date: Mon, 7 Nov 2022 20:58:49 +0100 Subject: [PATCH 05/16] refactor: lint man. instant elapsed and unch. dur. subtr. in single pass --- ..._subtraction.rs => instant_subtraction.rs} | 78 ++++++++++++++++--- clippy_lints/src/lib.rs | 5 +- clippy_lints/src/manual_instant_elapsed.rs | 69 ---------------- 3 files changed, 71 insertions(+), 81 deletions(-) rename clippy_lints/src/{unchecked_duration_subtraction.rs => instant_subtraction.rs} (52%) delete mode 100644 clippy_lints/src/manual_instant_elapsed.rs diff --git a/clippy_lints/src/unchecked_duration_subtraction.rs b/clippy_lints/src/instant_subtraction.rs similarity index 52% rename from clippy_lints/src/unchecked_duration_subtraction.rs rename to clippy_lints/src/instant_subtraction.rs index ae7960006..8cc5643c9 100644 --- a/clippy_lints/src/unchecked_duration_subtraction.rs +++ b/clippy_lints/src/instant_subtraction.rs @@ -1,17 +1,48 @@ -use clippy_utils::{diagnostics, meets_msrv, msrvs, source, ty}; +use clippy_utils::{ + diagnostics::{self, span_lint_and_sugg}, + meets_msrv, msrvs, source, ty, +}; use rustc_errors::Applicability; -use rustc_hir::*; +use rustc_hir::{BinOpKind, Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_semver::RustcVersion; use rustc_session::{declare_tool_lint, impl_lint_pass}; -use rustc_span::symbol::sym; +use rustc_span::{source_map::Spanned, sym}; + +declare_clippy_lint! { + /// ### What it does + /// Lints subtraction between `Instant::now()` and another `Instant`. + /// + /// ### Why is this bad? + /// It is easy to accidentally write `prev_instant - Instant::now()`, which will always be 0ns + /// as `Instant` subtraction saturates. + /// + /// `prev_instant.elapsed()` also more clearly signals intention. + /// + /// ### Example + /// ```rust + /// use std::time::Instant; + /// let prev_instant = Instant::now(); + /// let duration = Instant::now() - prev_instant; + /// ``` + /// Use instead: + /// ```rust + /// use std::time::Instant; + /// let prev_instant = Instant::now(); + /// let duration = prev_instant.elapsed(); + /// ``` + #[clippy::version = "1.64.0"] + pub MANUAL_INSTANT_ELAPSED, + pedantic, + "subtraction between `Instant::now()` and previous `Instant`" +} declare_clippy_lint! { /// ### What it does /// Finds patterns of unchecked subtraction of [`Duration`] from [`Instant::now()`]. /// /// ### Why is this bad? - /// Unchecked subtraction could cause underflow on certain platforms, leading to bugs and/or + /// Unchecked subtraction could cause underflow on certain platforms, leading to /// unintentional panics. /// /// ### Example @@ -32,21 +63,39 @@ declare_clippy_lint! { "finds unchecked subtraction of a 'Duration' from an 'Instant'" } -pub struct UncheckedDurationSubtraction { +pub struct InstantSubtraction { msrv: Option, } -impl UncheckedDurationSubtraction { +impl InstantSubtraction { #[must_use] pub fn new(msrv: Option) -> Self { Self { msrv } } } -impl_lint_pass!(UncheckedDurationSubtraction => [UNCHECKED_DURATION_SUBTRACTION]); +impl_lint_pass!(InstantSubtraction => [MANUAL_INSTANT_ELAPSED, UNCHECKED_DURATION_SUBTRACTION]); + +impl LateLintPass<'_> for InstantSubtraction { + fn check_expr(&mut self, cx: &LateContext<'_>, expr: &'_ Expr<'_>) { + if let ExprKind::Binary(Spanned {node: BinOpKind::Sub, ..}, lhs, rhs) = expr.kind + && check_instant_now_call(cx, lhs) + && let ty_resolved = cx.typeck_results().expr_ty(rhs) + && let rustc_middle::ty::Adt(def, _) = ty_resolved.kind() + && clippy_utils::match_def_path(cx, def.did(), &clippy_utils::paths::INSTANT) + && let Some(sugg) = clippy_utils::sugg::Sugg::hir_opt(cx, rhs) + { + span_lint_and_sugg( + cx, + MANUAL_INSTANT_ELAPSED, + expr.span, + "manual implementation of `Instant::elapsed`", + "try", + format!("{}.elapsed()", sugg.maybe_par()), + Applicability::MachineApplicable, + ); + } -impl<'tcx> LateLintPass<'tcx> for UncheckedDurationSubtraction { - fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) { if expr.span.from_expansion() || !meets_msrv(self.msrv, msrvs::TRY_FROM) { return; } @@ -67,6 +116,17 @@ impl<'tcx> LateLintPass<'tcx> for UncheckedDurationSubtraction { } } +fn check_instant_now_call(cx: &LateContext<'_>, expr_block: &'_ Expr<'_>) -> bool { + if let ExprKind::Call(fn_expr, []) = expr_block.kind + && let Some(fn_id) = clippy_utils::path_def_id(cx, fn_expr) + && clippy_utils::match_def_path(cx, fn_id, &clippy_utils::paths::INSTANT_NOW) + { + true + } else { + false + } +} + fn is_an_instant(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { let expr_ty = cx.typeck_results().expr_ty(expr); diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index a5407b65b..ce0e7ebfb 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -151,6 +151,7 @@ mod inherent_impl; mod inherent_to_string; mod init_numbered_fields; mod inline_fn_without_body; +mod instant_subtraction; mod int_plus_one; mod invalid_upcast_comparisons; mod invalid_utf8_in_unchecked; @@ -172,7 +173,6 @@ mod manual_assert; mod manual_async_fn; mod manual_bits; mod manual_clamp; -mod manual_instant_elapsed; mod manual_is_ascii_check; mod manual_let_else; mod manual_non_exhaustive; @@ -279,7 +279,6 @@ mod trailing_empty_array; mod trait_bounds; mod transmute; mod types; -mod unchecked_duration_subtraction; mod undocumented_unsafe_blocks; mod unicode; mod uninit_vec; @@ -908,7 +907,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_late_pass(move |_| Box::new(operators::Operators::new(verbose_bit_mask_threshold))); store.register_late_pass(|_| Box::new(invalid_utf8_in_unchecked::InvalidUtf8InUnchecked)); store.register_late_pass(|_| Box::::default()); - store.register_late_pass(|_| Box::new(manual_instant_elapsed::ManualInstantElapsed)); + store.register_late_pass(move |_| Box::new(instant_subtraction::InstantSubtraction::new(msrv))); store.register_late_pass(|_| Box::new(partialeq_to_none::PartialeqToNone)); store.register_late_pass(move |_| Box::new(manual_clamp::ManualClamp::new(msrv))); store.register_late_pass(|_| Box::new(manual_string_new::ManualStringNew)); diff --git a/clippy_lints/src/manual_instant_elapsed.rs b/clippy_lints/src/manual_instant_elapsed.rs deleted file mode 100644 index 1e60aa02d..000000000 --- a/clippy_lints/src/manual_instant_elapsed.rs +++ /dev/null @@ -1,69 +0,0 @@ -use clippy_utils::diagnostics::span_lint_and_sugg; -use rustc_errors::Applicability; -use rustc_hir::{BinOpKind, Expr, ExprKind}; -use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; -use rustc_span::source_map::Spanned; - -declare_clippy_lint! { - /// ### What it does - /// Lints subtraction between `Instant::now()` and another `Instant`. - /// - /// ### Why is this bad? - /// It is easy to accidentally write `prev_instant - Instant::now()`, which will always be 0ns - /// as `Instant` subtraction saturates. - /// - /// `prev_instant.elapsed()` also more clearly signals intention. - /// - /// ### Example - /// ```rust - /// use std::time::Instant; - /// let prev_instant = Instant::now(); - /// let duration = Instant::now() - prev_instant; - /// ``` - /// Use instead: - /// ```rust - /// use std::time::Instant; - /// let prev_instant = Instant::now(); - /// let duration = prev_instant.elapsed(); - /// ``` - #[clippy::version = "1.65.0"] - pub MANUAL_INSTANT_ELAPSED, - pedantic, - "subtraction between `Instant::now()` and previous `Instant`" -} - -declare_lint_pass!(ManualInstantElapsed => [MANUAL_INSTANT_ELAPSED]); - -impl LateLintPass<'_> for ManualInstantElapsed { - fn check_expr(&mut self, cx: &LateContext<'_>, expr: &'_ Expr<'_>) { - if let ExprKind::Binary(Spanned {node: BinOpKind::Sub, ..}, lhs, rhs) = expr.kind - && check_instant_now_call(cx, lhs) - && let ty_resolved = cx.typeck_results().expr_ty(rhs) - && let rustc_middle::ty::Adt(def, _) = ty_resolved.kind() - && clippy_utils::match_def_path(cx, def.did(), &clippy_utils::paths::INSTANT) - && let Some(sugg) = clippy_utils::sugg::Sugg::hir_opt(cx, rhs) - { - span_lint_and_sugg( - cx, - MANUAL_INSTANT_ELAPSED, - expr.span, - "manual implementation of `Instant::elapsed`", - "try", - format!("{}.elapsed()", sugg.maybe_par()), - Applicability::MachineApplicable, - ); - } - } -} - -fn check_instant_now_call(cx: &LateContext<'_>, expr_block: &'_ Expr<'_>) -> bool { - if let ExprKind::Call(fn_expr, []) = expr_block.kind - && let Some(fn_id) = clippy_utils::path_def_id(cx, fn_expr) - && clippy_utils::match_def_path(cx, fn_id, &clippy_utils::paths::INSTANT_NOW) - { - true - } else { - false - } -} From a566eb37659ecbdcfe1403f8ccab753714dbec60 Mon Sep 17 00:00:00 2001 From: Nadir Fejzic Date: Mon, 7 Nov 2022 20:59:55 +0100 Subject: [PATCH 06/16] docs: update docs for unchecked duration subtr. lint --- src/docs/unchecked_duration_subtraction.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/docs/unchecked_duration_subtraction.txt b/src/docs/unchecked_duration_subtraction.txt index 6b9c9308c..15a4c02c6 100644 --- a/src/docs/unchecked_duration_subtraction.txt +++ b/src/docs/unchecked_duration_subtraction.txt @@ -2,7 +2,7 @@ Finds patterns of unchecked subtraction of [`Duration`] from [`Instant::now()`]. ### Why is this bad? -Unchecked subtraction could cause underflow on certain platforms, leading to bugs and/or +Unchecked subtraction could cause underflow on certain platforms, leading to unintentional panics. ### Example From 80e3553f290cd252646c61086e9461fc7618b694 Mon Sep 17 00:00:00 2001 From: Nadir Fejzic Date: Mon, 7 Nov 2022 21:34:24 +0100 Subject: [PATCH 07/16] refactor: improve code re-use in InstantSubtraction lint pass --- clippy_lints/src/instant_subtraction.rs | 77 +++++++++++++++---------- 1 file changed, 46 insertions(+), 31 deletions(-) diff --git a/clippy_lints/src/instant_subtraction.rs b/clippy_lints/src/instant_subtraction.rs index 8cc5643c9..3166c62da 100644 --- a/clippy_lints/src/instant_subtraction.rs +++ b/clippy_lints/src/instant_subtraction.rs @@ -1,6 +1,8 @@ use clippy_utils::{ diagnostics::{self, span_lint_and_sugg}, - meets_msrv, msrvs, source, ty, + meets_msrv, msrvs, source, + sugg::Sugg, + ty, }; use rustc_errors::Applicability; use rustc_hir::{BinOpKind, Expr, ExprKind}; @@ -78,45 +80,41 @@ impl_lint_pass!(InstantSubtraction => [MANUAL_INSTANT_ELAPSED, UNCHECKED_DURATIO impl LateLintPass<'_> for InstantSubtraction { fn check_expr(&mut self, cx: &LateContext<'_>, expr: &'_ Expr<'_>) { - if let ExprKind::Binary(Spanned {node: BinOpKind::Sub, ..}, lhs, rhs) = expr.kind - && check_instant_now_call(cx, lhs) - && let ty_resolved = cx.typeck_results().expr_ty(rhs) - && let rustc_middle::ty::Adt(def, _) = ty_resolved.kind() - && clippy_utils::match_def_path(cx, def.did(), &clippy_utils::paths::INSTANT) - && let Some(sugg) = clippy_utils::sugg::Sugg::hir_opt(cx, rhs) + if let ExprKind::Binary( + Spanned { + node: BinOpKind::Sub, .. + }, + lhs, + rhs, + ) = expr.kind { - span_lint_and_sugg( - cx, - MANUAL_INSTANT_ELAPSED, - expr.span, - "manual implementation of `Instant::elapsed`", - "try", - format!("{}.elapsed()", sugg.maybe_par()), - Applicability::MachineApplicable, - ); - } + if_chain! { + if is_instant_now_call(cx, lhs); - if expr.span.from_expansion() || !meets_msrv(self.msrv, msrvs::TRY_FROM) { - return; - } + if is_an_instant(cx, rhs); + if let Some(sugg) = Sugg::hir_opt(cx, rhs); - if_chain! { - if let ExprKind::Binary(op, lhs, rhs) = expr.kind; + then { + print_manual_instant_elapsed_sugg(cx, expr, sugg) + } else { + if_chain! { + if !expr.span.from_expansion(); + if meets_msrv(self.msrv, msrvs::TRY_FROM); - if let BinOpKind::Sub = op.node; + if is_an_instant(cx, lhs); + if is_a_duration(cx, rhs); - // get types of left and right side - if is_an_instant(cx, lhs); - if is_a_duration(cx, rhs); - - then { - print_lint_and_sugg(cx, lhs, rhs, expr) + then { + print_unchecked_duration_subtraction_sugg(cx, lhs, rhs, expr) + } + } + } } } } } -fn check_instant_now_call(cx: &LateContext<'_>, expr_block: &'_ Expr<'_>) -> bool { +fn is_instant_now_call(cx: &LateContext<'_>, expr_block: &'_ Expr<'_>) -> bool { if let ExprKind::Call(fn_expr, []) = expr_block.kind && let Some(fn_id) = clippy_utils::path_def_id(cx, fn_expr) && clippy_utils::match_def_path(cx, fn_id, &clippy_utils::paths::INSTANT_NOW) @@ -141,7 +139,24 @@ fn is_a_duration(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { ty::is_type_diagnostic_item(cx, expr_ty, sym::Duration) } -fn print_lint_and_sugg(cx: &LateContext<'_>, left_expr: &Expr<'_>, right_expr: &Expr<'_>, expr: &Expr<'_>) { +fn print_manual_instant_elapsed_sugg(cx: &LateContext<'_>, expr: &Expr<'_>, sugg: Sugg<'_>) { + span_lint_and_sugg( + cx, + MANUAL_INSTANT_ELAPSED, + expr.span, + "manual implementation of `Instant::elapsed`", + "try", + format!("{}.elapsed()", sugg.maybe_par()), + Applicability::MachineApplicable, + ); +} + +fn print_unchecked_duration_subtraction_sugg( + cx: &LateContext<'_>, + left_expr: &Expr<'_>, + right_expr: &Expr<'_>, + expr: &Expr<'_>, +) { let mut applicability = Applicability::MachineApplicable; let left_expr = From 4bd6d0beb0ef8ad72ad8ce6a28eb25a48f9cbc4b Mon Sep 17 00:00:00 2001 From: Nadir Fejzic Date: Mon, 7 Nov 2022 21:37:04 +0100 Subject: [PATCH 08/16] test: update tests for manual_instant_elapsed lint --- tests/ui/manual_instant_elapsed.fixed | 1 + tests/ui/manual_instant_elapsed.rs | 1 + tests/ui/manual_instant_elapsed.stderr | 4 ++-- 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/tests/ui/manual_instant_elapsed.fixed b/tests/ui/manual_instant_elapsed.fixed index 0fa776b7b..85a91543c 100644 --- a/tests/ui/manual_instant_elapsed.fixed +++ b/tests/ui/manual_instant_elapsed.fixed @@ -1,6 +1,7 @@ // run-rustfix #![warn(clippy::manual_instant_elapsed)] #![allow(clippy::unnecessary_operation)] +#![allow(clippy::unchecked_duration_subtraction)] #![allow(unused_variables)] #![allow(unused_must_use)] diff --git a/tests/ui/manual_instant_elapsed.rs b/tests/ui/manual_instant_elapsed.rs index 5b11b8453..c98cb15b9 100644 --- a/tests/ui/manual_instant_elapsed.rs +++ b/tests/ui/manual_instant_elapsed.rs @@ -1,6 +1,7 @@ // run-rustfix #![warn(clippy::manual_instant_elapsed)] #![allow(clippy::unnecessary_operation)] +#![allow(clippy::unchecked_duration_subtraction)] #![allow(unused_variables)] #![allow(unused_must_use)] diff --git a/tests/ui/manual_instant_elapsed.stderr b/tests/ui/manual_instant_elapsed.stderr index 5537f5642..4ce1f6891 100644 --- a/tests/ui/manual_instant_elapsed.stderr +++ b/tests/ui/manual_instant_elapsed.stderr @@ -1,5 +1,5 @@ error: manual implementation of `Instant::elapsed` - --> $DIR/manual_instant_elapsed.rs:17:20 + --> $DIR/manual_instant_elapsed.rs:18:20 | LL | let duration = Instant::now() - prev_instant; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `prev_instant.elapsed()` @@ -7,7 +7,7 @@ LL | let duration = Instant::now() - prev_instant; = note: `-D clippy::manual-instant-elapsed` implied by `-D warnings` error: manual implementation of `Instant::elapsed` - --> $DIR/manual_instant_elapsed.rs:26:5 + --> $DIR/manual_instant_elapsed.rs:27:5 | LL | Instant::now() - *ref_to_instant; // to ensure parens are added correctly | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `(*ref_to_instant).elapsed()` From 852d80245148cdd23c5516bea015b0f3bf277ed4 Mon Sep 17 00:00:00 2001 From: Nadir Fejzic Date: Mon, 7 Nov 2022 22:21:32 +0100 Subject: [PATCH 09/16] style: inline variables in `format!` --- clippy_lints/src/instant_subtraction.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clippy_lints/src/instant_subtraction.rs b/clippy_lints/src/instant_subtraction.rs index 3166c62da..c039f1b5c 100644 --- a/clippy_lints/src/instant_subtraction.rs +++ b/clippy_lints/src/instant_subtraction.rs @@ -174,7 +174,7 @@ fn print_unchecked_duration_subtraction_sugg( expr.span, "unchecked subtraction of a 'Duration' from an 'Instant'", "try", - format!("{}.checked_sub({}).unwrap();", left_expr, right_expr), + format!("{left_expr}.checked_sub({right_expr}).unwrap();"), applicability, ); } From 62ab4fb9c265b9e25d61c99511cd26de0260f435 Mon Sep 17 00:00:00 2001 From: Nadir Fejzic Date: Tue, 8 Nov 2022 10:22:58 +0100 Subject: [PATCH 10/16] fix: add rust-fix annotation to unckd. duration subtr. lint test --- tests/ui/unchecked_duration_subtraction.fixed | 17 +++++++++++++++++ tests/ui/unchecked_duration_subtraction.rs | 1 + tests/ui/unchecked_duration_subtraction.stderr | 8 ++++---- 3 files changed, 22 insertions(+), 4 deletions(-) create mode 100644 tests/ui/unchecked_duration_subtraction.fixed diff --git a/tests/ui/unchecked_duration_subtraction.fixed b/tests/ui/unchecked_duration_subtraction.fixed new file mode 100644 index 000000000..bcc231d93 --- /dev/null +++ b/tests/ui/unchecked_duration_subtraction.fixed @@ -0,0 +1,17 @@ +// run-rustfix +#![warn(clippy::unchecked_duration_subtraction)] + +use std::time::{Duration, Instant}; + +fn main() { + let _first = Instant::now(); + let second = Duration::from_secs(3); + + let _ = _first.checked_sub(second).unwrap();; + + let _ = Instant::now().checked_sub(Duration::from_secs(5)).unwrap();; + + let _ = _first.checked_sub(Duration::from_secs(5)).unwrap();; + + let _ = Instant::now().checked_sub(second).unwrap();; +} diff --git a/tests/ui/unchecked_duration_subtraction.rs b/tests/ui/unchecked_duration_subtraction.rs index fff1d1372..a14a7ea57 100644 --- a/tests/ui/unchecked_duration_subtraction.rs +++ b/tests/ui/unchecked_duration_subtraction.rs @@ -1,3 +1,4 @@ +// run-rustfix #![warn(clippy::unchecked_duration_subtraction)] use std::time::{Duration, Instant}; diff --git a/tests/ui/unchecked_duration_subtraction.stderr b/tests/ui/unchecked_duration_subtraction.stderr index 6b297a01c..b949dbf70 100644 --- a/tests/ui/unchecked_duration_subtraction.stderr +++ b/tests/ui/unchecked_duration_subtraction.stderr @@ -1,5 +1,5 @@ error: unchecked subtraction of a 'Duration' from an 'Instant' - --> $DIR/unchecked_duration_subtraction.rs:9:13 + --> $DIR/unchecked_duration_subtraction.rs:10:13 | LL | let _ = _first - second; | ^^^^^^^^^^^^^^^ help: try: `_first.checked_sub(second).unwrap();` @@ -7,19 +7,19 @@ LL | let _ = _first - second; = note: `-D clippy::unchecked-duration-subtraction` implied by `-D warnings` error: unchecked subtraction of a 'Duration' from an 'Instant' - --> $DIR/unchecked_duration_subtraction.rs:11:13 + --> $DIR/unchecked_duration_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' - --> $DIR/unchecked_duration_subtraction.rs:13:13 + --> $DIR/unchecked_duration_subtraction.rs:14: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' - --> $DIR/unchecked_duration_subtraction.rs:15:13 + --> $DIR/unchecked_duration_subtraction.rs:16:13 | LL | let _ = Instant::now() - second; | ^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Instant::now().checked_sub(second).unwrap();` From 862ac29192bd4e2c9db04e9763dfd1a35a00a9cb Mon Sep 17 00:00:00 2001 From: Nadir Fejzic Date: Tue, 8 Nov 2022 15:04:32 +0100 Subject: [PATCH 11/16] fix: remove (redundant) semicolon in lint suggestion --- clippy_lints/src/instant_subtraction.rs | 2 +- tests/ui/unchecked_duration_subtraction.fixed | 8 ++++---- tests/ui/unchecked_duration_subtraction.stderr | 8 ++++---- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/clippy_lints/src/instant_subtraction.rs b/clippy_lints/src/instant_subtraction.rs index c039f1b5c..d83beb622 100644 --- a/clippy_lints/src/instant_subtraction.rs +++ b/clippy_lints/src/instant_subtraction.rs @@ -174,7 +174,7 @@ fn print_unchecked_duration_subtraction_sugg( expr.span, "unchecked subtraction of a 'Duration' from an 'Instant'", "try", - format!("{left_expr}.checked_sub({right_expr}).unwrap();"), + format!("{left_expr}.checked_sub({right_expr}).unwrap()"), applicability, ); } diff --git a/tests/ui/unchecked_duration_subtraction.fixed b/tests/ui/unchecked_duration_subtraction.fixed index bcc231d93..a0e49a8be 100644 --- a/tests/ui/unchecked_duration_subtraction.fixed +++ b/tests/ui/unchecked_duration_subtraction.fixed @@ -7,11 +7,11 @@ fn main() { let _first = Instant::now(); let second = Duration::from_secs(3); - let _ = _first.checked_sub(second).unwrap();; + let _ = _first.checked_sub(second).unwrap(); - let _ = Instant::now().checked_sub(Duration::from_secs(5)).unwrap();; + let _ = Instant::now().checked_sub(Duration::from_secs(5)).unwrap(); - let _ = _first.checked_sub(Duration::from_secs(5)).unwrap();; + let _ = _first.checked_sub(Duration::from_secs(5)).unwrap(); - let _ = Instant::now().checked_sub(second).unwrap();; + let _ = Instant::now().checked_sub(second).unwrap(); } diff --git a/tests/ui/unchecked_duration_subtraction.stderr b/tests/ui/unchecked_duration_subtraction.stderr index b949dbf70..a2e0aa1d7 100644 --- a/tests/ui/unchecked_duration_subtraction.stderr +++ b/tests/ui/unchecked_duration_subtraction.stderr @@ -2,7 +2,7 @@ error: unchecked subtraction of a 'Duration' from an 'Instant' --> $DIR/unchecked_duration_subtraction.rs:10:13 | LL | let _ = _first - second; - | ^^^^^^^^^^^^^^^ help: try: `_first.checked_sub(second).unwrap();` + | ^^^^^^^^^^^^^^^ help: try: `_first.checked_sub(second).unwrap()` | = note: `-D clippy::unchecked-duration-subtraction` implied by `-D warnings` @@ -10,19 +10,19 @@ error: unchecked subtraction of a 'Duration' from an 'Instant' --> $DIR/unchecked_duration_subtraction.rs:12:13 | LL | let _ = Instant::now() - Duration::from_secs(5); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Instant::now().checked_sub(Duration::from_secs(5)).unwrap();` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Instant::now().checked_sub(Duration::from_secs(5)).unwrap()` error: unchecked subtraction of a 'Duration' from an 'Instant' --> $DIR/unchecked_duration_subtraction.rs:14:13 | LL | let _ = _first - Duration::from_secs(5); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `_first.checked_sub(Duration::from_secs(5)).unwrap();` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `_first.checked_sub(Duration::from_secs(5)).unwrap()` error: unchecked subtraction of a 'Duration' from an 'Instant' --> $DIR/unchecked_duration_subtraction.rs:16:13 | LL | let _ = Instant::now() - second; - | ^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Instant::now().checked_sub(second).unwrap();` + | ^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Instant::now().checked_sub(second).unwrap()` error: aborting due to 4 previous errors From 36eac0cb4ae2e372193f73c3181d5290431d3ae4 Mon Sep 17 00:00:00 2001 From: Nadir Fejzic Date: Thu, 10 Nov 2022 15:55:45 +0100 Subject: [PATCH 12/16] fix: update lints --- clippy_lints/src/declared_lints.rs | 3 ++- clippy_lints/src/lib.rs | 1 - src/docs/unchecked_duration_subtraction.txt | 19 ------------------- 3 files changed, 2 insertions(+), 21 deletions(-) delete mode 100644 src/docs/unchecked_duration_subtraction.txt diff --git a/clippy_lints/src/declared_lints.rs b/clippy_lints/src/declared_lints.rs index 98265410e..7a705e563 100644 --- a/clippy_lints/src/declared_lints.rs +++ b/clippy_lints/src/declared_lints.rs @@ -202,6 +202,8 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[ crate::inherent_to_string::INHERENT_TO_STRING_SHADOW_DISPLAY_INFO, crate::init_numbered_fields::INIT_NUMBERED_FIELDS_INFO, crate::inline_fn_without_body::INLINE_FN_WITHOUT_BODY_INFO, + crate::instant_subtraction::MANUAL_INSTANT_ELAPSED_INFO, + crate::instant_subtraction::UNCHECKED_DURATION_SUBTRACTION_INFO, crate::int_plus_one::INT_PLUS_ONE_INFO, crate::invalid_upcast_comparisons::INVALID_UPCAST_COMPARISONS_INFO, crate::invalid_utf8_in_unchecked::INVALID_UTF8_IN_UNCHECKED_INFO, @@ -250,7 +252,6 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[ crate::manual_async_fn::MANUAL_ASYNC_FN_INFO, crate::manual_bits::MANUAL_BITS_INFO, crate::manual_clamp::MANUAL_CLAMP_INFO, - crate::manual_instant_elapsed::MANUAL_INSTANT_ELAPSED_INFO, crate::manual_is_ascii_check::MANUAL_IS_ASCII_CHECK_INFO, crate::manual_let_else::MANUAL_LET_ELSE_INFO, crate::manual_non_exhaustive::MANUAL_NON_EXHAUSTIVE_INFO, diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index ce0e7ebfb..3cfb2f491 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -921,7 +921,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_late_pass(|_| Box::new(from_raw_with_void_ptr::FromRawWithVoidPtr)); store.register_late_pass(|_| Box::new(suspicious_xor_used_as_pow::ConfusingXorAndPow)); store.register_late_pass(move |_| Box::new(manual_is_ascii_check::ManualIsAsciiCheck::new(msrv))); - store.register_late_pass(move || Box::new(unchecked_duration_subtraction::UncheckedDurationSubtraction::new(msrv))); // add lints here, do not remove this comment, it's used in `new_lint` } diff --git a/src/docs/unchecked_duration_subtraction.txt b/src/docs/unchecked_duration_subtraction.txt deleted file mode 100644 index 15a4c02c6..000000000 --- a/src/docs/unchecked_duration_subtraction.txt +++ /dev/null @@ -1,19 +0,0 @@ -### What it does -Finds patterns of unchecked subtraction of [`Duration`] from [`Instant::now()`]. - -### Why is this bad? -Unchecked subtraction could cause underflow on certain platforms, leading to -unintentional panics. - -### Example -``` -let time_passed = Instant::now() - Duration::from_secs(5); -``` - -Use instead: -``` -let time_passed = Instant::now().checked_sub(Duration::from_secs(5)); -``` - -[`Duration`]: std::time::Duration -[`Instant::now()`]: std::time::Instant::now; \ No newline at end of file From 3f89ab0618a1075f0c53c47d405c0f6e9bf43953 Mon Sep 17 00:00:00 2001 From: Nadir Fejzic Date: Mon, 14 Nov 2022 22:00:09 +0100 Subject: [PATCH 13/16] chore: update lint version of MANUAL_INSTAN_ELAPSED to 1.65 --- clippy_lints/src/instant_subtraction.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clippy_lints/src/instant_subtraction.rs b/clippy_lints/src/instant_subtraction.rs index d83beb622..6d23a6728 100644 --- a/clippy_lints/src/instant_subtraction.rs +++ b/clippy_lints/src/instant_subtraction.rs @@ -33,7 +33,7 @@ declare_clippy_lint! { /// let prev_instant = Instant::now(); /// let duration = prev_instant.elapsed(); /// ``` - #[clippy::version = "1.64.0"] + #[clippy::version = "1.65.0"] pub MANUAL_INSTANT_ELAPSED, pedantic, "subtraction between `Instant::now()` and previous `Instant`" From 912dc919af03427288b64921bb4aea0010d071bf Mon Sep 17 00:00:00 2001 From: Nadir Fejzic Date: Mon, 14 Nov 2022 22:08:11 +0100 Subject: [PATCH 14/16] docs: update unchecked duration subtraction lint doc --- clippy_lints/src/instant_subtraction.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clippy_lints/src/instant_subtraction.rs b/clippy_lints/src/instant_subtraction.rs index 6d23a6728..3f72222f3 100644 --- a/clippy_lints/src/instant_subtraction.rs +++ b/clippy_lints/src/instant_subtraction.rs @@ -41,7 +41,7 @@ declare_clippy_lint! { declare_clippy_lint! { /// ### What it does - /// Finds patterns of unchecked subtraction of [`Duration`] from [`Instant::now()`]. + /// Lints subtraction between an [`Instant`] and a [`Duration`]. /// /// ### Why is this bad? /// Unchecked subtraction could cause underflow on certain platforms, leading to From 72ab91d8066ee399cff3e3c8293bf4dbccfb6358 Mon Sep 17 00:00:00 2001 From: Nadir Fejzic Date: Mon, 14 Nov 2022 22:25:56 +0100 Subject: [PATCH 15/16] fix: add extract_msrv_attr call to instan_subtraction lint pass --- clippy_lints/src/instant_subtraction.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/clippy_lints/src/instant_subtraction.rs b/clippy_lints/src/instant_subtraction.rs index 3f72222f3..716c11bec 100644 --- a/clippy_lints/src/instant_subtraction.rs +++ b/clippy_lints/src/instant_subtraction.rs @@ -112,6 +112,8 @@ impl LateLintPass<'_> for InstantSubtraction { } } } + + extract_msrv_attr!(LateContext); } fn is_instant_now_call(cx: &LateContext<'_>, expr_block: &'_ Expr<'_>) -> bool { From 0dd6ce0b1931e3e5c274daf4bbf50e96a322befd Mon Sep 17 00:00:00 2001 From: Nadir Fejzic Date: Mon, 14 Nov 2022 22:37:25 +0100 Subject: [PATCH 16/16] docs: import Instant and Duration in doctests --- clippy_lints/src/instant_subtraction.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/clippy_lints/src/instant_subtraction.rs b/clippy_lints/src/instant_subtraction.rs index 716c11bec..60754b224 100644 --- a/clippy_lints/src/instant_subtraction.rs +++ b/clippy_lints/src/instant_subtraction.rs @@ -49,11 +49,13 @@ declare_clippy_lint! { /// /// ### Example /// ```rust + /// # use std::time::{Instant, Duration}; /// let time_passed = Instant::now() - Duration::from_secs(5); /// ``` /// /// Use instead: /// ```rust + /// # use std::time::{Instant, Duration}; /// let time_passed = Instant::now().checked_sub(Duration::from_secs(5)); /// ``` ///