@@ -4,7 +4,7 @@ use rustc_hir::*;
4
4
use rustc_lint:: { LateContext , LateLintPass } ;
5
5
use rustc_session:: { declare_lint_pass, declare_tool_lint} ;
6
6
7
- use crate :: utils:: { is_must_use_func_call, is_must_use_ty, span_lint_and_help} ;
7
+ use crate :: utils:: { is_must_use_func_call, is_must_use_ty, match_def_path , paths , span_lint_and_help} ;
8
8
9
9
declare_clippy_lint ! {
10
10
/// **What it does:** Checks for `let _ = <expr>`
@@ -30,7 +30,35 @@ declare_clippy_lint! {
30
30
"non-binding let on a `#[must_use]` expression"
31
31
}
32
32
33
- declare_lint_pass ! ( LetUnderscore => [ LET_UNDERSCORE_MUST_USE ] ) ;
33
+ declare_clippy_lint ! {
34
+ /// **What it does:** Checks for `let _ = sync_primitive.lock()`
35
+ ///
36
+ /// **Why is this bad?** This statement locks the synchronization
37
+ /// primitive and immediately drops the lock, which is probably
38
+ /// not intended. To extend lock lifetime to the end of the scope,
39
+ /// use an underscore-prefixed name instead (i.e. _lock).
40
+ ///
41
+ /// **Known problems:** None.
42
+ ///
43
+ /// **Example:**
44
+ ///
45
+ /// Bad:
46
+ /// ```rust
47
+ /// let _ = mutex.lock();
48
+ /// ```
49
+ ///
50
+ /// Good:
51
+ /// ```rust
52
+ /// let _lock = mutex.lock();
53
+ /// ```
54
+ pub LET_UNDERSCORE_LOCK ,
55
+ correctness,
56
+ "non-binding let on a synchronization lock"
57
+ }
58
+
59
+ declare_lint_pass ! ( LetUnderscore => [ LET_UNDERSCORE_MUST_USE , LET_UNDERSCORE_LOCK ] ) ;
60
+
61
+ const LOCK_METHODS_PATHS : [ & [ & str ] ; 3 ] = [ & paths:: MUTEX_LOCK , & paths:: RWLOCK_READ , & paths:: RWLOCK_WRITE ] ;
34
62
35
63
impl < ' a , ' tcx > LateLintPass < ' a , ' tcx > for LetUnderscore {
36
64
fn check_stmt ( & mut self , cx : & LateContext < ' _ , ' _ > , stmt : & Stmt < ' _ > ) {
@@ -43,22 +71,37 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for LetUnderscore {
43
71
if let PatKind :: Wild = local. pat. kind;
44
72
if let Some ( ref init) = local. init;
45
73
then {
46
- if is_must_use_ty( cx, cx. tables. expr_ty( init) ) {
47
- span_lint_and_help(
48
- cx,
49
- LET_UNDERSCORE_MUST_USE ,
50
- stmt. span,
51
- "non-binding let on an expression with `#[must_use]` type" ,
52
- "consider explicitly using expression value"
53
- )
54
- } else if is_must_use_func_call( cx, init) {
55
- span_lint_and_help(
56
- cx,
57
- LET_UNDERSCORE_MUST_USE ,
58
- stmt. span,
59
- "non-binding let on a result of a `#[must_use]` function" ,
60
- "consider explicitly using function result"
61
- )
74
+ if_chain! {
75
+ if let ExprKind :: MethodCall ( _, _, _) = init. kind;
76
+ let method_did = cx. tables. type_dependent_def_id( init. hir_id) . unwrap( ) ;
77
+ if LOCK_METHODS_PATHS . iter( ) . any( |path| match_def_path( cx, method_did, path) ) ;
78
+ then {
79
+ span_lint_and_help(
80
+ cx,
81
+ LET_UNDERSCORE_LOCK ,
82
+ stmt. span,
83
+ "non-binding let on an a synchronization lock" ,
84
+ "consider using an underscore-prefixed named binding"
85
+ )
86
+ } else {
87
+ if is_must_use_ty( cx, cx. tables. expr_ty( init) ) {
88
+ span_lint_and_help(
89
+ cx,
90
+ LET_UNDERSCORE_MUST_USE ,
91
+ stmt. span,
92
+ "non-binding let on an expression with `#[must_use]` type" ,
93
+ "consider explicitly using expression value"
94
+ )
95
+ } else if is_must_use_func_call( cx, init) {
96
+ span_lint_and_help(
97
+ cx,
98
+ LET_UNDERSCORE_MUST_USE ,
99
+ stmt. span,
100
+ "non-binding let on a result of a `#[must_use]` function" ,
101
+ "consider explicitly using function result"
102
+ )
103
+ }
104
+ }
62
105
}
63
106
}
64
107
}
0 commit comments