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 } ;
65
76use crate :: lints:: { NonLocalDefinitionsCargoUpdateNote , NonLocalDefinitionsDiag } ;
87use crate :: { LateContext , LateLintPass , LintContext } ;
@@ -67,17 +66,16 @@ impl<'tcx> LateLintPass<'tcx> for NonLocalDefinitions {
6766 return ;
6867 }
6968
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+ } ;
8179
8280 let cargo_update = || {
8381 let oexpn = item. span . ctxt ( ) . outer_expn_data ( ) ;
@@ -112,26 +110,52 @@ impl<'tcx> LateLintPass<'tcx> for NonLocalDefinitions {
112110 // If that's the case this means that this impl block declaration
113111 // is using local items and so we don't lint on it.
114112
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+ }
124144 } ;
125145
126146 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+ ) ,
130153 TyKind :: TraitObject ( [ principle_poly_trait_ref, ..] , _, _) => {
131154 path_has_local_parent (
132155 principle_poly_trait_ref. trait_ref . path ,
133156 cx,
134- & * local_parents,
157+ & mut parent_owner,
158+ & mut extra_local_parent,
135159 )
136160 }
137161 TyKind :: TraitObject ( [ ] , _, _)
@@ -153,17 +177,26 @@ impl<'tcx> LateLintPass<'tcx> for NonLocalDefinitions {
153177
154178 let of_trait_has_local_parent = impl_
155179 . of_trait
156- . map ( |of_trait| path_has_local_parent ( of_trait. path , cx, & * local_parents) )
180+ . map ( |of_trait| {
181+ path_has_local_parent (
182+ of_trait. path ,
183+ cx,
184+ & mut parent_owner,
185+ & mut extra_local_parent,
186+ )
187+ } )
157188 . unwrap_or ( false ) ;
158189
159190 // If none of them have a local parent (LOGICAL NOR) this means that
160191 // this impl definition is a non-local definition and so we lint on it.
161192 if !( self_ty_has_local_parent || of_trait_has_local_parent) {
193+ // Per RFC we (currently) ignore anon-const (`const _: Ty = ...`) in top-level module.
194+ if parent_owner_is_anon_const ( ) && self . body_depth == 1 {
195+ return ;
196+ }
197+
162198 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)
199+ && let OwnerNode :: Item ( item) = parent_owner ( ) . 1
167200 && let ItemKind :: Const ( ty, _, _) = item. kind
168201 && let TyKind :: Tup ( & [ ] ) = ty. kind
169202 {
@@ -172,14 +205,17 @@ impl<'tcx> LateLintPass<'tcx> for NonLocalDefinitions {
172205 None
173206 } ;
174207
208+ let parent_owner = parent_owner ( ) . 1 ;
209+
175210 cx. emit_span_lint (
176211 NON_LOCAL_DEFINITIONS ,
177212 item. span ,
178213 NonLocalDefinitionsDiag :: Impl {
179214 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 ( ) )
215+ body_kind_descr : "?" /* FIXME: cx.tcx.def_kind_descr(parent_def_kind, parent) */ ,
216+ body_name : parent_owner
217+ . ident ( )
218+ . map ( |s| s. name . to_ident_string ( ) )
183219 . unwrap_or_else ( || "<unnameable>" . to_string ( ) ) ,
184220 cargo_update : cargo_update ( ) ,
185221 const_anon,
@@ -190,14 +226,17 @@ impl<'tcx> LateLintPass<'tcx> for NonLocalDefinitions {
190226 ItemKind :: Macro ( _macro, MacroKind :: Bang )
191227 if cx. tcx . has_attr ( item. owner_id . def_id , sym:: macro_export) =>
192228 {
229+ let parent_owner = parent_owner ( ) . 1 ;
230+
193231 cx. emit_span_lint (
194232 NON_LOCAL_DEFINITIONS ,
195233 item. span ,
196234 NonLocalDefinitionsDiag :: MacroRules {
197235 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 ( ) )
236+ body_kind_descr : "?" /* FIXME: cx.tcx.def_kind_descr(parent_def_kind, parent) */ ,
237+ body_name : parent_owner
238+ . ident ( )
239+ . map ( |s| s. name . to_ident_string ( ) )
201240 . unwrap_or_else ( || "<unnameable>" . to_string ( ) ) ,
202241 cargo_update : cargo_update ( ) ,
203242 } ,
@@ -217,6 +256,22 @@ impl<'tcx> LateLintPass<'tcx> for NonLocalDefinitions {
217256/// std::convert::PartialEq<Foo<Bar>>
218257/// ^^^^^^^^^^^^^^^^^^^^^^^
219258/// ```
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) ) )
259+ fn path_has_local_parent < ' tcx > (
260+ path : & Path < ' _ > ,
261+ cx : & LateContext < ' tcx > ,
262+ local_parent : & mut impl FnMut ( ) -> ( OwnerId , OwnerNode < ' tcx > ) ,
263+ extra_local_parent : & mut impl FnMut ( ) -> Option < LocalDefId > ,
264+ ) -> bool {
265+ let Some ( res_did) = path. res . opt_def_id ( ) else {
266+ return true ;
267+ } ;
268+ let Some ( did) = res_did. as_local ( ) else {
269+ return false ;
270+ } ;
271+ let Some ( hir_id) = cx. tcx . opt_local_def_id_to_hir_id ( did) else {
272+ return true ;
273+ } ;
274+ let owner_id = cx. tcx . hir ( ) . get_parent_item ( hir_id) ;
275+ let res_parent = owner_id. def_id ;
276+ res_parent == local_parent ( ) . 0 . def_id || Some ( res_parent) == extra_local_parent ( )
222277}
0 commit comments