]> git.lizzy.rs Git - rust.git/blob - clippy_lints/src/atomic_ordering.rs
Auto merge of #5033 - JohnTitor:split-use-self, r=flip1995
[rust.git] / clippy_lints / src / atomic_ordering.rs
1 use crate::utils::{match_def_path, span_help_and_lint};
2 use if_chain::if_chain;
3 use rustc::ty;
4 use rustc_hir::def_id::DefId;
5 use rustc_hir::*;
6 use rustc_lint::{LateContext, LateLintPass};
7 use rustc_session::{declare_lint_pass, declare_tool_lint};
8
9 declare_clippy_lint! {
10     /// **What it does:** Checks for usage of invalid atomic
11     /// ordering in Atomic*::{load, store} calls.
12     ///
13     /// **Why is this bad?** Using an invalid atomic ordering
14     /// will cause a panic at run-time.
15     ///
16     /// **Known problems:** None.
17     ///
18     /// **Example:**
19     /// ```rust,no_run
20     /// # use std::sync::atomic::{AtomicBool, Ordering};
21     ///
22     /// let x = AtomicBool::new(true);
23     ///
24     /// let _ = x.load(Ordering::Release);
25     /// let _ = x.load(Ordering::AcqRel);
26     ///
27     /// x.store(false, Ordering::Acquire);
28     /// x.store(false, Ordering::AcqRel);
29     /// ```
30     pub INVALID_ATOMIC_ORDERING,
31     correctness,
32     "usage of invalid atomic ordering in atomic load/store calls"
33 }
34
35 declare_lint_pass!(AtomicOrdering => [INVALID_ATOMIC_ORDERING]);
36
37 const ATOMIC_TYPES: [&str; 12] = [
38     "AtomicBool",
39     "AtomicI8",
40     "AtomicI16",
41     "AtomicI32",
42     "AtomicI64",
43     "AtomicIsize",
44     "AtomicPtr",
45     "AtomicU8",
46     "AtomicU16",
47     "AtomicU32",
48     "AtomicU64",
49     "AtomicUsize",
50 ];
51
52 fn type_is_atomic(cx: &LateContext<'_, '_>, expr: &Expr<'_>) -> bool {
53     if let ty::Adt(&ty::AdtDef { did, .. }, _) = cx.tables.expr_ty(expr).kind {
54         ATOMIC_TYPES
55             .iter()
56             .any(|ty| match_def_path(cx, did, &["core", "sync", "atomic", ty]))
57     } else {
58         false
59     }
60 }
61
62 fn match_ordering_def_path(cx: &LateContext<'_, '_>, did: DefId, orderings: &[&str]) -> bool {
63     orderings
64         .iter()
65         .any(|ordering| match_def_path(cx, did, &["core", "sync", "atomic", "Ordering", ordering]))
66 }
67
68 impl<'a, 'tcx> LateLintPass<'a, 'tcx> for AtomicOrdering {
69     fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr<'_>) {
70         if_chain! {
71             if let ExprKind::MethodCall(ref method_path, _, args) = &expr.kind;
72             let method = method_path.ident.name.as_str();
73             if type_is_atomic(cx, &args[0]);
74             if method == "load" || method == "store";
75             let ordering_arg = if method == "load" { &args[1] } else { &args[2] };
76             if let ExprKind::Path(ref ordering_qpath) = ordering_arg.kind;
77             if let Some(ordering_def_id) = cx.tables.qpath_res(ordering_qpath, ordering_arg.hir_id).opt_def_id();
78             then {
79                 if method == "load" &&
80                     match_ordering_def_path(cx, ordering_def_id, &["Release", "AcqRel"]) {
81                     span_help_and_lint(
82                         cx,
83                         INVALID_ATOMIC_ORDERING,
84                         ordering_arg.span,
85                         "atomic loads cannot have `Release` and `AcqRel` ordering",
86                         "consider using ordering modes `Acquire`, `SeqCst` or `Relaxed`"
87                     );
88                 } else if method == "store" &&
89                     match_ordering_def_path(cx, ordering_def_id, &["Acquire", "AcqRel"]) {
90                     span_help_and_lint(
91                         cx,
92                         INVALID_ATOMIC_ORDERING,
93                         ordering_arg.span,
94                         "atomic stores cannot have `Acquire` and `AcqRel` ordering",
95                         "consider using ordering modes `Release`, `SeqCst` or `Relaxed`"
96                     );
97                 }
98             }
99         }
100     }
101 }