1
- use rustc_hir:: { def :: DefKind , Body , Item , ItemKind , Node , Path , QPath , TyKind } ;
1
+ use rustc_hir:: { Body , Item , ItemKind , OwnerNode , Path , QPath , TyKind } ;
2
2
use rustc_span:: def_id:: { DefId , LOCAL_CRATE } ;
3
- use rustc_span:: { sym, symbol:: kw, ExpnKind , MacroKind } ;
4
-
5
- use smallvec:: { smallvec, SmallVec } ;
3
+ use rustc_span:: { sym, symbol:: kw, symbol:: Ident , ExpnKind , MacroKind } ;
6
4
7
5
use crate :: lints:: { NonLocalDefinitionsCargoUpdateNote , NonLocalDefinitionsDiag } ;
8
6
use crate :: { LateContext , LateLintPass , LintContext } ;
@@ -67,17 +65,14 @@ impl<'tcx> LateLintPass<'tcx> for NonLocalDefinitions {
67
65
return ;
68
66
}
69
67
70
- let parent = cx. tcx . parent ( item. owner_id . def_id . into ( ) ) ;
71
- let parent_def_kind = cx. tcx . def_kind ( parent) ;
72
- let parent_opt_item_name = cx. tcx . opt_item_name ( parent) ;
73
-
74
- // Per RFC we (currently) ignore anon-const (`const _: Ty = ...`) in top-level module.
75
- if self . body_depth == 1
76
- && parent_def_kind == DefKind :: Const
77
- && parent_opt_item_name == Some ( kw:: Underscore )
78
- {
79
- return ;
80
- }
68
+ let mut parent_node = {
69
+ let mut parent_node_cache = None ;
70
+ move || {
71
+ * parent_node_cache. get_or_insert_with ( || {
72
+ cx. tcx . hir ( ) . parent_owner_iter ( item. hir_id ( ) ) . next ( ) . unwrap ( ) . 1
73
+ } )
74
+ }
75
+ } ;
81
76
82
77
let cargo_update = || {
83
78
let oexpn = item. span . ctxt ( ) . outer_expn_data ( ) ;
@@ -112,26 +107,50 @@ impl<'tcx> LateLintPass<'tcx> for NonLocalDefinitions {
112
107
// If that's the case this means that this impl block declaration
113
108
// is using local items and so we don't lint on it.
114
109
115
- // We also ignore anon-const in item by including the anon-const
116
- // parent as well; and since it's quite uncommon, we use smallvec
117
- // to avoid unnecessary heap allocations.
118
- let local_parents: SmallVec < [ DefId ; 1 ] > = if parent_def_kind == DefKind :: Const
119
- && parent_opt_item_name == Some ( kw:: Underscore )
120
- {
121
- smallvec ! [ parent, cx. tcx. parent( parent) ]
122
- } else {
123
- smallvec ! [ parent]
110
+ let mut parent_node_is_anon_const = {
111
+ let mut parent_node_is_anon_const = None ;
112
+ move || {
113
+ * parent_node_is_anon_const. get_or_insert_with ( || {
114
+ matches ! (
115
+ parent_node( ) ,
116
+ OwnerNode :: Item ( Item {
117
+ ident: Ident { name: kw:: Underscore , .. } ,
118
+ kind: ItemKind :: Const ( ..) ,
119
+ ..
120
+ } )
121
+ )
122
+ } )
123
+ }
124
+ } ;
125
+ let mut local_parent = {
126
+ let mut local_parent_cache = None ;
127
+ move || {
128
+ * local_parent_cache
129
+ . get_or_insert_with ( || cx. tcx . parent ( item. owner_id . to_def_id ( ) ) )
130
+ }
131
+ } ;
132
+ let mut extra_local_parent = {
133
+ let mut extra_parent_cache = None ;
134
+ move |did| {
135
+ * extra_parent_cache. get_or_insert_with ( || {
136
+ parent_node_is_anon_const ( ) . then ( || cx. tcx . parent ( did) )
137
+ } )
138
+ }
124
139
} ;
125
140
126
141
let self_ty_has_local_parent = match impl_. self_ty . kind {
127
- TyKind :: Path ( QPath :: Resolved ( _, ty_path) ) => {
128
- path_has_local_parent ( ty_path, cx, & * local_parents)
129
- }
142
+ TyKind :: Path ( QPath :: Resolved ( _, ty_path) ) => path_has_local_parent (
143
+ ty_path,
144
+ cx,
145
+ & mut local_parent,
146
+ & mut extra_local_parent,
147
+ ) ,
130
148
TyKind :: TraitObject ( [ principle_poly_trait_ref, ..] , _, _) => {
131
149
path_has_local_parent (
132
150
principle_poly_trait_ref. trait_ref . path ,
133
151
cx,
134
- & * local_parents,
152
+ & mut local_parent,
153
+ & mut extra_local_parent,
135
154
)
136
155
}
137
156
TyKind :: TraitObject ( [ ] , _, _)
@@ -153,17 +172,26 @@ impl<'tcx> LateLintPass<'tcx> for NonLocalDefinitions {
153
172
154
173
let of_trait_has_local_parent = impl_
155
174
. of_trait
156
- . map ( |of_trait| path_has_local_parent ( of_trait. path , cx, & * local_parents) )
175
+ . map ( |of_trait| {
176
+ path_has_local_parent (
177
+ of_trait. path ,
178
+ cx,
179
+ & mut local_parent,
180
+ & mut extra_local_parent,
181
+ )
182
+ } )
157
183
. unwrap_or ( false ) ;
158
184
159
185
// If none of them have a local parent (LOGICAL NOR) this means that
160
186
// this impl definition is a non-local definition and so we lint on it.
161
187
if !( self_ty_has_local_parent || of_trait_has_local_parent) {
188
+ // Per RFC we (currently) ignore anon-const (`const _: Ty = ...`) in top-level module.
189
+ if parent_node_is_anon_const ( ) && self . body_depth == 1 {
190
+ return ;
191
+ }
192
+
162
193
let const_anon = if self . body_depth == 1
163
- && parent_def_kind == DefKind :: Const
164
- && parent_opt_item_name != Some ( kw:: Underscore )
165
- && let Some ( parent) = parent. as_local ( )
166
- && let Node :: Item ( item) = cx. tcx . hir_node_by_def_id ( parent)
194
+ && let OwnerNode :: Item ( item) = parent_node ( )
167
195
&& let ItemKind :: Const ( ty, _, _) = item. kind
168
196
&& let TyKind :: Tup ( & [ ] ) = ty. kind
169
197
{
@@ -177,9 +205,10 @@ impl<'tcx> LateLintPass<'tcx> for NonLocalDefinitions {
177
205
item. span ,
178
206
NonLocalDefinitionsDiag :: Impl {
179
207
depth : self . body_depth ,
180
- body_kind_descr : cx. tcx . def_kind_descr ( parent_def_kind, parent) ,
181
- body_name : parent_opt_item_name
182
- . map ( |s| s. to_ident_string ( ) )
208
+ body_kind_descr : "?" /* FIXME: cx.tcx.def_kind_descr(parent_def_kind, parent) */ ,
209
+ body_name : parent_node ( )
210
+ . ident ( )
211
+ . map ( |s| s. name . to_ident_string ( ) )
183
212
. unwrap_or_else ( || "<unnameable>" . to_string ( ) ) ,
184
213
cargo_update : cargo_update ( ) ,
185
214
const_anon,
@@ -195,9 +224,10 @@ impl<'tcx> LateLintPass<'tcx> for NonLocalDefinitions {
195
224
item. span ,
196
225
NonLocalDefinitionsDiag :: MacroRules {
197
226
depth : self . body_depth ,
198
- body_kind_descr : cx. tcx . def_kind_descr ( parent_def_kind, parent) ,
199
- body_name : parent_opt_item_name
200
- . map ( |s| s. to_ident_string ( ) )
227
+ body_kind_descr : "?" /* FIXME: cx.tcx.def_kind_descr(parent_def_kind, parent) */ ,
228
+ body_name : parent_node ( )
229
+ . ident ( )
230
+ . map ( |s| s. name . to_ident_string ( ) )
201
231
. unwrap_or_else ( || "<unnameable>" . to_string ( ) ) ,
202
232
cargo_update : cargo_update ( ) ,
203
233
} ,
@@ -217,6 +247,20 @@ impl<'tcx> LateLintPass<'tcx> for NonLocalDefinitions {
217
247
/// std::convert::PartialEq<Foo<Bar>>
218
248
/// ^^^^^^^^^^^^^^^^^^^^^^^
219
249
/// ```
220
- fn path_has_local_parent ( path : & Path < ' _ > , cx : & LateContext < ' _ > , local_parents : & [ DefId ] ) -> bool {
221
- path. res . opt_def_id ( ) . is_some_and ( |did| local_parents. contains ( & cx. tcx . parent ( did) ) )
250
+ fn path_has_local_parent (
251
+ path : & Path < ' _ > ,
252
+ cx : & LateContext < ' _ > ,
253
+ local_parent : & mut impl FnMut ( ) -> DefId ,
254
+ extra_local_parent : & mut impl FnMut ( DefId ) -> Option < DefId > ,
255
+ ) -> bool {
256
+ if let Some ( did) = path. res . opt_def_id ( ) {
257
+ if !did. is_local ( ) {
258
+ false
259
+ } else {
260
+ let res_parent = cx. tcx . parent ( did) ;
261
+ res_parent == local_parent ( ) || Some ( res_parent) == extra_local_parent ( local_parent ( ) )
262
+ }
263
+ } else {
264
+ true
265
+ }
222
266
}
0 commit comments