1- use rustc_hir:: { def :: DefKind , Body , Item , ItemKind , Node , Path , QPath , TyKind } ;
1+ use rustc_hir:: { Body , Item , ItemKind , OwnerNode , Path , QPath , TyKind } ;
22use 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 } ;
64
75use crate :: lints:: { NonLocalDefinitionsCargoUpdateNote , NonLocalDefinitionsDiag } ;
86use crate :: { LateContext , LateLintPass , LintContext } ;
@@ -67,15 +65,24 @@ impl<'tcx> LateLintPass<'tcx> for NonLocalDefinitions {
6765 return ;
6866 }
6967
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) ;
68+ if !matches ! ( item. kind, ItemKind :: Impl ( _) | ItemKind :: Macro ( _, _) ) {
69+ return ;
70+ }
71+
72+ let Some ( ( _, parent_node) ) = cx. tcx . hir ( ) . parent_owner_iter ( item. hir_id ( ) ) . next ( ) else {
73+ return ;
74+ } ;
75+ let parent_is_anon_const = matches ! (
76+ parent_node,
77+ OwnerNode :: Item ( Item {
78+ ident: Ident { name: kw:: Underscore , .. } ,
79+ kind: ItemKind :: Const ( ..) ,
80+ ..
81+ } )
82+ ) ;
7383
7484 // 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- {
85+ if self . body_depth == 1 && parent_is_anon_const {
7986 return ;
8087 }
8188
@@ -115,23 +122,34 @@ impl<'tcx> LateLintPass<'tcx> for NonLocalDefinitions {
115122 // We also ignore anon-const in item by including the anon-const
116123 // parent as well; and since it's quite uncommon, we use smallvec
117124 // 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]
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
136+ . get_or_insert_with ( || parent_is_anon_const. then ( || cx. tcx . parent ( did) ) )
137+ }
124138 } ;
125139
126140 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- }
141+ TyKind :: Path ( QPath :: Resolved ( _, ty_path) ) => path_has_local_parent (
142+ ty_path,
143+ cx,
144+ & mut local_parent,
145+ & mut extra_local_parent,
146+ ) ,
130147 TyKind :: TraitObject ( [ principle_poly_trait_ref, ..] , _, _) => {
131148 path_has_local_parent (
132149 principle_poly_trait_ref. trait_ref . path ,
133150 cx,
134- & * local_parents,
151+ & mut local_parent,
152+ & mut extra_local_parent,
135153 )
136154 }
137155 TyKind :: TraitObject ( [ ] , _, _)
@@ -153,17 +171,21 @@ impl<'tcx> LateLintPass<'tcx> for NonLocalDefinitions {
153171
154172 let of_trait_has_local_parent = impl_
155173 . of_trait
156- . map ( |of_trait| path_has_local_parent ( of_trait. path , cx, & * local_parents) )
174+ . map ( |of_trait| {
175+ path_has_local_parent (
176+ of_trait. path ,
177+ cx,
178+ & mut local_parent,
179+ & mut extra_local_parent,
180+ )
181+ } )
157182 . unwrap_or ( false ) ;
158183
159184 // If none of them have a local parent (LOGICAL NOR) this means that
160185 // this impl definition is a non-local definition and so we lint on it.
161186 if !( self_ty_has_local_parent || of_trait_has_local_parent) {
162187 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)
188+ && let OwnerNode :: Item ( item) = parent_node
167189 && let ItemKind :: Const ( ty, _, _) = item. kind
168190 && let TyKind :: Tup ( & [ ] ) = ty. kind
169191 {
@@ -177,9 +199,10 @@ impl<'tcx> LateLintPass<'tcx> for NonLocalDefinitions {
177199 item. span ,
178200 NonLocalDefinitionsDiag :: Impl {
179201 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 ( ) )
202+ body_kind_descr : "?" /* FIXME: cx.tcx.def_kind_descr(parent_def_kind, parent) */ ,
203+ body_name : parent_node
204+ . ident ( )
205+ . map ( |s| s. name . to_ident_string ( ) )
183206 . unwrap_or_else ( || "<unnameable>" . to_string ( ) ) ,
184207 cargo_update : cargo_update ( ) ,
185208 const_anon,
@@ -195,9 +218,10 @@ impl<'tcx> LateLintPass<'tcx> for NonLocalDefinitions {
195218 item. span ,
196219 NonLocalDefinitionsDiag :: MacroRules {
197220 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 ( ) )
221+ body_kind_descr : "?" /* FIXME: cx.tcx.def_kind_descr(parent_def_kind, parent) */ ,
222+ body_name : parent_node
223+ . ident ( )
224+ . map ( |s| s. name . to_ident_string ( ) )
201225 . unwrap_or_else ( || "<unnameable>" . to_string ( ) ) ,
202226 cargo_update : cargo_update ( ) ,
203227 } ,
@@ -217,6 +241,20 @@ impl<'tcx> LateLintPass<'tcx> for NonLocalDefinitions {
217241/// std::convert::PartialEq<Foo<Bar>>
218242/// ^^^^^^^^^^^^^^^^^^^^^^^
219243/// ```
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) ) )
244+ fn path_has_local_parent (
245+ path : & Path < ' _ > ,
246+ cx : & LateContext < ' _ > ,
247+ local_parent : & mut impl FnMut ( ) -> DefId ,
248+ extra_local_parent : & mut impl FnMut ( DefId ) -> Option < DefId > ,
249+ ) -> bool {
250+ if let Some ( did) = path. res . opt_def_id ( ) {
251+ if !did. is_local ( ) {
252+ false
253+ } else {
254+ let res_parent = cx. tcx . parent ( did) ;
255+ res_parent == local_parent ( ) || Some ( res_parent) == extra_local_parent ( local_parent ( ) )
256+ }
257+ } else {
258+ true
259+ }
222260}
0 commit comments