@@ -2,8 +2,6 @@ use rustc_hir::{def::DefKind, Body, Item, ItemKind, Node, Path, QPath, TyKind};
2
2
use rustc_span:: def_id:: { DefId , LOCAL_CRATE } ;
3
3
use rustc_span:: { sym, symbol:: kw, ExpnKind , MacroKind } ;
4
4
5
- use smallvec:: { smallvec, SmallVec } ;
6
-
7
5
use crate :: lints:: { NonLocalDefinitionsCargoUpdateNote , NonLocalDefinitionsDiag } ;
8
6
use crate :: { LateContext , LateLintPass , LintContext } ;
9
7
@@ -67,24 +65,23 @@ impl<'tcx> LateLintPass<'tcx> for NonLocalDefinitions {
67
65
return ;
68
66
}
69
67
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 ;
68
+ macro_rules! lazy {
69
+ ( $ident: ident = $closure: expr) => {
70
+ let cache = :: std:: cell:: RefCell :: new( None ) ;
71
+ let $ident = || * cache. borrow_mut( ) . get_or_insert_with( $closure) ;
72
+ } ;
80
73
}
81
74
75
+ lazy ! ( parent = || cx. tcx. parent( item. owner_id. def_id. into( ) ) ) ;
76
+ lazy ! ( parent_def_kind = || cx. tcx. def_kind( parent( ) ) ) ;
77
+ lazy ! ( parent_opt_item_name = || cx. tcx. opt_item_name( parent( ) ) ) ;
78
+
82
79
let cargo_update = || {
83
80
let oexpn = item. span . ctxt ( ) . outer_expn_data ( ) ;
84
81
if let Some ( def_id) = oexpn. macro_def_id
85
82
&& let ExpnKind :: Macro ( macro_kind, macro_name) = oexpn. kind
86
83
&& def_id. krate != LOCAL_CRATE
87
- && std :: env :: var_os ( "CARGO" ) . is_some ( )
84
+ && rustc_session :: utils :: was_invoked_from_cargo ( )
88
85
{
89
86
Some ( NonLocalDefinitionsCargoUpdateNote {
90
87
macro_kind : macro_kind. descr ( ) ,
@@ -112,26 +109,24 @@ impl<'tcx> LateLintPass<'tcx> for NonLocalDefinitions {
112
109
// If that's the case this means that this impl block declaration
113
110
// is using local items and so we don't lint on it.
114
111
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
- } ;
112
+ lazy ! (
113
+ parent_is_anon_const = || parent_def_kind( ) == DefKind :: Const
114
+ && parent_opt_item_name( ) == Some ( kw:: Underscore )
115
+ ) ;
116
+ lazy ! (
117
+ extra_local_parent = || parent_is_anon_const( ) . then( || cx. tcx. parent( parent( ) ) )
118
+ ) ;
125
119
126
120
let self_ty_has_local_parent = match impl_. self_ty . kind {
127
121
TyKind :: Path ( QPath :: Resolved ( _, ty_path) ) => {
128
- path_has_local_parent ( ty_path, cx, & * local_parents )
122
+ path_has_local_parent ( ty_path, cx, & parent , & extra_local_parent )
129
123
}
130
124
TyKind :: TraitObject ( [ principle_poly_trait_ref, ..] , _, _) => {
131
125
path_has_local_parent (
132
126
principle_poly_trait_ref. trait_ref . path ,
133
127
cx,
134
- & * local_parents,
128
+ & parent,
129
+ & extra_local_parent,
135
130
)
136
131
}
137
132
TyKind :: TraitObject ( [ ] , _, _)
@@ -151,18 +146,27 @@ impl<'tcx> LateLintPass<'tcx> for NonLocalDefinitions {
151
146
| TyKind :: Err ( _) => false ,
152
147
} ;
153
148
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 ) ;
149
+ let of_trait_has_local_parent = self_ty_has_local_parent
150
+ || impl_
151
+ . of_trait
152
+ . map ( |of_trait| {
153
+ path_has_local_parent ( of_trait. path , cx, & parent, & extra_local_parent)
154
+ } )
155
+ . unwrap_or ( false ) ;
158
156
159
157
// If none of them have a local parent (LOGICAL NOR) this means that
160
158
// this impl definition is a non-local definition and so we lint on it.
161
159
if !( self_ty_has_local_parent || of_trait_has_local_parent) {
160
+ // Per RFC we (currently) ignore anon-const (`const _: Ty = ...`) in
161
+ // top-level module.
162
+ if self . body_depth == 1 && parent_is_anon_const ( ) {
163
+ return ;
164
+ }
165
+
162
166
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 ( )
167
+ && parent_def_kind ( ) == DefKind :: Const
168
+ && parent_opt_item_name ( ) != Some ( kw:: Underscore )
169
+ && let Some ( parent) = parent ( ) . as_local ( )
166
170
&& let Node :: Item ( item) = cx. tcx . hir_node_by_def_id ( parent)
167
171
&& let ItemKind :: Const ( ty, _, _) = item. kind
168
172
&& let TyKind :: Tup ( & [ ] ) = ty. kind
@@ -177,8 +181,8 @@ impl<'tcx> LateLintPass<'tcx> for NonLocalDefinitions {
177
181
item. span ,
178
182
NonLocalDefinitionsDiag :: Impl {
179
183
depth : self . body_depth ,
180
- body_kind_descr : cx. tcx . def_kind_descr ( parent_def_kind, parent) ,
181
- body_name : parent_opt_item_name
184
+ body_kind_descr : cx. tcx . def_kind_descr ( parent_def_kind ( ) , parent ( ) ) ,
185
+ body_name : parent_opt_item_name ( )
182
186
. map ( |s| s. to_ident_string ( ) )
183
187
. unwrap_or_else ( || "<unnameable>" . to_string ( ) ) ,
184
188
cargo_update : cargo_update ( ) ,
@@ -195,8 +199,8 @@ impl<'tcx> LateLintPass<'tcx> for NonLocalDefinitions {
195
199
item. span ,
196
200
NonLocalDefinitionsDiag :: MacroRules {
197
201
depth : self . body_depth ,
198
- body_kind_descr : cx. tcx . def_kind_descr ( parent_def_kind, parent) ,
199
- body_name : parent_opt_item_name
202
+ body_kind_descr : cx. tcx . def_kind_descr ( parent_def_kind ( ) , parent ( ) ) ,
203
+ body_name : parent_opt_item_name ( )
200
204
. map ( |s| s. to_ident_string ( ) )
201
205
. unwrap_or_else ( || "<unnameable>" . to_string ( ) ) ,
202
206
cargo_update : cargo_update ( ) ,
@@ -217,6 +221,16 @@ impl<'tcx> LateLintPass<'tcx> for NonLocalDefinitions {
217
221
/// std::convert::PartialEq<Foo<Bar>>
218
222
/// ^^^^^^^^^^^^^^^^^^^^^^^
219
223
/// ```
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) ) )
224
+ fn path_has_local_parent (
225
+ path : & Path < ' _ > ,
226
+ cx : & LateContext < ' _ > ,
227
+ parent : impl Fn ( ) -> DefId ,
228
+ extra_local_parent : impl Fn ( ) -> Option < DefId > ,
229
+ ) -> bool {
230
+ path. res . opt_def_id ( ) . is_some_and ( |did| {
231
+ did. is_local ( ) && {
232
+ let res_parent = cx. tcx . parent ( did) ;
233
+ res_parent == parent ( ) || Some ( res_parent) == extra_local_parent ( )
234
+ }
235
+ } )
222
236
}
0 commit comments