2016-03-19 17:48:29 +01:00
//! Checks for usage of `&Vec[_]` and `&String`.
2015-05-04 07:17:15 +02:00
2016-04-14 18:13:15 +02:00
use rustc ::hir ::* ;
2016-04-07 17:46:48 +02:00
use rustc ::hir ::map ::NodeItem ;
2016-02-24 17:38:57 +01:00
use rustc ::lint ::* ;
2016-03-27 19:59:02 +01:00
use rustc ::ty ;
2016-03-01 20:38:21 +01:00
use syntax ::ast ::NodeId ;
2016-04-14 18:13:15 +02:00
use utils ::{ match_type , paths , span_lint } ;
2015-05-04 07:17:15 +02:00
2016-02-06 00:41:54 +01:00
/// **What it does:** This lint checks for function arguments of type `&String` or `&Vec` unless the references are mutable.
2015-12-11 01:22:27 +01: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 07:17:15 +02:00
declare_lint! {
2015-05-04 08:15:24 +02:00
pub PTR_ARG ,
2015-10-14 19:51:54 +02:00
Warn ,
2015-08-13 10:32:35 +02:00
" fn arguments of the type `&Vec<...>` or `&String`, suggesting to use `&[...]` or `&str` \
instead , respectively "
2015-05-04 07:17:15 +02:00
}
#[ derive(Copy,Clone) ]
2015-05-04 08:15:24 +02:00
pub struct PtrArg ;
2015-05-04 07:17:15 +02:00
2015-05-04 08:15:24 +02:00
impl LintPass for PtrArg {
2015-05-04 07:17:15 +02:00
fn get_lints ( & self ) -> LintArray {
2015-05-04 08:15:24 +02:00
lint_array! ( PTR_ARG )
2015-05-04 07:17:15 +02:00
}
2015-09-19 08:23:04 +05:30
}
2015-08-11 20:22:20 +02:00
2015-09-19 08:23:04 +05:30
impl LateLintPass for PtrArg {
fn check_item ( & mut self , cx : & LateContext , item : & Item ) {
2015-11-25 02:44:40 +09:00
if let ItemFn ( ref decl , _ , _ , _ , _ , _ ) = item . node {
2016-03-01 20:38:21 +01:00
check_fn ( cx , decl , item . id ) ;
2015-08-11 20:22:20 +02:00
}
}
2015-09-19 08:23:04 +05:30
fn check_impl_item ( & mut self , cx : & LateContext , item : & ImplItem ) {
2015-11-25 02:44:40 +09:00
if let ImplItemKind ::Method ( ref sig , _ ) = item . node {
2016-01-22 17:54:44 +05:30
if let Some ( NodeItem ( it ) ) = cx . tcx . map . find ( cx . tcx . map . get_parent ( item . id ) ) {
2015-10-31 05:18:05 +05:30
if let ItemImpl ( _ , _ , _ , Some ( _ ) , _ , _ ) = it . node {
return ; // ignore trait impls
}
}
2016-03-01 20:38:21 +01:00
check_fn ( cx , & sig . decl , item . id ) ;
2015-08-11 20:22:20 +02:00
}
}
2015-09-19 08:23:04 +05:30
fn check_trait_item ( & mut self , cx : & LateContext , item : & TraitItem ) {
2015-11-25 02:44:40 +09:00
if let MethodTraitItem ( ref sig , _ ) = item . node {
2016-03-01 20:38:21 +01:00
check_fn ( cx , & sig . decl , item . id ) ;
2015-08-11 20:22:20 +02:00
}
}
2015-05-04 07:17:15 +02:00
}
2016-03-01 20:38:21 +01: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 18:13:15 +02:00
if match_type ( cx , ty , & paths ::VEC ) {
2016-03-01 20:38:21 +01: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 18:13:15 +02:00
} else if match_type ( cx , ty , & paths ::STRING ) {
2016-03-01 20:38:21 +01: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 18:28:17 +02:00
}
2015-08-11 20:22:20 +02:00
}
}
2015-05-04 07:17:15 +02:00
}