2015-09-03 14:42:17 +00:00
use rustc_front ::hir ::* ;
2015-08-16 06:54:43 +00:00
use rustc ::lint ::* ;
2015-08-11 18:53:50 +00:00
use rustc ::middle ::ty ;
2015-11-19 13:39:27 +00:00
use rustc ::middle ::subst ::{ Subst , TypeSpace } ;
2015-08-25 16:38:08 +00:00
use std ::iter ;
use std ::borrow ::Cow ;
2015-08-11 18:53:50 +00:00
2015-11-23 05:48:19 +00:00
use utils ::{ snippet , span_lint , span_note_and_lint , match_path , match_type , walk_ptrs_ty_depth ,
2015-11-19 13:39:27 +00:00
walk_ptrs_ty } ;
2015-08-21 16:48:36 +00:00
use utils ::{ OPTION_PATH , RESULT_PATH , STRING_PATH } ;
2015-08-11 18:53:50 +00:00
2015-08-24 16:13:02 +00:00
use self ::SelfKind ::* ;
use self ::OutType ::* ;
2015-11-19 13:39:27 +00:00
#[ derive(Clone) ]
2015-11-19 19:13:36 +00:00
pub struct MethodsPass ;
2015-08-11 18:53:50 +00:00
2015-12-11 00:22:27 +00:00
/// **What it does:** This lint checks for `.unwrap()` calls on `Option`s. It is `Allow` by default.
///
/// **Why is this bad?** Usually it is better to handle the `None` case, or to at least call `.expect(_)` with a more helpful message. Still, for a lot of quick-and-dirty code, `unwrap` is a good choice, which is why this lint is `Allow` by default.
///
/// **Known problems:** None
///
/// **Example:** `x.unwrap()`
2015-08-14 05:17:10 +00:00
declare_lint! ( pub OPTION_UNWRAP_USED , Allow ,
2015-08-13 08:32:35 +00:00
" using `Option.unwrap()`, which should at least get a better message using `expect()` " ) ;
2015-12-11 00:22:27 +00:00
/// **What it does:** This lint checks for `.unwrap()` calls on `Result`s. It is `Allow` by default.
///
/// **Why is this bad?** `result.unwrap()` will let the thread panic on `Err` values. Normally, you want to implement more sophisticated error handling, and propagate errors upwards with `try!`.
///
/// Even if you want to panic on errors, not all `Error`s implement good messages on display. Therefore it may be beneficial to look at the places where they may get displayed. Activate this lint to do just that.
///
/// **Known problems:** None
///
/// **Example:** `x.unwrap()`
2015-08-11 18:53:50 +00:00
declare_lint! ( pub RESULT_UNWRAP_USED , Allow ,
2015-08-13 08:32:35 +00:00
" using `Result.unwrap()`, which might be better handled " ) ;
2015-12-11 00:22:27 +00:00
/// **What it does:** This lint checks for `.to_string()` method calls on values of type `&str`. It is `Warn` by default.
///
/// **Why is this bad?** This uses the whole formatting machinery just to clone a string. Using `.to_owned()` is lighter on resources. You can also consider using a [`Cow<'a, str>`](http://doc.rust-lang.org/std/borrow/enum.Cow.html) instead in some cases.
///
/// **Known problems:** None
///
/// **Example:** `s.to_string()` where `s: &str`
2015-08-12 11:58:55 +00:00
declare_lint! ( pub STR_TO_STRING , Warn ,
2015-08-13 08:32:35 +00:00
" using `to_string()` on a str, which should be `to_owned()` " ) ;
2015-12-11 00:22:27 +00:00
/// **What it does:** This lint checks for `.to_string()` method calls on values of type `String`. It is `Warn` by default.
///
/// **Why is this bad?** As our string is already owned, this whole operation is basically a no-op, but still creates a clone of the string (which, if really wanted, should be done with `.clone()`).
///
/// **Known problems:** None
///
/// **Example:** `s.to_string()` where `s: String`
2015-08-12 15:02:49 +00:00
declare_lint! ( pub STRING_TO_STRING , Warn ,
2015-08-13 08:32:35 +00:00
" calling `String.to_string()` which is a no-op " ) ;
2015-12-11 00:22:27 +00:00
/// **What it does:** This lint checks for methods that should live in a trait implementation of a `std` trait (see [llogiq's blog post](http://llogiq.github.io/2015/07/30/traits.html) for further information) instead of an inherent implementation. It is `Warn` by default.
///
/// **Why is this bad?** Implementing the traits improve ergonomics for users of the code, often with very little cost. Also people seeing a `mul(..)` method may expect `*` to work equally, so you should have good reason to disappoint them.
///
/// **Known problems:** None
///
/// **Example:**
/// ```
/// struct X;
/// impl X {
/// fn add(&self, other: &X) -> X { .. }
/// }
/// ```
2015-08-24 16:13:02 +00:00
declare_lint! ( pub SHOULD_IMPLEMENT_TRAIT , Warn ,
" defining a method that should be implementing a std trait " ) ;
2015-12-11 00:22:27 +00:00
/// **What it does:** This lint checks for methods with certain name prefixes and `Warn`s (by default) if the prefix doesn't match how self is taken. The actual rules are:
///
/// |Prefix |`self` taken |
/// |-------|--------------------|
/// |`as_` |`&self` or &mut self|
/// |`from_`| none |
/// |`into_`|`self` |
/// |`is_` |`&self` or none |
/// |`to_` |`&self` |
///
/// **Why is this bad?** Consistency breeds readability. If you follow the conventions, your users won't be surprised that they e.g. need to supply a mutable reference to a `as_`.. function.
///
/// **Known problems:** None
///
/// **Example**
///
/// ```
/// impl X {
/// fn as_str(self) -> &str { .. }
/// }
/// ```
2015-09-01 16:52:48 +00:00
declare_lint! ( pub WRONG_SELF_CONVENTION , Warn ,
" defining a method named with an established prefix (like \" into_ \" ) that takes \
` self ` with the wrong convention " );
2015-12-11 00:22:27 +00:00
/// **What it does:** This is the same as [`wrong_self_convention`](#wrong_self_convention), but for public items. This lint is `Allow` by default.
///
/// **Why is this bad?** See [`wrong_self_convention`](#wrong_self_convention).
///
/// **Known problems:** Actually *renaming* the function may break clients if the function is part of the public interface. In that case, be mindful of the stability guarantees you've given your users.
///
/// **Example:**
/// ```
/// impl X {
/// pub fn as_str(self) -> &str { .. }
/// }
/// ```
2015-09-07 07:17:45 +00:00
declare_lint! ( pub WRONG_PUB_SELF_CONVENTION , Allow ,
" defining a public method named with an established prefix (like \" into_ \" ) that takes \
` self ` with the wrong convention " );
2015-11-19 13:39:27 +00:00
declare_lint! ( pub OK_EXPECT , Warn ,
" using `ok().expect()`, which gives worse error messages than \
calling ` expect ` directly on the Result " );
2015-11-23 05:48:19 +00:00
declare_lint! ( pub OPTION_MAP_UNWRAP_OR , Warn ,
" using `Option.map(f).unwrap_or(a)`, which is more succinctly expressed as \
` map_or ( a , f ) ` ) " );
declare_lint! ( pub OPTION_MAP_UNWRAP_OR_ELSE , Warn ,
" using `Option.map(f).unwrap_or_else(g)`, which is more succinctly expressed as \
` map_or_else ( g , f ) ` ) " );
2015-08-11 18:53:50 +00:00
impl LintPass for MethodsPass {
fn get_lints ( & self ) -> LintArray {
2015-08-24 16:13:02 +00:00
lint_array! ( OPTION_UNWRAP_USED , RESULT_UNWRAP_USED , STR_TO_STRING , STRING_TO_STRING ,
2015-11-23 05:48:19 +00:00
SHOULD_IMPLEMENT_TRAIT , WRONG_SELF_CONVENTION , OK_EXPECT , OPTION_MAP_UNWRAP_OR ,
OPTION_MAP_UNWRAP_OR_ELSE )
2015-08-11 18:53:50 +00:00
}
2015-09-19 02:53:04 +00:00
}
2015-08-11 18:53:50 +00:00
2015-09-19 02:53:04 +00:00
impl LateLintPass for MethodsPass {
fn check_expr ( & mut self , cx : & LateContext , expr : & Expr ) {
2015-11-19 13:39:27 +00:00
2015-09-24 00:30:39 +00:00
if let ExprMethodCall ( ref name , _ , ref args ) = expr . node {
2015-08-25 16:38:08 +00:00
let ( obj_ty , ptr_depth ) = walk_ptrs_ty_depth ( cx . tcx . expr_ty ( & args [ 0 ] ) ) ;
2015-12-03 11:43:50 +00:00
match & * name . node . as_str ( ) {
" unwrap " if match_type ( cx , obj_ty , & OPTION_PATH ) = > {
2015-08-21 17:00:33 +00:00
span_lint ( cx , OPTION_UNWRAP_USED , expr . span ,
" used unwrap() on an Option value. If you don't want \
to handle the None case gracefully , consider using \
expect ( ) to provide a better panic message " );
2015-12-03 11:43:50 +00:00
} ,
" unwrap " if match_type ( cx , obj_ty , & RESULT_PATH ) = > {
2015-08-21 17:00:33 +00:00
span_lint ( cx , RESULT_UNWRAP_USED , expr . span ,
" used unwrap() on a Result value. Graceful handling \
of Err values is preferred " );
2015-12-03 11:43:50 +00:00
} ,
" to_string " if obj_ty . sty = = ty ::TyStr = > {
2015-08-25 16:38:08 +00:00
let mut arg_str = snippet ( cx , args [ 0 ] . span , " _ " ) ;
if ptr_depth > 1 {
arg_str = Cow ::Owned ( format! (
" ({}{}) " ,
iter ::repeat ( '*' ) . take ( ptr_depth - 1 ) . collect ::< String > ( ) ,
arg_str ) ) ;
}
span_lint ( cx , STR_TO_STRING , expr . span , & format! (
" `{}.to_owned()` is faster " , arg_str ) ) ;
2015-12-03 11:43:50 +00:00
} ,
" to_string " if match_type ( cx , obj_ty , & STRING_PATH ) = > {
2015-08-25 10:45:52 +00:00
span_lint ( cx , STRING_TO_STRING , expr . span , " `String.to_string()` is a no-op; use \
` clone ( ) ` to make a copy " );
2015-12-03 11:43:50 +00:00
} ,
" expect " = > if let ExprMethodCall ( ref inner_name , _ , ref inner_args ) = args [ 0 ] . node {
2015-11-19 13:39:27 +00:00
if inner_name . node . as_str ( ) = = " ok "
& & match_type ( cx , cx . tcx . expr_ty ( & inner_args [ 0 ] ) , & RESULT_PATH ) {
let result_type = cx . tcx . expr_ty ( & inner_args [ 0 ] ) ;
if let Some ( error_type ) = get_error_type ( cx , result_type ) {
2015-11-19 19:13:36 +00:00
if has_debug_impl ( error_type , cx ) {
2015-11-19 13:39:27 +00:00
span_lint ( cx , OK_EXPECT , expr . span ,
" called `ok().expect()` on a Result \
2015-11-23 11:04:23 +00:00
value . You can call ` expect ` directly \
2015-11-19 13:39:27 +00:00
on the ` Result ` " );
}
}
}
2015-12-03 11:43:50 +00:00
} ,
// check Option.map(_).unwrap_or(_)
" unwrap_or " = > if let ExprMethodCall ( ref inner_name , _ , ref inner_args ) = args [ 0 ] . node {
2015-11-23 05:48:19 +00:00
if inner_name . node . as_str ( ) = = " map "
& & match_type ( cx , cx . tcx . expr_ty ( & inner_args [ 0 ] ) , & OPTION_PATH ) {
// lint message
let msg =
" called `map(f).unwrap_or(a)` on an Option value. This can be done \
more directly by calling ` map_or ( a , f ) ` instead " ;
// get args to map() and unwrap_or()
let map_arg = snippet ( cx , inner_args [ 1 ] . span , " .. " ) ;
let unwrap_arg = snippet ( cx , args [ 1 ] . span , " .. " ) ;
// lint, with note if neither arg is > 1 line and both map() and
// unwrap_or() have the same span
let multiline = map_arg . lines ( ) . count ( ) > 1
| | unwrap_arg . lines ( ) . count ( ) > 1 ;
let same_span = inner_args [ 1 ] . span . expn_id = = args [ 1 ] . span . expn_id ;
if same_span & & ! multiline {
span_note_and_lint (
cx , OPTION_MAP_UNWRAP_OR , expr . span , msg , expr . span ,
& format! ( " replace this with map_or( {1} , {0} ) " ,
map_arg , unwrap_arg )
) ;
}
else if same_span & & multiline {
span_lint ( cx , OPTION_MAP_UNWRAP_OR , expr . span , msg ) ;
} ;
}
2015-12-03 11:43:50 +00:00
} ,
// check Option.map(_).unwrap_or_else(_)
" unwrap_or_else " = > if let ExprMethodCall ( ref inner_name , _ , ref inner_args ) = args [ 0 ] . node {
2015-11-23 05:48:19 +00:00
if inner_name . node . as_str ( ) = = " map "
& & match_type ( cx , cx . tcx . expr_ty ( & inner_args [ 0 ] ) , & OPTION_PATH ) {
// lint message
let msg =
" called `map(f).unwrap_or_else(g)` on an Option value. This can be \
done more directly by calling ` map_or_else ( g , f ) ` instead " ;
// get args to map() and unwrap_or_else()
let map_arg = snippet ( cx , inner_args [ 1 ] . span , " .. " ) ;
let unwrap_arg = snippet ( cx , args [ 1 ] . span , " .. " ) ;
// lint, with note if neither arg is > 1 line and both map() and
// unwrap_or_else() have the same span
let multiline = map_arg . lines ( ) . count ( ) > 1
| | unwrap_arg . lines ( ) . count ( ) > 1 ;
let same_span = inner_args [ 1 ] . span . expn_id = = args [ 1 ] . span . expn_id ;
if same_span & & ! multiline {
span_note_and_lint (
cx , OPTION_MAP_UNWRAP_OR_ELSE , expr . span , msg , expr . span ,
& format! ( " replace this with map_or_else( {1} , {0} ) " ,
map_arg , unwrap_arg )
) ;
}
else if same_span & & multiline {
span_lint ( cx , OPTION_MAP_UNWRAP_OR_ELSE , expr . span , msg ) ;
} ;
}
2015-12-03 11:43:50 +00:00
} ,
_ = > { } ,
2015-11-23 05:48:19 +00:00
}
2015-08-11 18:53:50 +00:00
}
}
2015-08-24 16:13:02 +00:00
2015-09-19 02:53:04 +00:00
fn check_item ( & mut self , cx : & LateContext , item : & Item ) {
2015-09-01 19:08:49 +00:00
if let ItemImpl ( _ , _ , _ , None , ref ty , ref items ) = item . node {
for implitem in items {
2015-09-24 00:30:39 +00:00
let name = implitem . name ;
2015-11-19 14:51:30 +00:00
if let ImplItemKind ::Method ( ref sig , _ ) = implitem . node {
2015-09-01 16:52:48 +00:00
// check missing trait implementations
for & ( method_name , n_args , self_kind , out_type , trait_name ) in & TRAIT_METHODS {
if_let_chain! {
[
2015-09-28 05:04:06 +00:00
name . as_str ( ) = = method_name ,
2015-09-01 16:52:48 +00:00
sig . decl . inputs . len ( ) = = n_args ,
out_type . matches ( & sig . decl . output ) ,
2015-09-01 19:08:49 +00:00
self_kind . matches ( & sig . explicit_self . node , false )
2015-09-01 16:52:48 +00:00
] , {
2015-09-01 19:08:49 +00:00
span_lint ( cx , SHOULD_IMPLEMENT_TRAIT , implitem . span , & format! (
2015-09-01 16:52:48 +00:00
" defining a method called `{}` on this type; consider implementing \
the ` { } ` trait or choosing a less ambiguous name " , name, trait_name));
}
}
}
// check conventions w.r.t. conversion method names and predicates
2015-09-02 15:14:23 +00:00
let is_copy = is_copy ( cx , & ty , & item ) ;
for & ( prefix , self_kinds ) in & CONVENTIONS {
2015-09-01 19:08:49 +00:00
if name . as_str ( ) . starts_with ( prefix ) & &
2015-09-02 15:14:23 +00:00
! self_kinds . iter ( ) . any ( | k | k . matches ( & sig . explicit_self . node , is_copy ) ) {
2015-09-07 09:49:35 +00:00
let lint = if item . vis = = Visibility ::Public {
2015-09-07 07:17:45 +00:00
WRONG_PUB_SELF_CONVENTION
} else {
WRONG_SELF_CONVENTION
} ;
span_lint ( cx , lint , sig . explicit_self . span , & format! (
2015-09-01 16:52:48 +00:00
" methods called `{}*` usually take {}; consider choosing a less \
2015-09-02 15:14:23 +00:00
ambiguous name " , prefix,
& self_kinds . iter ( ) . map ( | k | k . description ( ) ) . collect ::< Vec < _ > > ( ) . join ( " or " ) ) ) ;
2015-08-24 16:13:02 +00:00
}
}
}
}
}
}
}
2015-11-19 13:39:27 +00:00
// Given a `Result<T, E>` type, return its error type (`E`)
fn get_error_type < ' a > ( cx : & LateContext , ty : ty ::Ty < ' a > ) -> Option < ty ::Ty < ' a > > {
if ! match_type ( cx , ty , & RESULT_PATH ) {
return None ;
}
if let ty ::TyEnum ( _ , substs ) = ty . sty {
if let Some ( err_ty ) = substs . types . opt_get ( TypeSpace , 1 ) {
return Some ( err_ty ) ;
}
}
None
}
2015-11-19 19:13:36 +00:00
// This checks whether a given type is known to implement Debug. It's
// conservative, i.e. it should not return false positives, but will return
// false negatives.
fn has_debug_impl < ' a , ' b > ( ty : ty ::Ty < ' a > , cx : & LateContext < ' b , ' a > ) -> bool {
2015-11-19 19:19:19 +00:00
let no_ref_ty = walk_ptrs_ty ( ty ) ;
2015-11-19 19:13:36 +00:00
let debug = match cx . tcx . lang_items . debug_trait ( ) {
Some ( debug ) = > debug ,
None = > return false
} ;
let debug_def = cx . tcx . lookup_trait_def ( debug ) ;
let mut debug_impl_exists = false ;
2015-11-19 19:19:19 +00:00
debug_def . for_each_relevant_impl ( cx . tcx , no_ref_ty , | d | {
2015-11-19 19:13:36 +00:00
let self_ty = & cx . tcx . impl_trait_ref ( d ) . and_then ( | im | im . substs . self_ty ( ) ) ;
if let Some ( self_ty ) = * self_ty {
if ! self_ty . flags . get ( ) . contains ( ty ::TypeFlags ::HAS_PARAMS ) {
debug_impl_exists = true ;
}
}
} ) ;
debug_impl_exists
}
2015-11-19 13:39:27 +00:00
2015-09-02 15:14:23 +00:00
const CONVENTIONS : [ ( & 'static str , & 'static [ SelfKind ] ) ; 5 ] = [
( " into_ " , & [ ValueSelf ] ) ,
( " to_ " , & [ RefSelf ] ) ,
2015-09-04 05:56:52 +00:00
( " as_ " , & [ RefSelf , RefMutSelf ] ) ,
2015-09-02 15:14:23 +00:00
( " is_ " , & [ RefSelf , NoSelf ] ) ,
( " from_ " , & [ NoSelf ] ) ,
2015-09-01 16:52:48 +00:00
] ;
2015-08-24 16:13:02 +00:00
const TRAIT_METHODS : [ ( & 'static str , usize , SelfKind , OutType , & 'static str ) ; 30 ] = [
2015-09-19 06:49:01 +00:00
( " add " , 2 , ValueSelf , AnyType , " std::ops::Add " ) ,
2015-08-24 16:13:02 +00:00
( " sub " , 2 , ValueSelf , AnyType , " std::ops::Sub " ) ,
( " mul " , 2 , ValueSelf , AnyType , " std::ops::Mul " ) ,
( " div " , 2 , ValueSelf , AnyType , " std::ops::Div " ) ,
( " rem " , 2 , ValueSelf , AnyType , " std::ops::Rem " ) ,
( " shl " , 2 , ValueSelf , AnyType , " std::ops::Shl " ) ,
( " shr " , 2 , ValueSelf , AnyType , " std::ops::Shr " ) ,
( " bitand " , 2 , ValueSelf , AnyType , " std::ops::BitAnd " ) ,
( " bitor " , 2 , ValueSelf , AnyType , " std::ops::BitOr " ) ,
( " bitxor " , 2 , ValueSelf , AnyType , " std::ops::BitXor " ) ,
( " neg " , 1 , ValueSelf , AnyType , " std::ops::Neg " ) ,
( " not " , 1 , ValueSelf , AnyType , " std::ops::Not " ) ,
( " drop " , 1 , RefMutSelf , UnitType , " std::ops::Drop " ) ,
( " index " , 2 , RefSelf , RefType , " std::ops::Index " ) ,
( " index_mut " , 2 , RefMutSelf , RefType , " std::ops::IndexMut " ) ,
( " deref " , 1 , RefSelf , RefType , " std::ops::Deref " ) ,
( " deref_mut " , 1 , RefMutSelf , RefType , " std::ops::DerefMut " ) ,
( " clone " , 1 , RefSelf , AnyType , " std::clone::Clone " ) ,
( " borrow " , 1 , RefSelf , RefType , " std::borrow::Borrow " ) ,
( " borrow_mut " , 1 , RefMutSelf , RefType , " std::borrow::BorrowMut " ) ,
( " as_ref " , 1 , RefSelf , RefType , " std::convert::AsRef " ) ,
( " as_mut " , 1 , RefMutSelf , RefType , " std::convert::AsMut " ) ,
( " eq " , 2 , RefSelf , BoolType , " std::cmp::PartialEq " ) ,
( " cmp " , 2 , RefSelf , AnyType , " std::cmp::Ord " ) ,
( " default " , 0 , NoSelf , AnyType , " std::default::Default " ) ,
( " hash " , 2 , RefSelf , UnitType , " std::hash::Hash " ) ,
( " next " , 1 , RefMutSelf , AnyType , " std::iter::Iterator " ) ,
( " into_iter " , 1 , ValueSelf , AnyType , " std::iter::IntoIterator " ) ,
( " from_iter " , 1 , NoSelf , AnyType , " std::iter::FromIterator " ) ,
( " from_str " , 1 , NoSelf , AnyType , " std::str::FromStr " ) ,
] ;
#[ derive(Clone, Copy) ]
enum SelfKind {
ValueSelf ,
RefSelf ,
RefMutSelf ,
2015-09-01 16:52:48 +00:00
NoSelf ,
2015-08-24 16:13:02 +00:00
}
impl SelfKind {
2015-09-01 19:08:49 +00:00
fn matches ( & self , slf : & ExplicitSelf_ , allow_value_for_ref : bool ) -> bool {
2015-08-24 16:13:02 +00:00
match ( self , slf ) {
( & ValueSelf , & SelfValue ( _ ) ) = > true ,
( & RefSelf , & SelfRegion ( _ , Mutability ::MutImmutable , _ ) ) = > true ,
( & RefMutSelf , & SelfRegion ( _ , Mutability ::MutMutable , _ ) ) = > true ,
2015-09-01 19:08:49 +00:00
( & RefSelf , & SelfValue ( _ ) ) = > allow_value_for_ref ,
( & RefMutSelf , & SelfValue ( _ ) ) = > allow_value_for_ref ,
2015-08-24 16:13:02 +00:00
( & NoSelf , & SelfStatic ) = > true ,
2015-09-01 19:08:49 +00:00
( _ , & SelfExplicit ( ref ty , _ ) ) = > self . matches_explicit_type ( ty , allow_value_for_ref ) ,
2015-08-24 16:13:02 +00:00
_ = > false
}
}
2015-09-01 16:52:48 +00:00
2015-09-01 19:08:49 +00:00
fn matches_explicit_type ( & self , ty : & Ty , allow_value_for_ref : bool ) -> bool {
2015-09-01 16:52:48 +00:00
match ( self , & ty . node ) {
( & ValueSelf , & TyPath ( .. ) ) = > true ,
( & RefSelf , & TyRptr ( _ , MutTy { mutbl : Mutability ::MutImmutable , .. } ) ) = > true ,
( & RefMutSelf , & TyRptr ( _ , MutTy { mutbl : Mutability ::MutMutable , .. } ) ) = > true ,
2015-09-01 19:08:49 +00:00
( & RefSelf , & TyPath ( .. ) ) = > allow_value_for_ref ,
( & RefMutSelf , & TyPath ( .. ) ) = > allow_value_for_ref ,
2015-09-01 16:52:48 +00:00
_ = > false
}
}
fn description ( & self ) -> & 'static str {
match * self {
ValueSelf = > " self by value " ,
RefSelf = > " self by reference " ,
RefMutSelf = > " self by mutable reference " ,
NoSelf = > " no self " ,
}
}
2015-08-24 16:13:02 +00:00
}
#[ derive(Clone, Copy) ]
enum OutType {
UnitType ,
BoolType ,
AnyType ,
RefType ,
}
impl OutType {
fn matches ( & self , ty : & FunctionRetTy ) -> bool {
match ( self , ty ) {
( & UnitType , & DefaultReturn ( _ ) ) = > true ,
( & UnitType , & Return ( ref ty ) ) if ty . node = = TyTup ( vec! [ ] ) = > true ,
( & BoolType , & Return ( ref ty ) ) if is_bool ( ty ) = > true ,
( & AnyType , & Return ( ref ty ) ) if ty . node ! = TyTup ( vec! [ ] ) = > true ,
( & RefType , & Return ( ref ty ) ) = > {
if let TyRptr ( _ , _ ) = ty . node { true } else { false }
}
_ = > false
}
}
}
fn is_bool ( ty : & Ty ) -> bool {
if let TyPath ( None , ref p ) = ty . node {
if match_path ( p , & [ " bool " ] ) {
return true ;
}
}
false
2015-08-11 18:53:50 +00:00
}
2015-09-01 19:08:49 +00:00
2015-09-19 02:53:04 +00:00
fn is_copy ( cx : & LateContext , ast_ty : & Ty , item : & Item ) -> bool {
2015-09-01 19:08:49 +00:00
match cx . tcx . ast_ty_to_ty_cache . borrow ( ) . get ( & ast_ty . id ) {
None = > false ,
Some ( ty ) = > {
let env = ty ::ParameterEnvironment ::for_item ( cx . tcx , item . id ) ;
2015-09-02 20:44:05 +00:00
! ty . subst ( cx . tcx , & env . free_substs ) . moves_by_default ( & env , ast_ty . span )
2015-09-01 19:08:49 +00:00
}
}
}