2015-05-04 05:17:15 +00:00
//! Checks for usage of &Vec[_] and &String
//!
2015-10-14 17:51:54 +00:00
//! This lint is **warn** by default
2015-05-04 05:17:15 +00:00
use rustc ::lint ::* ;
2015-09-03 14:42:17 +00:00
use rustc_front ::hir ::* ;
2015-08-21 16:28:17 +00:00
use rustc ::middle ::ty ;
2015-10-30 23:48:05 +00:00
use rustc ::front ::map ::Node ;
2015-08-16 06:54:43 +00:00
2015-08-21 17:00:33 +00:00
use utils ::{ span_lint , match_type } ;
2015-08-21 16:48:36 +00:00
use utils ::{ STRING_PATH , VEC_PATH } ;
2015-05-04 05:17:15 +00:00
2015-12-11 00:22:27 +00: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 05:17:15 +00:00
declare_lint! {
2015-05-04 06:15:24 +00:00
pub PTR_ARG ,
2015-10-14 17:51:54 +00:00
Warn ,
2015-08-13 08:32:35 +00:00
" fn arguments of the type `&Vec<...>` or `&String`, suggesting to use `&[...]` or `&str` \
instead , respectively "
2015-05-04 05:17:15 +00:00
}
#[ derive(Copy,Clone) ]
2015-05-04 06:15:24 +00:00
pub struct PtrArg ;
2015-05-04 05:17:15 +00:00
2015-05-04 06:15:24 +00:00
impl LintPass for PtrArg {
2015-05-04 05:17:15 +00:00
fn get_lints ( & self ) -> LintArray {
2015-05-04 06:15:24 +00:00
lint_array! ( PTR_ARG )
2015-05-04 05:17:15 +00:00
}
2015-09-19 02:53:04 +00:00
}
2015-08-11 18:22:20 +00:00
2015-09-19 02:53:04 +00:00
impl LateLintPass for PtrArg {
fn check_item ( & mut self , cx : & LateContext , item : & Item ) {
2015-11-24 17:44:40 +00:00
if let ItemFn ( ref decl , _ , _ , _ , _ , _ ) = item . node {
2015-08-11 18:22:20 +00:00
check_fn ( cx , decl ) ;
}
}
2015-09-19 02:53:04 +00:00
fn check_impl_item ( & mut self , cx : & LateContext , item : & ImplItem ) {
2015-11-24 17:44:40 +00:00
if let ImplItemKind ::Method ( ref sig , _ ) = item . node {
2015-10-30 23:48:05 +00: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 18:22:20 +00:00
check_fn ( cx , & sig . decl ) ;
}
}
2015-09-19 02:53:04 +00:00
fn check_trait_item ( & mut self , cx : & LateContext , item : & TraitItem ) {
2015-11-24 17:44:40 +00:00
if let MethodTraitItem ( ref sig , _ ) = item . node {
2015-08-11 18:22:20 +00:00
check_fn ( cx , & sig . decl ) ;
}
}
2015-05-04 05:17:15 +00:00
}
2015-09-19 02:53:04 +00:00
fn check_fn ( cx : & LateContext , decl : & FnDecl ) {
2015-08-11 18:22:20 +00:00
for arg in & decl . inputs {
2015-10-30 23:48:05 +00: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 06:57:05 +00:00
if match_type ( cx , ty , & VEC_PATH ) {
2016-01-04 04:26:12 +00: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 ` & [ .. . ] ` " );
2015-08-22 06:57:05 +00:00
} else if match_type ( cx , ty , & STRING_PATH ) {
2016-01-04 04:26:12 +00: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-22 06:57:05 +00:00
}
2015-08-21 16:28:17 +00:00
}
2015-08-11 18:22:20 +00:00
}
}
2015-05-04 05:17:15 +00:00
}