1
- use rustc:: lint:: { LateContext , LateLintPass , LintArray , LintPass } ;
2
- use rustc:: hir:: * ;
3
- use rustc:: hir:: intravisit:: { walk_path, NestedVisitorMap , Visitor } ;
4
1
use crate :: utils:: { in_macro, span_lint_and_then} ;
2
+ use rustc:: hir:: intravisit:: { walk_path, walk_ty, NestedVisitorMap , Visitor } ;
3
+ use rustc:: hir:: * ;
4
+ use rustc:: lint:: { LateContext , LateLintPass , LintArray , LintPass } ;
5
+ use rustc:: ty;
5
6
use syntax:: ast:: NodeId ;
7
+ use syntax:: symbol:: keywords;
6
8
use syntax_pos:: symbol:: keywords:: SelfType ;
7
9
8
10
/// **What it does:** Checks for unnecessary repetition of structure name when a
@@ -49,13 +51,93 @@ impl LintPass for UseSelf {
49
51
50
52
const SEGMENTS_MSG : & str = "segments should be composed of at least 1 element" ;
51
53
54
+ fn span_use_self_lint ( cx : & LateContext , path : & Path ) {
55
+ span_lint_and_then ( cx, USE_SELF , path. span , "unnecessary structure name repetition" , |db| {
56
+ db. span_suggestion ( path. span , "use the applicable keyword" , "Self" . to_owned ( ) ) ;
57
+ } ) ;
58
+ }
59
+
60
+ struct TraitImplTyVisitor < ' a , ' tcx : ' a > {
61
+ cx : & ' a LateContext < ' a , ' tcx > ,
62
+ type_walker : ty:: walk:: TypeWalker < ' tcx > ,
63
+ }
64
+
65
+ impl < ' a , ' tcx > Visitor < ' tcx > for TraitImplTyVisitor < ' a , ' tcx > {
66
+ fn visit_ty ( & mut self , t : & ' tcx Ty ) {
67
+ let trait_ty = self . type_walker . next ( ) ;
68
+ if let TyPath ( QPath :: Resolved ( _, path) ) = & t. node {
69
+ let impl_is_self_ty = if let def:: Def :: SelfTy ( ..) = path. def {
70
+ true
71
+ } else {
72
+ false
73
+ } ;
74
+ if !impl_is_self_ty {
75
+ let trait_is_self_ty = if let Some ( ty:: TyParam ( ty:: ParamTy { name, .. } ) ) = trait_ty. map ( |ty| & ty. sty ) {
76
+ * name == keywords:: SelfType . name ( ) . as_str ( )
77
+ } else {
78
+ false
79
+ } ;
80
+ if trait_is_self_ty {
81
+ span_use_self_lint ( self . cx , path) ;
82
+ }
83
+ }
84
+ }
85
+ walk_ty ( self , t)
86
+ }
87
+
88
+ fn nested_visit_map < ' this > ( & ' this mut self ) -> NestedVisitorMap < ' this , ' tcx > {
89
+ NestedVisitorMap :: None
90
+ }
91
+ }
92
+
93
+ fn check_trait_method_impl_decl < ' a , ' tcx : ' a > (
94
+ cx : & ' a LateContext < ' a , ' tcx > ,
95
+ impl_item : & ImplItem ,
96
+ impl_decl : & ' tcx FnDecl ,
97
+ impl_trait_ref : & ty:: TraitRef ,
98
+ ) {
99
+ let trait_method = cx
100
+ . tcx
101
+ . associated_items ( impl_trait_ref. def_id )
102
+ . find ( |assoc_item| {
103
+ assoc_item. kind == ty:: AssociatedKind :: Method
104
+ && cx
105
+ . tcx
106
+ . hygienic_eq ( impl_item. ident , assoc_item. ident , impl_trait_ref. def_id )
107
+ } )
108
+ . expect ( "impl method matches a trait method" ) ;
109
+
110
+ let trait_method_sig = cx. tcx . fn_sig ( trait_method. def_id ) ;
111
+ let trait_method_sig = cx. tcx . erase_late_bound_regions ( & trait_method_sig) ;
112
+
113
+ let output_ty = if let FunctionRetTy :: Return ( ty) = & impl_decl. output {
114
+ Some ( & * * ty)
115
+ } else {
116
+ None
117
+ } ;
118
+
119
+ for ( impl_ty, trait_ty) in impl_decl
120
+ . inputs
121
+ . iter ( )
122
+ . chain ( output_ty)
123
+ . zip ( trait_method_sig. inputs_and_output )
124
+ {
125
+ let mut visitor = TraitImplTyVisitor {
126
+ cx,
127
+ type_walker : trait_ty. walk ( ) ,
128
+ } ;
129
+
130
+ visitor. visit_ty ( & impl_ty) ;
131
+ }
132
+ }
133
+
52
134
impl < ' a , ' tcx > LateLintPass < ' a , ' tcx > for UseSelf {
53
135
fn check_item ( & mut self , cx : & LateContext < ' a , ' tcx > , item : & ' tcx Item ) {
54
136
if in_macro ( item. span ) {
55
137
return ;
56
138
}
57
139
if_chain ! {
58
- if let ItemImpl ( .., ref item_type, ref refs) = item. node;
140
+ if let ItemImpl ( .., item_type, refs) = & item. node;
59
141
if let Ty_ :: TyPath ( QPath :: Resolved ( _, ref item_path) ) = item_type. node;
60
142
then {
61
143
let parameters = & item_path. segments. last( ) . expect( SEGMENTS_MSG ) . args;
@@ -67,13 +149,32 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UseSelf {
67
149
} else {
68
150
true
69
151
} ;
152
+
70
153
if should_check {
71
154
let visitor = & mut UseSelfVisitor {
72
155
item_path,
73
156
cx,
74
157
} ;
75
- for impl_item_ref in refs {
76
- visitor. visit_impl_item( cx. tcx. hir. impl_item( impl_item_ref. id) ) ;
158
+ let impl_def_id = cx. tcx. hir. local_def_id( item. id) ;
159
+ let impl_trait_ref = cx. tcx. impl_trait_ref( impl_def_id) ;
160
+
161
+ if let Some ( impl_trait_ref) = impl_trait_ref {
162
+ for impl_item_ref in refs {
163
+ let impl_item = cx. tcx. hir. impl_item( impl_item_ref. id) ;
164
+ if let ImplItemKind :: Method ( MethodSig { decl: impl_decl, .. } , impl_body_id)
165
+ = & impl_item. node {
166
+ check_trait_method_impl_decl( cx, impl_item, impl_decl, & impl_trait_ref) ;
167
+ let body = cx. tcx. hir. body( * impl_body_id) ;
168
+ visitor. visit_body( body) ;
169
+ } else {
170
+ visitor. visit_impl_item( impl_item) ;
171
+ }
172
+ }
173
+ } else {
174
+ for impl_item_ref in refs {
175
+ let impl_item = cx. tcx. hir. impl_item( impl_item_ref. id) ;
176
+ visitor. visit_impl_item( impl_item) ;
177
+ }
77
178
}
78
179
}
79
180
}
@@ -89,9 +190,7 @@ struct UseSelfVisitor<'a, 'tcx: 'a> {
89
190
impl < ' a , ' tcx > Visitor < ' tcx > for UseSelfVisitor < ' a , ' tcx > {
90
191
fn visit_path ( & mut self , path : & ' tcx Path , _id : NodeId ) {
91
192
if self . item_path . def == path. def && path. segments . last ( ) . expect ( SEGMENTS_MSG ) . ident . name != SelfType . name ( ) {
92
- span_lint_and_then ( self . cx , USE_SELF , path. span , "unnecessary structure name repetition" , |db| {
93
- db. span_suggestion ( path. span , "use the applicable keyword" , "Self" . to_owned ( ) ) ;
94
- } ) ;
193
+ span_use_self_lint ( self . cx , path) ;
95
194
}
96
195
97
196
walk_path ( self , path) ;
0 commit comments