2015-05-04 00:17:15 -05:00
//! Checks for usage of &Vec[_] and &String
//!
2015-10-14 12:51:54 -05:00
//! This lint is **warn** by default
2015-05-04 00:17:15 -05:00
use rustc ::lint ::* ;
2015-09-03 09:42:17 -05:00
use rustc_front ::hir ::* ;
2015-08-21 11:28:17 -05:00
use rustc ::middle ::ty ;
2015-10-30 18:48:05 -05:00
use rustc ::front ::map ::Node ;
2015-08-16 01:54:43 -05:00
2015-08-21 12:00:33 -05:00
use utils ::{ span_lint , match_type } ;
2015-08-21 11:48:36 -05:00
use utils ::{ STRING_PATH , VEC_PATH } ;
2015-05-04 00:17:15 -05:00
2015-12-10 18:22:27 -06:00
/// **What it does:** This lint checks for function arguments of type `&String` or `&Vec` unless the references are mutable. It is `Warn` by default.
///
/// **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 {
2015-08-11 13:22:20 -05:00
check_fn ( cx , decl ) ;
}
}
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 {
2015-10-30 18:48:05 -05:00
if let Some ( Node ::NodeItem ( it ) ) = cx . tcx . map . find ( cx . tcx . map . get_parent ( item . id ) ) {
if let ItemImpl ( _ , _ , _ , Some ( _ ) , _ , _ ) = it . node {
return ; // ignore trait impls
}
}
2015-08-11 13:22:20 -05:00
check_fn ( cx , & sig . decl ) ;
}
}
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 {
2015-08-11 13:22:20 -05:00
check_fn ( cx , & sig . decl ) ;
}
}
2015-05-04 00:17:15 -05:00
}
2015-09-18 21:53:04 -05:00
fn check_fn ( cx : & LateContext , decl : & FnDecl ) {
2015-08-11 13:22:20 -05:00
for arg in & decl . inputs {
2015-10-30 18:48:05 -05:00
if let Some ( ty ) = cx . tcx . ast_ty_to_ty_cache . borrow ( ) . get ( & arg . ty . id ) {
if let ty ::TyRef ( _ , ty ::TypeAndMut { ty , mutbl : MutImmutable } ) = ty . sty {
2015-08-22 01:57:05 -05:00
if match_type ( cx , ty , & VEC_PATH ) {
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 ` & [ .. . ] ` " );
} else if match_type ( cx , ty , & STRING_PATH ) {
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
}