]>
Commit | Line | Data |
---|---|---|
cdc7bbd5 XL |
1 | use clippy_utils::diagnostics::span_lint_and_help; |
2 | use clippy_utils::ty::{is_must_use_ty, match_type}; | |
3 | use clippy_utils::{is_must_use_func_call, paths}; | |
f20569fa XL |
4 | use if_chain::if_chain; |
5 | use rustc_hir::{Local, PatKind}; | |
6 | use rustc_lint::{LateContext, LateLintPass}; | |
7 | use rustc_middle::lint::in_external_macro; | |
8 | use rustc_middle::ty::subst::GenericArgKind; | |
9 | use rustc_session::{declare_lint_pass, declare_tool_lint}; | |
10 | ||
f20569fa | 11 | declare_clippy_lint! { |
94222f64 | 12 | /// ### What it does |
3c0e092e | 13 | /// Checks for `let _ = <expr>` where expr is `#[must_use]` |
f20569fa | 14 | /// |
94222f64 | 15 | /// ### Why is this bad? |
3c0e092e XL |
16 | /// It's better to explicitly handle the value of a `#[must_use]` |
17 | /// expr | |
f20569fa | 18 | /// |
94222f64 | 19 | /// ### Example |
f20569fa XL |
20 | /// ```rust |
21 | /// fn f() -> Result<u32, u32> { | |
22 | /// Ok(0) | |
23 | /// } | |
24 | /// | |
25 | /// let _ = f(); | |
26 | /// // is_ok() is marked #[must_use] | |
27 | /// let _ = f().is_ok(); | |
28 | /// ``` | |
a2a8927a | 29 | #[clippy::version = "1.42.0"] |
f20569fa XL |
30 | pub LET_UNDERSCORE_MUST_USE, |
31 | restriction, | |
32 | "non-binding let on a `#[must_use]` expression" | |
33 | } | |
34 | ||
35 | declare_clippy_lint! { | |
94222f64 | 36 | /// ### What it does |
a2a8927a XL |
37 | /// Checks for `let _ = sync_lock`. |
38 | /// This supports `mutex` and `rwlock` in `std::sync` and `parking_lot`. | |
f20569fa | 39 | /// |
94222f64 XL |
40 | /// ### Why is this bad? |
41 | /// This statement immediately drops the lock instead of | |
f20569fa XL |
42 | /// extending its lifetime to the end of the scope, which is often not intended. |
43 | /// To extend lock lifetime to the end of the scope, use an underscore-prefixed | |
44 | /// name instead (i.e. _lock). If you want to explicitly drop the lock, | |
45 | /// `std::mem::drop` conveys your intention better and is less error-prone. | |
46 | /// | |
94222f64 | 47 | /// ### Example |
f20569fa XL |
48 | /// ```rust,ignore |
49 | /// let _ = mutex.lock(); | |
50 | /// ``` | |
51 | /// | |
923072b8 | 52 | /// Use instead: |
f20569fa XL |
53 | /// ```rust,ignore |
54 | /// let _lock = mutex.lock(); | |
55 | /// ``` | |
a2a8927a | 56 | #[clippy::version = "1.43.0"] |
f20569fa XL |
57 | pub LET_UNDERSCORE_LOCK, |
58 | correctness, | |
59 | "non-binding let on a synchronization lock" | |
60 | } | |
61 | ||
62 | declare_clippy_lint! { | |
94222f64 XL |
63 | /// ### What it does |
64 | /// Checks for `let _ = <expr>` | |
f20569fa XL |
65 | /// where expr has a type that implements `Drop` |
66 | /// | |
94222f64 XL |
67 | /// ### Why is this bad? |
68 | /// This statement immediately drops the initializer | |
f20569fa XL |
69 | /// expression instead of extending its lifetime to the end of the scope, which |
70 | /// is often not intended. To extend the expression's lifetime to the end of the | |
71 | /// scope, use an underscore-prefixed name instead (i.e. _var). If you want to | |
72 | /// explicitly drop the expression, `std::mem::drop` conveys your intention | |
73 | /// better and is less error-prone. | |
74 | /// | |
94222f64 | 75 | /// ### Example |
923072b8 FG |
76 | /// ```rust |
77 | /// # struct DroppableItem; | |
f20569fa | 78 | /// { |
923072b8 FG |
79 | /// let _ = DroppableItem; |
80 | /// // ^ dropped here | |
f20569fa XL |
81 | /// /* more code */ |
82 | /// } | |
83 | /// ``` | |
84 | /// | |
923072b8 FG |
85 | /// Use instead: |
86 | /// ```rust | |
87 | /// # struct DroppableItem; | |
f20569fa | 88 | /// { |
923072b8 | 89 | /// let _droppable = DroppableItem; |
f20569fa XL |
90 | /// /* more code */ |
91 | /// // dropped at end of scope | |
92 | /// } | |
93 | /// ``` | |
a2a8927a | 94 | #[clippy::version = "1.50.0"] |
f20569fa XL |
95 | pub LET_UNDERSCORE_DROP, |
96 | pedantic, | |
97 | "non-binding let on a type that implements `Drop`" | |
98 | } | |
99 | ||
100 | declare_lint_pass!(LetUnderscore => [LET_UNDERSCORE_MUST_USE, LET_UNDERSCORE_LOCK, LET_UNDERSCORE_DROP]); | |
101 | ||
a2a8927a | 102 | const SYNC_GUARD_PATHS: [&[&str]; 5] = [ |
f20569fa XL |
103 | &paths::MUTEX_GUARD, |
104 | &paths::RWLOCK_READ_GUARD, | |
105 | &paths::RWLOCK_WRITE_GUARD, | |
a2a8927a XL |
106 | &paths::PARKING_LOT_RAWMUTEX, |
107 | &paths::PARKING_LOT_RAWRWLOCK, | |
f20569fa XL |
108 | ]; |
109 | ||
110 | impl<'tcx> LateLintPass<'tcx> for LetUnderscore { | |
111 | fn check_local(&mut self, cx: &LateContext<'_>, local: &Local<'_>) { | |
112 | if in_external_macro(cx.tcx.sess, local.span) { | |
113 | return; | |
114 | } | |
115 | ||
116 | if_chain! { | |
117 | if let PatKind::Wild = local.pat.kind; | |
cdc7bbd5 | 118 | if let Some(init) = local.init; |
f20569fa XL |
119 | then { |
120 | let init_ty = cx.typeck_results().expr_ty(init); | |
5099ac24 | 121 | let contains_sync_guard = init_ty.walk().any(|inner| match inner.unpack() { |
f20569fa XL |
122 | GenericArgKind::Type(inner_ty) => { |
123 | SYNC_GUARD_PATHS.iter().any(|path| match_type(cx, inner_ty, path)) | |
124 | }, | |
125 | ||
126 | GenericArgKind::Lifetime(_) | GenericArgKind::Const(_) => false, | |
127 | }); | |
128 | if contains_sync_guard { | |
129 | span_lint_and_help( | |
130 | cx, | |
131 | LET_UNDERSCORE_LOCK, | |
132 | local.span, | |
133 | "non-binding let on a synchronization lock", | |
134 | None, | |
135 | "consider using an underscore-prefixed named \ | |
136 | binding or dropping explicitly with `std::mem::drop`" | |
17df50a5 | 137 | ); |
f20569fa XL |
138 | } else if init_ty.needs_drop(cx.tcx, cx.param_env) { |
139 | span_lint_and_help( | |
140 | cx, | |
141 | LET_UNDERSCORE_DROP, | |
142 | local.span, | |
143 | "non-binding `let` on a type that implements `Drop`", | |
144 | None, | |
145 | "consider using an underscore-prefixed named \ | |
146 | binding or dropping explicitly with `std::mem::drop`" | |
17df50a5 | 147 | ); |
f20569fa XL |
148 | } else if is_must_use_ty(cx, cx.typeck_results().expr_ty(init)) { |
149 | span_lint_and_help( | |
150 | cx, | |
151 | LET_UNDERSCORE_MUST_USE, | |
152 | local.span, | |
153 | "non-binding let on an expression with `#[must_use]` type", | |
154 | None, | |
155 | "consider explicitly using expression value" | |
17df50a5 | 156 | ); |
f20569fa XL |
157 | } else if is_must_use_func_call(cx, init) { |
158 | span_lint_and_help( | |
159 | cx, | |
160 | LET_UNDERSCORE_MUST_USE, | |
161 | local.span, | |
162 | "non-binding let on a result of a `#[must_use]` function", | |
163 | None, | |
164 | "consider explicitly using function result" | |
17df50a5 | 165 | ); |
f20569fa XL |
166 | } |
167 | } | |
168 | } | |
169 | } | |
170 | } |