1
- use rustc_front:: hir:: * ;
2
1
use rustc:: lint:: * ;
3
- use rustc:: middle:: ty;
4
2
use rustc:: middle:: subst:: { Subst , TypeSpace } ;
5
- use std:: iter;
3
+ use rustc:: middle:: ty;
4
+ use rustc_front:: hir:: * ;
6
5
use std:: borrow:: Cow ;
7
- use syntax :: ptr :: P ;
6
+ use std :: { fmt , iter } ;
8
7
use syntax:: codemap:: Span ;
8
+ use syntax:: ptr:: P ;
9
9
10
10
use utils:: { get_trait_def_id, implements_trait, in_external_macro, in_macro, match_path, match_trait_method,
11
11
match_type, method_chain_args, snippet, snippet_opt, span_lint, span_lint_and_then, span_note_and_lint,
@@ -274,11 +274,27 @@ declare_lint! {
274
274
/// println!("{:p} {:p}",*y, z); // prints out the same pointer
275
275
/// }
276
276
/// ```
277
- ///
278
277
declare_lint ! {
279
278
pub CLONE_DOUBLE_REF , Warn , "using `clone` on `&&T`"
280
279
}
281
280
281
+ /// **What it does:** This lint warns about `new` not returning `Self`.
282
+ ///
283
+ /// **Why is this bad?** As a convention, `new` methods are used to make a new instance of a type.
284
+ ///
285
+ /// **Known problems:** None.
286
+ ///
287
+ /// **Example:**
288
+ /// ```rust
289
+ /// impl Foo {
290
+ /// fn new(..) -> NotAFoo {
291
+ /// }
292
+ /// }
293
+ /// ```
294
+ declare_lint ! {
295
+ pub NEW_RET_NO_SELF , Warn , "not returning `Self` in a `new` method"
296
+ }
297
+
282
298
impl LintPass for MethodsPass {
283
299
fn get_lints ( & self ) -> LintArray {
284
300
lint_array ! ( EXTEND_FROM_SLICE ,
@@ -295,7 +311,8 @@ impl LintPass for MethodsPass {
295
311
OR_FUN_CALL ,
296
312
CHARS_NEXT_CMP ,
297
313
CLONE_ON_COPY ,
298
- CLONE_DOUBLE_REF )
314
+ CLONE_DOUBLE_REF ,
315
+ NEW_RET_NO_SELF )
299
316
}
300
317
}
301
318
@@ -368,10 +385,11 @@ impl LateLintPass for MethodsPass {
368
385
}
369
386
}
370
387
}
388
+
371
389
// check conventions w.r.t. conversion method names and predicates
372
390
let is_copy = is_copy ( cx, & ty, & item) ;
373
- for & ( prefix , self_kinds) in & CONVENTIONS {
374
- if name. as_str ( ) . starts_with ( prefix ) &&
391
+ for & ( ref conv , self_kinds) in & CONVENTIONS {
392
+ if conv . check ( & name. as_str ( ) ) &&
375
393
!self_kinds. iter ( ) . any ( |k| k. matches ( & sig. explicit_self . node , is_copy) ) {
376
394
let lint = if item. vis == Visibility :: Public {
377
395
WRONG_PUB_SELF_CONVENTION
@@ -381,15 +399,38 @@ impl LateLintPass for MethodsPass {
381
399
span_lint ( cx,
382
400
lint,
383
401
sig. explicit_self . span ,
384
- & format ! ( "methods called `{}* ` usually take {}; consider choosing a less \
402
+ & format ! ( "methods called `{}` usually take {}; consider choosing a less \
385
403
ambiguous name",
386
- prefix ,
404
+ conv ,
387
405
& self_kinds. iter( )
388
406
. map( |k| k. description( ) )
389
407
. collect:: <Vec <_>>( )
390
408
. join( " or " ) ) ) ;
391
409
}
392
410
}
411
+
412
+ if & name. as_str ( ) == & "new" {
413
+ let returns_self = if let FunctionRetTy :: Return ( ref ret_ty) = sig. decl . output {
414
+ let ast_ty_to_ty_cache = cx. tcx . ast_ty_to_ty_cache . borrow ( ) ;
415
+ let ty = ast_ty_to_ty_cache. get ( & ty. id ) ;
416
+ let ret_ty = ast_ty_to_ty_cache. get ( & ret_ty. id ) ;
417
+
418
+ match ( ty, ret_ty) {
419
+ ( Some ( & ty) , Some ( & ret_ty) ) => ret_ty. walk ( ) . any ( |t| t == ty) ,
420
+ _ => false ,
421
+ }
422
+ }
423
+ else {
424
+ false
425
+ } ;
426
+
427
+ if !returns_self {
428
+ span_lint ( cx,
429
+ NEW_RET_NO_SELF ,
430
+ sig. explicit_self . span ,
431
+ "methods called `new` usually return `Self`" ) ;
432
+ }
433
+ }
393
434
}
394
435
}
395
436
}
@@ -789,69 +830,61 @@ fn get_error_type<'a>(cx: &LateContext, ty: ty::Ty<'a>) -> Option<ty::Ty<'a>> {
789
830
None
790
831
}
791
832
792
- /// This checks whether a given type is known to implement Debug. It's
793
- /// conservative, i.e. it should not return false positives, but will return
794
- /// false negatives.
833
+ /// This checks whether a given type is known to implement Debug.
795
834
fn has_debug_impl < ' a , ' b > ( ty : ty:: Ty < ' a > , cx : & LateContext < ' b , ' a > ) -> bool {
796
- let no_ref_ty = walk_ptrs_ty ( ty) ;
797
- let debug = match cx. tcx . lang_items . debug_trait ( ) {
798
- Some ( debug) => debug,
799
- None => return false ,
800
- } ;
801
- let debug_def = cx. tcx . lookup_trait_def ( debug) ;
802
- let mut debug_impl_exists = false ;
803
- debug_def. for_each_relevant_impl ( cx. tcx , no_ref_ty, |d| {
804
- let self_ty = & cx. tcx . impl_trait_ref ( d) . and_then ( |im| im. substs . self_ty ( ) ) ;
805
- if let Some ( self_ty) = * self_ty {
806
- if !self_ty. flags . get ( ) . contains ( ty:: TypeFlags :: HAS_PARAMS ) {
807
- debug_impl_exists = true ;
808
- }
809
- }
810
- } ) ;
811
- debug_impl_exists
835
+ match cx. tcx . lang_items . debug_trait ( ) {
836
+ Some ( debug) => implements_trait ( cx, ty, debug, Some ( vec ! [ ] ) ) ,
837
+ None => false ,
838
+ }
839
+ }
840
+
841
+ enum Convention {
842
+ Eq ( & ' static str ) ,
843
+ StartsWith ( & ' static str ) ,
812
844
}
813
845
814
846
#[ cfg_attr( rustfmt, rustfmt_skip) ]
815
- const CONVENTIONS : [ ( & ' static str , & ' static [ SelfKind ] ) ; 5 ] = [
816
- ( "into_" , & [ SelfKind :: Value ] ) ,
817
- ( "to_" , & [ SelfKind :: Ref ] ) ,
818
- ( "as_" , & [ SelfKind :: Ref , SelfKind :: RefMut ] ) ,
819
- ( "is_" , & [ SelfKind :: Ref , SelfKind :: No ] ) ,
820
- ( "from_" , & [ SelfKind :: No ] ) ,
847
+ const CONVENTIONS : [ ( Convention , & ' static [ SelfKind ] ) ; 6 ] = [
848
+ ( Convention :: Eq ( "new" ) , & [ SelfKind :: No ] ) ,
849
+ ( Convention :: StartsWith ( "as_" ) , & [ SelfKind :: Ref , SelfKind :: RefMut ] ) ,
850
+ ( Convention :: StartsWith ( "from_" ) , & [ SelfKind :: No ] ) ,
851
+ ( Convention :: StartsWith ( "into_" ) , & [ SelfKind :: Value ] ) ,
852
+ ( Convention :: StartsWith ( "is_" ) , & [ SelfKind :: Ref , SelfKind :: No ] ) ,
853
+ ( Convention :: StartsWith ( "to_" ) , & [ SelfKind :: Ref ] ) ,
821
854
] ;
822
855
823
856
#[ cfg_attr( rustfmt, rustfmt_skip) ]
824
857
const TRAIT_METHODS : [ ( & ' static str , usize , SelfKind , OutType , & ' static str ) ; 30 ] = [
825
858
( "add" , 2 , SelfKind :: Value , OutType :: Any , "std::ops::Add" ) ,
826
- ( "sub" , 2 , SelfKind :: Value , OutType :: Any , "std::ops::Sub" ) ,
827
- ( "mul" , 2 , SelfKind :: Value , OutType :: Any , "std::ops::Mul" ) ,
828
- ( "div" , 2 , SelfKind :: Value , OutType :: Any , "std::ops::Div" ) ,
829
- ( "rem" , 2 , SelfKind :: Value , OutType :: Any , "std::ops::Rem" ) ,
830
- ( "shl" , 2 , SelfKind :: Value , OutType :: Any , "std::ops::Shl" ) ,
831
- ( "shr" , 2 , SelfKind :: Value , OutType :: Any , "std::ops::Shr" ) ,
859
+ ( "as_mut" , 1 , SelfKind :: RefMut , OutType :: Ref , "std::convert::AsMut" ) ,
860
+ ( "as_ref" , 1 , SelfKind :: Ref , OutType :: Ref , "std::convert::AsRef" ) ,
832
861
( "bitand" , 2 , SelfKind :: Value , OutType :: Any , "std::ops::BitAnd" ) ,
833
862
( "bitor" , 2 , SelfKind :: Value , OutType :: Any , "std::ops::BitOr" ) ,
834
863
( "bitxor" , 2 , SelfKind :: Value , OutType :: Any , "std::ops::BitXor" ) ,
835
- ( "neg" , 1 , SelfKind :: Value , OutType :: Any , "std::ops::Neg" ) ,
836
- ( "not" , 1 , SelfKind :: Value , OutType :: Any , "std::ops::Not" ) ,
837
- ( "drop" , 1 , SelfKind :: RefMut , OutType :: Unit , "std::ops::Drop" ) ,
838
- ( "index" , 2 , SelfKind :: Ref , OutType :: Ref , "std::ops::Index" ) ,
839
- ( "index_mut" , 2 , SelfKind :: RefMut , OutType :: Ref , "std::ops::IndexMut" ) ,
840
- ( "deref" , 1 , SelfKind :: Ref , OutType :: Ref , "std::ops::Deref" ) ,
841
- ( "deref_mut" , 1 , SelfKind :: RefMut , OutType :: Ref , "std::ops::DerefMut" ) ,
842
- ( "clone" , 1 , SelfKind :: Ref , OutType :: Any , "std::clone::Clone" ) ,
843
864
( "borrow" , 1 , SelfKind :: Ref , OutType :: Ref , "std::borrow::Borrow" ) ,
844
865
( "borrow_mut" , 1 , SelfKind :: RefMut , OutType :: Ref , "std::borrow::BorrowMut" ) ,
845
- ( "as_ref" , 1 , SelfKind :: Ref , OutType :: Ref , "std::convert::AsRef" ) ,
846
- ( "as_mut" , 1 , SelfKind :: RefMut , OutType :: Ref , "std::convert::AsMut" ) ,
847
- ( "eq" , 2 , SelfKind :: Ref , OutType :: Bool , "std::cmp::PartialEq" ) ,
866
+ ( "clone" , 1 , SelfKind :: Ref , OutType :: Any , "std::clone::Clone" ) ,
848
867
( "cmp" , 2 , SelfKind :: Ref , OutType :: Any , "std::cmp::Ord" ) ,
849
868
( "default" , 0 , SelfKind :: No , OutType :: Any , "std::default::Default" ) ,
850
- ( "hash" , 2 , SelfKind :: Ref , OutType :: Unit , "std::hash::Hash" ) ,
851
- ( "next" , 1 , SelfKind :: RefMut , OutType :: Any , "std::iter::Iterator" ) ,
852
- ( "into_iter" , 1 , SelfKind :: Value , OutType :: Any , "std::iter::IntoIterator" ) ,
869
+ ( "deref" , 1 , SelfKind :: Ref , OutType :: Ref , "std::ops::Deref" ) ,
870
+ ( "deref_mut" , 1 , SelfKind :: RefMut , OutType :: Ref , "std::ops::DerefMut" ) ,
871
+ ( "div" , 2 , SelfKind :: Value , OutType :: Any , "std::ops::Div" ) ,
872
+ ( "drop" , 1 , SelfKind :: RefMut , OutType :: Unit , "std::ops::Drop" ) ,
873
+ ( "eq" , 2 , SelfKind :: Ref , OutType :: Bool , "std::cmp::PartialEq" ) ,
853
874
( "from_iter" , 1 , SelfKind :: No , OutType :: Any , "std::iter::FromIterator" ) ,
854
875
( "from_str" , 1 , SelfKind :: No , OutType :: Any , "std::str::FromStr" ) ,
876
+ ( "hash" , 2 , SelfKind :: Ref , OutType :: Unit , "std::hash::Hash" ) ,
877
+ ( "index" , 2 , SelfKind :: Ref , OutType :: Ref , "std::ops::Index" ) ,
878
+ ( "index_mut" , 2 , SelfKind :: RefMut , OutType :: Ref , "std::ops::IndexMut" ) ,
879
+ ( "into_iter" , 1 , SelfKind :: Value , OutType :: Any , "std::iter::IntoIterator" ) ,
880
+ ( "mul" , 2 , SelfKind :: Value , OutType :: Any , "std::ops::Mul" ) ,
881
+ ( "neg" , 1 , SelfKind :: Value , OutType :: Any , "std::ops::Neg" ) ,
882
+ ( "next" , 1 , SelfKind :: RefMut , OutType :: Any , "std::iter::Iterator" ) ,
883
+ ( "not" , 1 , SelfKind :: Value , OutType :: Any , "std::ops::Not" ) ,
884
+ ( "rem" , 2 , SelfKind :: Value , OutType :: Any , "std::ops::Rem" ) ,
885
+ ( "shl" , 2 , SelfKind :: Value , OutType :: Any , "std::ops::Shl" ) ,
886
+ ( "shr" , 2 , SelfKind :: Value , OutType :: Any , "std::ops::Shr" ) ,
887
+ ( "sub" , 2 , SelfKind :: Value , OutType :: Any , "std::ops::Sub" ) ,
855
888
] ;
856
889
857
890
#[ derive( Clone , Copy ) ]
@@ -896,6 +929,24 @@ impl SelfKind {
896
929
}
897
930
}
898
931
932
+ impl Convention {
933
+ fn check ( & self , other : & str ) -> bool {
934
+ match * self {
935
+ Convention :: Eq ( this) => this == other,
936
+ Convention :: StartsWith ( this) => other. starts_with ( this) ,
937
+ }
938
+ }
939
+ }
940
+
941
+ impl fmt:: Display for Convention {
942
+ fn fmt ( & self , f : & mut fmt:: Formatter ) -> Result < ( ) , fmt:: Error > {
943
+ match * self {
944
+ Convention :: Eq ( this) => this. fmt ( f) ,
945
+ Convention :: StartsWith ( this) => this. fmt ( f) . and_then ( |_| '*' . fmt ( f) ) ,
946
+ }
947
+ }
948
+ }
949
+
899
950
#[ derive( Clone , Copy ) ]
900
951
enum OutType {
901
952
Unit ,
0 commit comments