]>
Commit | Line | Data |
---|---|---|
9c376795 FG |
1 | use crate::{ |
2 | lints::{NonBindingLet, NonBindingLetSub}, | |
3 | LateContext, LateLintPass, LintContext, | |
4 | }; | |
5 | use rustc_errors::MultiSpan; | |
f2b60f7d FG |
6 | use rustc_hir as hir; |
7 | use rustc_middle::ty; | |
8 | use rustc_span::Symbol; | |
9 | ||
10 | declare_lint! { | |
11 | /// The `let_underscore_drop` lint checks for statements which don't bind | |
12 | /// an expression which has a non-trivial Drop implementation to anything, | |
13 | /// causing the expression to be dropped immediately instead of at end of | |
14 | /// scope. | |
15 | /// | |
16 | /// ### Example | |
487cf647 FG |
17 | /// |
18 | /// ```rust | |
f2b60f7d FG |
19 | /// struct SomeStruct; |
20 | /// impl Drop for SomeStruct { | |
21 | /// fn drop(&mut self) { | |
22 | /// println!("Dropping SomeStruct"); | |
23 | /// } | |
24 | /// } | |
25 | /// | |
26 | /// fn main() { | |
27 | /// #[warn(let_underscore_drop)] | |
28 | /// // SomeStuct is dropped immediately instead of at end of scope, | |
29 | /// // so "Dropping SomeStruct" is printed before "end of main". | |
30 | /// // The order of prints would be reversed if SomeStruct was bound to | |
31 | /// // a name (such as "_foo"). | |
32 | /// let _ = SomeStruct; | |
33 | /// println!("end of main"); | |
34 | /// } | |
35 | /// ``` | |
36 | /// | |
37 | /// {{produces}} | |
38 | /// | |
39 | /// ### Explanation | |
40 | /// | |
41 | /// Statements which assign an expression to an underscore causes the | |
42 | /// expression to immediately drop instead of extending the expression's | |
43 | /// lifetime to the end of the scope. This is usually unintended, | |
44 | /// especially for types like `MutexGuard`, which are typically used to | |
45 | /// lock a mutex for the duration of an entire scope. | |
46 | /// | |
47 | /// If you want to extend the expression's lifetime to the end of the scope, | |
48 | /// assign an underscore-prefixed name (such as `_foo`) to the expression. | |
49 | /// If you do actually want to drop the expression immediately, then | |
50 | /// calling `std::mem::drop` on the expression is clearer and helps convey | |
51 | /// intent. | |
52 | pub LET_UNDERSCORE_DROP, | |
53 | Allow, | |
54 | "non-binding let on a type that implements `Drop`" | |
55 | } | |
56 | ||
57 | declare_lint! { | |
58 | /// The `let_underscore_lock` lint checks for statements which don't bind | |
59 | /// a mutex to anything, causing the lock to be released immediately instead | |
60 | /// of at end of scope, which is typically incorrect. | |
61 | /// | |
62 | /// ### Example | |
487cf647 | 63 | /// ```rust,compile_fail |
f2b60f7d FG |
64 | /// use std::sync::{Arc, Mutex}; |
65 | /// use std::thread; | |
66 | /// let data = Arc::new(Mutex::new(0)); | |
67 | /// | |
68 | /// thread::spawn(move || { | |
69 | /// // The lock is immediately released instead of at the end of the | |
70 | /// // scope, which is probably not intended. | |
71 | /// let _ = data.lock().unwrap(); | |
72 | /// println!("doing some work"); | |
73 | /// let mut lock = data.lock().unwrap(); | |
74 | /// *lock += 1; | |
75 | /// }); | |
76 | /// ``` | |
77 | /// | |
78 | /// {{produces}} | |
79 | /// | |
80 | /// ### Explanation | |
81 | /// | |
82 | /// Statements which assign an expression to an underscore causes the | |
83 | /// expression to immediately drop instead of extending the expression's | |
84 | /// lifetime to the end of the scope. This is usually unintended, | |
85 | /// especially for types like `MutexGuard`, which are typically used to | |
86 | /// lock a mutex for the duration of an entire scope. | |
87 | /// | |
88 | /// If you want to extend the expression's lifetime to the end of the scope, | |
89 | /// assign an underscore-prefixed name (such as `_foo`) to the expression. | |
90 | /// If you do actually want to drop the expression immediately, then | |
91 | /// calling `std::mem::drop` on the expression is clearer and helps convey | |
92 | /// intent. | |
93 | pub LET_UNDERSCORE_LOCK, | |
94 | Deny, | |
95 | "non-binding let on a synchronization lock" | |
96 | } | |
97 | ||
98 | declare_lint_pass!(LetUnderscore => [LET_UNDERSCORE_DROP, LET_UNDERSCORE_LOCK]); | |
99 | ||
100 | const SYNC_GUARD_SYMBOLS: [Symbol; 3] = [ | |
101 | rustc_span::sym::MutexGuard, | |
102 | rustc_span::sym::RwLockReadGuard, | |
103 | rustc_span::sym::RwLockWriteGuard, | |
104 | ]; | |
105 | ||
106 | impl<'tcx> LateLintPass<'tcx> for LetUnderscore { | |
107 | fn check_local(&mut self, cx: &LateContext<'_>, local: &hir::Local<'_>) { | |
108 | if !matches!(local.pat.kind, hir::PatKind::Wild) { | |
109 | return; | |
110 | } | |
111 | if let Some(init) = local.init { | |
112 | let init_ty = cx.typeck_results().expr_ty(init); | |
113 | // If the type has a trivial Drop implementation, then it doesn't | |
114 | // matter that we drop the value immediately. | |
115 | if !init_ty.needs_drop(cx.tcx, cx.param_env) { | |
116 | return; | |
117 | } | |
118 | let is_sync_lock = match init_ty.kind() { | |
119 | ty::Adt(adt, _) => SYNC_GUARD_SYMBOLS | |
120 | .iter() | |
121 | .any(|guard_symbol| cx.tcx.is_diagnostic_item(*guard_symbol, adt.did())), | |
122 | _ => false, | |
123 | }; | |
124 | ||
9c376795 FG |
125 | let sub = NonBindingLetSub { |
126 | suggestion: local.pat.span, | |
127 | multi_suggestion_start: local.span.until(init.span), | |
128 | multi_suggestion_end: init.span.shrink_to_hi(), | |
129 | }; | |
f2b60f7d FG |
130 | if is_sync_lock { |
131 | let mut span = MultiSpan::from_spans(vec![local.pat.span, init.span]); | |
132 | span.push_span_label( | |
133 | local.pat.span, | |
134 | "this lock is not assigned to a binding and is immediately dropped".to_string(), | |
135 | ); | |
136 | span.push_span_label( | |
137 | init.span, | |
138 | "this binding will immediately drop the value assigned to it".to_string(), | |
139 | ); | |
9c376795 | 140 | cx.emit_spanned_lint(LET_UNDERSCORE_LOCK, span, NonBindingLet::SyncLock { sub }); |
f2b60f7d | 141 | } else { |
9c376795 | 142 | cx.emit_spanned_lint( |
2b03887a FG |
143 | LET_UNDERSCORE_DROP, |
144 | local.span, | |
9c376795 FG |
145 | NonBindingLet::DropType { sub }, |
146 | ); | |
f2b60f7d FG |
147 | } |
148 | } | |
149 | } | |
150 | } |