about summary refs log tree commit diff
path: root/clippy_lints/src/methods
diff options
context:
space:
mode:
Diffstat (limited to 'clippy_lints/src/methods')
-rw-r--r--clippy_lints/src/methods/mod.rs27
-rw-r--r--clippy_lints/src/methods/waker_clone_wake.rs32
2 files changed, 59 insertions, 0 deletions
diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs
index 373d8606b1d..e1a14e29358 100644
--- a/clippy_lints/src/methods/mod.rs
+++ b/clippy_lints/src/methods/mod.rs
@@ -112,6 +112,7 @@ mod useless_asref;
 mod utils;
 mod vec_resize_to_zero;
 mod verbose_file_reads;
+mod waker_clone_wake;
 mod wrong_self_convention;
 mod zst_offset;
 
@@ -3632,6 +3633,28 @@ declare_clippy_lint! {
     "`as_str` used to call a method on `str` that is also available on `String`"
 }
 
+declare_clippy_lint! {
+    /// ### What it does
+    /// Checks for usage of `waker.clone().wake()`
+    ///
+    /// ### Why is this bad?
+    /// Cloning the waker is not necessary, `wake_by_ref()` enables the same operation
+    /// without extra cloning/dropping.
+    ///
+    /// ### Example
+    /// ```rust,ignore
+    /// waker.clone().wake();
+    /// ```
+    /// Should be written
+    /// ```rust,ignore
+    /// waker.wake_by_ref();
+    /// ```
+    #[clippy::version = "1.75.0"]
+    pub WAKER_CLONE_WAKE,
+    perf,
+    "cloning a `Waker` only to wake it"
+}
+
 pub struct Methods {
     avoid_breaking_exported_api: bool,
     msrv: Msrv,
@@ -3777,6 +3800,7 @@ impl_lint_pass!(Methods => [
     ITER_OUT_OF_BOUNDS,
     PATH_ENDS_WITH_EXT,
     REDUNDANT_AS_STR,
+    WAKER_CLONE_WAKE,
 ]);
 
 /// Extracts a method call name, args, and `Span` of the method name.
@@ -4365,6 +4389,9 @@ impl Methods {
                     }
                     unnecessary_literal_unwrap::check(cx, expr, recv, name, args);
                 },
+                ("wake", []) => {
+                    waker_clone_wake::check(cx, expr, recv);
+                }
                 ("write", []) => {
                     readonly_write_lock::check(cx, expr, recv);
                 }
diff --git a/clippy_lints/src/methods/waker_clone_wake.rs b/clippy_lints/src/methods/waker_clone_wake.rs
new file mode 100644
index 00000000000..da66632d55f
--- /dev/null
+++ b/clippy_lints/src/methods/waker_clone_wake.rs
@@ -0,0 +1,32 @@
+use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::source::snippet_with_applicability;
+use clippy_utils::{is_trait_method, match_def_path, paths};
+use rustc_errors::Applicability;
+use rustc_hir::{Expr, ExprKind};
+use rustc_lint::LateContext;
+use rustc_span::sym;
+
+use super::WAKER_CLONE_WAKE;
+
+pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, recv: &'tcx Expr<'_>) {
+    let ty = cx.typeck_results().expr_ty(recv);
+
+    if let Some(did) = ty.ty_adt_def()
+        && match_def_path(cx, did.did(), &paths::WAKER)
+        && let ExprKind::MethodCall(_, waker_ref, &[], _) = recv.kind
+        && is_trait_method(cx, recv, sym::Clone)
+    {
+        let mut applicability = Applicability::MachineApplicable;
+        let snippet = snippet_with_applicability(cx, waker_ref.span.source_callsite(), "..", &mut applicability);
+
+        span_lint_and_sugg(
+            cx,
+            WAKER_CLONE_WAKE,
+            expr.span,
+            "cloning a `Waker` only to wake it",
+            "replace with",
+            format!("{snippet}.wake_by_ref()"),
+            applicability,
+        );
+    }
+}