1
- use rustc_hir:: { def :: DefKind , Body , Item , ItemKind , Node , Path , QPath , TyKind } ;
1
+ use rustc_hir:: { Body , Item , ItemKind , OwnerNode , Path , QPath , TyKind } ;
2
2
use 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 } ;
6
4
7
5
use crate :: lints:: { NonLocalDefinitionsCargoUpdateNote , NonLocalDefinitionsDiag } ;
8
6
use crate :: { LateContext , LateLintPass , LintContext } ;
@@ -71,15 +69,20 @@ impl<'tcx> LateLintPass<'tcx> for NonLocalDefinitions {
71
69
return ;
72
70
}
73
71
74
- let parent = cx. tcx . parent ( item. owner_id . def_id . into ( ) ) ;
75
- let parent_def_kind = cx. tcx . def_kind ( parent) ;
76
- let parent_opt_item_name = cx. tcx . opt_item_name ( parent) ;
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
+ ) ;
77
83
78
84
// Per RFC we (currently) ignore anon-const (`const _: Ty = ...`) in top-level module.
79
- if self . body_depth == 1
80
- && parent_def_kind == DefKind :: Const
81
- && parent_opt_item_name == Some ( kw:: Underscore )
82
- {
85
+ if self . body_depth == 1 && parent_is_anon_const {
83
86
return ;
84
87
}
85
88
@@ -119,23 +122,34 @@ impl<'tcx> LateLintPass<'tcx> for NonLocalDefinitions {
119
122
// We also ignore anon-const in item by including the anon-const
120
123
// parent as well; and since it's quite uncommon, we use smallvec
121
124
// to avoid unnecessary heap allocations.
122
- let local_parents: SmallVec < [ DefId ; 1 ] > = if parent_def_kind == DefKind :: Const
123
- && parent_opt_item_name == Some ( kw:: Underscore )
124
- {
125
- smallvec ! [ parent, cx. tcx. parent( parent) ]
126
- } else {
127
- 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
+ }
128
138
} ;
129
139
130
140
let self_ty_has_local_parent = match impl_. self_ty . kind {
131
- TyKind :: Path ( QPath :: Resolved ( _, ty_path) ) => {
132
- path_has_local_parent ( ty_path, cx, & * local_parents)
133
- }
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
+ ) ,
134
147
TyKind :: TraitObject ( [ principle_poly_trait_ref, ..] , _, _) => {
135
148
path_has_local_parent (
136
149
principle_poly_trait_ref. trait_ref . path ,
137
150
cx,
138
- & * local_parents,
151
+ & mut local_parent,
152
+ & mut extra_local_parent,
139
153
)
140
154
}
141
155
TyKind :: TraitObject ( [ ] , _, _)
@@ -157,17 +171,21 @@ impl<'tcx> LateLintPass<'tcx> for NonLocalDefinitions {
157
171
158
172
let of_trait_has_local_parent = impl_
159
173
. of_trait
160
- . 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
+ } )
161
182
. unwrap_or ( false ) ;
162
183
163
184
// If none of them have a local parent (LOGICAL NOR) this means that
164
185
// this impl definition is a non-local definition and so we lint on it.
165
186
if !( self_ty_has_local_parent || of_trait_has_local_parent) {
166
187
let const_anon = if self . body_depth == 1
167
- && parent_def_kind == DefKind :: Const
168
- && parent_opt_item_name != Some ( kw:: Underscore )
169
- && let Some ( parent) = parent. as_local ( )
170
- && let Node :: Item ( item) = cx. tcx . hir_node_by_def_id ( parent)
188
+ && let OwnerNode :: Item ( item) = parent_node
171
189
&& let ItemKind :: Const ( ty, _, _) = item. kind
172
190
&& let TyKind :: Tup ( & [ ] ) = ty. kind
173
191
{
@@ -181,9 +199,10 @@ impl<'tcx> LateLintPass<'tcx> for NonLocalDefinitions {
181
199
item. span ,
182
200
NonLocalDefinitionsDiag :: Impl {
183
201
depth : self . body_depth ,
184
- body_kind_descr : cx. tcx . def_kind_descr ( parent_def_kind, parent) ,
185
- body_name : parent_opt_item_name
186
- . 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 ( ) )
187
206
. unwrap_or_else ( || "<unnameable>" . to_string ( ) ) ,
188
207
cargo_update : cargo_update ( ) ,
189
208
const_anon,
@@ -199,9 +218,10 @@ impl<'tcx> LateLintPass<'tcx> for NonLocalDefinitions {
199
218
item. span ,
200
219
NonLocalDefinitionsDiag :: MacroRules {
201
220
depth : self . body_depth ,
202
- body_kind_descr : cx. tcx . def_kind_descr ( parent_def_kind, parent) ,
203
- body_name : parent_opt_item_name
204
- . 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 ( ) )
205
225
. unwrap_or_else ( || "<unnameable>" . to_string ( ) ) ,
206
226
cargo_update : cargo_update ( ) ,
207
227
} ,
@@ -221,6 +241,20 @@ impl<'tcx> LateLintPass<'tcx> for NonLocalDefinitions {
221
241
/// std::convert::PartialEq<Foo<Bar>>
222
242
/// ^^^^^^^^^^^^^^^^^^^^^^^
223
243
/// ```
224
- fn path_has_local_parent ( path : & Path < ' _ > , cx : & LateContext < ' _ > , local_parents : & [ DefId ] ) -> bool {
225
- 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
+ }
226
260
}
0 commit comments