@@ -169,6 +169,10 @@ struct EmbargoVisitor<'a, 'tcx: 'a> {
169
169
changed : bool ,
170
170
}
171
171
172
+ struct ReachEverythingInTheInterfaceVisitor < ' b , ' a : ' b , ' tcx : ' a > {
173
+ ev : & ' b mut EmbargoVisitor < ' a , ' tcx > ,
174
+ }
175
+
172
176
impl < ' a , ' tcx > EmbargoVisitor < ' a , ' tcx > {
173
177
fn ty_level ( & self , ty : & hir:: Ty ) -> Option < AccessLevel > {
174
178
if let hir:: TyPath ( ..) = ty. node {
@@ -214,6 +218,10 @@ impl<'a, 'tcx> EmbargoVisitor<'a, 'tcx> {
214
218
old_level
215
219
}
216
220
}
221
+
222
+ fn reach < ' b > ( & ' b mut self ) -> ReachEverythingInTheInterfaceVisitor < ' b , ' a , ' tcx > {
223
+ ReachEverythingInTheInterfaceVisitor { ev : self }
224
+ }
217
225
}
218
226
219
227
impl < ' a , ' tcx , ' v > Visitor < ' v > for EmbargoVisitor < ' a , ' tcx > {
@@ -245,10 +253,10 @@ impl<'a, 'tcx, 'v> Visitor<'v> for EmbargoVisitor<'a, 'tcx> {
245
253
}
246
254
} ;
247
255
248
- // Update id of the item itself
256
+ // Update level of the item itself
249
257
let item_level = self . update ( item. id , inherited_item_level) ;
250
258
251
- // Update ids of nested things
259
+ // Update levels of nested things
252
260
match item. node {
253
261
hir:: ItemEnum ( ref def, _) => {
254
262
for variant in & def. variants {
@@ -292,19 +300,72 @@ impl<'a, 'tcx, 'v> Visitor<'v> for EmbargoVisitor<'a, 'tcx> {
292
300
}
293
301
}
294
302
}
295
- hir:: ItemTy ( ref ty, _) if item_level. is_some ( ) => {
296
- if let hir:: TyPath ( ..) = ty. node {
297
- match self . tcx . def_map . borrow ( ) . get ( & ty. id ) . unwrap ( ) . full_def ( ) {
298
- Def :: PrimTy ( ..) | Def :: SelfTy ( ..) | Def :: TyParam ( ..) => { } ,
299
- def => {
300
- if let Some ( node_id) = self . tcx . map . as_local_node_id ( def. def_id ( ) ) {
301
- self . update ( node_id, Some ( AccessLevel :: Reachable ) ) ;
302
- }
303
+ _ => { }
304
+ }
305
+
306
+ // Mark all items in interfaces of reachable items as reachable
307
+ match item. node {
308
+ // The interface is empty
309
+ hir:: ItemExternCrate ( ..) => { }
310
+ // All nested items are checked by visit_item
311
+ hir:: ItemMod ( ..) => { }
312
+ // Reexports are handled in visit_mod
313
+ hir:: ItemUse ( ..) => { }
314
+ // Visit everything
315
+ hir:: ItemConst ( ..) | hir:: ItemStatic ( ..) | hir:: ItemFn ( ..) |
316
+ hir:: ItemTrait ( ..) | hir:: ItemTy ( ..) | hir:: ItemImpl ( _, _, _, Some ( ..) , _, _) => {
317
+ if item_level. is_some ( ) {
318
+ self . reach ( ) . visit_item ( item) ;
319
+ }
320
+ }
321
+ // Visit everything, but enum variants have their own levels
322
+ hir:: ItemEnum ( ref def, ref generics) => {
323
+ if item_level. is_some ( ) {
324
+ self . reach ( ) . visit_generics ( generics) ;
325
+ }
326
+ for variant in & def. variants {
327
+ if self . get ( variant. node . data . id ( ) ) . is_some ( ) {
328
+ for field in variant. node . data . fields ( ) {
329
+ self . reach ( ) . visit_struct_field ( field) ;
330
+ }
331
+ // Corner case: if the variant is reachable, but its
332
+ // enum is not, make the enum reachable as well.
333
+ self . update ( item. id , Some ( AccessLevel :: Reachable ) ) ;
334
+ }
335
+ }
336
+ }
337
+ // Visit everything, but foreign items have their own levels
338
+ hir:: ItemForeignMod ( ref foreign_mod) => {
339
+ for foreign_item in & foreign_mod. items {
340
+ if self . get ( foreign_item. id ) . is_some ( ) {
341
+ self . reach ( ) . visit_foreign_item ( foreign_item) ;
342
+ }
343
+ }
344
+ }
345
+ // Visit everything except for private fields
346
+ hir:: ItemStruct ( ref struct_def, ref generics) => {
347
+ if item_level. is_some ( ) {
348
+ self . reach ( ) . visit_generics ( generics) ;
349
+ for field in struct_def. fields ( ) {
350
+ if self . get ( field. node . id ) . is_some ( ) {
351
+ self . reach ( ) . visit_struct_field ( field) ;
352
+ }
353
+ }
354
+ }
355
+ }
356
+ // The interface is empty
357
+ hir:: ItemDefaultImpl ( ..) => { }
358
+ // Visit everything except for private impl items
359
+ hir:: ItemImpl ( _, _, ref generics, None , _, ref impl_items) => {
360
+ if item_level. is_some ( ) {
361
+ self . reach ( ) . visit_generics ( generics) ;
362
+ for impl_item in impl_items {
363
+ if self . get ( impl_item. id ) . is_some ( ) {
364
+ self . reach ( ) . visit_impl_item ( impl_item) ;
303
365
}
304
366
}
305
367
}
306
368
}
307
- _ => { }
308
369
}
309
370
310
371
let orig_level = self . prev_level ;
@@ -347,6 +408,68 @@ impl<'a, 'tcx, 'v> Visitor<'v> for EmbargoVisitor<'a, 'tcx> {
347
408
}
348
409
}
349
410
411
+ impl < ' b , ' a , ' tcx : ' a > ReachEverythingInTheInterfaceVisitor < ' b , ' a , ' tcx > {
412
+ // Make the type hidden under a type alias reachable
413
+ fn reach_aliased_type ( & mut self , item : & hir:: Item , path : & hir:: Path ) {
414
+ if let hir:: ItemTy ( ref ty, ref generics) = item. node {
415
+ // See `fn is_public_type_alias` for details
416
+ self . visit_ty ( ty) ;
417
+ let provided_params = path. segments . last ( ) . unwrap ( ) . parameters . types ( ) . len ( ) ;
418
+ for ty_param in & generics. ty_params [ provided_params..] {
419
+ if let Some ( ref default_ty) = ty_param. default {
420
+ self . visit_ty ( default_ty) ;
421
+ }
422
+ }
423
+ }
424
+ }
425
+ }
426
+
427
+ impl < ' b , ' a , ' tcx : ' a , ' v > Visitor < ' v > for ReachEverythingInTheInterfaceVisitor < ' b , ' a , ' tcx > {
428
+ fn visit_ty ( & mut self , ty : & hir:: Ty ) {
429
+ if let hir:: TyPath ( _, ref path) = ty. node {
430
+ let def = self . ev . tcx . def_map . borrow ( ) . get ( & ty. id ) . unwrap ( ) . full_def ( ) ;
431
+ match def {
432
+ Def :: Struct ( def_id) | Def :: Enum ( def_id) | Def :: TyAlias ( def_id) |
433
+ Def :: Trait ( def_id) | Def :: AssociatedTy ( def_id, _) => {
434
+ if let Some ( node_id) = self . ev . tcx . map . as_local_node_id ( def_id) {
435
+ let item = self . ev . tcx . map . expect_item ( node_id) ;
436
+ if let Def :: TyAlias ( ..) = def {
437
+ // Type aliases are substituted. Associated type aliases are not
438
+ // substituted yet, but ideally they should be.
439
+ if self . ev . get ( item. id ) . is_none ( ) {
440
+ self . reach_aliased_type ( item, path) ;
441
+ }
442
+ } else {
443
+ self . ev . update ( item. id , Some ( AccessLevel :: Reachable ) ) ;
444
+ }
445
+ }
446
+ }
447
+
448
+ _ => { }
449
+ }
450
+ }
451
+
452
+ intravisit:: walk_ty ( self , ty) ;
453
+ }
454
+
455
+ fn visit_trait_ref ( & mut self , trait_ref : & hir:: TraitRef ) {
456
+ let def_id = self . ev . tcx . trait_ref_to_def_id ( trait_ref) ;
457
+ if let Some ( node_id) = self . ev . tcx . map . as_local_node_id ( def_id) {
458
+ let item = self . ev . tcx . map . expect_item ( node_id) ;
459
+ self . ev . update ( item. id , Some ( AccessLevel :: Reachable ) ) ;
460
+ }
461
+
462
+ intravisit:: walk_trait_ref ( self , trait_ref) ;
463
+ }
464
+
465
+ // Don't recurse into function bodies
466
+ fn visit_block ( & mut self , _: & hir:: Block ) { }
467
+ // Don't recurse into expressions in array sizes or const initializers
468
+ fn visit_expr ( & mut self , _: & hir:: Expr ) { }
469
+ // Don't recurse into patterns in function arguments
470
+ fn visit_pat ( & mut self , _: & hir:: Pat ) { }
471
+ }
472
+
350
473
////////////////////////////////////////////////////////////////////////////////
351
474
/// The privacy visitor, where privacy checks take place (violations reported)
352
475
////////////////////////////////////////////////////////////////////////////////
0 commit comments