1- use rustc_hir:: { def:: DefKind , Body , Item , ItemKind , Node , Path , QPath , TyKind } ;
2- use rustc_span:: def_id:: { DefId , LOCAL_CRATE } ;
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:: symbol:: Ident ;
35use rustc_span:: { sym, symbol:: kw, ExpnKind , MacroKind } ;
46
5- use smallvec:: { smallvec, SmallVec } ;
6-
77use crate :: lints:: { NonLocalDefinitionsCargoUpdateNote , NonLocalDefinitionsDiag } ;
88use crate :: { LateContext , LateLintPass , LintContext } ;
99
@@ -67,24 +67,19 @@ impl<'tcx> LateLintPass<'tcx> for NonLocalDefinitions {
6767 return ;
6868 }
6969
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) ;
70+ let mut parent_iter = cx. tcx . hir ( ) . parent_owner_iter ( item. hir_id ( ) ) ;
7371
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- }
72+ // Unwrap SAFETY: `ParentOwnerIterator` documentation garenties that
73+ // it only panic when reaching the crate root but we made sure above
74+ // that we are not at crate root. So we are fine here.
75+ let ( parent_owner_id, parent_owner_node) = parent_iter. next ( ) . unwrap ( ) ;
8176
8277 let cargo_update = || {
8378 let oexpn = item. span . ctxt ( ) . outer_expn_data ( ) ;
8479 if let Some ( def_id) = oexpn. macro_def_id
8580 && let ExpnKind :: Macro ( macro_kind, macro_name) = oexpn. kind
8681 && def_id. krate != LOCAL_CRATE
87- && std :: env :: var_os ( "CARGO" ) . is_some ( )
82+ && rustc_session :: utils :: was_invoked_from_cargo ( )
8883 {
8984 Some ( NonLocalDefinitionsCargoUpdateNote {
9085 macro_kind : macro_kind. descr ( ) ,
@@ -112,26 +107,35 @@ impl<'tcx> LateLintPass<'tcx> for NonLocalDefinitions {
112107 // If that's the case this means that this impl block declaration
113108 // is using local items and so we don't lint on it.
114109
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]
124- } ;
110+ let parent_owner_is_anon_const = matches ! (
111+ parent_owner_node,
112+ OwnerNode :: Item ( Item {
113+ ident: Ident { name: kw:: Underscore , .. } ,
114+ kind: ItemKind :: Const ( ..) ,
115+ ..
116+ } )
117+ ) ;
118+
119+ // Per RFC we (currently) ignore `impl` def in anon-const (`const _: Ty = ...`)
120+ // at the top-level module.
121+ if self . body_depth == 1 && parent_owner_is_anon_const {
122+ return ;
123+ }
124+
125+ let parent_parent_def_id = parent_owner_is_anon_const
126+ . then ( || parent_iter. next ( ) . map ( |( owner_id, _) | owner_id. def_id ) )
127+ . flatten ( ) ;
125128
126129 let self_ty_has_local_parent = match impl_. self_ty . kind {
127130 TyKind :: Path ( QPath :: Resolved ( _, ty_path) ) => {
128- path_has_local_parent ( ty_path, cx, & * local_parents )
131+ path_has_local_parent ( ty_path, cx, parent_owner_id , parent_parent_def_id )
129132 }
130133 TyKind :: TraitObject ( [ principle_poly_trait_ref, ..] , _, _) => {
131134 path_has_local_parent (
132135 principle_poly_trait_ref. trait_ref . path ,
133136 cx,
134- & * local_parents,
137+ parent_owner_id,
138+ parent_parent_def_id,
135139 )
136140 }
137141 TyKind :: TraitObject ( [ ] , _, _)
@@ -151,19 +155,25 @@ impl<'tcx> LateLintPass<'tcx> for NonLocalDefinitions {
151155 | TyKind :: Err ( _) => false ,
152156 } ;
153157
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 ) ;
158+ let of_trait_has_local_parent = self_ty_has_local_parent
159+ || impl_
160+ . of_trait
161+ . map ( |of_trait| {
162+ path_has_local_parent (
163+ of_trait. path ,
164+ cx,
165+ parent_owner_id,
166+ parent_parent_def_id,
167+ )
168+ } )
169+ . unwrap_or ( false ) ;
158170
159171 // If none of them have a local parent (LOGICAL NOR) this means that
160172 // this impl definition is a non-local definition and so we lint on it.
161173 if !( self_ty_has_local_parent || of_trait_has_local_parent) {
162174 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)
175+ && let OwnerNode :: Item ( item) = parent_owner_node
176+ && item. ident . name != kw:: Underscore
167177 && let ItemKind :: Const ( ty, _, _) = item. kind
168178 && let TyKind :: Tup ( & [ ] ) = ty. kind
169179 {
@@ -177,9 +187,10 @@ impl<'tcx> LateLintPass<'tcx> for NonLocalDefinitions {
177187 item. span ,
178188 NonLocalDefinitionsDiag :: Impl {
179189 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 ( ) )
190+ body_kind_descr : parent_owner_node. descr ( ) ,
191+ body_name : parent_owner_node
192+ . ident ( )
193+ . map ( |s| s. name . to_ident_string ( ) )
183194 . unwrap_or_else ( || "<unnameable>" . to_string ( ) ) ,
184195 cargo_update : cargo_update ( ) ,
185196 const_anon,
@@ -195,9 +206,10 @@ impl<'tcx> LateLintPass<'tcx> for NonLocalDefinitions {
195206 item. span ,
196207 NonLocalDefinitionsDiag :: MacroRules {
197208 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 ( ) )
209+ body_kind_descr : parent_owner_node. descr ( ) ,
210+ body_name : parent_owner_node
211+ . ident ( )
212+ . map ( |s| s. name . to_ident_string ( ) )
201213 . unwrap_or_else ( || "<unnameable>" . to_string ( ) ) ,
202214 cargo_update : cargo_update ( ) ,
203215 } ,
@@ -217,6 +229,26 @@ impl<'tcx> LateLintPass<'tcx> for NonLocalDefinitions {
217229/// std::convert::PartialEq<Foo<Bar>>
218230/// ^^^^^^^^^^^^^^^^^^^^^^^
219231/// ```
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) ) )
232+ fn path_has_local_parent < ' tcx > (
233+ path : & Path < ' _ > ,
234+ cx : & LateContext < ' tcx > ,
235+ local_parent : OwnerId ,
236+ extra_local_parent : Option < LocalDefId > ,
237+ ) -> bool {
238+ let Some ( res_did) = path. res . opt_def_id ( ) else {
239+ return true ;
240+ } ;
241+ let Some ( did) = res_did. as_local ( ) else {
242+ return false ;
243+ } ;
244+
245+ let res_parent = {
246+ let Some ( hir_id) = cx. tcx . opt_local_def_id_to_hir_id ( did) else {
247+ return true ;
248+ } ;
249+ let owner_id = cx. tcx . hir ( ) . get_parent_item ( hir_id) ;
250+ owner_id. def_id
251+ } ;
252+
253+ res_parent == local_parent. def_id || Some ( res_parent) == extra_local_parent
222254}
0 commit comments