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 , Path , QPath , TyKind } ;
3
+ use rustc_hir:: { OwnerId , OwnerNode } ;
4
+ use rustc_span:: def_id:: LOCAL_CRATE ;
5
+ use rustc_span:: symbol:: Ident ;
3
6
use rustc_span:: { sym, symbol:: kw, ExpnKind , MacroKind } ;
4
7
5
- use smallvec:: { smallvec, SmallVec } ;
6
-
7
8
use crate :: lints:: { NonLocalDefinitionsCargoUpdateNote , NonLocalDefinitionsDiag } ;
8
9
use crate :: { LateContext , LateLintPass , LintContext } ;
9
10
@@ -67,24 +68,27 @@ impl<'tcx> LateLintPass<'tcx> for NonLocalDefinitions {
67
68
return ;
68
69
}
69
70
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 ;
71
+ macro_rules! lazy {
72
+ ( $ident: ident = $closure: expr) => {
73
+ let cache = :: std:: cell:: RefCell :: new( None ) ;
74
+ let $ident = || * cache. borrow_mut( ) . get_or_insert_with( $closure) ;
75
+ } ;
80
76
}
81
77
78
+ lazy ! (
79
+ parent_owner = || {
80
+ // Unwrap safety: can only panic when reaching the crate root
81
+ // but we made sure above that we are not at crate root.
82
+ cx. tcx. hir( ) . parent_owner_iter( item. hir_id( ) ) . next( ) . unwrap( )
83
+ }
84
+ ) ;
85
+
82
86
let cargo_update = || {
83
87
let oexpn = item. span . ctxt ( ) . outer_expn_data ( ) ;
84
88
if let Some ( def_id) = oexpn. macro_def_id
85
89
&& let ExpnKind :: Macro ( macro_kind, macro_name) = oexpn. kind
86
90
&& def_id. krate != LOCAL_CRATE
87
- && std :: env :: var_os ( "CARGO" ) . is_some ( )
91
+ && rustc_session :: utils :: was_invoked_from_cargo ( )
88
92
{
89
93
Some ( NonLocalDefinitionsCargoUpdateNote {
90
94
macro_kind : macro_kind. descr ( ) ,
@@ -112,26 +116,39 @@ impl<'tcx> LateLintPass<'tcx> for NonLocalDefinitions {
112
116
// If that's the case this means that this impl block declaration
113
117
// is using local items and so we don't lint on it.
114
118
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
- } ;
119
+ lazy ! (
120
+ parent_owner_is_anon_const = || matches!(
121
+ parent_owner( ) . 1 ,
122
+ OwnerNode :: Item ( Item {
123
+ ident: Ident { name: kw:: Underscore , .. } ,
124
+ kind: ItemKind :: Const ( ..) ,
125
+ ..
126
+ } )
127
+ )
128
+ ) ;
129
+ lazy ! (
130
+ extra_local_parent = || parent_owner_is_anon_const( )
131
+ . then( || {
132
+ cx. tcx
133
+ . hir( )
134
+ . parent_owner_iter( item. hir_id( ) )
135
+ . skip( 1 )
136
+ . next( )
137
+ . map( |( owner_id, _owner_node) | owner_id. def_id)
138
+ } )
139
+ . flatten( )
140
+ ) ;
125
141
126
142
let self_ty_has_local_parent = match impl_. self_ty . kind {
127
143
TyKind :: Path ( QPath :: Resolved ( _, ty_path) ) => {
128
- path_has_local_parent ( ty_path, cx, & * local_parents )
144
+ path_has_local_parent ( ty_path, cx, & parent_owner , & extra_local_parent )
129
145
}
130
146
TyKind :: TraitObject ( [ principle_poly_trait_ref, ..] , _, _) => {
131
147
path_has_local_parent (
132
148
principle_poly_trait_ref. trait_ref . path ,
133
149
cx,
134
- & * local_parents,
150
+ & parent_owner,
151
+ & extra_local_parent,
135
152
)
136
153
}
137
154
TyKind :: TraitObject ( [ ] , _, _)
@@ -151,19 +168,31 @@ impl<'tcx> LateLintPass<'tcx> for NonLocalDefinitions {
151
168
| TyKind :: Err ( _) => false ,
152
169
} ;
153
170
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 ) ;
171
+ let of_trait_has_local_parent = self_ty_has_local_parent
172
+ || impl_
173
+ . of_trait
174
+ . map ( |of_trait| {
175
+ path_has_local_parent (
176
+ of_trait. path ,
177
+ cx,
178
+ & parent_owner,
179
+ & extra_local_parent,
180
+ )
181
+ } )
182
+ . unwrap_or ( false ) ;
158
183
159
184
// If none of them have a local parent (LOGICAL NOR) this means that
160
185
// this impl definition is a non-local definition and so we lint on it.
161
186
if !( self_ty_has_local_parent || of_trait_has_local_parent) {
187
+ // Per RFC we (currently) ignore anon-const (`const _: Ty = ...`) in
188
+ // top-level module.
189
+ if self . body_depth == 1 && parent_owner_is_anon_const ( ) {
190
+ return ;
191
+ }
192
+
162
193
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)
194
+ && let OwnerNode :: Item ( item) = parent_owner ( ) . 1
195
+ && item. ident . name != kw:: Underscore
167
196
&& let ItemKind :: Const ( ty, _, _) = item. kind
168
197
&& let TyKind :: Tup ( & [ ] ) = ty. kind
169
198
{
@@ -177,9 +206,10 @@ impl<'tcx> LateLintPass<'tcx> for NonLocalDefinitions {
177
206
item. span ,
178
207
NonLocalDefinitionsDiag :: Impl {
179
208
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 ( ) )
209
+ body_kind_descr : "?" /*cx.tcx.def_kind_descr(parent_def_kind(), parent())*/ ,
210
+ body_name : parent_owner ( ) . 1
211
+ . ident ( )
212
+ . map ( |s| s. name . to_ident_string ( ) )
183
213
. unwrap_or_else ( || "<unnameable>" . to_string ( ) ) ,
184
214
cargo_update : cargo_update ( ) ,
185
215
const_anon,
@@ -195,9 +225,11 @@ impl<'tcx> LateLintPass<'tcx> for NonLocalDefinitions {
195
225
item. span ,
196
226
NonLocalDefinitionsDiag :: MacroRules {
197
227
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 ( ) )
228
+ body_kind_descr : "?" , /*cx.tcx.def_kind_descr(parent_def_kind(), parent())*/
229
+ body_name : parent_owner ( )
230
+ . 1
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,26 @@ 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 < ' tcx > (
253
+ path : & Path < ' _ > ,
254
+ cx : & LateContext < ' tcx > ,
255
+ local_parent : impl Fn ( ) -> ( OwnerId , OwnerNode < ' tcx > ) ,
256
+ extra_local_parent : impl Fn ( ) -> Option < LocalDefId > ,
257
+ ) -> bool {
258
+ let Some ( res_did) = path. res . opt_def_id ( ) else {
259
+ return true ;
260
+ } ;
261
+ let Some ( did) = res_did. as_local ( ) else {
262
+ return false ;
263
+ } ;
264
+
265
+ let res_parent = {
266
+ let Some ( hir_id) = cx. tcx . opt_local_def_id_to_hir_id ( did) else {
267
+ return true ;
268
+ } ;
269
+ let owner_id = cx. tcx . hir ( ) . get_parent_item ( hir_id) ;
270
+ owner_id. def_id
271
+ } ;
272
+
273
+ res_parent == local_parent ( ) . 0 . def_id || Some ( res_parent) == extra_local_parent ( )
222
274
}
0 commit comments