@@ -14,6 +14,7 @@ use rustc_middle::ty;
1414use rustc_middle:: ty:: { DefIdTree , Ty } ;
1515use rustc_session:: { declare_lint_pass, declare_tool_lint} ;
1616use rustc_span:: symbol:: kw;
17+ use rustc_typeck:: hir_ty_to_ty;
1718
1819use crate :: utils:: { differing_macro_contexts, span_lint_and_sugg} ;
1920
@@ -80,37 +81,28 @@ fn span_use_self_lint(cx: &LateContext<'_, '_>, path: &Path<'_>, last_segment: O
8081 ) ;
8182}
8283
83- struct TraitImplTyVisitor < ' a , ' tcx > {
84- item_type : Ty < ' tcx > ,
84+ // FIXME: always use this (more correct) visitor, not just in method signatures.
85+ struct SemanticUseSelfVisitor < ' a , ' tcx > {
8586 cx : & ' a LateContext < ' a , ' tcx > ,
86- trait_type_walker : ty:: walk:: TypeWalker < ' tcx > ,
87- impl_type_walker : ty:: walk:: TypeWalker < ' tcx > ,
87+ self_ty : Ty < ' tcx > ,
8888}
8989
90- impl < ' a , ' tcx > Visitor < ' tcx > for TraitImplTyVisitor < ' a , ' tcx > {
90+ impl < ' a , ' tcx > Visitor < ' tcx > for SemanticUseSelfVisitor < ' a , ' tcx > {
9191 type Map = Map < ' tcx > ;
9292
93- fn visit_ty ( & mut self , t : & ' tcx hir:: Ty < ' _ > ) {
94- let trait_ty = self . trait_type_walker . next ( ) ;
95- let impl_ty = self . impl_type_walker . next ( ) ;
96-
97- if_chain ! {
98- if let TyKind :: Path ( QPath :: Resolved ( _, path) ) = & t. kind;
99-
100- // The implementation and trait types don't match which means that
101- // the concrete type was specified by the implementation
102- if impl_ty != trait_ty;
103- if let Some ( impl_ty) = impl_ty;
104- if self . item_type == impl_ty;
105- then {
106- match path. res {
107- def:: Res :: SelfTy ( ..) => { } ,
108- _ => span_use_self_lint( self . cx, path, None )
109- }
93+ fn visit_ty ( & mut self , hir_ty : & ' tcx hir:: Ty < ' _ > ) {
94+ if let TyKind :: Path ( QPath :: Resolved ( _, path) ) = & hir_ty. kind {
95+ match path. res {
96+ def:: Res :: SelfTy ( ..) => { } ,
97+ _ => {
98+ if hir_ty_to_ty ( self . cx . tcx , hir_ty) == self . self_ty {
99+ span_use_self_lint ( self . cx , path, None ) ;
100+ }
101+ } ,
110102 }
111103 }
112104
113- walk_ty ( self , t )
105+ walk_ty ( self , hir_ty )
114106 }
115107
116108 fn nested_visit_map ( & mut self ) -> NestedVisitorMap < Self :: Map > {
@@ -120,10 +112,9 @@ impl<'a, 'tcx> Visitor<'tcx> for TraitImplTyVisitor<'a, 'tcx> {
120112
121113fn check_trait_method_impl_decl < ' a , ' tcx > (
122114 cx : & ' a LateContext < ' a , ' tcx > ,
123- item_type : Ty < ' tcx > ,
124115 impl_item : & ImplItem < ' _ > ,
125116 impl_decl : & ' tcx FnDecl < ' _ > ,
126- impl_trait_ref : & ty:: TraitRef < ' _ > ,
117+ impl_trait_ref : ty:: TraitRef < ' tcx > ,
127118) {
128119 let trait_method = cx
129120 . tcx
@@ -134,34 +125,35 @@ fn check_trait_method_impl_decl<'a, 'tcx>(
134125 let trait_method_sig = cx. tcx . fn_sig ( trait_method. def_id ) ;
135126 let trait_method_sig = cx. tcx . erase_late_bound_regions ( & trait_method_sig) ;
136127
137- let impl_method_def_id = cx. tcx . hir ( ) . local_def_id ( impl_item. hir_id ) ;
138- let impl_method_sig = cx. tcx . fn_sig ( impl_method_def_id) ;
139- let impl_method_sig = cx. tcx . erase_late_bound_regions ( & impl_method_sig) ;
140-
141- let output_ty = if let FnRetTy :: Return ( ty) = & impl_decl. output {
128+ let output_hir_ty = if let FnRetTy :: Return ( ty) = & impl_decl. output {
142129 Some ( & * * ty)
143130 } else {
144131 None
145132 } ;
146133
147- // `impl_decl_ty` (of type `hir::Ty`) represents the type declared in the signature.
148- // `impl_ty` (of type `ty:TyS`) is the concrete type that the compiler has determined for
149- // that declaration. We use `impl_decl_ty` to see if the type was declared as `Self`
150- // and use `impl_ty` to check its concrete type.
151- for ( impl_decl_ty, ( impl_ty, trait_ty) ) in impl_decl. inputs . iter ( ) . chain ( output_ty) . zip (
152- impl_method_sig
153- . inputs_and_output
154- . iter ( )
155- . zip ( trait_method_sig. inputs_and_output ) ,
156- ) {
157- let mut visitor = TraitImplTyVisitor {
158- cx,
159- item_type,
160- trait_type_walker : trait_ty. walk ( ) ,
161- impl_type_walker : impl_ty. walk ( ) ,
162- } ;
163-
164- visitor. visit_ty ( & impl_decl_ty) ;
134+ // `impl_hir_ty` (of type `hir::Ty`) represents the type written in the signature.
135+ // `trait_ty` (of type `ty::Ty`) is the semantic type for the signature in the trait.
136+ // We use `impl_hir_ty` to see if the type was written as `Self`,
137+ // `hir_ty_to_ty(...)` to check semantic types of paths, and
138+ // `trait_ty` to determine which parts of the signature in the trait, mention
139+ // the type being implemented verbatim (as opposed to `Self`).
140+ for ( impl_hir_ty, trait_ty) in impl_decl
141+ . inputs
142+ . iter ( )
143+ . chain ( output_hir_ty)
144+ . zip ( trait_method_sig. inputs_and_output )
145+ {
146+ // Check if the input/output type in the trait method specifies the implemented
147+ // type verbatim, and only suggest `Self` if that isn't the case.
148+ // This avoids suggestions to e.g. replace `Vec<u8>` with `Vec<Self>`,
149+ // in an `impl Trait for u8`, when the trait always uses `Vec<u8>`.
150+ // See also https://github.com/rust-lang/rust-clippy/issues/2894.
151+ let self_ty = impl_trait_ref. self_ty ( ) ;
152+ if !trait_ty. walk ( ) . any ( |inner| inner == self_ty. into ( ) ) {
153+ let mut visitor = SemanticUseSelfVisitor { cx, self_ty } ;
154+
155+ visitor. visit_ty ( & impl_hir_ty) ;
156+ }
165157 }
166158}
167159
@@ -197,8 +189,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UseSelf {
197189 let impl_item = cx. tcx. hir( ) . impl_item( impl_item_ref. id) ;
198190 if let ImplItemKind :: Fn ( FnSig { decl: impl_decl, .. } , impl_body_id)
199191 = & impl_item. kind {
200- let item_type = cx. tcx. type_of( impl_def_id) ;
201- check_trait_method_impl_decl( cx, item_type, impl_item, impl_decl, & impl_trait_ref) ;
192+ check_trait_method_impl_decl( cx, impl_item, impl_decl, impl_trait_ref) ;
202193
203194 let body = cx. tcx. hir( ) . body( * impl_body_id) ;
204195 visitor. visit_body( body) ;
0 commit comments