2015-09-29 06:11:19 -05:00
use rustc ::lint ::* ;
use rustc_front ::hir ::* ;
use utils ::span_lint ;
2015-09-30 06:08:29 -05:00
use rustc ::middle ::ty ::{ TypeAndMut , TypeVariants , MethodCall , TyS } ;
use syntax ::ptr ::P ;
2015-09-29 06:11:19 -05:00
2016-01-01 10:48:19 -06:00
/// **What it does:** This lint detects giving a mutable reference to a function that only requires an immutable reference. It is `Warn` by default.
2015-12-10 18:22:27 -06:00
///
/// **Why is this bad?** The immutable reference rules out all other references to the value. Also the code misleads about the intent of the call site.
///
/// **Known problems:** None
///
/// **Example** `my_vec.push(&mut value)`
2015-09-29 06:11:19 -05:00
declare_lint! {
pub UNNECESSARY_MUT_PASSED ,
Warn ,
2015-09-29 11:43:38 -05:00
" an argument is passed as a mutable reference although the function/method only demands an \
2015-09-29 06:11:19 -05:00
immutable reference "
}
#[ derive(Copy,Clone) ]
pub struct UnnecessaryMutPassed ;
impl LintPass for UnnecessaryMutPassed {
fn get_lints ( & self ) -> LintArray {
lint_array! ( UNNECESSARY_MUT_PASSED )
}
}
impl LateLintPass for UnnecessaryMutPassed {
fn check_expr ( & mut self , cx : & LateContext , e : & Expr ) {
2015-09-30 06:08:29 -05:00
let borrowed_table = cx . tcx . tables . borrow ( ) ;
2015-09-29 11:43:38 -05:00
match e . node {
ExprCall ( ref fn_expr , ref arguments ) = > {
2015-09-30 06:08:29 -05:00
match borrowed_table . node_types . get ( & fn_expr . id ) {
Some ( function_type ) = > {
if let ExprPath ( _ , ref path ) = fn_expr . node {
2016-01-03 22:26:12 -06:00
check_arguments ( cx , & arguments , function_type , & format! ( " {} " , path ) ) ;
2015-09-30 06:08:29 -05:00
}
2015-11-16 22:39:42 -06:00
}
2015-09-29 11:43:38 -05:00
None = > unreachable! ( ) , // A function with unknown type is called.
2016-01-03 22:26:12 -06:00
// If this happened the compiler would have aborted the
// compilation long ago.
2015-09-29 11:43:38 -05:00
} ;
2015-09-30 06:08:29 -05:00
2015-11-16 22:39:42 -06:00
}
2015-09-29 11:43:38 -05:00
ExprMethodCall ( ref name , _ , ref arguments ) = > {
let method_call = MethodCall ::expr ( e . id ) ;
2015-09-30 06:08:29 -05:00
match borrowed_table . method_map . get ( & method_call ) {
2016-01-03 22:26:12 -06:00
Some ( method_type ) = > {
check_arguments ( cx , & arguments , method_type . ty , & format! ( " {} " , name . node . as_str ( ) ) )
}
2015-09-29 11:43:38 -05:00
None = > unreachable! ( ) , // Just like above, this should never happen.
} ;
2015-11-16 22:39:42 -06:00
}
2015-09-29 11:43:38 -05:00
_ = > { }
2015-09-29 06:11:19 -05:00
}
}
}
2015-09-30 06:08:29 -05:00
fn check_arguments ( cx : & LateContext , arguments : & [ P < Expr > ] , type_definition : & TyS , name : & str ) {
if let TypeVariants ::TyBareFn ( _ , ref fn_type ) = type_definition . sty {
let parameters = & fn_type . sig . skip_binder ( ) . inputs ;
for ( argument , parameter ) in arguments . iter ( ) . zip ( parameters . iter ( ) ) {
match parameter . sty {
2015-12-05 20:21:34 -06:00
TypeVariants ::TyRef ( _ , TypeAndMut { mutbl : MutImmutable , .. } ) |
TypeVariants ::TyRawPtr ( TypeAndMut { mutbl : MutImmutable , .. } ) = > {
2015-11-27 09:47:24 -06:00
if let ExprAddrOf ( MutMutable , _ ) = argument . node {
2016-01-03 22:26:12 -06:00
span_lint ( cx ,
UNNECESSARY_MUT_PASSED ,
argument . span ,
& format! ( " The function/method \" {} \" doesn't need a mutable reference " , name ) ) ;
2015-09-30 06:08:29 -05:00
}
2015-11-16 22:39:42 -06:00
}
2015-09-30 06:08:29 -05:00
_ = > { }
}
}
}
}