2016-02-01 12:53:03 -06:00
use rustc ::lint ::* ;
2016-03-27 13:59:02 -05:00
use rustc ::ty ;
2016-04-07 10:46:48 -05:00
use rustc ::hir ::* ;
2016-02-01 12:53:03 -06:00
use syntax ::codemap ::Span ;
2016-04-14 11:13:15 -05:00
use utils ::{ match_def_path , paths , span_note_and_lint } ;
2016-02-01 12:53:03 -06:00
/// **What it does:** This lint checks for calls to `std::mem::drop` with a reference instead of an owned value.
///
/// **Why is this bad?** Calling `drop` on a reference will only drop the reference itself, which is a no-op. It will not call the `drop` method (from the `Drop` trait implementation) on the underlying referenced value, which is likely what was intended.
///
/// **Known problems:** None
///
/// **Example:**
/// ```rust
/// let mut lock_guard = mutex.lock();
2016-02-05 17:41:54 -06:00
/// std::mem::drop(&lock_guard) // Should have been drop(lock_guard), mutex still locked
2016-02-01 12:53:03 -06:00
/// operation_that_requires_mutex_to_be_unlocked();
/// ```
2016-02-05 17:13:29 -06:00
declare_lint! {
pub DROP_REF , Warn ,
2016-02-01 12:53:03 -06:00
" call to `std::mem::drop` with a reference instead of an owned value, \
2016-02-05 17:13:29 -06:00
which will not call the ` Drop ::drop ` method on the underlying value "
}
2016-02-01 12:53:03 -06:00
#[ allow(missing_copy_implementations) ]
2016-06-10 09:17:20 -05:00
pub struct Pass ;
2016-02-01 12:53:03 -06:00
2016-06-10 09:17:20 -05:00
impl LintPass for Pass {
2016-02-01 12:53:03 -06:00
fn get_lints ( & self ) -> LintArray {
lint_array! ( DROP_REF )
}
}
2016-06-10 09:17:20 -05:00
impl LateLintPass for Pass {
2016-02-01 12:53:03 -06:00
fn check_expr ( & mut self , cx : & LateContext , expr : & Expr ) {
if let ExprCall ( ref path , ref args ) = expr . node {
if let ExprPath ( None , _ ) = path . node {
2016-06-10 12:47:10 -05:00
let def_id = cx . tcx . expect_def ( path . id ) . def_id ( ) ;
2016-04-14 11:13:15 -05:00
if match_def_path ( cx , def_id , & paths ::DROP ) {
2016-02-01 12:53:03 -06:00
if args . len ( ) ! = 1 {
return ;
}
check_drop_arg ( cx , expr . span , & * args [ 0 ] ) ;
}
}
}
}
}
fn check_drop_arg ( cx : & LateContext , call_span : Span , arg : & Expr ) {
let arg_ty = cx . tcx . expr_ty ( arg ) ;
if let ty ::TyRef ( .. ) = arg_ty . sty {
span_note_and_lint ( cx ,
DROP_REF ,
call_span ,
" call to `std::mem::drop` with a reference argument. \
Dropping a reference does nothing " ,
arg . span ,
& format! ( " argument has type {} " , arg_ty . sty ) ) ;
}
}