1
- use rustc_hir:: { def:: DefKind , Body , Item , ItemKind , Node , Path , QPath , TyKind } ;
2
- use rustc_span:: def_id:: { DefId , LOCAL_CRATE } ;
3
- use rustc_span:: { sym, symbol:: kw, ExpnKind , MacroKind } ;
4
-
5
- use smallvec:: { smallvec, SmallVec } ;
1
+ use rustc_hir:: def_id:: LocalDefId ;
2
+ use rustc_hir:: { Body , Item , ItemKind , OwnerId , OwnerNode , Path , QPath , TyKind } ;
3
+ use rustc_span:: def_id:: LOCAL_CRATE ;
4
+ use rustc_span:: { sym, symbol:: kw, symbol:: Ident , ExpnKind , MacroKind } ;
6
5
7
6
use crate :: lints:: { NonLocalDefinitionsCargoUpdateNote , NonLocalDefinitionsDiag } ;
8
7
use crate :: { LateContext , LateLintPass , LintContext } ;
@@ -67,17 +66,16 @@ impl<'tcx> LateLintPass<'tcx> for NonLocalDefinitions {
67
66
return ;
68
67
}
69
68
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
- }
69
+ let mut parent_owner = {
70
+ let mut parent_owner_cache = None ;
71
+ move || {
72
+ * parent_owner_cache. get_or_insert_with ( || {
73
+ // Unwrap safety: can only panic when reaching the crate root
74
+ // but we made sure above that we are not at crate root.
75
+ cx. tcx . hir ( ) . parent_owner_iter ( item. hir_id ( ) ) . next ( ) . unwrap ( )
76
+ } )
77
+ }
78
+ } ;
81
79
82
80
let cargo_update = || {
83
81
let oexpn = item. span . ctxt ( ) . outer_expn_data ( ) ;
@@ -112,26 +110,52 @@ impl<'tcx> LateLintPass<'tcx> for NonLocalDefinitions {
112
110
// If that's the case this means that this impl block declaration
113
111
// is using local items and so we don't lint on it.
114
112
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]
113
+ let mut parent_owner_is_anon_const = {
114
+ let mut parent_owner_is_anon_const = None ;
115
+ move || {
116
+ * parent_owner_is_anon_const. get_or_insert_with ( || {
117
+ matches ! (
118
+ parent_owner( ) . 1 ,
119
+ OwnerNode :: Item ( Item {
120
+ ident: Ident { name: kw:: Underscore , .. } ,
121
+ kind: ItemKind :: Const ( ..) ,
122
+ ..
123
+ } )
124
+ )
125
+ } )
126
+ }
127
+ } ;
128
+ let mut extra_local_parent = {
129
+ let mut extra_parent_cache = None ;
130
+ move || {
131
+ * extra_parent_cache. get_or_insert_with ( || {
132
+ parent_owner_is_anon_const ( )
133
+ . then ( || {
134
+ cx. tcx
135
+ . hir ( )
136
+ . parent_owner_iter ( item. hir_id ( ) )
137
+ . skip ( 1 )
138
+ . next ( )
139
+ . map ( |( owner_id, _owner_node) | owner_id. def_id )
140
+ } )
141
+ . flatten ( )
142
+ } )
143
+ }
124
144
} ;
125
145
126
146
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
- }
147
+ TyKind :: Path ( QPath :: Resolved ( _, ty_path) ) => path_has_local_parent (
148
+ ty_path,
149
+ cx,
150
+ & mut parent_owner,
151
+ & mut extra_local_parent,
152
+ ) ,
130
153
TyKind :: TraitObject ( [ principle_poly_trait_ref, ..] , _, _) => {
131
154
path_has_local_parent (
132
155
principle_poly_trait_ref. trait_ref . path ,
133
156
cx,
134
- & * local_parents,
157
+ & mut parent_owner,
158
+ & mut extra_local_parent,
135
159
)
136
160
}
137
161
TyKind :: TraitObject ( [ ] , _, _)
@@ -151,19 +175,29 @@ impl<'tcx> LateLintPass<'tcx> for NonLocalDefinitions {
151
175
| TyKind :: Err ( _) => false ,
152
176
} ;
153
177
154
- let of_trait_has_local_parent = impl_
155
- . of_trait
156
- . map ( |of_trait| path_has_local_parent ( of_trait. path , cx, & * local_parents) )
157
- . unwrap_or ( false ) ;
178
+ let of_trait_has_local_parent = self_ty_has_local_parent
179
+ || impl_
180
+ . of_trait
181
+ . map ( |of_trait| {
182
+ path_has_local_parent (
183
+ of_trait. path ,
184
+ cx,
185
+ & mut parent_owner,
186
+ & mut extra_local_parent,
187
+ )
188
+ } )
189
+ . unwrap_or ( false ) ;
158
190
159
191
// If none of them have a local parent (LOGICAL NOR) this means that
160
192
// this impl definition is a non-local definition and so we lint on it.
161
193
if !( self_ty_has_local_parent || of_trait_has_local_parent) {
194
+ // Per RFC we (currently) ignore anon-const (`const _: Ty = ...`) in top-level module.
195
+ if parent_owner_is_anon_const ( ) && self . body_depth == 1 {
196
+ return ;
197
+ }
198
+
162
199
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)
200
+ && let OwnerNode :: Item ( item) = parent_owner ( ) . 1
167
201
&& let ItemKind :: Const ( ty, _, _) = item. kind
168
202
&& let TyKind :: Tup ( & [ ] ) = ty. kind
169
203
{
@@ -172,14 +206,17 @@ impl<'tcx> LateLintPass<'tcx> for NonLocalDefinitions {
172
206
None
173
207
} ;
174
208
209
+ let parent_owner = parent_owner ( ) . 1 ;
210
+
175
211
cx. emit_span_lint (
176
212
NON_LOCAL_DEFINITIONS ,
177
213
item. span ,
178
214
NonLocalDefinitionsDiag :: Impl {
179
215
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 ( ) )
216
+ body_kind_descr : "?" /* FIXME: cx.tcx.def_kind_descr(parent_def_kind, parent) */ ,
217
+ body_name : parent_owner
218
+ . ident ( )
219
+ . map ( |s| s. name . to_ident_string ( ) )
183
220
. unwrap_or_else ( || "<unnameable>" . to_string ( ) ) ,
184
221
cargo_update : cargo_update ( ) ,
185
222
const_anon,
@@ -190,14 +227,17 @@ impl<'tcx> LateLintPass<'tcx> for NonLocalDefinitions {
190
227
ItemKind :: Macro ( _macro, MacroKind :: Bang )
191
228
if cx. tcx . has_attr ( item. owner_id . def_id , sym:: macro_export) =>
192
229
{
230
+ let parent_owner = parent_owner ( ) . 1 ;
231
+
193
232
cx. emit_span_lint (
194
233
NON_LOCAL_DEFINITIONS ,
195
234
item. span ,
196
235
NonLocalDefinitionsDiag :: MacroRules {
197
236
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 ( ) )
237
+ body_kind_descr : "?" /* FIXME: cx.tcx.def_kind_descr(parent_def_kind, parent) */ ,
238
+ body_name : parent_owner
239
+ . ident ( )
240
+ . map ( |s| s. name . to_ident_string ( ) )
201
241
. unwrap_or_else ( || "<unnameable>" . to_string ( ) ) ,
202
242
cargo_update : cargo_update ( ) ,
203
243
} ,
@@ -217,6 +257,22 @@ impl<'tcx> LateLintPass<'tcx> for NonLocalDefinitions {
217
257
/// std::convert::PartialEq<Foo<Bar>>
218
258
/// ^^^^^^^^^^^^^^^^^^^^^^^
219
259
/// ```
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) ) )
260
+ fn path_has_local_parent < ' tcx > (
261
+ path : & Path < ' _ > ,
262
+ cx : & LateContext < ' tcx > ,
263
+ local_parent : & mut impl FnMut ( ) -> ( OwnerId , OwnerNode < ' tcx > ) ,
264
+ extra_local_parent : & mut impl FnMut ( ) -> Option < LocalDefId > ,
265
+ ) -> bool {
266
+ let Some ( res_did) = path. res . opt_def_id ( ) else {
267
+ return true ;
268
+ } ;
269
+ let Some ( did) = res_did. as_local ( ) else {
270
+ return false ;
271
+ } ;
272
+ let Some ( hir_id) = cx. tcx . opt_local_def_id_to_hir_id ( did) else {
273
+ return true ;
274
+ } ;
275
+ let owner_id = cx. tcx . hir ( ) . get_parent_item ( hir_id) ;
276
+ let res_parent = owner_id. def_id ;
277
+ res_parent == local_parent ( ) . 0 . def_id || Some ( res_parent) == extra_local_parent ( )
222
278
}
0 commit comments