@@ -5,98 +5,24 @@ use clippy_utils::source::{indent_of, snippet};
5
5
use rustc_errors:: { Applicability , Diagnostic } ;
6
6
use rustc_hir:: intravisit:: { walk_expr, Visitor } ;
7
7
use rustc_hir:: { Expr , ExprKind , MatchSource } ;
8
- use rustc_lint:: { LateContext , LateLintPass , LintContext } ;
8
+ use rustc_lint:: { LateContext , LintContext } ;
9
9
use rustc_middle:: ty:: subst:: GenericArgKind ;
10
10
use rustc_middle:: ty:: { Ty , TypeAndMut } ;
11
- use rustc_session:: { declare_lint_pass, declare_tool_lint} ;
12
11
use rustc_span:: Span ;
13
12
14
- declare_clippy_lint ! {
15
- /// ### What it does
16
- /// Check for temporaries returned from function calls in a match scrutinee that have the
17
- /// `clippy::has_significant_drop` attribute.
18
- ///
19
- /// ### Why is this bad?
20
- /// The `clippy::has_significant_drop` attribute can be added to types whose Drop impls have
21
- /// an important side-effect, such as unlocking a mutex, making it important for users to be
22
- /// able to accurately understand their lifetimes. When a temporary is returned in a function
23
- /// call in a match scrutinee, its lifetime lasts until the end of the match block, which may
24
- /// be surprising.
25
- ///
26
- /// For `Mutex`es this can lead to a deadlock. This happens when the match scrutinee uses a
27
- /// function call that returns a `MutexGuard` and then tries to lock again in one of the match
28
- /// arms. In that case the `MutexGuard` in the scrutinee will not be dropped until the end of
29
- /// the match block and thus will not unlock.
30
- ///
31
- /// ### Example
32
- /// ```rust.ignore
33
- /// # use std::sync::Mutex;
34
- ///
35
- /// # struct State {}
36
- ///
37
- /// # impl State {
38
- /// # fn foo(&self) -> bool {
39
- /// # true
40
- /// # }
41
- ///
42
- /// # fn bar(&self) {}
43
- /// # }
44
- ///
45
- ///
46
- /// let mutex = Mutex::new(State {});
47
- ///
48
- /// match mutex.lock().unwrap().foo() {
49
- /// true => {
50
- /// mutex.lock().unwrap().bar(); // Deadlock!
51
- /// }
52
- /// false => {}
53
- /// };
54
- ///
55
- /// println!("All done!");
56
- ///
57
- /// ```
58
- /// Use instead:
59
- /// ```rust
60
- /// # use std::sync::Mutex;
61
- ///
62
- /// # struct State {}
63
- ///
64
- /// # impl State {
65
- /// # fn foo(&self) -> bool {
66
- /// # true
67
- /// # }
68
- ///
69
- /// # fn bar(&self) {}
70
- /// # }
71
- ///
72
- /// let mutex = Mutex::new(State {});
73
- ///
74
- /// let is_foo = mutex.lock().unwrap().foo();
75
- /// match is_foo {
76
- /// true => {
77
- /// mutex.lock().unwrap().bar();
78
- /// }
79
- /// false => {}
80
- /// };
81
- ///
82
- /// println!("All done!");
83
- /// ```
84
- #[ clippy:: version = "1.60.0" ]
85
- pub SIGNIFICANT_DROP_IN_SCRUTINEE ,
86
- suspicious,
87
- "warns when a temporary of a type with a drop with a significant side-effect might have a surprising lifetime"
88
- }
89
-
90
- declare_lint_pass ! ( SignificantDropInScrutinee => [ SIGNIFICANT_DROP_IN_SCRUTINEE ] ) ;
13
+ use super :: SIGNIFICANT_DROP_IN_SCRUTINEE ;
91
14
92
- impl < ' tcx > LateLintPass < ' tcx > for SignificantDropInScrutinee {
93
- fn check_expr ( & mut self , cx : & LateContext < ' tcx > , expr : & ' tcx Expr < ' tcx > ) {
94
- if let Some ( ( suggestions, message) ) = has_significant_drop_in_scrutinee ( cx, expr) {
95
- for found in suggestions {
96
- span_lint_and_then ( cx, SIGNIFICANT_DROP_IN_SCRUTINEE , found. found_span , message, |diag| {
97
- set_diagnostic ( diag, cx, expr, found) ;
98
- } ) ;
99
- }
15
+ pub ( super ) fn check < ' tcx > (
16
+ cx : & LateContext < ' tcx > ,
17
+ expr : & ' tcx Expr < ' tcx > ,
18
+ scrutinee : & ' tcx Expr < ' _ > ,
19
+ source : MatchSource ,
20
+ ) {
21
+ if let Some ( ( suggestions, message) ) = has_significant_drop_in_scrutinee ( cx, scrutinee, source) {
22
+ for found in suggestions {
23
+ span_lint_and_then ( cx, SIGNIFICANT_DROP_IN_SCRUTINEE , found. found_span , message, |diag| {
24
+ set_diagnostic ( diag, cx, expr, found) ;
25
+ } ) ;
100
26
}
101
27
}
102
28
}
@@ -148,28 +74,18 @@ fn set_diagnostic<'tcx>(diag: &mut Diagnostic, cx: &LateContext<'tcx>, expr: &'t
148
74
/// may have a surprising lifetime.
149
75
fn has_significant_drop_in_scrutinee < ' tcx , ' a > (
150
76
cx : & ' a LateContext < ' tcx > ,
151
- expr : & ' tcx Expr < ' tcx > ,
77
+ scrutinee : & ' tcx Expr < ' tcx > ,
78
+ source : MatchSource ,
152
79
) -> Option < ( Vec < FoundSigDrop > , & ' static str ) > {
153
- match expr. kind {
154
- ExprKind :: Match ( match_expr, _, source) => {
155
- match source {
156
- MatchSource :: Normal | MatchSource :: ForLoopDesugar => {
157
- let mut helper = SigDropHelper :: new ( cx) ;
158
- helper. find_sig_drop ( match_expr) . map ( |drops| {
159
- let message = if source == MatchSource :: Normal {
160
- "temporary with significant drop in match scrutinee"
161
- } else {
162
- "temporary with significant drop in for loop"
163
- } ;
164
- ( drops, message)
165
- } )
166
- } ,
167
- // MatchSource of TryDesugar or AwaitDesugar is out of scope for this lint
168
- MatchSource :: TryDesugar | MatchSource :: AwaitDesugar => None ,
169
- }
170
- } ,
171
- _ => None ,
172
- }
80
+ let mut helper = SigDropHelper :: new ( cx) ;
81
+ helper. find_sig_drop ( scrutinee) . map ( |drops| {
82
+ let message = if source == MatchSource :: Normal {
83
+ "temporary with significant drop in match scrutinee"
84
+ } else {
85
+ "temporary with significant drop in for loop"
86
+ } ;
87
+ ( drops, message)
88
+ } )
173
89
}
174
90
175
91
struct SigDropHelper < ' a , ' tcx > {
0 commit comments