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 } ;
1+ #![ allow( warnings) ]
42
5- use smallvec:: { smallvec, SmallVec } ;
3+ use rustc_hir:: { Body , Item , ItemKind , OwnerNode , Path , QPath , TyKind } ;
4+ use rustc_span:: def_id:: { DefId , LOCAL_CRATE } ;
5+ use rustc_span:: { sym, symbol:: kw, symbol:: Ident , ExpnKind , MacroKind } ;
66
77use crate :: lints:: { NonLocalDefinitionsCargoUpdateNote , NonLocalDefinitionsDiag } ;
88use crate :: { LateContext , LateLintPass , LintContext } ;
@@ -67,17 +67,14 @@ 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) ;
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- }
70+ let mut parent_node = {
71+ let mut parent_node_cache = None ;
72+ move || {
73+ * parent_node_cache. get_or_insert_with ( || {
74+ cx. tcx . hir ( ) . parent_owner_iter ( item. hir_id ( ) ) . next ( ) . unwrap ( ) . 1
75+ } )
76+ }
77+ } ;
8178
8279 let cargo_update = || {
8380 let oexpn = item. span . ctxt ( ) . outer_expn_data ( ) ;
@@ -97,96 +94,130 @@ impl<'tcx> LateLintPass<'tcx> for NonLocalDefinitions {
9794 } ;
9895
9996 match item. kind {
100- ItemKind :: Impl ( impl_) => {
101- // The RFC states:
102- //
103- // > An item nested inside an expression-containing item (through any
104- // > level of nesting) may not define an impl Trait for Type unless
105- // > either the **Trait** or the **Type** is also nested inside the
106- // > same expression-containing item.
107- //
108- // To achieve this we get try to get the paths of the _Trait_ and
109- // _Type_, and we look inside thoses paths to try a find in one
110- // of them a type whose parent is the same as the impl definition.
111- //
112- // If that's the case this means that this impl block declaration
113- // is using local items and so we don't lint on it.
114-
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- } ;
125-
126- 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- }
130- TyKind :: TraitObject ( [ principle_poly_trait_ref, ..] , _, _) => {
131- path_has_local_parent (
132- principle_poly_trait_ref. trait_ref . path ,
133- cx,
134- & * local_parents,
135- )
136- }
137- TyKind :: TraitObject ( [ ] , _, _)
138- | TyKind :: InferDelegation ( _, _)
139- | TyKind :: Slice ( _)
140- | TyKind :: Array ( _, _)
141- | TyKind :: Ptr ( _)
142- | TyKind :: Ref ( _, _)
143- | TyKind :: BareFn ( _)
144- | TyKind :: Never
145- | TyKind :: Tup ( _)
146- | TyKind :: Path ( _)
147- | TyKind :: AnonAdt ( _)
148- | TyKind :: OpaqueDef ( _, _, _)
149- | TyKind :: Typeof ( _)
150- | TyKind :: Infer
151- | TyKind :: Err ( _) => false ,
152- } ;
153-
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-
159- // If none of them have a local parent (LOGICAL NOR) this means that
160- // this impl definition is a non-local definition and so we lint on it.
161- if !( self_ty_has_local_parent || of_trait_has_local_parent) {
162- 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)
167- && let ItemKind :: Const ( ty, _, _) = item. kind
168- && let TyKind :: Tup ( & [ ] ) = ty. kind
169- {
170- Some ( item. ident . span )
171- } else {
172- None
173- } ;
174-
175- cx. emit_span_lint (
176- NON_LOCAL_DEFINITIONS ,
177- item. span ,
178- NonLocalDefinitionsDiag :: Impl {
179- 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 ( ) )
183- . unwrap_or_else ( || "<unnameable>" . to_string ( ) ) ,
184- cargo_update : cargo_update ( ) ,
185- const_anon,
186- } ,
187- )
188- }
189- }
97+ // ItemKind::Impl(impl_) => {
98+ // // The RFC states:
99+ // //
100+ // // > An item nested inside an expression-containing item (through any
101+ // // > level of nesting) may not define an impl Trait for Type unless
102+ // // > either the **Trait** or the **Type** is also nested inside the
103+ // // > same expression-containing item.
104+ // //
105+ // // To achieve this we get try to get the paths of the _Trait_ and
106+ // // _Type_, and we look inside thoses paths to try a find in one
107+ // // of them a type whose parent is the same as the impl definition.
108+ // //
109+ // // If that's the case this means that this impl block declaration
110+ // // is using local items and so we don't lint on it.
111+ //
112+ // let mut parent_node_is_anon_const = {
113+ // let mut parent_node_is_anon_const = None;
114+ // move || {
115+ // *parent_node_is_anon_const.get_or_insert_with(|| {
116+ // matches!(
117+ // parent_node(),
118+ // OwnerNode::Item(Item {
119+ // ident: Ident { name: kw::Underscore, .. },
120+ // kind: ItemKind::Const(..),
121+ // ..
122+ // })
123+ // )
124+ // })
125+ // }
126+ // };
127+ // let mut local_parent = {
128+ // let mut local_parent_cache = None;
129+ // move || {
130+ // *local_parent_cache
131+ // .get_or_insert_with(|| cx.tcx.parent(item.owner_id.to_def_id()))
132+ // }
133+ // };
134+ // let mut extra_local_parent = {
135+ // let mut extra_parent_cache = None;
136+ // move |did| {
137+ // *extra_parent_cache.get_or_insert_with(|| {
138+ // parent_node_is_anon_const().then(|| cx.tcx.parent(did))
139+ // })
140+ // }
141+ // };
142+ //
143+ // let self_ty_has_local_parent = match impl_.self_ty.kind {
144+ // TyKind::Path(QPath::Resolved(_, ty_path)) => path_has_local_parent(
145+ // ty_path,
146+ // cx,
147+ // &mut local_parent,
148+ // &mut extra_local_parent,
149+ // ),
150+ // TyKind::TraitObject([principle_poly_trait_ref, ..], _, _) => {
151+ // path_has_local_parent(
152+ // principle_poly_trait_ref.trait_ref.path,
153+ // cx,
154+ // &mut local_parent,
155+ // &mut extra_local_parent,
156+ // )
157+ // }
158+ // TyKind::TraitObject([], _, _)
159+ // | TyKind::InferDelegation(_, _)
160+ // | TyKind::Slice(_)
161+ // | TyKind::Array(_, _)
162+ // | TyKind::Ptr(_)
163+ // | TyKind::Ref(_, _)
164+ // | TyKind::BareFn(_)
165+ // | TyKind::Never
166+ // | TyKind::Tup(_)
167+ // | TyKind::Path(_)
168+ // | TyKind::AnonAdt(_)
169+ // | TyKind::OpaqueDef(_, _, _)
170+ // | TyKind::Typeof(_)
171+ // | TyKind::Infer
172+ // | TyKind::Err(_) => false,
173+ // };
174+ //
175+ // let of_trait_has_local_parent = impl_
176+ // .of_trait
177+ // .map(|of_trait| {
178+ // path_has_local_parent(
179+ // of_trait.path,
180+ // cx,
181+ // &mut local_parent,
182+ // &mut extra_local_parent,
183+ // )
184+ // })
185+ // .unwrap_or(false);
186+ //
187+ // // If none of them have a local parent (LOGICAL NOR) this means that
188+ // // this impl definition is a non-local definition and so we lint on it.
189+ // if !(self_ty_has_local_parent || of_trait_has_local_parent) {
190+ // // Per RFC we (currently) ignore anon-const (`const _: Ty = ...`) in top-level module.
191+ // if parent_node_is_anon_const() && self.body_depth == 1 {
192+ // return;
193+ // }
194+ //
195+ // let const_anon = if self.body_depth == 1
196+ // && let OwnerNode::Item(item) = parent_node()
197+ // && let ItemKind::Const(ty, _, _) = item.kind
198+ // && let TyKind::Tup(&[]) = ty.kind
199+ // {
200+ // Some(item.ident.span)
201+ // } else {
202+ // None
203+ // };
204+ //
205+ // cx.emit_span_lint(
206+ // NON_LOCAL_DEFINITIONS,
207+ // item.span,
208+ // NonLocalDefinitionsDiag::Impl {
209+ // depth: self.body_depth,
210+ // body_kind_descr: "?" /* FIXME: cx.tcx.def_kind_descr(parent_def_kind, parent) */,
211+ // body_name: parent_node()
212+ // .ident()
213+ // .map(|s| s.name.to_ident_string())
214+ // .unwrap_or_else(|| "<unnameable>".to_string()),
215+ // cargo_update: cargo_update(),
216+ // const_anon,
217+ // },
218+ // )
219+ // }
220+ // }
190221 ItemKind :: Macro ( _macro, MacroKind :: Bang )
191222 if cx. tcx . has_attr ( item. owner_id . def_id , sym:: macro_export) =>
192223 {
@@ -195,9 +226,10 @@ impl<'tcx> LateLintPass<'tcx> for NonLocalDefinitions {
195226 item. span ,
196227 NonLocalDefinitionsDiag :: MacroRules {
197228 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 ( ) )
229+ body_kind_descr : "?" /* FIXME: cx.tcx.def_kind_descr(parent_def_kind, parent) */ ,
230+ body_name : parent_node ( )
231+ . ident ( )
232+ . map ( |s| s. name . to_ident_string ( ) )
201233 . unwrap_or_else ( || "<unnameable>" . to_string ( ) ) ,
202234 cargo_update : cargo_update ( ) ,
203235 } ,
@@ -217,6 +249,20 @@ impl<'tcx> LateLintPass<'tcx> for NonLocalDefinitions {
217249/// std::convert::PartialEq<Foo<Bar>>
218250/// ^^^^^^^^^^^^^^^^^^^^^^^
219251/// ```
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) ) )
252+ fn path_has_local_parent (
253+ path : & Path < ' _ > ,
254+ cx : & LateContext < ' _ > ,
255+ local_parent : & mut impl FnMut ( ) -> DefId ,
256+ extra_local_parent : & mut impl FnMut ( DefId ) -> Option < DefId > ,
257+ ) -> bool {
258+ if let Some ( did) = path. res . opt_def_id ( ) {
259+ if !did. is_local ( ) {
260+ false
261+ } else {
262+ let res_parent = cx. tcx . parent ( did) ;
263+ res_parent == local_parent ( ) || Some ( res_parent) == extra_local_parent ( local_parent ( ) )
264+ }
265+ } else {
266+ true
267+ }
222268}
0 commit comments