2015-08-16 06:54:43 +00:00
//! checks for attributes
2015-05-30 13:10:19 +00:00
use rustc ::lint ::* ;
2015-09-03 14:42:17 +00:00
use rustc_front ::hir ::* ;
use reexport ::* ;
2015-09-06 08:53:55 +00:00
use syntax ::codemap ::Span ;
2015-09-17 00:01:41 +00:00
use syntax ::attr ::* ;
use syntax ::ast ::{ Attribute , MetaList , MetaWord } ;
2015-12-23 21:37:52 +00:00
use utils ::{ in_macro , match_path , span_lint , BEGIN_UNWIND } ;
2015-05-30 13:10:19 +00:00
2016-01-01 16:48:19 +00:00
/// **What it does:** This lint `Warn`s on items annotated with `#[inline(always)]`, unless the annotated function is empty or simply panics.
2015-12-11 00:22:27 +00:00
///
/// **Why is this bad?** While there are valid uses of this annotation (and once you know when to use it, by all means `allow` this lint), it's a common newbie-mistake to pepper one's code with it.
///
/// As a rule of thumb, before slapping `#[inline(always)]` on a function, measure if that additional function call really affects your runtime profile sufficiently to make up for the increase in compile time.
///
/// **Known problems:** False positives, big time. This lint is meant to be deactivated by everyone doing serious performance work. This means having done the measurement.
///
/// **Example:**
/// ```
/// #[inline(always)]
/// fn not_quite_hot_code(..) { ... }
/// ```
2015-05-30 13:10:19 +00:00
declare_lint! { pub INLINE_ALWAYS , Warn ,
2015-08-13 08:32:35 +00:00
" `#[inline(always)]` is a bad idea in most cases " }
2015-05-30 13:10:19 +00:00
#[ derive(Copy,Clone) ]
pub struct AttrPass ;
impl LintPass for AttrPass {
fn get_lints ( & self ) -> LintArray {
lint_array! ( INLINE_ALWAYS )
}
2015-09-19 02:53:04 +00:00
}
2015-08-11 18:22:20 +00:00
2015-09-19 02:53:04 +00:00
impl LateLintPass for AttrPass {
fn check_item ( & mut self , cx : & LateContext , item : & Item ) {
2015-08-11 18:22:20 +00:00
if is_relevant_item ( item ) {
2015-09-24 00:30:39 +00:00
check_attrs ( cx , item . span , & item . name , & item . attrs )
2015-08-11 18:22:20 +00:00
}
}
2015-09-19 02:53:04 +00:00
fn check_impl_item ( & mut self , cx : & LateContext , item : & ImplItem ) {
2015-08-11 18:22:20 +00:00
if is_relevant_impl ( item ) {
2015-09-24 00:30:39 +00:00
check_attrs ( cx , item . span , & item . name , & item . attrs )
2015-08-11 18:22:20 +00:00
}
}
2015-09-19 02:53:04 +00:00
fn check_trait_item ( & mut self , cx : & LateContext , item : & TraitItem ) {
2015-08-11 18:22:20 +00:00
if is_relevant_trait ( item ) {
2015-09-24 00:30:39 +00:00
check_attrs ( cx , item . span , & item . name , & item . attrs )
2015-08-11 18:22:20 +00:00
}
}
2015-06-07 10:03:56 +00:00
}
fn is_relevant_item ( item : & Item ) -> bool {
2015-11-24 17:44:40 +00:00
if let ItemFn ( _ , _ , _ , _ , _ , ref block ) = item . node {
2015-08-11 18:22:20 +00:00
is_relevant_block ( block )
} else { false }
2015-06-07 10:03:56 +00:00
}
fn is_relevant_impl ( item : & ImplItem ) -> bool {
2015-08-11 18:22:20 +00:00
match item . node {
2015-11-19 14:51:30 +00:00
ImplItemKind ::Method ( _ , ref block ) = > is_relevant_block ( block ) ,
2015-08-11 18:22:20 +00:00
_ = > false
}
2015-06-07 10:03:56 +00:00
}
fn is_relevant_trait ( item : & TraitItem ) -> bool {
2015-08-11 18:22:20 +00:00
match item . node {
MethodTraitItem ( _ , None ) = > true ,
MethodTraitItem ( _ , Some ( ref block ) ) = > is_relevant_block ( block ) ,
_ = > false
}
2015-06-07 10:03:56 +00:00
}
fn is_relevant_block ( block : & Block ) -> bool {
2015-08-13 13:36:31 +00:00
for stmt in & block . stmts {
2015-08-11 18:22:20 +00:00
match stmt . node {
StmtDecl ( _ , _ ) = > return true ,
StmtExpr ( ref expr , _ ) | StmtSemi ( ref expr , _ ) = > {
return is_relevant_expr ( expr ) ;
}
}
}
2015-08-25 12:41:35 +00:00
block . expr . as_ref ( ) . map_or ( false , | e | is_relevant_expr ( e ) )
2015-06-07 10:03:56 +00:00
}
fn is_relevant_expr ( expr : & Expr ) -> bool {
2015-08-11 18:22:20 +00:00
match expr . node {
ExprBlock ( ref block ) = > is_relevant_block ( block ) ,
2015-09-19 02:53:04 +00:00
ExprRet ( Some ( ref e ) ) = > is_relevant_expr ( e ) ,
2015-09-03 14:42:17 +00:00
ExprRet ( None ) | ExprBreak ( _ ) = > false ,
2015-08-11 18:22:20 +00:00
ExprCall ( ref path_expr , _ ) = > {
if let ExprPath ( _ , ref path ) = path_expr . node {
2015-12-23 21:37:52 +00:00
! match_path ( path , & BEGIN_UNWIND )
2015-08-11 18:22:20 +00:00
} else { true }
}
_ = > true
}
2015-05-30 13:10:19 +00:00
}
2015-09-24 00:30:39 +00:00
fn check_attrs ( cx : & LateContext , span : Span , name : & Name ,
2015-09-06 08:53:55 +00:00
attrs : & [ Attribute ] ) {
if in_macro ( cx , span ) { return ; }
2015-08-11 18:22:20 +00:00
for attr in attrs {
if let MetaList ( ref inline , ref values ) = attr . node . value . node {
if values . len ( ) ! = 1 | | inline ! = & " inline " { continue ; }
if let MetaWord ( ref always ) = values [ 0 ] . node {
if always ! = & " always " { continue ; }
span_lint ( cx , INLINE_ALWAYS , attr . span , & format! (
2015-08-12 08:46:49 +00:00
" you have declared `#[inline(always)]` on `{}`. This \
2015-10-12 05:59:08 +00:00
is usually a bad idea " ,
2015-09-24 00:30:39 +00:00
name ) ) ;
2015-08-11 18:22:20 +00:00
}
}
}
2015-05-30 13:10:19 +00:00
}