2015-08-16 01:54:43 -05:00
//! checks for attributes
2015-05-30 08:10:19 -05:00
use rustc ::lint ::* ;
2015-09-03 09:42:17 -05:00
use rustc_front ::hir ::* ;
use reexport ::* ;
2015-09-06 03:53:55 -05:00
use syntax ::codemap ::Span ;
2015-09-16 19:01:41 -05:00
use syntax ::attr ::* ;
use syntax ::ast ::{ Attribute , MetaList , MetaWord } ;
2015-07-26 09:53:11 -05:00
use utils ::{ in_macro , match_path , span_lint } ;
2015-05-30 08:10:19 -05:00
2015-12-10 18:22:27 -06:00
/// **What it does:** This lint warns on items annotated with `#[inline(always)]`, unless the annotated function is empty or simply panics.
///
/// **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 08:10:19 -05:00
declare_lint! { pub INLINE_ALWAYS , Warn ,
2015-08-13 03:32:35 -05:00
" `#[inline(always)]` is a bad idea in most cases " }
2015-05-30 08:10:19 -05:00
#[ derive(Copy,Clone) ]
pub struct AttrPass ;
impl LintPass for AttrPass {
fn get_lints ( & self ) -> LintArray {
lint_array! ( INLINE_ALWAYS )
}
2015-09-18 21:53:04 -05:00
}
2015-08-11 13:22:20 -05:00
2015-09-18 21:53:04 -05:00
impl LateLintPass for AttrPass {
fn check_item ( & mut self , cx : & LateContext , item : & Item ) {
2015-08-11 13:22:20 -05:00
if is_relevant_item ( item ) {
2015-09-23 19:30:39 -05:00
check_attrs ( cx , item . span , & item . name , & item . attrs )
2015-08-11 13:22:20 -05:00
}
}
2015-09-18 21:53:04 -05:00
fn check_impl_item ( & mut self , cx : & LateContext , item : & ImplItem ) {
2015-08-11 13:22:20 -05:00
if is_relevant_impl ( item ) {
2015-09-23 19:30:39 -05:00
check_attrs ( cx , item . span , & item . name , & item . attrs )
2015-08-11 13:22:20 -05:00
}
}
2015-09-18 21:53:04 -05:00
fn check_trait_item ( & mut self , cx : & LateContext , item : & TraitItem ) {
2015-08-11 13:22:20 -05:00
if is_relevant_trait ( item ) {
2015-09-23 19:30:39 -05:00
check_attrs ( cx , item . span , & item . name , & item . attrs )
2015-08-11 13:22:20 -05:00
}
}
2015-06-07 05:03:56 -05:00
}
fn is_relevant_item ( item : & Item ) -> bool {
2015-11-24 11:44:40 -06:00
if let ItemFn ( _ , _ , _ , _ , _ , ref block ) = item . node {
2015-08-11 13:22:20 -05:00
is_relevant_block ( block )
} else { false }
2015-06-07 05:03:56 -05:00
}
fn is_relevant_impl ( item : & ImplItem ) -> bool {
2015-08-11 13:22:20 -05:00
match item . node {
2015-11-19 08:51:30 -06:00
ImplItemKind ::Method ( _ , ref block ) = > is_relevant_block ( block ) ,
2015-08-11 13:22:20 -05:00
_ = > false
}
2015-06-07 05:03:56 -05:00
}
fn is_relevant_trait ( item : & TraitItem ) -> bool {
2015-08-11 13:22:20 -05:00
match item . node {
MethodTraitItem ( _ , None ) = > true ,
MethodTraitItem ( _ , Some ( ref block ) ) = > is_relevant_block ( block ) ,
_ = > false
}
2015-06-07 05:03:56 -05:00
}
fn is_relevant_block ( block : & Block ) -> bool {
2015-08-13 08:36:31 -05:00
for stmt in & block . stmts {
2015-08-11 13:22:20 -05:00
match stmt . node {
StmtDecl ( _ , _ ) = > return true ,
StmtExpr ( ref expr , _ ) | StmtSemi ( ref expr , _ ) = > {
return is_relevant_expr ( expr ) ;
}
}
}
2015-08-25 07:41:35 -05:00
block . expr . as_ref ( ) . map_or ( false , | e | is_relevant_expr ( e ) )
2015-06-07 05:03:56 -05:00
}
fn is_relevant_expr ( expr : & Expr ) -> bool {
2015-08-11 13:22:20 -05:00
match expr . node {
ExprBlock ( ref block ) = > is_relevant_block ( block ) ,
2015-09-18 21:53:04 -05:00
ExprRet ( Some ( ref e ) ) = > is_relevant_expr ( e ) ,
2015-09-03 09:42:17 -05:00
ExprRet ( None ) | ExprBreak ( _ ) = > false ,
2015-08-11 13:22:20 -05:00
ExprCall ( ref path_expr , _ ) = > {
if let ExprPath ( _ , ref path ) = path_expr . node {
! match_path ( path , & [ " std " , " rt " , " begin_unwind " ] )
} else { true }
}
_ = > true
}
2015-05-30 08:10:19 -05:00
}
2015-09-23 19:30:39 -05:00
fn check_attrs ( cx : & LateContext , span : Span , name : & Name ,
2015-09-06 03:53:55 -05:00
attrs : & [ Attribute ] ) {
if in_macro ( cx , span ) { return ; }
2015-08-11 13:22:20 -05: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 03:46:49 -05:00
" you have declared `#[inline(always)]` on `{}`. This \
2015-10-12 00:59:08 -05:00
is usually a bad idea " ,
2015-09-23 19:30:39 -05:00
name ) ) ;
2015-08-11 13:22:20 -05:00
}
}
}
2015-05-30 08:10:19 -05:00
}