]> git.lizzy.rs Git - rust.git/commitdiff
refactor: lint man. instant elapsed and unch. dur. subtr. in single pass
authorNadir Fejzic <nadirfejzo@gmail.com>
Mon, 7 Nov 2022 19:58:49 +0000 (20:58 +0100)
committerNadir Fejzic <nadirfejzo@gmail.com>
Thu, 10 Nov 2022 14:47:12 +0000 (15:47 +0100)
clippy_lints/src/instant_subtraction.rs [new file with mode: 0644]
clippy_lints/src/lib.rs
clippy_lints/src/manual_instant_elapsed.rs [deleted file]
clippy_lints/src/unchecked_duration_subtraction.rs [deleted file]

diff --git a/clippy_lints/src/instant_subtraction.rs b/clippy_lints/src/instant_subtraction.rs
new file mode 100644 (file)
index 0000000..8cc5643
--- /dev/null
@@ -0,0 +1,165 @@
+use clippy_utils::{
+    diagnostics::{self, span_lint_and_sugg},
+    meets_msrv, msrvs, source, ty,
+};
+use rustc_errors::Applicability;
+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::{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
+    /// 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 InstantSubtraction {
+    msrv: Option<RustcVersion>,
+}
+
+impl InstantSubtraction {
+    #[must_use]
+    pub fn new(msrv: Option<RustcVersion>) -> Self {
+        Self { msrv }
+    }
+}
+
+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,
+            );
+        }
+
+        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 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);
+
+    match expr_ty.kind() {
+        rustc_middle::ty::Adt(def, _) => clippy_utils::match_def_path(cx, 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,
+    );
+}
index a5407b65b88d1633f5bf2c8d7642e46dfdad3133..ce0e7ebfbf1b63e6761654c7711a370e3e606f8e 100644 (file)
 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;
 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;
 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::<std_instead_of_core::StdReexports>::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 (file)
index 1e60aa0..0000000
+++ /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
-    }
-}
diff --git a/clippy_lints/src/unchecked_duration_subtraction.rs b/clippy_lints/src/unchecked_duration_subtraction.rs
deleted file mode 100644 (file)
index ae79600..0000000
+++ /dev/null
@@ -1,105 +0,0 @@
-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<RustcVersion>,
-}
-
-impl UncheckedDurationSubtraction {
-    #[must_use]
-    pub fn new(msrv: Option<RustcVersion>) -> 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, 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,
-    );
-}