]>
Commit | Line | Data |
---|---|---|
49aad941 | 1 | //! Checks for usage of mutex where an atomic value could be used |
f20569fa | 2 | //! |
9c376795 | 3 | //! This lint is **allow** by default |
f20569fa | 4 | |
cdc7bbd5 XL |
5 | use clippy_utils::diagnostics::span_lint; |
6 | use clippy_utils::ty::is_type_diagnostic_item; | |
f20569fa XL |
7 | use rustc_hir::Expr; |
8 | use rustc_lint::{LateContext, LateLintPass}; | |
9 | use rustc_middle::ty::{self, Ty}; | |
10 | use rustc_session::{declare_lint_pass, declare_tool_lint}; | |
c295e0f8 | 11 | use rustc_span::sym; |
f20569fa XL |
12 | |
13 | declare_clippy_lint! { | |
94222f64 | 14 | /// ### What it does |
49aad941 | 15 | /// Checks for usage of `Mutex<X>` where an atomic will do. |
f20569fa | 16 | /// |
94222f64 XL |
17 | /// ### Why is this bad? |
18 | /// Using a mutex just to make access to a plain bool or | |
f20569fa XL |
19 | /// reference sequential is shooting flies with cannons. |
20 | /// `std::sync::atomic::AtomicBool` and `std::sync::atomic::AtomicPtr` are leaner and | |
21 | /// faster. | |
22 | /// | |
9c376795 FG |
23 | /// On the other hand, `Mutex`es are, in general, easier to |
24 | /// verify correctness. An atomic does not behave the same as | |
25 | /// an equivalent mutex. See [this issue](https://github.com/rust-lang/rust-clippy/issues/4295)'s commentary for more details. | |
26 | /// | |
94222f64 XL |
27 | /// ### Known problems |
28 | /// This lint cannot detect if the mutex is actually used | |
f20569fa XL |
29 | /// for waiting before a critical section. |
30 | /// | |
94222f64 | 31 | /// ### Example |
f20569fa XL |
32 | /// ```rust |
33 | /// # let y = true; | |
f20569fa XL |
34 | /// # use std::sync::Mutex; |
35 | /// let x = Mutex::new(&y); | |
923072b8 | 36 | /// ``` |
f20569fa | 37 | /// |
923072b8 FG |
38 | /// Use instead: |
39 | /// ```rust | |
40 | /// # let y = true; | |
f20569fa XL |
41 | /// # use std::sync::atomic::AtomicBool; |
42 | /// let x = AtomicBool::new(y); | |
43 | /// ``` | |
a2a8927a | 44 | #[clippy::version = "pre 1.29.0"] |
f20569fa | 45 | pub MUTEX_ATOMIC, |
9c376795 FG |
46 | restriction, |
47 | "using a mutex where an atomic value could be used instead." | |
f20569fa XL |
48 | } |
49 | ||
50 | declare_clippy_lint! { | |
94222f64 | 51 | /// ### What it does |
49aad941 | 52 | /// Checks for usage of `Mutex<X>` where `X` is an integral |
f20569fa XL |
53 | /// type. |
54 | /// | |
94222f64 XL |
55 | /// ### Why is this bad? |
56 | /// Using a mutex just to make access to a plain integer | |
f20569fa XL |
57 | /// sequential is |
58 | /// shooting flies with cannons. `std::sync::atomic::AtomicUsize` is leaner and faster. | |
59 | /// | |
94222f64 XL |
60 | /// ### Known problems |
61 | /// This lint cannot detect if the mutex is actually used | |
f20569fa XL |
62 | /// for waiting before a critical section. |
63 | /// | |
94222f64 | 64 | /// ### Example |
f20569fa XL |
65 | /// ```rust |
66 | /// # use std::sync::Mutex; | |
67 | /// let x = Mutex::new(0usize); | |
923072b8 | 68 | /// ``` |
f20569fa | 69 | /// |
923072b8 FG |
70 | /// Use instead: |
71 | /// ```rust | |
f20569fa XL |
72 | /// # use std::sync::atomic::AtomicUsize; |
73 | /// let x = AtomicUsize::new(0usize); | |
74 | /// ``` | |
a2a8927a | 75 | #[clippy::version = "pre 1.29.0"] |
f20569fa XL |
76 | pub MUTEX_INTEGER, |
77 | nursery, | |
78 | "using a mutex for an integer type" | |
79 | } | |
80 | ||
81 | declare_lint_pass!(Mutex => [MUTEX_ATOMIC, MUTEX_INTEGER]); | |
82 | ||
83 | impl<'tcx> LateLintPass<'tcx> for Mutex { | |
84 | fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { | |
85 | let ty = cx.typeck_results().expr_ty(expr); | |
86 | if let ty::Adt(_, subst) = ty.kind() { | |
c295e0f8 | 87 | if is_type_diagnostic_item(cx, ty, sym::Mutex) { |
f20569fa XL |
88 | let mutex_param = subst.type_at(0); |
89 | if let Some(atomic_name) = get_atomic_name(mutex_param) { | |
90 | let msg = format!( | |
2b03887a FG |
91 | "consider using an `{atomic_name}` instead of a `Mutex` here; if you just want the locking \ |
92 | behavior and not the internal type, consider using `Mutex<()>`" | |
f20569fa XL |
93 | ); |
94 | match *mutex_param.kind() { | |
95 | ty::Uint(t) if t != ty::UintTy::Usize => span_lint(cx, MUTEX_INTEGER, expr.span, &msg), | |
96 | ty::Int(t) if t != ty::IntTy::Isize => span_lint(cx, MUTEX_INTEGER, expr.span, &msg), | |
97 | _ => span_lint(cx, MUTEX_ATOMIC, expr.span, &msg), | |
98 | }; | |
99 | } | |
100 | } | |
101 | } | |
102 | } | |
103 | } | |
104 | ||
105 | fn get_atomic_name(ty: Ty<'_>) -> Option<&'static str> { | |
106 | match ty.kind() { | |
107 | ty::Bool => Some("AtomicBool"), | |
108 | ty::Uint(_) => Some("AtomicUsize"), | |
109 | ty::Int(_) => Some("AtomicIsize"), | |
110 | ty::RawPtr(_) => Some("AtomicPtr"), | |
111 | _ => None, | |
112 | } | |
113 | } |