Skip to content

Commit d03b0f5

Browse files
If re-export is private, get the next item until a public one is found or expose the private item directly
1 parent 1a449dc commit d03b0f5

File tree

1 file changed

+93
-3
lines changed

1 file changed

+93
-3
lines changed

src/librustdoc/clean/mod.rs

Lines changed: 93 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1479,8 +1479,93 @@ pub(crate) fn clean_middle_assoc_item<'tcx>(
14791479
Item::from_def_id_and_parts(assoc_item.def_id, Some(assoc_item.name), kind, cx)
14801480
}
14811481

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_not_private(
1487+
cx: &mut DocContext<'_>,
1488+
hir_id: hir::HirId,
1489+
path: &hir::Path<'_>,
1490+
) -> Option<Path> {
1491+
if path.segments.is_empty() {
1492+
return None;
1493+
}
1494+
let parent_def_id = if path.segments.len() == 1 {
1495+
// Then it's available in the same scope as the owner.
1496+
hir_id.owner.def_id
1497+
} else {
1498+
// It's not available in the same scope, so we start from the parent of the item.
1499+
path.segments[path.segments.len() - 2].res.opt_def_id()?.as_local()?
1500+
};
1501+
let target_def_id = path.res.opt_def_id()?;
1502+
let mut ident = path.segments.last().unwrap().ident;
1503+
// First we try to get the `DefId` of the item.
1504+
for child in cx
1505+
.tcx
1506+
.module_children_local(cx.tcx.local_parent(parent_def_id))
1507+
.iter()
1508+
.filter(move |c| c.ident == ident)
1509+
{
1510+
if let Res::Def(DefKind::Ctor(..), _) | Res::SelfCtor(..) = child.res {
1511+
continue;
1512+
}
1513+
1514+
if let Some(def_id) = child.res.opt_def_id() && target_def_id == def_id {
1515+
let mut last_path_res = None;
1516+
'reexps: for reexp in child.reexport_chain.iter() {
1517+
if let Some(use_def_id) = reexp.id() &&
1518+
let Some(local_use_def_id) = use_def_id.as_local()
1519+
{
1520+
let hir = cx.tcx.hir();
1521+
// let parent_mod = hir.local_def_id_to_hir_id();
1522+
for item_id in hir.module_items(cx.tcx.local_parent(local_use_def_id)) {
1523+
let item = hir.item(item_id);
1524+
if item.ident == ident {
1525+
match item.kind {
1526+
hir::ItemKind::Use(path, _) => {
1527+
for res in &path.res {
1528+
if let Res::Def(DefKind::Ctor(..), _) | Res::SelfCtor(..) = res {
1529+
continue;
1530+
}
1531+
if !cx.tcx.is_doc_hidden(use_def_id) &&
1532+
cx.tcx.local_visibility(local_use_def_id).is_public() {
1533+
break 'reexps;
1534+
}
1535+
ident = path.segments.last().unwrap().ident;
1536+
last_path_res = Some((path, res));
1537+
continue 'reexps;
1538+
}
1539+
}
1540+
_ => {}
1541+
}
1542+
}
1543+
}
1544+
}
1545+
}
1546+
if !child.reexport_chain.is_empty() {
1547+
// So in here, we use the data we gathered from iterating the reexports. If
1548+
// `last_path_res` is set, it can mean two things:
1549+
//
1550+
// 1. We found a public reexport.
1551+
// 2. We didn't find a public reexport so it's the "end type" path.
1552+
if let Some((path, res)) = last_path_res {
1553+
let path = hir::Path { segments: path.segments, res: *res, span: path.span };
1554+
return Some(clean_path(&path, cx));
1555+
}
1556+
// If `last_path_res` is `None`, it can mean two things:
1557+
//
1558+
// 1. The re-export is public, no need to change anything, just use the path as is.
1559+
// 2. Nothing was found, so let's just return the original path.
1560+
return None;
1561+
}
1562+
}
1563+
}
1564+
None
1565+
}
1566+
14821567
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;
1568+
let hir::Ty { hir_id, span, ref kind } = *hir_ty;
14841569
let hir::TyKind::Path(qpath) = kind else { unreachable!() };
14851570

14861571
match qpath {
@@ -1497,7 +1582,12 @@ fn clean_qpath<'tcx>(hir_ty: &hir::Ty<'tcx>, cx: &mut DocContext<'tcx>) -> Type
14971582
if let Some(expanded) = maybe_expand_private_type_alias(cx, path) {
14981583
expanded
14991584
} else {
1500-
let path = clean_path(path, cx);
1585+
// First we check if it's a private re-export.
1586+
let path = if let Some(path) = first_not_private(cx, hir_id, &path) {
1587+
path
1588+
} else {
1589+
clean_path(path, cx)
1590+
};
15011591
resolve_type(cx, path)
15021592
}
15031593
}
@@ -1649,7 +1739,7 @@ fn maybe_expand_private_type_alias<'tcx>(
16491739
}
16501740
}
16511741

1652-
Some(cx.enter_alias(substs, def_id.to_def_id(), |cx| clean_ty(ty, cx)))
1742+
Some(cx.enter_alias(substs, def_id.to_def_id(), |cx| clean_ty(&ty, cx)))
16531743
}
16541744

16551745
pub(crate) fn clean_ty<'tcx>(ty: &hir::Ty<'tcx>, cx: &mut DocContext<'tcx>) -> Type {

0 commit comments

Comments
 (0)