2015-10-06 23:17:57 +00:00
//! Checks for uses of Mutex where an atomic value could be used
//!
//! This lint is **warn** by default
use rustc ::lint ::{ LintPass , LintArray , LateLintPass , LateContext } ;
2016-03-27 18:59:02 +00:00
use rustc ::ty ::subst ::ParamSpace ;
use rustc ::ty ;
2016-04-07 15:46:48 +00:00
use rustc ::hir ::Expr ;
2015-10-06 23:17:57 +00:00
use syntax ::ast ;
use utils ::{ span_lint , MUTEX_PATH , match_type } ;
2016-02-05 23:41:54 +00:00
/// **What it does:** This lint checks for usages of `Mutex<X>` where an atomic will do.
2015-12-14 07:03:01 +00:00
///
/// **Why is this bad?** Using a Mutex just to make access to a plain bool or reference sequential is shooting flies with cannons. `std::atomic::AtomicBool` and `std::atomic::AtomicPtr` are leaner and faster.
///
/// **Known problems:** This lint cannot detect if the Mutex is actually used for waiting before a critical section.
///
/// **Example:** `let x = Mutex::new(&y);`
2015-10-06 23:17:57 +00:00
declare_lint! {
pub MUTEX_ATOMIC ,
Warn ,
" using a Mutex where an atomic value could be used instead "
}
2016-02-05 23:41:54 +00:00
/// **What it does:** This lint checks for usages of `Mutex<X>` where `X` is an integral type.
2015-12-14 07:03:01 +00:00
///
/// **Why is this bad?** Using a Mutex just to make access to a plain integer sequential is shooting flies with cannons. `std::atomic::usize` is leaner and faster.
///
/// **Known problems:** This lint cannot detect if the Mutex is actually used for waiting before a critical section.
///
/// **Example:** `let x = Mutex::new(0usize);`
2015-10-07 20:58:34 +00:00
declare_lint! {
pub MUTEX_INTEGER ,
Allow ,
" using a Mutex for an integer type "
}
2015-10-06 23:17:57 +00:00
impl LintPass for MutexAtomic {
fn get_lints ( & self ) -> LintArray {
2015-10-07 20:58:34 +00:00
lint_array! ( MUTEX_ATOMIC , MUTEX_INTEGER )
2015-10-06 23:17:57 +00:00
}
}
2015-10-07 20:58:34 +00:00
2015-10-06 23:17:57 +00:00
pub struct MutexAtomic ;
impl LateLintPass for MutexAtomic {
fn check_expr ( & mut self , cx : & LateContext , expr : & Expr ) {
let ty = cx . tcx . expr_ty ( expr ) ;
2015-11-24 17:44:40 +00:00
if let ty ::TyStruct ( _ , subst ) = ty . sty {
2015-10-06 23:17:57 +00:00
if match_type ( cx , ty , & MUTEX_PATH ) {
let mutex_param = & subst . types . get ( ParamSpace ::TypeSpace , 0 ) . sty ;
if let Some ( atomic_name ) = get_atomic_name ( mutex_param ) {
2016-01-04 04:26:12 +00:00
let msg = format! ( " Consider using an {} instead of a Mutex here. If you just want the locking \
behaviour and not the internal type , consider using Mutex < ( ) > . " ,
2015-10-11 14:07:00 +00:00
atomic_name ) ;
2015-10-07 20:58:34 +00:00
match * mutex_param {
2016-02-12 17:35:44 +00:00
ty ::TyUint ( t ) if t ! = ast ::UintTy ::Us = > span_lint ( cx , MUTEX_INTEGER , expr . span , & msg ) ,
ty ::TyInt ( t ) if t ! = ast ::IntTy ::Is = > span_lint ( cx , MUTEX_INTEGER , expr . span , & msg ) ,
2016-01-04 04:26:12 +00:00
_ = > span_lint ( cx , MUTEX_ATOMIC , expr . span , & msg ) ,
2015-12-31 20:39:03 +00:00
} ;
2015-10-06 23:17:57 +00:00
}
}
}
}
}
fn get_atomic_name ( ty : & ty ::TypeVariants ) -> Option < ( & 'static str ) > {
match * ty {
ty ::TyBool = > Some ( " AtomicBool " ) ,
2015-10-07 20:58:34 +00:00
ty ::TyUint ( _ ) = > Some ( " AtomicUsize " ) ,
ty ::TyInt ( _ ) = > Some ( " AtomicIsize " ) ,
2015-10-06 23:17:57 +00:00
ty ::TyRawPtr ( _ ) = > Some ( " AtomicPtr " ) ,
2016-01-04 04:26:12 +00:00
_ = > None ,
2015-10-06 23:17:57 +00:00
}
}