@@ -15,24 +15,24 @@ use rustc_ast::ast;
15
15
use rustc_errors:: Applicability ;
16
16
use rustc_hir as hir;
17
17
use rustc_hir:: intravisit:: { self , Visitor } ;
18
+ use rustc_hir:: { TraitItem , TraitItemKind } ;
18
19
use rustc_lint:: { LateContext , LateLintPass , Lint , LintContext } ;
19
20
use rustc_middle:: hir:: map:: Map ;
20
21
use rustc_middle:: lint:: in_external_macro;
21
- use rustc_middle:: ty:: subst:: GenericArgKind ;
22
- use rustc_middle:: ty:: { self , Ty , TyS } ;
22
+ use rustc_middle:: ty:: { self , TraitRef , Ty , TyS } ;
23
23
use rustc_session:: { declare_lint_pass, declare_tool_lint} ;
24
24
use rustc_span:: source_map:: Span ;
25
25
use rustc_span:: symbol:: { sym, SymbolStr } ;
26
26
27
27
use crate :: consts:: { constant, Constant } ;
28
28
use crate :: utils:: usage:: mutated_variables;
29
29
use crate :: utils:: {
30
- get_arg_name, get_parent_expr, get_trait_def_id, has_iter_method, higher, implements_trait, in_macro, is_copy ,
31
- is_ctor_or_promotable_const_function, is_expn_of, is_type_diagnostic_item, iter_input_pats, last_path_segment ,
32
- match_def_path, match_qpath, match_trait_method, match_type, match_var, method_calls, method_chain_args , paths ,
33
- remove_blocks, return_ty, single_segment_path, snippet, snippet_with_applicability, snippet_with_macro_callsite ,
34
- span_lint, span_lint_and_help, span_lint_and_note, span_lint_and_sugg, span_lint_and_then , sugg , walk_ptrs_ty ,
35
- walk_ptrs_ty_depth, SpanlessEq ,
30
+ contains_ty , get_arg_name, get_parent_expr, get_trait_def_id, has_iter_method, higher, implements_trait, in_macro,
31
+ is_copy , is_ctor_or_promotable_const_function, is_expn_of, is_type_diagnostic_item, iter_input_pats,
32
+ last_path_segment , match_def_path, match_qpath, match_trait_method, match_type, match_var, method_calls,
33
+ method_chain_args , paths , remove_blocks, return_ty, single_segment_path, snippet, snippet_with_applicability,
34
+ snippet_with_macro_callsite , span_lint, span_lint_and_help, span_lint_and_note, span_lint_and_sugg,
35
+ span_lint_and_then , sugg , walk_ptrs_ty , walk_ptrs_ty_depth, SpanlessEq ,
36
36
} ;
37
37
38
38
declare_clippy_lint ! {
@@ -724,6 +724,7 @@ declare_clippy_lint! {
724
724
/// **Known problems:** None.
725
725
///
726
726
/// **Example:**
727
+ /// In an impl block:
727
728
/// ```rust
728
729
/// # struct Foo;
729
730
/// # struct NotAFoo;
@@ -736,25 +737,40 @@ declare_clippy_lint! {
736
737
///
737
738
/// ```rust
738
739
/// # struct Foo;
739
- /// # struct FooError ;
740
+ /// struct Bar(Foo) ;
740
741
/// impl Foo {
741
- /// // Good. Return type contains `Self`
742
- /// fn new() -> Result<Foo, FooError> {
743
- /// # Ok (Foo)
742
+ /// // Bad. The type name must contain `Self`
743
+ /// fn new() -> Bar {
744
+ /// # Bar (Foo)
744
745
/// }
745
746
/// }
746
747
/// ```
747
748
///
748
749
/// ```rust
749
750
/// # struct Foo;
750
- /// struct Bar(Foo) ;
751
+ /// # struct FooError ;
751
752
/// impl Foo {
752
- /// // Bad. The type name must contain `Self`.
753
- /// fn new() -> Bar {
754
- /// # Bar (Foo)
753
+ /// // Good. Return type contains `Self`
754
+ /// fn new() -> Result<Foo, FooError> {
755
+ /// # Ok (Foo)
755
756
/// }
756
757
/// }
757
758
/// ```
759
+ ///
760
+ /// Or in a trait definition:
761
+ /// ```rust
762
+ /// pub trait Trait {
763
+ /// // Bad. The type name must contain `Self`
764
+ /// fn new();
765
+ /// }
766
+ /// ```
767
+ ///
768
+ /// ```rust
769
+ /// pub trait Trait {
770
+ /// // Good. Return type contains `Self`
771
+ /// fn new() -> Self;
772
+ /// }
773
+ /// ```
758
774
pub NEW_RET_NO_SELF ,
759
775
style,
760
776
"not returning type containing `Self` in a `new` method"
@@ -1631,19 +1647,16 @@ impl<'tcx> LateLintPass<'tcx> for Methods {
1631
1647
}
1632
1648
}
1633
1649
1650
+ // if this impl block implements a trait, lint in trait definition instead
1651
+ if let hir:: ItemKind :: Impl { of_trait : Some ( _) , .. } = item. kind {
1652
+ return ;
1653
+ }
1654
+
1634
1655
if let hir:: ImplItemKind :: Fn ( _, _) = impl_item. kind {
1635
1656
let ret_ty = return_ty ( cx, impl_item. hir_id ) ;
1636
1657
1637
- let contains_self_ty = |ty : Ty < ' tcx > | {
1638
- ty. walk ( ) . any ( |inner| match inner. unpack ( ) {
1639
- GenericArgKind :: Type ( inner_ty) => TyS :: same_type ( self_ty, inner_ty) ,
1640
-
1641
- GenericArgKind :: Lifetime ( _) | GenericArgKind :: Const ( _) => false ,
1642
- } )
1643
- } ;
1644
-
1645
1658
// walk the return type and check for Self (this does not check associated types)
1646
- if contains_self_ty ( ret_ty) {
1659
+ if contains_ty ( ret_ty, self_ty ) {
1647
1660
return ;
1648
1661
}
1649
1662
@@ -1653,7 +1666,7 @@ impl<'tcx> LateLintPass<'tcx> for Methods {
1653
1666
for & ( predicate, _span) in cx. tcx . predicates_of ( def_id) . predicates {
1654
1667
if let ty:: PredicateAtom :: Projection ( projection_predicate) = predicate. skip_binders ( ) {
1655
1668
// walk the associated type and check for Self
1656
- if contains_self_ty ( projection_predicate. ty ) {
1669
+ if contains_ty ( projection_predicate. ty , self_ty ) {
1657
1670
return ;
1658
1671
}
1659
1672
}
@@ -1670,6 +1683,26 @@ impl<'tcx> LateLintPass<'tcx> for Methods {
1670
1683
}
1671
1684
}
1672
1685
}
1686
+
1687
+ fn check_trait_item ( & mut self , cx : & LateContext < ' tcx > , item : & ' tcx TraitItem < ' _ > ) {
1688
+ if_chain ! {
1689
+ if !in_external_macro( cx. tcx. sess, item. span) ;
1690
+ if item. ident. name == sym!( new) ;
1691
+ if let TraitItemKind :: Fn ( _, _) = item. kind;
1692
+ let ret_ty = return_ty( cx, item. hir_id) ;
1693
+ let self_ty = TraitRef :: identity( cx. tcx, item. hir_id. owner. to_def_id( ) ) . self_ty( ) ;
1694
+ if !contains_ty( ret_ty, self_ty) ;
1695
+
1696
+ then {
1697
+ span_lint(
1698
+ cx,
1699
+ NEW_RET_NO_SELF ,
1700
+ item. span,
1701
+ "methods called `new` usually return `Self`" ,
1702
+ ) ;
1703
+ }
1704
+ }
1705
+ }
1673
1706
}
1674
1707
1675
1708
/// Checks for the `OR_FUN_CALL` lint.
0 commit comments