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) ]
4
2
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 } ;
6
6
7
7
use crate :: lints:: { NonLocalDefinitionsCargoUpdateNote , NonLocalDefinitionsDiag } ;
8
8
use crate :: { LateContext , LateLintPass , LintContext } ;
@@ -67,17 +67,14 @@ impl<'tcx> LateLintPass<'tcx> for NonLocalDefinitions {
67
67
return ;
68
68
}
69
69
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
+ } ;
81
78
82
79
let cargo_update = || {
83
80
let oexpn = item. span . ctxt ( ) . outer_expn_data ( ) ;
@@ -97,96 +94,130 @@ impl<'tcx> LateLintPass<'tcx> for NonLocalDefinitions {
97
94
} ;
98
95
99
96
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
+ // }
190
221
ItemKind :: Macro ( _macro, MacroKind :: Bang )
191
222
if cx. tcx . has_attr ( item. owner_id . def_id , sym:: macro_export) =>
192
223
{
@@ -195,9 +226,10 @@ impl<'tcx> LateLintPass<'tcx> for NonLocalDefinitions {
195
226
item. span ,
196
227
NonLocalDefinitionsDiag :: MacroRules {
197
228
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 ( ) )
201
233
. unwrap_or_else ( || "<unnameable>" . to_string ( ) ) ,
202
234
cargo_update : cargo_update ( ) ,
203
235
} ,
@@ -217,6 +249,20 @@ impl<'tcx> LateLintPass<'tcx> for NonLocalDefinitions {
217
249
/// std::convert::PartialEq<Foo<Bar>>
218
250
/// ^^^^^^^^^^^^^^^^^^^^^^^
219
251
/// ```
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
+ }
222
268
}
0 commit comments