2015-09-03 09:42:17 -05:00
use rustc_front ::hir ::* ;
2015-08-16 01:54:43 -05:00
use rustc ::lint ::* ;
2015-08-11 13:53:50 -05:00
use rustc ::middle ::ty ;
2015-11-19 07:39:27 -06:00
use rustc ::middle ::subst ::{ Subst , TypeSpace } ;
2015-08-25 11:38:08 -05:00
use std ::iter ;
use std ::borrow ::Cow ;
2016-01-16 11:47:45 -06:00
use syntax ::ptr ::P ;
2016-01-18 06:11:07 -06:00
use syntax ::codemap ::Span ;
2015-08-11 13:53:50 -05:00
2016-01-19 17:53:26 -06:00
use utils ::{
2016-01-20 11:32:17 -06:00
get_trait_def_id , implements_trait , in_external_macro , in_macro , match_path ,
match_trait_method , match_type , method_chain_args , snippet , span_lint , span_lint_and_then ,
span_note_and_lint , walk_ptrs_ty , walk_ptrs_ty_depth ,
2016-01-19 19:23:39 -06:00
} ;
use utils ::{
BTREEMAP_ENTRY_PATH , DEFAULT_TRAIT_PATH , HASHMAP_ENTRY_PATH , OPTION_PATH , RESULT_PATH ,
2016-01-25 07:02:47 -06:00
STRING_PATH , VEC_PATH ,
2016-01-19 17:53:26 -06:00
} ;
2015-12-27 16:15:09 -06:00
use utils ::MethodArgs ;
2016-01-18 06:11:07 -06:00
use rustc ::middle ::cstore ::CrateStore ;
2015-08-11 13:53:50 -05:00
2015-11-19 07:39:27 -06:00
#[ derive(Clone) ]
2015-11-19 13:13:36 -06:00
pub struct MethodsPass ;
2015-08-11 13:53:50 -05:00
2015-12-10 18:22:27 -06: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 00:17:10 -05:00
declare_lint! ( pub OPTION_UNWRAP_USED , Allow ,
2015-08-13 03:32:35 -05:00
" using `Option.unwrap()`, which should at least get a better message using `expect()` " ) ;
2015-12-14 15:16:56 -06:00
2015-12-10 18:22:27 -06: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 13:53:50 -05:00
declare_lint! ( pub RESULT_UNWRAP_USED , Allow ,
2015-08-13 03:32:35 -05:00
" using `Result.unwrap()`, which might be better handled " ) ;
2015-12-14 15:16:56 -06:00
2015-12-10 18:22:27 -06: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 06:58:55 -05:00
declare_lint! ( pub STR_TO_STRING , Warn ,
2015-08-13 03:32:35 -05:00
" using `to_string()` on a str, which should be `to_owned()` " ) ;
2015-12-14 15:16:56 -06:00
2015-12-10 18:22:27 -06: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 10:02:49 -05:00
declare_lint! ( pub STRING_TO_STRING , Warn ,
2015-08-13 03:32:35 -05:00
" calling `String.to_string()` which is a no-op " ) ;
2015-12-14 15:16:56 -06:00
2015-12-10 18:22:27 -06: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 11:13:02 -05:00
declare_lint! ( pub SHOULD_IMPLEMENT_TRAIT , Warn ,
" defining a method that should be implementing a std trait " ) ;
2015-12-14 15:16:56 -06:00
2015-12-10 18:22:27 -06: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 11:52:48 -05: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-14 15:16:56 -06:00
2015-12-10 18:22:27 -06: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 02:17:45 -05: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-12-14 15:16:56 -06:00
/// **What it does:** This lint `Warn`s on using `ok().expect(..)`.
///
/// **Why is this bad?** Because you usually call `expect()` on the `Result` directly to get a good error message.
///
/// **Known problems:** None.
///
/// **Example:** `x.ok().expect("why did I do this again?")`
2015-11-19 07:39:27 -06:00
declare_lint! ( pub OK_EXPECT , Warn ,
" using `ok().expect()`, which gives worse error messages than \
calling ` expect ` directly on the Result " );
2015-12-14 15:16:56 -06:00
/// **What it does:** This lint `Warn`s on `_.map(_).unwrap_or(_)`.
///
/// **Why is this bad?** Readability, this can be written more concisely as `_.map_or(_, _)`.
///
/// **Known problems:** None.
///
/// **Example:** `x.map(|a| a + 1).unwrap_or(0)`
2015-11-22 23:48:19 -06:00
declare_lint! ( pub OPTION_MAP_UNWRAP_OR , Warn ,
" using `Option.map(f).unwrap_or(a)`, which is more succinctly expressed as \
2015-12-28 18:56:58 -06:00
` map_or ( a , f ) ` " );
2015-12-14 15:16:56 -06:00
/// **What it does:** This lint `Warn`s on `_.map(_).unwrap_or_else(_)`.
///
/// **Why is this bad?** Readability, this can be written more concisely as `_.map_or_else(_, _)`.
///
/// **Known problems:** None.
///
/// **Example:** `x.map(|a| a + 1).unwrap_or_else(some_function)`
2015-11-22 23:48:19 -06:00
declare_lint! ( pub OPTION_MAP_UNWRAP_OR_ELSE , Warn ,
" using `Option.map(f).unwrap_or_else(g)`, which is more succinctly expressed as \
2015-12-28 18:56:58 -06:00
` map_or_else ( g , f ) ` " );
/// **What it does:** This lint `Warn`s on `_.filter(_).next()`.
///
/// **Why is this bad?** Readability, this can be written more concisely as `_.find(_)`.
///
/// **Known problems:** None.
///
/// **Example:** `iter.filter(|x| x == 0).next()`
declare_lint! ( pub FILTER_NEXT , Warn ,
" using `filter(p).next()`, which is more succinctly expressed as `.find(p)` " ) ;
2015-08-11 13:53:50 -05:00
2015-12-30 02:38:03 -06:00
/// **What it does:** This lint `Warn`s on an iterator search (such as `find()`, `position()`, or
/// `rposition()`) followed by a call to `is_some()`.
///
/// **Why is this bad?** Readability, this can be written more concisely as `_.any(_)`.
///
/// **Known problems:** None.
///
/// **Example:** `iter.find(|x| x == 0).is_some()`
declare_lint! ( pub SEARCH_IS_SOME , Warn ,
" using an iterator search followed by `is_some()`, which is more succinctly \
expressed as a call to ` any ( ) ` " );
2016-01-19 19:23:39 -06:00
/// **What it does:** This lint `Warn`s on using `.chars().next()` on a `str` to check if it
/// starts with a given char.
///
/// **Why is this bad?** Readability, this can be written more concisely as `_.starts_with(_)`.
///
/// **Known problems:** None.
///
/// **Example:** `name.chars().next() == Some('_')`
declare_lint! ( pub CHARS_NEXT_CMP , Warn ,
" using `.chars().next()` to check if a string starts with a char " ) ;
2016-01-16 11:47:45 -06:00
/// **What it does:** This lint checks for calls to `.or(foo(..))`, `.unwrap_or(foo(..))`, etc., and
2016-01-18 06:11:07 -06:00
/// suggests to use `or_else`, `unwrap_or_else`, etc., or `unwrap_or_default` instead.
2016-01-16 11:47:45 -06:00
///
/// **Why is this bad?** The function will always be called and potentially allocate an object
/// in expressions such as:
/// ```rust
/// foo.unwrap_or(String::new())
/// ```
/// this can instead be written:
/// ```rust
/// foo.unwrap_or_else(String::new)
/// ```
2016-01-18 06:11:07 -06:00
/// or
/// ```rust
/// foo.unwrap_or_default()
/// ```
2016-01-16 11:47:45 -06:00
///
/// **Known problems:** If the function as side-effects, not calling it will change the semantic of
2016-01-18 06:11:07 -06:00
/// the program, but you shouldn't rely on that anyway.
2016-01-16 11:47:45 -06:00
declare_lint! ( pub OR_FUN_CALL , Warn ,
" using any `*or` method when the `*or_else` would do " ) ;
2016-01-25 07:02:47 -06:00
/// **What it does:** This lint `Warn`s on using `.extend(s)` on a `vec` to extend the vec by a slice.
///
/// **Why is this bad?** Since Rust 1.6, the `extend_from_slice(_)` method is stable and at least for now faster.
///
/// **Known problems:** None.
///
/// **Example:** `my_vec.extend(&xs)`
declare_lint! ( pub EXTEND_FROM_SLICE , Warn ,
" `.extend_from_slice(_)` is a faster way to extend a Vec by a slice " ) ;
2015-08-11 13:53:50 -05:00
impl LintPass for MethodsPass {
fn get_lints ( & self ) -> LintArray {
2016-01-25 07:02:47 -06:00
lint_array! ( EXTEND_FROM_SLICE ,
OPTION_UNWRAP_USED ,
2016-01-03 22:26:12 -06:00
RESULT_UNWRAP_USED ,
STR_TO_STRING ,
STRING_TO_STRING ,
SHOULD_IMPLEMENT_TRAIT ,
WRONG_SELF_CONVENTION ,
WRONG_PUB_SELF_CONVENTION ,
OK_EXPECT ,
OPTION_MAP_UNWRAP_OR ,
2016-01-16 11:47:45 -06:00
OPTION_MAP_UNWRAP_OR_ELSE ,
2016-01-19 19:23:39 -06:00
OR_FUN_CALL ,
CHARS_NEXT_CMP )
2015-08-11 13:53:50 -05:00
}
2015-09-18 21:53:04 -05:00
}
2015-08-11 13:53:50 -05:00
2015-09-18 21:53:04 -05:00
impl LateLintPass for MethodsPass {
fn check_expr ( & mut self , cx : & LateContext , expr : & Expr ) {
2016-01-20 11:32:17 -06:00
if in_macro ( cx , expr . span ) {
return ;
}
2016-01-19 19:23:39 -06:00
match expr . node {
ExprMethodCall ( name , _ , ref args ) = > {
// Chain calls
if let Some ( arglists ) = method_chain_args ( expr , & [ " unwrap " ] ) {
lint_unwrap ( cx , expr , arglists [ 0 ] ) ;
} else if let Some ( arglists ) = method_chain_args ( expr , & [ " to_string " ] ) {
lint_to_string ( cx , expr , arglists [ 0 ] ) ;
} else if let Some ( arglists ) = method_chain_args ( expr , & [ " ok " , " expect " ] ) {
lint_ok_expect ( cx , expr , arglists [ 0 ] ) ;
} else if let Some ( arglists ) = method_chain_args ( expr , & [ " map " , " unwrap_or " ] ) {
lint_map_unwrap_or ( cx , expr , arglists [ 0 ] , arglists [ 1 ] ) ;
} else if let Some ( arglists ) = method_chain_args ( expr , & [ " map " , " unwrap_or_else " ] ) {
lint_map_unwrap_or_else ( cx , expr , arglists [ 0 ] , arglists [ 1 ] ) ;
} else if let Some ( arglists ) = method_chain_args ( expr , & [ " filter " , " next " ] ) {
lint_filter_next ( cx , expr , arglists [ 0 ] ) ;
} else if let Some ( arglists ) = method_chain_args ( expr , & [ " find " , " is_some " ] ) {
lint_search_is_some ( cx , expr , " find " , arglists [ 0 ] , arglists [ 1 ] ) ;
} else if let Some ( arglists ) = method_chain_args ( expr , & [ " position " , " is_some " ] ) {
lint_search_is_some ( cx , expr , " position " , arglists [ 0 ] , arglists [ 1 ] ) ;
} else if let Some ( arglists ) = method_chain_args ( expr , & [ " rposition " , " is_some " ] ) {
lint_search_is_some ( cx , expr , " rposition " , arglists [ 0 ] , arglists [ 1 ] ) ;
2016-01-25 07:02:47 -06:00
} else if let Some ( arglists ) = method_chain_args ( expr , & [ " extend " ] ) {
lint_extend ( cx , expr , arglists [ 0 ] ) ;
2016-01-19 19:23:39 -06:00
}
2016-01-16 11:47:45 -06:00
2016-01-19 19:23:39 -06:00
lint_or_fun_call ( cx , expr , & name . node . as_str ( ) , & args ) ;
}
ExprBinary ( op , ref lhs , ref rhs ) if op . node = = BiEq | | op . node = = BiNe = > {
if ! lint_chars_next ( cx , expr , lhs , rhs , op . node = = BiEq ) {
lint_chars_next ( cx , expr , rhs , lhs , op . node = = BiEq ) ;
}
}
_ = > ( ) ,
2015-08-11 13:53:50 -05:00
}
}
2015-08-24 11:13:02 -05:00
2015-09-18 21:53:04 -05:00
fn check_item ( & mut self , cx : & LateContext , item : & Item ) {
2016-01-20 11:32:17 -06:00
if in_external_macro ( cx , item . span ) {
return ;
}
2015-09-01 14:08:49 -05:00
if let ItemImpl ( _ , _ , _ , None , ref ty , ref items ) = item . node {
for implitem in items {
2015-09-23 19:30:39 -05:00
let name = implitem . name ;
2015-11-19 08:51:30 -06:00
if let ImplItemKind ::Method ( ref sig , _ ) = implitem . node {
2015-09-01 11:52:48 -05: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 00:04:06 -05:00
name . as_str ( ) = = method_name ,
2015-09-01 11:52:48 -05:00
sig . decl . inputs . len ( ) = = n_args ,
out_type . matches ( & sig . decl . output ) ,
2015-09-01 14:08:49 -05:00
self_kind . matches ( & sig . explicit_self . node , false )
2015-09-01 11:52:48 -05:00
] , {
2015-09-01 14:08:49 -05:00
span_lint ( cx , SHOULD_IMPLEMENT_TRAIT , implitem . span , & format! (
2015-09-01 11:52:48 -05: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 10:14:23 -05:00
let is_copy = is_copy ( cx , & ty , & item ) ;
for & ( prefix , self_kinds ) in & CONVENTIONS {
2015-09-01 14:08:49 -05:00
if name . as_str ( ) . starts_with ( prefix ) & &
2016-01-03 22:26:12 -06:00
! self_kinds . iter ( ) . any ( | k | k . matches ( & sig . explicit_self . node , is_copy ) ) {
2015-09-07 04:49:35 -05:00
let lint = if item . vis = = Visibility ::Public {
2015-09-07 02:17:45 -05:00
WRONG_PUB_SELF_CONVENTION
} else {
WRONG_SELF_CONVENTION
} ;
2016-01-03 22:26:12 -06:00
span_lint ( cx ,
lint ,
sig . explicit_self . span ,
& format! ( " methods called ` {} *` usually take {} ; consider choosing a less \
ambiguous name " ,
prefix ,
& self_kinds . iter ( )
. map ( | k | k . description ( ) )
. collect ::< Vec < _ > > ( )
. join ( " or " ) ) ) ;
2015-08-24 11:13:02 -05:00
}
}
}
}
}
}
}
2016-01-16 11:47:45 -06:00
/// Checks for the `OR_FUN_CALL` lint.
fn lint_or_fun_call ( cx : & LateContext , expr : & Expr , name : & str , args : & [ P < Expr > ] ) {
2016-01-18 06:11:07 -06:00
/// Check for `unwrap_or(T::new())` or `unwrap_or(T::default())`.
fn check_unwrap_or_default (
cx : & LateContext ,
name : & str ,
fun : & Expr ,
self_expr : & Expr ,
arg : & Expr ,
or_has_args : bool ,
span : Span
) -> bool {
if or_has_args {
return false ;
}
if name = = " unwrap_or " {
if let ExprPath ( _ , ref path ) = fun . node {
let path : & str = & path . segments . last ( )
. expect ( " A path must have at least one segment " )
. identifier . name . as_str ( ) ;
if [ " default " , " new " ] . contains ( & path ) {
let arg_ty = cx . tcx . expr_ty ( arg ) ;
let default_trait_id = if let Some ( default_trait_id ) = get_trait_def_id ( cx , & DEFAULT_TRAIT_PATH ) {
default_trait_id
}
else {
return false ;
} ;
2016-01-18 08:35:50 -06:00
if implements_trait ( cx , arg_ty , default_trait_id , None ) {
2016-01-18 06:11:07 -06:00
span_lint ( cx , OR_FUN_CALL , span ,
& format! ( " use of ` {} ` followed by a call to ` {} ` " , name , path ) )
. span_suggestion ( span , " try this " ,
format! ( " {} .unwrap_or_default() " ,
snippet ( cx , self_expr . span , " _ " ) ) ) ;
return true ;
}
}
}
}
false
}
/// Check for `*or(foo())`.
fn check_general_case (
cx : & LateContext ,
name : & str ,
fun : & Expr ,
self_expr : & Expr ,
arg : & Expr ,
or_has_args : bool ,
span : Span
) {
2016-01-19 17:53:26 -06:00
// (path, fn_has_argument, methods)
let know_types : & [ ( & [ _ ] , _ , & [ _ ] , _ ) ] = & [
( & BTREEMAP_ENTRY_PATH , false , & [ " or_insert " ] , " with " ) ,
( & HASHMAP_ENTRY_PATH , false , & [ " or_insert " ] , " with " ) ,
( & OPTION_PATH , false , & [ " map_or " , " ok_or " , " or " , " unwrap_or " ] , " else " ) ,
( & RESULT_PATH , true , & [ " or " , " unwrap_or " ] , " else " ) ,
] ;
2016-01-18 06:11:07 -06:00
let self_ty = cx . tcx . expr_ty ( self_expr ) ;
2016-01-16 11:47:45 -06:00
2016-01-19 17:53:26 -06:00
let ( fn_has_arguments , poss , suffix ) =
if let Some ( & ( _ , fn_has_arguments , poss , suffix ) ) = know_types . iter ( ) . find ( | & & i | {
match_type ( cx , self_ty , i . 0 )
} ) {
( fn_has_arguments , poss , suffix )
}
else {
return
} ;
if ! poss . contains ( & name ) {
return
2016-01-16 11:47:45 -06:00
}
2016-01-19 17:53:26 -06:00
let sugg = match ( fn_has_arguments , ! or_has_args ) {
2016-01-18 06:11:07 -06:00
( true , _ ) = > format! ( " |_| {} " , snippet ( cx , arg . span , " .. " ) ) ,
( false , false ) = > format! ( " || {} " , snippet ( cx , arg . span , " .. " ) ) ,
( false , true ) = > format! ( " {} " , snippet ( cx , fun . span , " .. " ) ) ,
} ;
span_lint ( cx , OR_FUN_CALL , span ,
& format! ( " use of ` {} ` followed by a function call " , name ) )
. span_suggestion ( span , " try this " ,
2016-01-19 17:53:26 -06:00
format! ( " {} . {} _ {} ( {} ) " ,
2016-01-18 06:11:07 -06:00
snippet ( cx , self_expr . span , " _ " ) ,
name ,
2016-01-19 17:53:26 -06:00
suffix ,
2016-01-18 06:11:07 -06:00
sugg ) ) ;
}
2016-01-19 17:53:26 -06:00
if args . len ( ) = = 2 {
2016-01-16 11:47:45 -06:00
if let ExprCall ( ref fun , ref or_args ) = args [ 1 ] . node {
2016-01-18 06:11:07 -06:00
let or_has_args = ! or_args . is_empty ( ) ;
if ! check_unwrap_or_default ( cx , name , fun , & args [ 0 ] , & args [ 1 ] , or_has_args , expr . span ) {
check_general_case ( cx , name , fun , & args [ 0 ] , & args [ 1 ] , or_has_args , expr . span ) ;
}
2016-01-16 11:47:45 -06:00
}
}
}
2016-01-25 07:02:47 -06:00
fn lint_extend ( cx : & LateContext , expr : & Expr , args : & MethodArgs ) {
let ( obj_ty , _ ) = walk_ptrs_ty_depth ( cx . tcx . expr_ty ( & args [ 0 ] ) ) ;
if ! match_type ( cx , obj_ty , & VEC_PATH ) {
2016-01-26 16:51:06 -06:00
return ;
2016-01-25 07:02:47 -06:00
}
2016-01-26 16:51:06 -06:00
let arg_ty = cx . tcx . expr_ty ( & args [ 1 ] ) ;
2016-01-27 07:51:30 -06:00
if let Some ( ( span , r ) ) = derefs_to_slice ( cx , & args [ 1 ] , & arg_ty ) {
2016-01-25 07:02:47 -06:00
span_lint ( cx , EXTEND_FROM_SLICE , expr . span ,
& format! ( " use of `extend` to extend a Vec by a slice " ) )
. span_suggestion ( expr . span , " try this " ,
2016-01-27 07:51:30 -06:00
format! ( " {} .extend_from_slice( {} {} ) " ,
2016-01-25 07:02:47 -06:00
snippet ( cx , args [ 0 ] . span , " _ " ) ,
2016-01-27 07:51:30 -06:00
r , snippet ( cx , span , " _ " ) ) ) ;
2016-01-25 07:02:47 -06:00
}
}
2016-02-01 05:51:33 -06:00
fn derefs_to_slice ( cx : & LateContext , expr : & Expr , ty : & ty ::Ty )
2016-01-27 07:51:30 -06:00
-> Option < ( Span , & 'static str ) > {
fn may_slice ( cx : & LateContext , ty : & ty ::Ty ) -> bool {
2016-01-26 16:51:06 -06:00
match ty . sty {
2016-02-01 05:51:33 -06:00
ty ::TySlice ( _ ) = > true ,
2016-01-26 16:51:06 -06:00
ty ::TyStruct ( .. ) = > match_type ( cx , ty , & VEC_PATH ) ,
ty ::TyArray ( _ , size ) = > size < 32 ,
ty ::TyRef ( _ , ty ::TypeAndMut { ty : ref inner , .. } ) |
2016-01-27 07:51:30 -06:00
ty ::TyBox ( ref inner ) = > may_slice ( cx , inner ) ,
2016-01-26 16:51:06 -06:00
_ = > false
}
}
2016-01-25 12:46:56 -06:00
if let ExprMethodCall ( name , _ , ref args ) = expr . node {
2016-02-01 05:51:33 -06:00
if & name . node . as_str ( ) = = & " iter " & &
2016-01-27 07:51:30 -06:00
may_slice ( cx , & cx . tcx . expr_ty ( & args [ 0 ] ) ) {
Some ( ( args [ 0 ] . span , " & " ) )
} else {
None
}
} else {
match ty . sty {
ty ::TySlice ( _ ) = > Some ( ( expr . span , " " ) ) ,
ty ::TyRef ( _ , ty ::TypeAndMut { ty : ref inner , .. } ) |
2016-02-01 05:51:33 -06:00
ty ::TyBox ( ref inner ) = > if may_slice ( cx , inner ) {
2016-01-27 07:51:30 -06:00
Some ( ( expr . span , " " ) )
} else { None } ,
_ = > None
}
2016-01-25 07:02:47 -06:00
}
}
2016-01-03 22:26:12 -06:00
#[ allow(ptr_arg) ]
// Type of MethodArgs is potentially a Vec
2015-12-27 03:22:53 -06:00
/// lint use of `unwrap()` for `Option`s and `Result`s
2015-12-27 16:15:09 -06:00
fn lint_unwrap ( cx : & LateContext , expr : & Expr , unwrap_args : & MethodArgs ) {
let ( obj_ty , _ ) = walk_ptrs_ty_depth ( cx . tcx . expr_ty ( & unwrap_args [ 0 ] ) ) ;
2015-12-27 03:22:53 -06:00
2016-01-03 07:36:24 -06:00
let mess = if match_type ( cx , obj_ty , & OPTION_PATH ) {
Some ( ( OPTION_UNWRAP_USED , " an Option " , " None " ) )
2016-01-03 22:26:12 -06:00
} else if match_type ( cx , obj_ty , & RESULT_PATH ) {
2016-01-03 07:36:24 -06:00
Some ( ( RESULT_UNWRAP_USED , " a Result " , " Err " ) )
2016-01-03 22:26:12 -06:00
} else {
2016-01-03 07:36:24 -06:00
None
} ;
if let Some ( ( lint , kind , none_value ) ) = mess {
2016-01-03 22:26:12 -06:00
span_lint ( cx ,
lint ,
expr . span ,
& format! ( " used unwrap() on {} value. If you don't want to handle the {} case gracefully, consider \
using expect ( ) to provide a better panic
message " ,
kind ,
none_value ) ) ;
2015-12-27 03:22:53 -06:00
}
}
2016-01-03 22:26:12 -06:00
#[ allow(ptr_arg) ]
// Type of MethodArgs is potentially a Vec
2015-12-27 03:22:53 -06:00
/// lint use of `to_string()` for `&str`s and `String`s
2015-12-27 16:15:09 -06:00
fn lint_to_string ( cx : & LateContext , expr : & Expr , to_string_args : & MethodArgs ) {
let ( obj_ty , ptr_depth ) = walk_ptrs_ty_depth ( cx . tcx . expr_ty ( & to_string_args [ 0 ] ) ) ;
2015-12-27 03:22:53 -06:00
if obj_ty . sty = = ty ::TyStr {
2015-12-27 16:15:09 -06:00
let mut arg_str = snippet ( cx , to_string_args [ 0 ] . span , " _ " ) ;
2015-12-27 03:22:53 -06:00
if ptr_depth > 1 {
2016-01-03 22:26:12 -06:00
arg_str = Cow ::Owned ( format! ( " ( {} {} ) " , iter ::repeat ( '*' ) . take ( ptr_depth - 1 ) . collect ::< String > ( ) , arg_str ) ) ;
2015-12-27 03:22:53 -06:00
}
2016-01-03 22:26:12 -06:00
span_lint ( cx , STR_TO_STRING , expr . span , & format! ( " ` {} .to_owned()` is faster " , arg_str ) ) ;
} else if match_type ( cx , obj_ty , & STRING_PATH ) {
span_lint ( cx ,
STRING_TO_STRING ,
expr . span ,
2015-12-27 03:22:53 -06:00
" `String.to_string()` is a no-op; use `clone()` to make a copy " ) ;
}
}
2016-01-03 22:26:12 -06:00
#[ allow(ptr_arg) ]
// Type of MethodArgs is potentially a Vec
2015-12-27 03:22:53 -06:00
/// lint use of `ok().expect()` for `Result`s
2015-12-27 16:15:09 -06:00
fn lint_ok_expect ( cx : & LateContext , expr : & Expr , ok_args : & MethodArgs ) {
2015-12-27 03:22:53 -06:00
// lint if the caller of `ok()` is a `Result`
if match_type ( cx , cx . tcx . expr_ty ( & ok_args [ 0 ] ) , & RESULT_PATH ) {
let result_type = cx . tcx . expr_ty ( & ok_args [ 0 ] ) ;
if let Some ( error_type ) = get_error_type ( cx , result_type ) {
if has_debug_impl ( error_type , cx ) {
2016-01-03 22:26:12 -06:00
span_lint ( cx ,
OK_EXPECT ,
expr . span ,
" called `ok().expect()` on a Result value. You can call `expect` directly on the `Result` " ) ;
2015-12-27 03:22:53 -06:00
}
}
}
}
2016-01-03 22:26:12 -06:00
#[ allow(ptr_arg) ]
// Type of MethodArgs is potentially a Vec
2015-12-27 03:22:53 -06:00
/// lint use of `map().unwrap_or()` for `Option`s
2016-01-03 22:26:12 -06:00
fn lint_map_unwrap_or ( cx : & LateContext , expr : & Expr , map_args : & MethodArgs , unwrap_args : & MethodArgs ) {
2015-12-27 03:22:53 -06:00
// lint if the caller of `map()` is an `Option`
if match_type ( cx , cx . tcx . expr_ty ( & map_args [ 0 ] ) , & OPTION_PATH ) {
// lint message
2016-01-03 22:26:12 -06:00
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 " ;
2015-12-27 03:22:53 -06:00
// get snippets for args to map() and unwrap_or()
let map_snippet = snippet ( cx , map_args [ 1 ] . span , " .. " ) ;
let unwrap_snippet = snippet ( cx , unwrap_args [ 1 ] . span , " .. " ) ;
// lint, with note if neither arg is > 1 line and both map() and
// unwrap_or() have the same span
2016-01-03 22:26:12 -06:00
let multiline = map_snippet . lines ( ) . count ( ) > 1 | | unwrap_snippet . lines ( ) . count ( ) > 1 ;
2015-12-27 03:22:53 -06:00
let same_span = map_args [ 1 ] . span . expn_id = = unwrap_args [ 1 ] . span . expn_id ;
if same_span & & ! multiline {
2016-01-03 22:26:12 -06:00
span_note_and_lint ( cx ,
OPTION_MAP_UNWRAP_OR ,
expr . span ,
msg ,
expr . span ,
& format! ( " replace `map( {0} ).unwrap_or( {1} )` with `map_or( {1} , {0} )` " ,
map_snippet ,
unwrap_snippet ) ) ;
} else if same_span & & multiline {
2015-12-27 03:22:53 -06:00
span_lint ( cx , OPTION_MAP_UNWRAP_OR , expr . span , msg ) ;
} ;
}
}
2016-01-03 22:26:12 -06:00
#[ allow(ptr_arg) ]
// Type of MethodArgs is potentially a Vec
2015-12-27 03:22:53 -06:00
/// lint use of `map().unwrap_or_else()` for `Option`s
2016-01-03 22:26:12 -06:00
fn lint_map_unwrap_or_else ( cx : & LateContext , expr : & Expr , map_args : & MethodArgs , unwrap_args : & MethodArgs ) {
2015-12-27 16:15:09 -06:00
// lint if the caller of `map()` is an `Option`
2015-12-27 03:22:53 -06:00
if match_type ( cx , cx . tcx . expr_ty ( & map_args [ 0 ] ) , & OPTION_PATH ) {
// lint message
2016-01-03 22:26:12 -06:00
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 " ;
2015-12-27 03:22:53 -06:00
// get snippets for args to map() and unwrap_or_else()
let map_snippet = snippet ( cx , map_args [ 1 ] . span , " .. " ) ;
let unwrap_snippet = snippet ( cx , unwrap_args [ 1 ] . span , " .. " ) ;
// lint, with note if neither arg is > 1 line and both map() and
// unwrap_or_else() have the same span
2016-01-03 22:26:12 -06:00
let multiline = map_snippet . lines ( ) . count ( ) > 1 | | unwrap_snippet . lines ( ) . count ( ) > 1 ;
2015-12-27 03:22:53 -06:00
let same_span = map_args [ 1 ] . span . expn_id = = unwrap_args [ 1 ] . span . expn_id ;
if same_span & & ! multiline {
2016-01-03 22:26:12 -06:00
span_note_and_lint ( cx ,
OPTION_MAP_UNWRAP_OR_ELSE ,
expr . span ,
msg ,
expr . span ,
& format! ( " replace `map( {0} ).unwrap_or_else( {1} )` with `with map_or_else( {1} , {0} )` " ,
map_snippet ,
unwrap_snippet ) ) ;
} else if same_span & & multiline {
2015-12-27 03:22:53 -06:00
span_lint ( cx , OPTION_MAP_UNWRAP_OR_ELSE , expr . span , msg ) ;
} ;
}
}
2016-01-03 22:26:12 -06:00
#[ allow(ptr_arg) ]
// Type of MethodArgs is potentially a Vec
2015-12-28 18:56:58 -06:00
/// lint use of `filter().next() for Iterators`
fn lint_filter_next ( cx : & LateContext , expr : & Expr , filter_args : & MethodArgs ) {
// lint if caller of `.filter().next()` is an Iterator
if match_trait_method ( cx , expr , & [ " core " , " iter " , " Iterator " ] ) {
2016-01-03 22:26:12 -06:00
let msg = " called `filter(p).next()` on an Iterator. This is more succinctly expressed by calling `.find(p)` \
instead . " ;
2015-12-28 18:56:58 -06:00
let filter_snippet = snippet ( cx , filter_args [ 1 ] . span , " .. " ) ;
2016-01-03 22:26:12 -06:00
if filter_snippet . lines ( ) . count ( ) < = 1 {
// add note if not multi-line
span_note_and_lint ( cx ,
FILTER_NEXT ,
expr . span ,
msg ,
expr . span ,
& format! ( " replace `filter( {0} ).next()` with `find( {0} )` " , filter_snippet ) ) ;
} else {
2015-12-28 18:56:58 -06:00
span_lint ( cx , FILTER_NEXT , expr . span , msg ) ;
}
}
}
2016-01-03 22:26:12 -06:00
#[ allow(ptr_arg) ]
// Type of MethodArgs is potentially a Vec
2015-12-30 02:38:03 -06:00
/// lint searching an Iterator followed by `is_some()`
fn lint_search_is_some ( cx : & LateContext , expr : & Expr , search_method : & str , search_args : & MethodArgs ,
is_some_args : & MethodArgs ) {
// lint if caller of search is an Iterator
if match_trait_method ( cx , & * is_some_args [ 0 ] , & [ " core " , " iter " , " Iterator " ] ) {
2016-01-03 22:26:12 -06:00
let msg = format! ( " called `is_some()` after searching an iterator with {} . This is more succinctly expressed \
by calling ` any ( ) ` . " ,
search_method ) ;
2015-12-30 02:38:03 -06:00
let search_snippet = snippet ( cx , search_args [ 1 ] . span , " .. " ) ;
2016-01-03 22:26:12 -06:00
if search_snippet . lines ( ) . count ( ) < = 1 {
// add note if not multi-line
span_note_and_lint ( cx ,
SEARCH_IS_SOME ,
expr . span ,
& msg ,
expr . span ,
& format! ( " replace ` {0} ( {1} ).is_some()` with `any( {1} )` " , search_method , search_snippet ) ) ;
} else {
2015-12-30 02:38:03 -06:00
span_lint ( cx , SEARCH_IS_SOME , expr . span , & msg ) ;
}
}
}
2016-01-19 19:23:39 -06:00
/// Checks for the `CHARS_NEXT_CMP` lint.
fn lint_chars_next ( cx : & LateContext , expr : & Expr , chain : & Expr , other : & Expr , eq : bool ) -> bool {
if_let_chain! { [
let Some ( args ) = method_chain_args ( chain , & [ " chars " , " next " ] ) ,
let ExprCall ( ref fun , ref arg_char ) = other . node ,
arg_char . len ( ) = = 1 ,
let ExprPath ( None , ref path ) = fun . node ,
path . segments . len ( ) = = 1 & & path . segments [ 0 ] . identifier . name . as_str ( ) = = " Some "
] , {
let self_ty = walk_ptrs_ty ( cx . tcx . expr_ty_adjusted ( & args [ 0 ] [ 0 ] ) ) ;
if self_ty . sty ! = ty ::TyStr {
return false ;
}
span_lint_and_then ( cx ,
CHARS_NEXT_CMP ,
expr . span ,
" you should use the `starts_with` method " ,
| db | {
let sugg = format! ( " {} {} .starts_with( {} ) " ,
if eq { " " } else { " ! " } ,
snippet ( cx , args [ 0 ] [ 0 ] . span , " _ " ) ,
snippet ( cx , arg_char [ 0 ] . span , " _ " )
) ;
db . span_suggestion ( expr . span , " like this " , sugg ) ;
} ) ;
return true ;
} }
false
}
2015-11-19 07:39:27 -06: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 13:13:36 -06: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 13:19:19 -06:00
let no_ref_ty = walk_ptrs_ty ( ty ) ;
2015-11-19 13:13:36 -06:00
let debug = match cx . tcx . lang_items . debug_trait ( ) {
Some ( debug ) = > debug ,
2016-01-03 22:26:12 -06:00
None = > return false ,
2015-11-19 13:13:36 -06:00
} ;
let debug_def = cx . tcx . lookup_trait_def ( debug ) ;
let mut debug_impl_exists = false ;
2015-11-19 13:19:19 -06:00
debug_def . for_each_relevant_impl ( cx . tcx , no_ref_ty , | d | {
2015-11-19 13:13:36 -06: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 07:39:27 -06:00
2016-01-30 06:39:16 -06:00
#[ rustfmt_skip ]
const CONVENTIONS : [ ( & 'static str , & 'static [ SelfKind ] ) ; 5 ] = [
( " into_ " , & [ SelfKind ::Value ] ) ,
( " to_ " , & [ SelfKind ::Ref ] ) ,
( " as_ " , & [ SelfKind ::Ref , SelfKind ::RefMut ] ) ,
( " is_ " , & [ SelfKind ::Ref , SelfKind ::No ] ) ,
( " from_ " , & [ SelfKind ::No ] ) ,
] ;
#[ rustfmt_skip ]
const TRAIT_METHODS : [ ( & 'static str , usize , SelfKind , OutType , & 'static str ) ; 30 ] = [
( " add " , 2 , SelfKind ::Value , OutType ::Any , " std::ops::Add " ) ,
( " sub " , 2 , SelfKind ::Value , OutType ::Any , " std::ops::Sub " ) ,
( " mul " , 2 , SelfKind ::Value , OutType ::Any , " std::ops::Mul " ) ,
( " div " , 2 , SelfKind ::Value , OutType ::Any , " std::ops::Div " ) ,
( " rem " , 2 , SelfKind ::Value , OutType ::Any , " std::ops::Rem " ) ,
( " shl " , 2 , SelfKind ::Value , OutType ::Any , " std::ops::Shl " ) ,
( " shr " , 2 , SelfKind ::Value , OutType ::Any , " std::ops::Shr " ) ,
( " bitand " , 2 , SelfKind ::Value , OutType ::Any , " std::ops::BitAnd " ) ,
( " bitor " , 2 , SelfKind ::Value , OutType ::Any , " std::ops::BitOr " ) ,
( " bitxor " , 2 , SelfKind ::Value , OutType ::Any , " std::ops::BitXor " ) ,
( " neg " , 1 , SelfKind ::Value , OutType ::Any , " std::ops::Neg " ) ,
( " not " , 1 , SelfKind ::Value , OutType ::Any , " std::ops::Not " ) ,
( " drop " , 1 , SelfKind ::RefMut , OutType ::Unit , " std::ops::Drop " ) ,
( " index " , 2 , SelfKind ::Ref , OutType ::Ref , " std::ops::Index " ) ,
( " index_mut " , 2 , SelfKind ::RefMut , OutType ::Ref , " std::ops::IndexMut " ) ,
( " deref " , 1 , SelfKind ::Ref , OutType ::Ref , " std::ops::Deref " ) ,
( " deref_mut " , 1 , SelfKind ::RefMut , OutType ::Ref , " std::ops::DerefMut " ) ,
( " clone " , 1 , SelfKind ::Ref , OutType ::Any , " std::clone::Clone " ) ,
( " borrow " , 1 , SelfKind ::Ref , OutType ::Ref , " std::borrow::Borrow " ) ,
( " borrow_mut " , 1 , SelfKind ::RefMut , OutType ::Ref , " std::borrow::BorrowMut " ) ,
( " as_ref " , 1 , SelfKind ::Ref , OutType ::Ref , " std::convert::AsRef " ) ,
( " as_mut " , 1 , SelfKind ::RefMut , OutType ::Ref , " std::convert::AsMut " ) ,
( " eq " , 2 , SelfKind ::Ref , OutType ::Bool , " std::cmp::PartialEq " ) ,
( " cmp " , 2 , SelfKind ::Ref , OutType ::Any , " std::cmp::Ord " ) ,
( " default " , 0 , SelfKind ::No , OutType ::Any , " std::default::Default " ) ,
( " hash " , 2 , SelfKind ::Ref , OutType ::Unit , " std::hash::Hash " ) ,
( " next " , 1 , SelfKind ::RefMut , OutType ::Any , " std::iter::Iterator " ) ,
( " into_iter " , 1 , SelfKind ::Value , OutType ::Any , " std::iter::IntoIterator " ) ,
( " from_iter " , 1 , SelfKind ::No , OutType ::Any , " std::iter::FromIterator " ) ,
( " from_str " , 1 , SelfKind ::No , OutType ::Any , " std::str::FromStr " ) ,
] ;
2015-08-24 11:13:02 -05:00
#[ derive(Clone, Copy) ]
enum SelfKind {
2016-02-01 05:51:33 -06:00
Value ,
Ref ,
RefMut ,
No ,
2015-08-24 11:13:02 -05:00
}
impl SelfKind {
2015-09-01 14:08:49 -05:00
fn matches ( & self , slf : & ExplicitSelf_ , allow_value_for_ref : bool ) -> bool {
2015-08-24 11:13:02 -05:00
match ( self , slf ) {
2016-02-01 05:51:33 -06:00
( & SelfKind ::Value , & SelfValue ( _ ) ) = > true ,
( & SelfKind ::Ref , & SelfRegion ( _ , Mutability ::MutImmutable , _ ) ) = > true ,
( & SelfKind ::RefMut , & SelfRegion ( _ , Mutability ::MutMutable , _ ) ) = > true ,
( & SelfKind ::Ref , & SelfValue ( _ ) ) = > allow_value_for_ref ,
( & SelfKind ::RefMut , & SelfValue ( _ ) ) = > allow_value_for_ref ,
( & SelfKind ::No , & SelfStatic ) = > true ,
2015-09-01 14:08:49 -05:00
( _ , & SelfExplicit ( ref ty , _ ) ) = > self . matches_explicit_type ( ty , allow_value_for_ref ) ,
2016-01-03 22:26:12 -06:00
_ = > false ,
2015-08-24 11:13:02 -05:00
}
}
2015-09-01 11:52:48 -05:00
2015-09-01 14:08:49 -05:00
fn matches_explicit_type ( & self , ty : & Ty , allow_value_for_ref : bool ) -> bool {
2015-09-01 11:52:48 -05:00
match ( self , & ty . node ) {
2016-02-01 05:51:33 -06:00
( & SelfKind ::Value , & TyPath ( .. ) ) = > true ,
( & SelfKind ::Ref , & TyRptr ( _ , MutTy { mutbl : Mutability ::MutImmutable , .. } ) ) = > true ,
( & SelfKind ::RefMut , & TyRptr ( _ , MutTy { mutbl : Mutability ::MutMutable , .. } ) ) = > true ,
( & SelfKind ::Ref , & TyPath ( .. ) ) = > allow_value_for_ref ,
( & SelfKind ::RefMut , & TyPath ( .. ) ) = > allow_value_for_ref ,
2016-01-03 22:26:12 -06:00
_ = > false ,
2015-09-01 11:52:48 -05:00
}
}
fn description ( & self ) -> & 'static str {
match * self {
2016-02-01 05:51:33 -06:00
SelfKind ::Value = > " self by value " ,
SelfKind ::Ref = > " self by reference " ,
SelfKind ::RefMut = > " self by mutable reference " ,
SelfKind ::No = > " no self " ,
2015-09-01 11:52:48 -05:00
}
}
2015-08-24 11:13:02 -05:00
}
#[ derive(Clone, Copy) ]
enum OutType {
2016-02-01 05:51:33 -06:00
Unit ,
Bool ,
Any ,
Ref ,
2015-08-24 11:13:02 -05:00
}
impl OutType {
fn matches ( & self , ty : & FunctionRetTy ) -> bool {
match ( self , ty ) {
2016-02-01 05:51:33 -06:00
( & OutType ::Unit , & DefaultReturn ( _ ) ) = > true ,
( & OutType ::Unit , & Return ( ref ty ) ) if ty . node = = TyTup ( vec! [ ] . into ( ) ) = > true ,
( & OutType ::Bool , & Return ( ref ty ) ) if is_bool ( ty ) = > true ,
( & OutType ::Any , & Return ( ref ty ) ) if ty . node ! = TyTup ( vec! [ ] . into ( ) ) = > true ,
( & OutType ::Ref , & Return ( ref ty ) ) = > {
2016-01-03 22:26:12 -06:00
if let TyRptr ( _ , _ ) = ty . node {
true
} else {
false
}
2015-08-24 11:13:02 -05:00
}
2016-01-03 22:26:12 -06:00
_ = > false ,
2015-08-24 11:13:02 -05:00
}
}
}
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 13:53:50 -05:00
}
2015-09-01 14:08:49 -05:00
2015-09-18 21:53:04 -05:00
fn is_copy ( cx : & LateContext , ast_ty : & Ty , item : & Item ) -> bool {
2015-09-01 14:08:49 -05: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 15:44:05 -05:00
! ty . subst ( cx . tcx , & env . free_substs ) . moves_by_default ( & env , ast_ty . span )
2015-09-01 14:08:49 -05:00
}
}
}