@@ -1479,8 +1479,97 @@ pub(crate) fn clean_middle_assoc_item<'tcx>(
1479
1479
Item :: from_def_id_and_parts ( assoc_item. def_id , Some ( assoc_item. name ) , kind, cx)
1480
1480
}
1481
1481
1482
+ /// The goal of this function is to return the first `Path` which is not private (ie not private
1483
+ /// or `doc(hidden)`). If it's not possible, it'll return the "end type".
1484
+ ///
1485
+ /// If the path is not a re-export or is public, it'll return `None`.
1486
+ fn first_non_private (
1487
+ cx : & mut DocContext < ' _ > ,
1488
+ hir_id : hir:: HirId ,
1489
+ path : & hir:: Path < ' _ > ,
1490
+ ) -> Option < Path > {
1491
+ let ( parent_def_id, mut ident) = match & path. segments [ ..] {
1492
+ [ ] => return None ,
1493
+ // Relative paths are available in the same scope as the owner.
1494
+ [ leaf] => ( cx. tcx . local_parent ( hir_id. owner . def_id ) , leaf. ident ) ,
1495
+ // So are self paths.
1496
+ [ parent, leaf] if parent. ident . name == kw:: SelfLower => {
1497
+ ( cx. tcx . local_parent ( hir_id. owner . def_id ) , leaf. ident )
1498
+ }
1499
+ // Crate paths are not. We start from the crate root.
1500
+ [ parent, leaf] if matches ! ( parent. ident. name, kw:: Crate | kw:: PathRoot ) => {
1501
+ ( LOCAL_CRATE . as_def_id ( ) . as_local ( ) ?, leaf. ident )
1502
+ }
1503
+ [ parent, leaf] if parent. ident . name == kw:: Super => {
1504
+ let parent_mod = cx. tcx . parent_module ( hir_id) ;
1505
+ if let Some ( super_parent) = cx. tcx . opt_local_parent ( parent_mod) {
1506
+ ( super_parent, leaf. ident )
1507
+ } else {
1508
+ // If we can't find the parent of the parent, then the parent is already the crate.
1509
+ ( LOCAL_CRATE . as_def_id ( ) . as_local ( ) ?, leaf. ident )
1510
+ }
1511
+ }
1512
+ // Absolute paths are not. We start from the parent of the item.
1513
+ [ .., parent, leaf] => ( parent. res . opt_def_id ( ) ?. as_local ( ) ?, leaf. ident ) ,
1514
+ } ;
1515
+ let target_def_id = path. res . opt_def_id ( ) ?;
1516
+ // First we try to get the `DefId` of the item.
1517
+ for child in
1518
+ cx. tcx . module_children_local ( parent_def_id) . iter ( ) . filter ( move |c| c. ident == ident)
1519
+ {
1520
+ if let Res :: Def ( DefKind :: Ctor ( ..) , _) | Res :: SelfCtor ( ..) = child. res {
1521
+ continue ;
1522
+ }
1523
+
1524
+ if let Some ( def_id) = child. res . opt_def_id ( ) && target_def_id == def_id {
1525
+ let mut last_path_res = None ;
1526
+ ' reexps: for reexp in child. reexport_chain . iter ( ) {
1527
+ if let Some ( use_def_id) = reexp. id ( ) &&
1528
+ let Some ( local_use_def_id) = use_def_id. as_local ( )
1529
+ {
1530
+ let hir = cx. tcx . hir ( ) ;
1531
+ for item_id in hir. module_items ( cx. tcx . local_parent ( local_use_def_id) ) {
1532
+ let item = hir. item ( item_id) ;
1533
+ if item. ident == ident && let hir:: ItemKind :: Use ( path, _) = item. kind {
1534
+ for res in & path. res {
1535
+ if let Res :: Def ( DefKind :: Ctor ( ..) , _) | Res :: SelfCtor ( ..) = res {
1536
+ continue ;
1537
+ }
1538
+ if !cx. tcx . is_doc_hidden ( use_def_id) &&
1539
+ cx. tcx . local_visibility ( local_use_def_id) . is_public ( ) {
1540
+ break ' reexps;
1541
+ }
1542
+ ident = path. segments . last ( ) . unwrap ( ) . ident ;
1543
+ last_path_res = Some ( ( path, res) ) ;
1544
+ continue ' reexps;
1545
+ }
1546
+ }
1547
+ }
1548
+ }
1549
+ }
1550
+ if !child. reexport_chain . is_empty ( ) {
1551
+ // So in here, we use the data we gathered from iterating the reexports. If
1552
+ // `last_path_res` is set, it can mean two things:
1553
+ //
1554
+ // 1. We found a public reexport.
1555
+ // 2. We didn't find a public reexport so it's the "end type" path.
1556
+ if let Some ( ( path, res) ) = last_path_res {
1557
+ let path = hir:: Path { segments : path. segments , res : * res, span : path. span } ;
1558
+ return Some ( clean_path ( & path, cx) ) ;
1559
+ }
1560
+ // If `last_path_res` is `None`, it can mean two things:
1561
+ //
1562
+ // 1. The re-export is public, no need to change anything, just use the path as is.
1563
+ // 2. Nothing was found, so let's just return the original path.
1564
+ return None ;
1565
+ }
1566
+ }
1567
+ }
1568
+ None
1569
+ }
1570
+
1482
1571
fn clean_qpath < ' tcx > ( hir_ty : & hir:: Ty < ' tcx > , cx : & mut DocContext < ' tcx > ) -> Type {
1483
- let hir:: Ty { hir_id : _ , span, ref kind } = * hir_ty;
1572
+ let hir:: Ty { hir_id, span, ref kind } = * hir_ty;
1484
1573
let hir:: TyKind :: Path ( qpath) = kind else { unreachable ! ( ) } ;
1485
1574
1486
1575
match qpath {
@@ -1497,7 +1586,12 @@ fn clean_qpath<'tcx>(hir_ty: &hir::Ty<'tcx>, cx: &mut DocContext<'tcx>) -> Type
1497
1586
if let Some ( expanded) = maybe_expand_private_type_alias ( cx, path) {
1498
1587
expanded
1499
1588
} else {
1500
- let path = clean_path ( path, cx) ;
1589
+ // First we check if it's a private re-export.
1590
+ let path = if let Some ( path) = first_non_private ( cx, hir_id, & path) {
1591
+ path
1592
+ } else {
1593
+ clean_path ( path, cx)
1594
+ } ;
1501
1595
resolve_type ( cx, path)
1502
1596
}
1503
1597
}
@@ -1649,7 +1743,7 @@ fn maybe_expand_private_type_alias<'tcx>(
1649
1743
}
1650
1744
}
1651
1745
1652
- Some ( cx. enter_alias ( substs, def_id. to_def_id ( ) , |cx| clean_ty ( ty, cx) ) )
1746
+ Some ( cx. enter_alias ( substs, def_id. to_def_id ( ) , |cx| clean_ty ( & ty, cx) ) )
1653
1747
}
1654
1748
1655
1749
pub ( crate ) fn clean_ty < ' tcx > ( ty : & hir:: Ty < ' tcx > , cx : & mut DocContext < ' tcx > ) -> Type {
0 commit comments