@@ -169,6 +169,10 @@ struct EmbargoVisitor<'a, 'tcx: 'a> {
169169 changed : bool ,
170170}
171171
172+ struct ReachEverythingInTheInterfaceVisitor < ' b , ' a : ' b , ' tcx : ' a > {
173+ ev : & ' b mut EmbargoVisitor < ' a , ' tcx > ,
174+ }
175+
172176impl < ' a , ' tcx > EmbargoVisitor < ' a , ' tcx > {
173177 fn ty_level ( & self , ty : & hir:: Ty ) -> Option < AccessLevel > {
174178 if let hir:: TyPath ( ..) = ty. node {
@@ -214,6 +218,10 @@ impl<'a, 'tcx> EmbargoVisitor<'a, 'tcx> {
214218 old_level
215219 }
216220 }
221+
222+ fn reach < ' b > ( & ' b mut self ) -> ReachEverythingInTheInterfaceVisitor < ' b , ' a , ' tcx > {
223+ ReachEverythingInTheInterfaceVisitor { ev : self }
224+ }
217225}
218226
219227impl < ' a , ' tcx , ' v > Visitor < ' v > for EmbargoVisitor < ' a , ' tcx > {
@@ -245,10 +253,10 @@ impl<'a, 'tcx, 'v> Visitor<'v> for EmbargoVisitor<'a, 'tcx> {
245253 }
246254 } ;
247255
248- // Update id of the item itself
256+ // Update level of the item itself
249257 let item_level = self . update ( item. id , inherited_item_level) ;
250258
251- // Update ids of nested things
259+ // Update levels of nested things
252260 match item. node {
253261 hir:: ItemEnum ( ref def, _) => {
254262 for variant in & def. variants {
@@ -292,19 +300,72 @@ impl<'a, 'tcx, 'v> Visitor<'v> for EmbargoVisitor<'a, 'tcx> {
292300 }
293301 }
294302 }
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) ;
303365 }
304366 }
305367 }
306368 }
307- _ => { }
308369 }
309370
310371 let orig_level = self . prev_level ;
@@ -347,6 +408,68 @@ impl<'a, 'tcx, 'v> Visitor<'v> for EmbargoVisitor<'a, 'tcx> {
347408 }
348409}
349410
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+
350473////////////////////////////////////////////////////////////////////////////////
351474/// The privacy visitor, where privacy checks take place (violations reported)
352475////////////////////////////////////////////////////////////////////////////////
0 commit comments