2015-09-29 11:11:19 +00:00
use rustc ::lint ::* ;
2015-09-30 11:08:29 +00:00
use rustc ::middle ::ty ::{ TypeAndMut , TypeVariants , MethodCall , TyS } ;
2016-02-24 16:38:57 +00:00
use rustc_front ::hir ::* ;
2015-09-30 11:08:29 +00:00
use syntax ::ptr ::P ;
2016-02-24 16:38:57 +00:00
use utils ::span_lint ;
2015-09-29 11:11:19 +00:00
2016-02-05 23:41:54 +00:00
/// **What it does:** This lint detects giving a mutable reference to a function that only requires an immutable reference.
2015-12-11 00:22:27 +00: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 11:11:19 +00:00
declare_lint! {
pub UNNECESSARY_MUT_PASSED ,
Warn ,
2015-09-29 16:43:38 +00:00
" an argument is passed as a mutable reference although the function/method only demands an \
2015-09-29 11:11:19 +00: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 11:08:29 +00:00
let borrowed_table = cx . tcx . tables . borrow ( ) ;
2015-09-29 16:43:38 +00:00
match e . node {
ExprCall ( ref fn_expr , ref arguments ) = > {
2016-02-01 10:28:39 +00:00
let function_type = borrowed_table . node_types
. get ( & fn_expr . id )
. expect ( " A function with an unknown type is called. \
If this happened , the compiler would have \
aborted the compilation long ago " );
if let ExprPath ( _ , ref path ) = fn_expr . node {
2016-02-20 20:03:45 +00:00
check_arguments ( cx , & arguments , function_type , & path . to_string ( ) ) ;
2016-02-01 10:28:39 +00:00
}
2015-11-17 04:39:42 +00:00
}
2015-09-29 16:43:38 +00:00
ExprMethodCall ( ref name , _ , ref arguments ) = > {
let method_call = MethodCall ::expr ( e . id ) ;
2016-02-01 10:28:39 +00:00
let method_type = borrowed_table . method_map . get ( & method_call ) . expect ( " This should never happen. " ) ;
2016-02-20 20:03:45 +00:00
check_arguments ( cx , & arguments , method_type . ty , & name . node . as_str ( ) )
2015-11-17 04:39:42 +00:00
}
2015-09-29 16:43:38 +00:00
_ = > { }
2015-09-29 11:11:19 +00:00
}
}
}
2015-09-30 11:08:29 +00:00
fn check_arguments ( cx : & LateContext , arguments : & [ P < Expr > ] , type_definition : & TyS , name : & str ) {
2016-03-10 17:13:49 +00:00
match type_definition . sty {
TypeVariants ::TyFnDef ( _ , _ , ref fn_type ) | TypeVariants ::TyFnPtr ( ref fn_type ) = > {
let parameters = & fn_type . sig . skip_binder ( ) . inputs ;
for ( argument , parameter ) in arguments . iter ( ) . zip ( parameters . iter ( ) ) {
match parameter . sty {
TypeVariants ::TyRef ( _ , TypeAndMut { mutbl : MutImmutable , .. } ) |
TypeVariants ::TyRawPtr ( TypeAndMut { mutbl : MutImmutable , .. } ) = > {
if let ExprAddrOf ( MutMutable , _ ) = argument . node {
span_lint ( cx ,
UNNECESSARY_MUT_PASSED ,
argument . span ,
& format! ( " The function/method \" {} \" doesn't need a mutable reference " , name ) ) ;
}
2015-09-30 11:08:29 +00:00
}
2016-03-10 17:13:49 +00:00
_ = > { }
2015-11-17 04:39:42 +00:00
}
2015-09-30 11:08:29 +00:00
}
}
2016-03-10 17:13:49 +00:00
_ = > ( ) ,
2015-09-30 11:08:29 +00:00
}
}