1
- use rustc:: lint:: { LateContext , LateLintPass , LintArray , LintPass } ;
2
- use rustc:: { declare_lint, lint_array} ;
1
+ use crate :: utils:: { in_macro, span_lint_and_sugg} ;
3
2
use if_chain:: if_chain;
3
+ use rustc:: hir:: intravisit:: { walk_path, walk_ty, NestedVisitorMap , Visitor } ;
4
4
use rustc:: hir:: * ;
5
- use rustc:: hir:: intravisit:: { walk_path, NestedVisitorMap , Visitor } ;
6
- use crate :: utils:: { in_macro, span_lint_and_then} ;
5
+ use rustc:: lint:: { LateContext , LateLintPass , LintArray , LintPass } ;
6
+ use rustc:: ty;
7
+ use rustc:: { declare_lint, lint_array} ;
7
8
use syntax:: ast:: NodeId ;
8
9
use syntax_pos:: symbol:: keywords:: SelfType ;
9
10
@@ -51,6 +52,105 @@ impl LintPass for UseSelf {
51
52
52
53
const SEGMENTS_MSG : & str = "segments should be composed of at least 1 element" ;
53
54
55
+ fn span_use_self_lint ( cx : & LateContext < ' _ , ' _ > , path : & Path ) {
56
+ span_lint_and_sugg (
57
+ cx,
58
+ USE_SELF ,
59
+ path. span ,
60
+ "unnecessary structure name repetition" ,
61
+ "use the applicable keyword" ,
62
+ "Self" . to_owned ( ) ,
63
+ ) ;
64
+ }
65
+
66
+ struct TraitImplTyVisitor < ' a , ' tcx : ' a > {
67
+ item_path : & ' a Path ,
68
+ cx : & ' a LateContext < ' a , ' tcx > ,
69
+ trait_type_walker : ty:: walk:: TypeWalker < ' tcx > ,
70
+ impl_type_walker : ty:: walk:: TypeWalker < ' tcx > ,
71
+ }
72
+
73
+ impl < ' a , ' tcx > Visitor < ' tcx > for TraitImplTyVisitor < ' a , ' tcx > {
74
+ fn visit_ty ( & mut self , t : & ' tcx Ty ) {
75
+ let trait_ty = self . trait_type_walker . next ( ) ;
76
+ let impl_ty = self . impl_type_walker . next ( ) ;
77
+
78
+ if let TyKind :: Path ( QPath :: Resolved ( _, path) ) = & t. node {
79
+ if self . item_path . def == path. def {
80
+ let is_self_ty = if let def:: Def :: SelfTy ( ..) = path. def {
81
+ true
82
+ } else {
83
+ false
84
+ } ;
85
+
86
+ if !is_self_ty && impl_ty != trait_ty {
87
+ // The implementation and trait types don't match which means that
88
+ // the concrete type was specified by the implementation but
89
+ // it didn't use `Self`
90
+ span_use_self_lint ( self . cx , path) ;
91
+ }
92
+ }
93
+ }
94
+ walk_ty ( self , t)
95
+ }
96
+
97
+ fn nested_visit_map < ' this > ( & ' this mut self ) -> NestedVisitorMap < ' this , ' tcx > {
98
+ NestedVisitorMap :: None
99
+ }
100
+ }
101
+
102
+ fn check_trait_method_impl_decl < ' a , ' tcx : ' a > (
103
+ cx : & ' a LateContext < ' a , ' tcx > ,
104
+ item_path : & ' a Path ,
105
+ impl_item : & ImplItem ,
106
+ impl_decl : & ' tcx FnDecl ,
107
+ impl_trait_ref : & ty:: TraitRef < ' _ > ,
108
+ ) {
109
+ let trait_method = cx
110
+ . tcx
111
+ . associated_items ( impl_trait_ref. def_id )
112
+ . find ( |assoc_item| {
113
+ assoc_item. kind == ty:: AssociatedKind :: Method
114
+ && cx
115
+ . tcx
116
+ . hygienic_eq ( impl_item. ident , assoc_item. ident , impl_trait_ref. def_id )
117
+ } )
118
+ . expect ( "impl method matches a trait method" ) ;
119
+
120
+ let trait_method_sig = cx. tcx . fn_sig ( trait_method. def_id ) ;
121
+ let trait_method_sig = cx. tcx . erase_late_bound_regions ( & trait_method_sig) ;
122
+
123
+ let impl_method_def_id = cx. tcx . hir . local_def_id ( impl_item. id ) ;
124
+ let impl_method_sig = cx. tcx . fn_sig ( impl_method_def_id) ;
125
+ let impl_method_sig = cx. tcx . erase_late_bound_regions ( & impl_method_sig) ;
126
+
127
+ let output_ty = if let FunctionRetTy :: Return ( ty) = & impl_decl. output {
128
+ Some ( & * * ty)
129
+ } else {
130
+ None
131
+ } ;
132
+
133
+ // `impl_decl_ty` (of type `hir::Ty`) represents the type declared in the signature.
134
+ // `impl_ty` (of type `ty:TyS`) is the concrete type that the compiler has determined for
135
+ // that declaration. We use `impl_decl_ty` to see if the type was declared as `Self`
136
+ // and use `impl_ty` to check its concrete type.
137
+ for ( impl_decl_ty, ( impl_ty, trait_ty) ) in impl_decl. inputs . iter ( ) . chain ( output_ty) . zip (
138
+ impl_method_sig
139
+ . inputs_and_output
140
+ . iter ( )
141
+ . zip ( trait_method_sig. inputs_and_output ) ,
142
+ ) {
143
+ let mut visitor = TraitImplTyVisitor {
144
+ cx,
145
+ item_path,
146
+ trait_type_walker : trait_ty. walk ( ) ,
147
+ impl_type_walker : impl_ty. walk ( ) ,
148
+ } ;
149
+
150
+ visitor. visit_ty ( & impl_decl_ty) ;
151
+ }
152
+ }
153
+
54
154
impl < ' a , ' tcx > LateLintPass < ' a , ' tcx > for UseSelf {
55
155
fn check_item ( & mut self , cx : & LateContext < ' a , ' tcx > , item : & ' tcx Item ) {
56
156
if in_macro ( item. span ) {
@@ -69,13 +169,32 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UseSelf {
69
169
} else {
70
170
true
71
171
} ;
172
+
72
173
if should_check {
73
174
let visitor = & mut UseSelfVisitor {
74
175
item_path,
75
176
cx,
76
177
} ;
77
- for impl_item_ref in refs {
78
- visitor. visit_impl_item( cx. tcx. hir. impl_item( impl_item_ref. id) ) ;
178
+ let impl_def_id = cx. tcx. hir. local_def_id( item. id) ;
179
+ let impl_trait_ref = cx. tcx. impl_trait_ref( impl_def_id) ;
180
+
181
+ if let Some ( impl_trait_ref) = impl_trait_ref {
182
+ for impl_item_ref in refs {
183
+ let impl_item = cx. tcx. hir. impl_item( impl_item_ref. id) ;
184
+ if let ImplItemKind :: Method ( MethodSig { decl: impl_decl, .. } , impl_body_id)
185
+ = & impl_item. node {
186
+ check_trait_method_impl_decl( cx, item_path, impl_item, impl_decl, & impl_trait_ref) ;
187
+ let body = cx. tcx. hir. body( * impl_body_id) ;
188
+ visitor. visit_body( body) ;
189
+ } else {
190
+ visitor. visit_impl_item( impl_item) ;
191
+ }
192
+ }
193
+ } else {
194
+ for impl_item_ref in refs {
195
+ let impl_item = cx. tcx. hir. impl_item( impl_item_ref. id) ;
196
+ visitor. visit_impl_item( impl_item) ;
197
+ }
79
198
}
80
199
}
81
200
}
@@ -91,9 +210,7 @@ struct UseSelfVisitor<'a, 'tcx: 'a> {
91
210
impl < ' a , ' tcx > Visitor < ' tcx > for UseSelfVisitor < ' a , ' tcx > {
92
211
fn visit_path ( & mut self , path : & ' tcx Path , _id : NodeId ) {
93
212
if self . item_path . def == path. def && path. segments . last ( ) . expect ( SEGMENTS_MSG ) . ident . name != SelfType . name ( ) {
94
- span_lint_and_then ( self . cx , USE_SELF , path. span , "unnecessary structure name repetition" , |db| {
95
- db. span_suggestion ( path. span , "use the applicable keyword" , "Self" . to_owned ( ) ) ;
96
- } ) ;
213
+ span_use_self_lint ( self . cx , path) ;
97
214
}
98
215
99
216
walk_path ( self , path) ;
0 commit comments