@@ -55,6 +55,7 @@ mod iter_skip_zero;
55
55
mod iter_with_drain;
56
56
mod iterator_step_by_zero;
57
57
mod join_absolute_paths;
58
+ mod lib;
58
59
mod manual_c_str_literals;
59
60
mod manual_contains;
60
61
mod manual_inspect;
@@ -102,6 +103,7 @@ mod return_and_then;
102
103
mod search_is_some;
103
104
mod seek_from_current;
104
105
mod seek_to_start_instead_of_rewind;
106
+ mod should_implement_trait;
105
107
mod single_char_add_str;
106
108
mod skip_while_next;
107
109
mod sliced_string_as_bytes;
@@ -146,19 +148,18 @@ mod zst_offset;
146
148
147
149
use clippy_config:: Conf ;
148
150
use clippy_utils:: consts:: { ConstEvalCtxt , Constant } ;
149
- use clippy_utils:: diagnostics:: { span_lint, span_lint_and_help } ;
151
+ use clippy_utils:: diagnostics:: span_lint;
150
152
use clippy_utils:: macros:: FormatArgsStorage ;
151
153
use clippy_utils:: msrvs:: { self , Msrv } ;
152
- use clippy_utils:: ty:: { contains_ty_adt_constructor_opaque, implements_trait , is_copy } ;
153
- use clippy_utils:: { contains_return, is_bool , is_trait_method, iter_input_pats, peel_blocks, return_ty, sym} ;
154
+ use clippy_utils:: ty:: contains_ty_adt_constructor_opaque;
155
+ use clippy_utils:: { contains_return, is_trait_method, iter_input_pats, peel_blocks, return_ty, sym} ;
154
156
pub use path_ends_with_ext:: DEFAULT_ALLOWED_DOTFILES ;
155
- use rustc_abi:: ExternAbi ;
156
157
use rustc_data_structures:: fx:: FxHashSet ;
157
158
use rustc_hir:: { self as hir, Expr , ExprKind , Node , Stmt , StmtKind , TraitItem , TraitItemKind } ;
158
159
use rustc_lint:: { LateContext , LateLintPass , LintContext } ;
159
- use rustc_middle:: ty:: { self , TraitRef , Ty } ;
160
+ use rustc_middle:: ty:: TraitRef ;
160
161
use rustc_session:: impl_lint_pass;
161
- use rustc_span:: { Span , Symbol , kw } ;
162
+ use rustc_span:: { Span , Symbol } ;
162
163
163
164
declare_clippy_lint ! {
164
165
/// ### What it does
@@ -4888,47 +4889,17 @@ impl<'tcx> LateLintPass<'tcx> for Methods {
4888
4889
if impl_item. span . in_external_macro ( cx. sess ( ) . source_map ( ) ) {
4889
4890
return ;
4890
4891
}
4892
+
4891
4893
if let hir:: ImplItemKind :: Fn ( ref sig, id) = impl_item. kind {
4892
- let name = impl_item. ident . name ;
4893
4894
let parent = cx. tcx . hir_get_parent_item ( impl_item. hir_id ( ) ) . def_id ;
4894
4895
let item = cx. tcx . hir_expect_item ( parent) ;
4895
4896
let self_ty = cx. tcx . type_of ( item. owner_id ) . instantiate_identity ( ) ;
4896
-
4897
4897
let implements_trait = matches ! ( item. kind, hir:: ItemKind :: Impl ( hir:: Impl { of_trait: Some ( _) , .. } ) ) ;
4898
+
4898
4899
let method_sig = cx. tcx . fn_sig ( impl_item. owner_id ) . instantiate_identity ( ) ;
4899
4900
let method_sig = cx. tcx . instantiate_bound_regions_with_erased ( method_sig) ;
4900
4901
let first_arg_ty_opt = method_sig. inputs ( ) . iter ( ) . next ( ) . copied ( ) ;
4901
- // if this impl block implements a trait, lint in trait definition instead
4902
- if !implements_trait && cx. effective_visibilities . is_exported ( impl_item. owner_id . def_id ) {
4903
- // check missing trait implementations
4904
- for method_config in & TRAIT_METHODS {
4905
- if name == method_config. method_name
4906
- && sig. decl . inputs . len ( ) == method_config. param_count
4907
- && method_config. output_type . matches ( & sig. decl . output )
4908
- // in case there is no first arg, since we already have checked the number of arguments
4909
- // it's should be always true
4910
- && first_arg_ty_opt
4911
- . is_none_or ( |first_arg_ty| method_config. self_kind . matches ( cx, self_ty, first_arg_ty) )
4912
- && fn_header_equals ( method_config. fn_header , sig. header )
4913
- && method_config. lifetime_param_cond ( impl_item)
4914
- {
4915
- span_lint_and_help (
4916
- cx,
4917
- SHOULD_IMPLEMENT_TRAIT ,
4918
- impl_item. span ,
4919
- format ! (
4920
- "method `{}` can be confused for the standard trait method `{}::{}`" ,
4921
- method_config. method_name, method_config. trait_name, method_config. method_name
4922
- ) ,
4923
- None ,
4924
- format ! (
4925
- "consider implementing the trait `{}` or choosing a less ambiguous method name" ,
4926
- method_config. trait_name
4927
- ) ,
4928
- ) ;
4929
- }
4930
- }
4931
- }
4902
+ should_implement_trait:: check_impl_item ( cx, impl_item, self_ty, implements_trait, first_arg_ty_opt, sig) ;
4932
4903
4933
4904
if sig. decl . implicit_self . has_implicit_self ( )
4934
4905
&& !( self . avoid_breaking_exported_api
@@ -4938,7 +4909,7 @@ impl<'tcx> LateLintPass<'tcx> for Methods {
4938
4909
{
4939
4910
wrong_self_convention:: check (
4940
4911
cx,
4941
- name,
4912
+ impl_item . ident . name ,
4942
4913
self_ty,
4943
4914
first_arg_ty,
4944
4915
first_arg. pat . span ,
@@ -5711,181 +5682,3 @@ fn lint_binary_expr_with_method_call(cx: &LateContext<'_>, info: &mut BinaryExpr
5711
5682
lint_with_both_lhs_and_rhs ! ( chars_next_cmp_with_unwrap:: check, cx, info) ;
5712
5683
lint_with_both_lhs_and_rhs ! ( chars_last_cmp_with_unwrap:: check, cx, info) ;
5713
5684
}
5714
-
5715
- const FN_HEADER : hir:: FnHeader = hir:: FnHeader {
5716
- safety : hir:: HeaderSafety :: Normal ( hir:: Safety :: Safe ) ,
5717
- constness : hir:: Constness :: NotConst ,
5718
- asyncness : hir:: IsAsync :: NotAsync ,
5719
- abi : ExternAbi :: Rust ,
5720
- } ;
5721
-
5722
- struct ShouldImplTraitCase {
5723
- trait_name : & ' static str ,
5724
- method_name : Symbol ,
5725
- param_count : usize ,
5726
- fn_header : hir:: FnHeader ,
5727
- // implicit self kind expected (none, self, &self, ...)
5728
- self_kind : SelfKind ,
5729
- // checks against the output type
5730
- output_type : OutType ,
5731
- // certain methods with explicit lifetimes can't implement the equivalent trait method
5732
- lint_explicit_lifetime : bool ,
5733
- }
5734
- impl ShouldImplTraitCase {
5735
- const fn new (
5736
- trait_name : & ' static str ,
5737
- method_name : Symbol ,
5738
- param_count : usize ,
5739
- fn_header : hir:: FnHeader ,
5740
- self_kind : SelfKind ,
5741
- output_type : OutType ,
5742
- lint_explicit_lifetime : bool ,
5743
- ) -> ShouldImplTraitCase {
5744
- ShouldImplTraitCase {
5745
- trait_name,
5746
- method_name,
5747
- param_count,
5748
- fn_header,
5749
- self_kind,
5750
- output_type,
5751
- lint_explicit_lifetime,
5752
- }
5753
- }
5754
-
5755
- fn lifetime_param_cond ( & self , impl_item : & hir:: ImplItem < ' _ > ) -> bool {
5756
- self . lint_explicit_lifetime
5757
- || !impl_item. generics . params . iter ( ) . any ( |p| {
5758
- matches ! (
5759
- p. kind,
5760
- hir:: GenericParamKind :: Lifetime {
5761
- kind: hir:: LifetimeParamKind :: Explicit
5762
- }
5763
- )
5764
- } )
5765
- }
5766
- }
5767
-
5768
- #[ rustfmt:: skip]
5769
- const TRAIT_METHODS : [ ShouldImplTraitCase ; 30 ] = [
5770
- ShouldImplTraitCase :: new ( "std::ops::Add" , sym:: add, 2 , FN_HEADER , SelfKind :: Value , OutType :: Any , true ) ,
5771
- ShouldImplTraitCase :: new ( "std::convert::AsMut" , sym:: as_mut, 1 , FN_HEADER , SelfKind :: RefMut , OutType :: Ref , true ) ,
5772
- ShouldImplTraitCase :: new ( "std::convert::AsRef" , sym:: as_ref, 1 , FN_HEADER , SelfKind :: Ref , OutType :: Ref , true ) ,
5773
- ShouldImplTraitCase :: new ( "std::ops::BitAnd" , sym:: bitand, 2 , FN_HEADER , SelfKind :: Value , OutType :: Any , true ) ,
5774
- ShouldImplTraitCase :: new ( "std::ops::BitOr" , sym:: bitor, 2 , FN_HEADER , SelfKind :: Value , OutType :: Any , true ) ,
5775
- ShouldImplTraitCase :: new ( "std::ops::BitXor" , sym:: bitxor, 2 , FN_HEADER , SelfKind :: Value , OutType :: Any , true ) ,
5776
- ShouldImplTraitCase :: new ( "std::borrow::Borrow" , sym:: borrow, 1 , FN_HEADER , SelfKind :: Ref , OutType :: Ref , true ) ,
5777
- ShouldImplTraitCase :: new ( "std::borrow::BorrowMut" , sym:: borrow_mut, 1 , FN_HEADER , SelfKind :: RefMut , OutType :: Ref , true ) ,
5778
- ShouldImplTraitCase :: new ( "std::clone::Clone" , sym:: clone, 1 , FN_HEADER , SelfKind :: Ref , OutType :: Any , true ) ,
5779
- ShouldImplTraitCase :: new ( "std::cmp::Ord" , sym:: cmp, 2 , FN_HEADER , SelfKind :: Ref , OutType :: Any , true ) ,
5780
- ShouldImplTraitCase :: new ( "std::default::Default" , kw:: Default , 0 , FN_HEADER , SelfKind :: No , OutType :: Any , true ) ,
5781
- ShouldImplTraitCase :: new ( "std::ops::Deref" , sym:: deref, 1 , FN_HEADER , SelfKind :: Ref , OutType :: Ref , true ) ,
5782
- ShouldImplTraitCase :: new ( "std::ops::DerefMut" , sym:: deref_mut, 1 , FN_HEADER , SelfKind :: RefMut , OutType :: Ref , true ) ,
5783
- ShouldImplTraitCase :: new ( "std::ops::Div" , sym:: div, 2 , FN_HEADER , SelfKind :: Value , OutType :: Any , true ) ,
5784
- ShouldImplTraitCase :: new ( "std::ops::Drop" , sym:: drop, 1 , FN_HEADER , SelfKind :: RefMut , OutType :: Unit , true ) ,
5785
- ShouldImplTraitCase :: new ( "std::cmp::PartialEq" , sym:: eq, 2 , FN_HEADER , SelfKind :: Ref , OutType :: Bool , true ) ,
5786
- ShouldImplTraitCase :: new ( "std::iter::FromIterator" , sym:: from_iter, 1 , FN_HEADER , SelfKind :: No , OutType :: Any , true ) ,
5787
- ShouldImplTraitCase :: new ( "std::str::FromStr" , sym:: from_str, 1 , FN_HEADER , SelfKind :: No , OutType :: Any , true ) ,
5788
- ShouldImplTraitCase :: new ( "std::hash::Hash" , sym:: hash, 2 , FN_HEADER , SelfKind :: Ref , OutType :: Unit , true ) ,
5789
- ShouldImplTraitCase :: new ( "std::ops::Index" , sym:: index, 2 , FN_HEADER , SelfKind :: Ref , OutType :: Ref , true ) ,
5790
- ShouldImplTraitCase :: new ( "std::ops::IndexMut" , sym:: index_mut, 2 , FN_HEADER , SelfKind :: RefMut , OutType :: Ref , true ) ,
5791
- ShouldImplTraitCase :: new ( "std::iter::IntoIterator" , sym:: into_iter, 1 , FN_HEADER , SelfKind :: Value , OutType :: Any , true ) ,
5792
- ShouldImplTraitCase :: new ( "std::ops::Mul" , sym:: mul, 2 , FN_HEADER , SelfKind :: Value , OutType :: Any , true ) ,
5793
- ShouldImplTraitCase :: new ( "std::ops::Neg" , sym:: neg, 1 , FN_HEADER , SelfKind :: Value , OutType :: Any , true ) ,
5794
- ShouldImplTraitCase :: new ( "std::iter::Iterator" , sym:: next, 1 , FN_HEADER , SelfKind :: RefMut , OutType :: Any , false ) ,
5795
- ShouldImplTraitCase :: new ( "std::ops::Not" , sym:: not, 1 , FN_HEADER , SelfKind :: Value , OutType :: Any , true ) ,
5796
- ShouldImplTraitCase :: new ( "std::ops::Rem" , sym:: rem, 2 , FN_HEADER , SelfKind :: Value , OutType :: Any , true ) ,
5797
- ShouldImplTraitCase :: new ( "std::ops::Shl" , sym:: shl, 2 , FN_HEADER , SelfKind :: Value , OutType :: Any , true ) ,
5798
- ShouldImplTraitCase :: new ( "std::ops::Shr" , sym:: shr, 2 , FN_HEADER , SelfKind :: Value , OutType :: Any , true ) ,
5799
- ShouldImplTraitCase :: new ( "std::ops::Sub" , sym:: sub, 2 , FN_HEADER , SelfKind :: Value , OutType :: Any , true ) ,
5800
- ] ;
5801
-
5802
- #[ derive( Clone , Copy , PartialEq , Eq , Debug ) ]
5803
- enum SelfKind {
5804
- Value ,
5805
- Ref ,
5806
- RefMut ,
5807
- No , // When we want the first argument type to be different than `Self`
5808
- }
5809
-
5810
- impl SelfKind {
5811
- fn matches < ' a > ( self , cx : & LateContext < ' a > , parent_ty : Ty < ' a > , ty : Ty < ' a > ) -> bool {
5812
- fn matches_value < ' a > ( cx : & LateContext < ' a > , parent_ty : Ty < ' a > , ty : Ty < ' a > ) -> bool {
5813
- if ty == parent_ty {
5814
- true
5815
- } else if let Some ( boxed_ty) = ty. boxed_ty ( ) {
5816
- boxed_ty == parent_ty
5817
- } else if let ty:: Adt ( adt, args) = ty. kind ( )
5818
- && matches ! ( cx. tcx. get_diagnostic_name( adt. did( ) ) , Some ( sym:: Rc | sym:: Arc ) )
5819
- {
5820
- args. types ( ) . next ( ) == Some ( parent_ty)
5821
- } else {
5822
- false
5823
- }
5824
- }
5825
-
5826
- fn matches_ref < ' a > ( cx : & LateContext < ' a > , mutability : hir:: Mutability , parent_ty : Ty < ' a > , ty : Ty < ' a > ) -> bool {
5827
- if let ty:: Ref ( _, t, m) = * ty. kind ( ) {
5828
- return m == mutability && t == parent_ty;
5829
- }
5830
-
5831
- let trait_sym = match mutability {
5832
- hir:: Mutability :: Not => sym:: AsRef ,
5833
- hir:: Mutability :: Mut => sym:: AsMut ,
5834
- } ;
5835
-
5836
- let Some ( trait_def_id) = cx. tcx . get_diagnostic_item ( trait_sym) else {
5837
- return false ;
5838
- } ;
5839
- implements_trait ( cx, ty, trait_def_id, & [ parent_ty. into ( ) ] )
5840
- }
5841
-
5842
- fn matches_none < ' a > ( cx : & LateContext < ' a > , parent_ty : Ty < ' a > , ty : Ty < ' a > ) -> bool {
5843
- !matches_value ( cx, parent_ty, ty)
5844
- && !matches_ref ( cx, hir:: Mutability :: Not , parent_ty, ty)
5845
- && !matches_ref ( cx, hir:: Mutability :: Mut , parent_ty, ty)
5846
- }
5847
-
5848
- match self {
5849
- Self :: Value => matches_value ( cx, parent_ty, ty) ,
5850
- Self :: Ref => matches_ref ( cx, hir:: Mutability :: Not , parent_ty, ty) || ty == parent_ty && is_copy ( cx, ty) ,
5851
- Self :: RefMut => matches_ref ( cx, hir:: Mutability :: Mut , parent_ty, ty) ,
5852
- Self :: No => matches_none ( cx, parent_ty, ty) ,
5853
- }
5854
- }
5855
-
5856
- #[ must_use]
5857
- fn description ( self ) -> & ' static str {
5858
- match self {
5859
- Self :: Value => "`self` by value" ,
5860
- Self :: Ref => "`self` by reference" ,
5861
- Self :: RefMut => "`self` by mutable reference" ,
5862
- Self :: No => "no `self`" ,
5863
- }
5864
- }
5865
- }
5866
-
5867
- #[ derive( Clone , Copy ) ]
5868
- enum OutType {
5869
- Unit ,
5870
- Bool ,
5871
- Any ,
5872
- Ref ,
5873
- }
5874
-
5875
- impl OutType {
5876
- fn matches ( self , ty : & hir:: FnRetTy < ' _ > ) -> bool {
5877
- let is_unit = |ty : & hir:: Ty < ' _ > | matches ! ( ty. kind, hir:: TyKind :: Tup ( & [ ] ) ) ;
5878
- match ( self , ty) {
5879
- ( Self :: Unit , & hir:: FnRetTy :: DefaultReturn ( _) ) => true ,
5880
- ( Self :: Unit , & hir:: FnRetTy :: Return ( ty) ) if is_unit ( ty) => true ,
5881
- ( Self :: Bool , & hir:: FnRetTy :: Return ( ty) ) if is_bool ( ty) => true ,
5882
- ( Self :: Any , & hir:: FnRetTy :: Return ( ty) ) if !is_unit ( ty) => true ,
5883
- ( Self :: Ref , & hir:: FnRetTy :: Return ( ty) ) => matches ! ( ty. kind, hir:: TyKind :: Ref ( _, _) ) ,
5884
- _ => false ,
5885
- }
5886
- }
5887
- }
5888
-
5889
- fn fn_header_equals ( expected : hir:: FnHeader , actual : hir:: FnHeader ) -> bool {
5890
- expected. constness == actual. constness && expected. safety == actual. safety && expected. asyncness == actual. asyncness
5891
- }
0 commit comments