@@ -4,7 +4,7 @@ use rustc_hir::*;
44use rustc_lint:: { LateContext , LateLintPass } ;
55use rustc_session:: { declare_lint_pass, declare_tool_lint} ;
66
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} ;
88
99declare_clippy_lint ! {
1010 /// **What it does:** Checks for `let _ = <expr>`
@@ -30,7 +30,35 @@ declare_clippy_lint! {
3030 "non-binding let on a `#[must_use]` expression"
3131}
3232
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,ignore
47+ /// let _ = mutex.lock();
48+ /// ```
49+ ///
50+ /// Good:
51+ /// ```rust,ignore
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 ] ;
3462
3563impl < ' a , ' tcx > LateLintPass < ' a , ' tcx > for LetUnderscore {
3664 fn check_stmt ( & mut self , cx : & LateContext < ' _ , ' _ > , stmt : & Stmt < ' _ > ) {
@@ -43,22 +71,37 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for LetUnderscore {
4371 if let PatKind :: Wild = local. pat. kind;
4472 if let Some ( ref init) = local. init;
4573 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+ }
62105 }
63106 }
64107 }
0 commit comments