@@ -2,9 +2,12 @@ use syntax::ast::*;
2
2
use rustc:: lint:: * ;
3
3
use rustc:: middle:: ty;
4
4
5
- use utils:: { span_lint, match_type, walk_ptrs_ty} ;
5
+ use utils:: { span_lint, match_path , match_type, walk_ptrs_ty} ;
6
6
use utils:: { OPTION_PATH , RESULT_PATH , STRING_PATH } ;
7
7
8
+ use self :: SelfKind :: * ;
9
+ use self :: OutType :: * ;
10
+
8
11
#[ derive( Copy , Clone ) ]
9
12
pub struct MethodsPass ;
10
13
@@ -16,10 +19,13 @@ declare_lint!(pub STR_TO_STRING, Warn,
16
19
"using `to_string()` on a str, which should be `to_owned()`" ) ;
17
20
declare_lint ! ( pub STRING_TO_STRING , Warn ,
18
21
"calling `String.to_string()` which is a no-op" ) ;
22
+ declare_lint ! ( pub SHOULD_IMPLEMENT_TRAIT , Warn ,
23
+ "defining a method that should be implementing a std trait" ) ;
19
24
20
25
impl LintPass for MethodsPass {
21
26
fn get_lints ( & self ) -> LintArray {
22
- lint_array ! ( OPTION_UNWRAP_USED , RESULT_UNWRAP_USED , STR_TO_STRING , STRING_TO_STRING )
27
+ lint_array ! ( OPTION_UNWRAP_USED , RESULT_UNWRAP_USED , STR_TO_STRING , STRING_TO_STRING ,
28
+ SHOULD_IMPLEMENT_TRAIT )
23
29
}
24
30
25
31
fn check_expr ( & mut self , cx : & Context , expr : & Expr ) {
@@ -46,4 +52,112 @@ impl LintPass for MethodsPass {
46
52
}
47
53
}
48
54
}
55
+
56
+ fn check_item ( & mut self , cx : & Context , item : & Item ) {
57
+ if let ItemImpl ( _, _, _, None , _, ref items) = item. node {
58
+ for item in items {
59
+ let name = item. ident . name ;
60
+ for & ( method_name, n_args, self_kind, out_type, trait_name) in & TRAIT_METHODS {
61
+ if_let_chain ! {
62
+ [
63
+ name == method_name,
64
+ let MethodImplItem ( ref sig, _) = item. node,
65
+ sig. decl. inputs. len( ) == n_args,
66
+ out_type. matches( & sig. decl. output) ,
67
+ self_kind. matches( & sig. explicit_self. node)
68
+ ] , {
69
+ span_lint( cx, SHOULD_IMPLEMENT_TRAIT , item. span, & format!(
70
+ "defining a method called `{}` on this type; consider implementing \
71
+ the `{}` trait or choosing a less ambiguous name", name, trait_name) ) ;
72
+ }
73
+ }
74
+ }
75
+ }
76
+ }
77
+ }
78
+ }
79
+
80
+ const TRAIT_METHODS : [ ( & ' static str , usize , SelfKind , OutType , & ' static str ) ; 30 ] = [
81
+ ( "add" , 2 , ValueSelf , AnyType , "std::ops::Add`" ) ,
82
+ ( "sub" , 2 , ValueSelf , AnyType , "std::ops::Sub" ) ,
83
+ ( "mul" , 2 , ValueSelf , AnyType , "std::ops::Mul" ) ,
84
+ ( "div" , 2 , ValueSelf , AnyType , "std::ops::Div" ) ,
85
+ ( "rem" , 2 , ValueSelf , AnyType , "std::ops::Rem" ) ,
86
+ ( "shl" , 2 , ValueSelf , AnyType , "std::ops::Shl" ) ,
87
+ ( "shr" , 2 , ValueSelf , AnyType , "std::ops::Shr" ) ,
88
+ ( "bitand" , 2 , ValueSelf , AnyType , "std::ops::BitAnd" ) ,
89
+ ( "bitor" , 2 , ValueSelf , AnyType , "std::ops::BitOr" ) ,
90
+ ( "bitxor" , 2 , ValueSelf , AnyType , "std::ops::BitXor" ) ,
91
+ ( "neg" , 1 , ValueSelf , AnyType , "std::ops::Neg" ) ,
92
+ ( "not" , 1 , ValueSelf , AnyType , "std::ops::Not" ) ,
93
+ ( "drop" , 1 , RefMutSelf , UnitType , "std::ops::Drop" ) ,
94
+ ( "index" , 2 , RefSelf , RefType , "std::ops::Index" ) ,
95
+ ( "index_mut" , 2 , RefMutSelf , RefType , "std::ops::IndexMut" ) ,
96
+ ( "deref" , 1 , RefSelf , RefType , "std::ops::Deref" ) ,
97
+ ( "deref_mut" , 1 , RefMutSelf , RefType , "std::ops::DerefMut" ) ,
98
+ ( "clone" , 1 , RefSelf , AnyType , "std::clone::Clone" ) ,
99
+ ( "borrow" , 1 , RefSelf , RefType , "std::borrow::Borrow" ) ,
100
+ ( "borrow_mut" , 1 , RefMutSelf , RefType , "std::borrow::BorrowMut" ) ,
101
+ ( "as_ref" , 1 , RefSelf , RefType , "std::convert::AsRef" ) ,
102
+ ( "as_mut" , 1 , RefMutSelf , RefType , "std::convert::AsMut" ) ,
103
+ ( "eq" , 2 , RefSelf , BoolType , "std::cmp::PartialEq" ) ,
104
+ ( "cmp" , 2 , RefSelf , AnyType , "std::cmp::Ord" ) ,
105
+ ( "default" , 0 , NoSelf , AnyType , "std::default::Default" ) ,
106
+ ( "hash" , 2 , RefSelf , UnitType , "std::hash::Hash" ) ,
107
+ ( "next" , 1 , RefMutSelf , AnyType , "std::iter::Iterator" ) ,
108
+ ( "into_iter" , 1 , ValueSelf , AnyType , "std::iter::IntoIterator" ) ,
109
+ ( "from_iter" , 1 , NoSelf , AnyType , "std::iter::FromIterator" ) ,
110
+ ( "from_str" , 1 , NoSelf , AnyType , "std::str::FromStr" ) ,
111
+ ] ;
112
+
113
+ #[ derive( Clone , Copy ) ]
114
+ enum SelfKind {
115
+ ValueSelf ,
116
+ RefSelf ,
117
+ RefMutSelf ,
118
+ NoSelf
119
+ }
120
+
121
+ impl SelfKind {
122
+ fn matches ( & self , slf : & ExplicitSelf_ ) -> bool {
123
+ match ( self , slf) {
124
+ ( & ValueSelf , & SelfValue ( _) ) => true ,
125
+ ( & RefSelf , & SelfRegion ( _, Mutability :: MutImmutable , _) ) => true ,
126
+ ( & RefMutSelf , & SelfRegion ( _, Mutability :: MutMutable , _) ) => true ,
127
+ ( & NoSelf , & SelfStatic ) => true ,
128
+ _ => false
129
+ }
130
+ }
131
+ }
132
+
133
+ #[ derive( Clone , Copy ) ]
134
+ enum OutType {
135
+ UnitType ,
136
+ BoolType ,
137
+ AnyType ,
138
+ RefType ,
139
+ }
140
+
141
+ impl OutType {
142
+ fn matches ( & self , ty : & FunctionRetTy ) -> bool {
143
+ match ( self , ty) {
144
+ ( & UnitType , & DefaultReturn ( _) ) => true ,
145
+ ( & UnitType , & Return ( ref ty) ) if ty. node == TyTup ( vec ! [ ] ) => true ,
146
+ ( & BoolType , & Return ( ref ty) ) if is_bool ( ty) => true ,
147
+ ( & AnyType , & Return ( ref ty) ) if ty. node != TyTup ( vec ! [ ] ) => true ,
148
+ ( & RefType , & Return ( ref ty) ) => {
149
+ if let TyRptr ( _, _) = ty. node { true } else { false }
150
+ }
151
+ _ => false
152
+ }
153
+ }
154
+ }
155
+
156
+ fn is_bool ( ty : & Ty ) -> bool {
157
+ if let TyPath ( None , ref p) = ty. node {
158
+ if match_path ( p, & [ "bool" ] ) {
159
+ return true ;
160
+ }
161
+ }
162
+ false
49
163
}
0 commit comments