2015-10-07 01:17:57 +02: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-06 00:41:54 +01:00
/// **What it does:** This lint checks for usages of `Mutex<X>` where an atomic will do.
2015-12-14 08:03:01 +01: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-07 01:17:57 +02:00
declare_lint! {
pub MUTEX_ATOMIC ,
Warn ,
" using a Mutex where an atomic value could be used instead "
}
2016-02-06 00:41:54 +01:00
/// **What it does:** This lint checks for usages of `Mutex<X>` where `X` is an integral type.
2015-12-14 08:03:01 +01: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 22:58:34 +02:00
declare_lint! {
pub MUTEX_INTEGER ,
Allow ,
" using a Mutex for an integer type "
}
2015-10-07 01:17:57 +02:00
impl LintPass for MutexAtomic {
fn get_lints ( & self ) -> LintArray {
2015-10-07 22:58:34 +02:00
lint_array! ( MUTEX_ATOMIC , MUTEX_INTEGER )
2015-10-07 01:17:57 +02:00
}
}
2015-10-07 22:58:34 +02:00
2015-10-07 01:17:57 +02: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-25 02:44:40 +09:00
if let ty ::TyStruct ( _ , subst ) = ty . sty {
2015-10-07 01:17:57 +02: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 09:56:12 +05:30
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 16:07:00 +02:00
atomic_name ) ;
2015-10-07 22:58:34 +02:00
match * mutex_param {
2016-01-04 09:56:12 +05:30
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 ) ,
2016-01-01 02:09:03 +05:30
} ;
2015-10-07 01:17:57 +02:00
}
}
}
}
}
fn get_atomic_name ( ty : & ty ::TypeVariants ) -> Option < ( & 'static str ) > {
match * ty {
ty ::TyBool = > Some ( " AtomicBool " ) ,
2015-10-07 22:58:34 +02:00
ty ::TyUint ( _ ) = > Some ( " AtomicUsize " ) ,
ty ::TyInt ( _ ) = > Some ( " AtomicIsize " ) ,
2015-10-07 01:17:57 +02:00
ty ::TyRawPtr ( _ ) = > Some ( " AtomicPtr " ) ,
2016-01-04 09:56:12 +05:30
_ = > None ,
2015-10-07 01:17:57 +02:00
}
}