@@ -5,98 +5,24 @@ use clippy_utils::source::{indent_of, snippet};
55use rustc_errors:: { Applicability , Diagnostic } ;
66use rustc_hir:: intravisit:: { walk_expr, Visitor } ;
77use rustc_hir:: { Expr , ExprKind , MatchSource } ;
8- use rustc_lint:: { LateContext , LateLintPass , LintContext } ;
8+ use rustc_lint:: { LateContext , LintContext } ;
99use rustc_middle:: ty:: subst:: GenericArgKind ;
1010use rustc_middle:: ty:: { Ty , TypeAndMut } ;
11- use rustc_session:: { declare_lint_pass, declare_tool_lint} ;
1211use rustc_span:: Span ;
1312
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 ;
9114
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+ } ) ;
10026 }
10127 }
10228}
@@ -148,28 +74,18 @@ fn set_diagnostic<'tcx>(diag: &mut Diagnostic, cx: &LateContext<'tcx>, expr: &'t
14874/// may have a surprising lifetime.
14975fn has_significant_drop_in_scrutinee < ' tcx , ' a > (
15076 cx : & ' a LateContext < ' tcx > ,
151- expr : & ' tcx Expr < ' tcx > ,
77+ scrutinee : & ' tcx Expr < ' tcx > ,
78+ source : MatchSource ,
15279) -> 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+ } )
17389}
17490
17591struct SigDropHelper < ' a , ' tcx > {
0 commit comments