2016-03-19 11:48:29 -05:00
//! Checks for usage of `&Vec[_]` and `&String`.
2015-05-04 00:17:15 -05:00
2016-04-14 11:13:15 -05:00
use rustc ::hir ::* ;
2016-04-07 10:46:48 -05:00
use rustc ::hir ::map ::NodeItem ;
2016-02-24 10:38:57 -06:00
use rustc ::lint ::* ;
2016-03-27 13:59:02 -05:00
use rustc ::ty ;
2016-03-01 13:38:21 -06:00
use syntax ::ast ::NodeId ;
2016-04-14 11:13:15 -05:00
use utils ::{ match_type , paths , span_lint } ;
2015-05-04 00:17:15 -05:00
2016-02-05 17:41:54 -06:00
/// **What it does:** This lint checks for function arguments of type `&String` or `&Vec` unless the references are mutable.
2015-12-10 18:22:27 -06:00
///
/// **Why is this bad?** Requiring the argument to be of the specific size makes the function less useful for no benefit; slices in the form of `&[T]` or `&str` usually suffice and can be obtained from other types, too.
///
/// **Known problems:** None
///
/// **Example:** `fn foo(&Vec<u32>) { .. }`
2015-05-04 00:17:15 -05:00
declare_lint! {
2015-05-04 01:15:24 -05:00
pub PTR_ARG ,
2015-10-14 12:51:54 -05:00
Warn ,
2015-08-13 03:32:35 -05:00
" fn arguments of the type `&Vec<...>` or `&String`, suggesting to use `&[...]` or `&str` \
instead , respectively "
2015-05-04 00:17:15 -05:00
}
#[ derive(Copy,Clone) ]
2015-05-04 01:15:24 -05:00
pub struct PtrArg ;
2015-05-04 00:17:15 -05:00
2015-05-04 01:15:24 -05:00
impl LintPass for PtrArg {
2015-05-04 00:17:15 -05:00
fn get_lints ( & self ) -> LintArray {
2015-05-04 01:15:24 -05:00
lint_array! ( PTR_ARG )
2015-05-04 00:17:15 -05:00
}
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 PtrArg {
fn check_item ( & mut self , cx : & LateContext , item : & Item ) {
2015-11-24 11:44:40 -06:00
if let ItemFn ( ref decl , _ , _ , _ , _ , _ ) = item . node {
2016-03-01 13:38:21 -06:00
check_fn ( cx , decl , item . id ) ;
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-11-24 11:44:40 -06:00
if let ImplItemKind ::Method ( ref sig , _ ) = item . node {
2016-01-22 06:24:44 -06:00
if let Some ( NodeItem ( it ) ) = cx . tcx . map . find ( cx . tcx . map . get_parent ( item . id ) ) {
2015-10-30 18:48:05 -05:00
if let ItemImpl ( _ , _ , _ , Some ( _ ) , _ , _ ) = it . node {
return ; // ignore trait impls
}
}
2016-03-01 13:38:21 -06:00
check_fn ( cx , & sig . decl , item . id ) ;
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-11-24 11:44:40 -06:00
if let MethodTraitItem ( ref sig , _ ) = item . node {
2016-03-01 13:38:21 -06:00
check_fn ( cx , & sig . decl , item . id ) ;
2015-08-11 13:22:20 -05:00
}
}
2015-05-04 00:17:15 -05:00
}
2016-03-01 13:38:21 -06:00
fn check_fn ( cx : & LateContext , decl : & FnDecl , fn_id : NodeId ) {
let fn_ty = cx . tcx . node_id_to_type ( fn_id ) . fn_sig ( ) . skip_binder ( ) ;
for ( arg , ty ) in decl . inputs . iter ( ) . zip ( & fn_ty . inputs ) {
if let ty ::TyRef ( _ , ty ::TypeAndMut { ty , mutbl : MutImmutable } ) = ty . sty {
2016-04-14 11:13:15 -05:00
if match_type ( cx , ty , & paths ::VEC ) {
2016-03-01 13:38:21 -06:00
span_lint ( cx ,
PTR_ARG ,
arg . ty . span ,
" writing `&Vec<_>` instead of `&[_]` involves one more reference and cannot be used \
with non - Vec - based slices . Consider changing the type to ` & [ .. . ] ` " );
2016-04-14 11:13:15 -05:00
} else if match_type ( cx , ty , & paths ::STRING ) {
2016-03-01 13:38:21 -06:00
span_lint ( cx ,
PTR_ARG ,
arg . ty . span ,
" writing `&String` instead of `&str` involves a new object where a slice will do. \
Consider changing the type to ` & str ` " );
2015-08-21 11:28:17 -05:00
}
2015-08-11 13:22:20 -05:00
}
}
2015-05-04 00:17:15 -05:00
}