2015-10-06 18:17:57 -05: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 } ;
use rustc_front ::hir ::Expr ;
use syntax ::ast ;
use rustc ::middle ::ty ;
use rustc ::middle ::subst ::ParamSpace ;
use utils ::{ span_lint , MUTEX_PATH , match_type } ;
2016-02-05 17:41:54 -06:00
/// **What it does:** This lint checks for usages of `Mutex<X>` where an atomic will do.
2015-12-14 01:03:01 -06: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 18:17:57 -05:00
declare_lint! {
pub MUTEX_ATOMIC ,
Warn ,
" using a Mutex where an atomic value could be used instead "
}
2016-02-05 17:41:54 -06:00
/// **What it does:** This lint checks for usages of `Mutex<X>` where `X` is an integral type.
2015-12-14 01:03:01 -06: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 15:58:34 -05:00
declare_lint! {
pub MUTEX_INTEGER ,
Allow ,
" using a Mutex for an integer type "
}
2015-10-06 18:17:57 -05:00
impl LintPass for MutexAtomic {
fn get_lints ( & self ) -> LintArray {
2015-10-07 15:58:34 -05:00
lint_array! ( MUTEX_ATOMIC , MUTEX_INTEGER )
2015-10-06 18:17:57 -05:00
}
}
2015-10-07 15:58:34 -05:00
2015-10-06 18:17:57 -05: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 11:44:40 -06:00
if let ty ::TyStruct ( _ , subst ) = ty . sty {
2015-10-06 18:17:57 -05: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-03 22:26:12 -06: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 09:07:00 -05:00
atomic_name ) ;
2015-10-07 15:58:34 -05:00
match * mutex_param {
2016-01-03 22:26:12 -06:00
ty ::TyUint ( t ) if t ! = ast ::TyUs = > span_lint ( cx , MUTEX_INTEGER , expr . span , & msg ) ,
ty ::TyInt ( t ) if t ! = ast ::TyIs = > span_lint ( cx , MUTEX_INTEGER , expr . span , & msg ) ,
_ = > span_lint ( cx , MUTEX_ATOMIC , expr . span , & msg ) ,
2015-12-31 14:39:03 -06:00
} ;
2015-10-06 18:17:57 -05:00
}
}
}
}
}
fn get_atomic_name ( ty : & ty ::TypeVariants ) -> Option < ( & 'static str ) > {
match * ty {
ty ::TyBool = > Some ( " AtomicBool " ) ,
2015-10-07 15:58:34 -05:00
ty ::TyUint ( _ ) = > Some ( " AtomicUsize " ) ,
ty ::TyInt ( _ ) = > Some ( " AtomicIsize " ) ,
2015-10-06 18:17:57 -05:00
ty ::TyRawPtr ( _ ) = > Some ( " AtomicPtr " ) ,
2016-01-03 22:26:12 -06:00
_ = > None ,
2015-10-06 18:17:57 -05:00
}
}