Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit 9339f44

Browse files
committed
Auto merge of #113374 - GuillaumeGomez:private-to-public-path, r=notriddle,fmease
[rustdoc] If re-export is private, get the next item until a public one is found or expose the private item directly Fixes #81141. If we have: ```rust use Private as Something; pub fn foo() -> Something {} ``` Then `Something` will be replaced by `Private`. r? `@notriddle`
2 parents b73e9a4 + 2461d0c commit 9339f44

9 files changed

+344
-3
lines changed

‎src/librustdoc/clean/mod.rs‎

Lines changed: 121 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1514,8 +1514,121 @@ pub(crate) fn clean_middle_assoc_item<'tcx>(
15141514
Item::from_def_id_and_parts(assoc_item.def_id, Some(assoc_item.name), kind, cx)
15151515
}
15161516

1517+
fn first_non_private_clean_path<'tcx>(
1518+
cx: &mut DocContext<'tcx>,
1519+
path: &hir::Path<'tcx>,
1520+
new_path_segments: &'tcx [hir::PathSegment<'tcx>],
1521+
new_path_span: rustc_span::Span,
1522+
) -> Path {
1523+
let new_hir_path =
1524+
hir::Path { segments: new_path_segments, res: path.res, span: new_path_span };
1525+
let mut new_clean_path = clean_path(&new_hir_path, cx);
1526+
// In here we need to play with the path data one last time to provide it the
1527+
// missing `args` and `res` of the final `Path` we get, which, since it comes
1528+
// from a re-export, doesn't have the generics that were originally there, so
1529+
// we add them by hand.
1530+
if let Some(path_last) = path.segments.last().as_ref()
1531+
&& let Some(new_path_last) = new_clean_path.segments[..].last_mut()
1532+
&& let Some(path_last_args) = path_last.args.as_ref()
1533+
&& path_last.args.is_some()
1534+
{
1535+
assert!(new_path_last.args.is_empty());
1536+
new_path_last.args = clean_generic_args(path_last_args, cx);
1537+
}
1538+
new_clean_path
1539+
}
1540+
1541+
/// The goal of this function is to return the first `Path` which is not private (ie not private
1542+
/// or `doc(hidden)`). If it's not possible, it'll return the "end type".
1543+
///
1544+
/// If the path is not a re-export or is public, it'll return `None`.
1545+
fn first_non_private<'tcx>(
1546+
cx: &mut DocContext<'tcx>,
1547+
hir_id: hir::HirId,
1548+
path: &hir::Path<'tcx>,
1549+
) -> Option<Path> {
1550+
let target_def_id = path.res.opt_def_id()?;
1551+
let (parent_def_id, ident) = match &path.segments[..] {
1552+
[] => return None,
1553+
// Relative paths are available in the same scope as the owner.
1554+
[leaf] => (cx.tcx.local_parent(hir_id.owner.def_id), leaf.ident),
1555+
// So are self paths.
1556+
[parent, leaf] if parent.ident.name == kw::SelfLower => {
1557+
(cx.tcx.local_parent(hir_id.owner.def_id), leaf.ident)
1558+
}
1559+
// Crate paths are not. We start from the crate root.
1560+
[parent, leaf] if matches!(parent.ident.name, kw::Crate | kw::PathRoot) => {
1561+
(LOCAL_CRATE.as_def_id().as_local()?, leaf.ident)
1562+
}
1563+
[parent, leaf] if parent.ident.name == kw::Super => {
1564+
let parent_mod = cx.tcx.parent_module(hir_id);
1565+
if let Some(super_parent) = cx.tcx.opt_local_parent(parent_mod) {
1566+
(super_parent, leaf.ident)
1567+
} else {
1568+
// If we can't find the parent of the parent, then the parent is already the crate.
1569+
(LOCAL_CRATE.as_def_id().as_local()?, leaf.ident)
1570+
}
1571+
}
1572+
// Absolute paths are not. We start from the parent of the item.
1573+
[.., parent, leaf] => (parent.res.opt_def_id()?.as_local()?, leaf.ident),
1574+
};
1575+
let hir = cx.tcx.hir();
1576+
// First we try to get the `DefId` of the item.
1577+
for child in
1578+
cx.tcx.module_children_local(parent_def_id).iter().filter(move |c| c.ident == ident)
1579+
{
1580+
if let Res::Def(DefKind::Ctor(..), _) | Res::SelfCtor(..) = child.res {
1581+
continue;
1582+
}
1583+
1584+
if let Some(def_id) = child.res.opt_def_id() && target_def_id == def_id {
1585+
let mut last_path_res = None;
1586+
'reexps: for reexp in child.reexport_chain.iter() {
1587+
if let Some(use_def_id) = reexp.id() &&
1588+
let Some(local_use_def_id) = use_def_id.as_local() &&
1589+
let Some(hir::Node::Item(item)) = hir.find_by_def_id(local_use_def_id) &&
1590+
!item.ident.name.is_empty() &&
1591+
let hir::ItemKind::Use(path, _) = item.kind
1592+
{
1593+
for res in &path.res {
1594+
if let Res::Def(DefKind::Ctor(..), _) | Res::SelfCtor(..) = res {
1595+
continue;
1596+
}
1597+
if (cx.render_options.document_hidden ||
1598+
!cx.tcx.is_doc_hidden(use_def_id)) &&
1599+
// We never check for "cx.render_options.document_private"
1600+
// because if a re-export is not fully public, it's never
1601+
// documented.
1602+
cx.tcx.local_visibility(local_use_def_id).is_public() {
1603+
break 'reexps;
1604+
}
1605+
last_path_res = Some((path, res));
1606+
continue 'reexps;
1607+
}
1608+
}
1609+
}
1610+
if !child.reexport_chain.is_empty() {
1611+
// So in here, we use the data we gathered from iterating the reexports. If
1612+
// `last_path_res` is set, it can mean two things:
1613+
//
1614+
// 1. We found a public reexport.
1615+
// 2. We didn't find a public reexport so it's the "end type" path.
1616+
if let Some((new_path, _)) = last_path_res {
1617+
return Some(first_non_private_clean_path(cx, path, new_path.segments, new_path.span));
1618+
}
1619+
// If `last_path_res` is `None`, it can mean two things:
1620+
//
1621+
// 1. The re-export is public, no need to change anything, just use the path as is.
1622+
// 2. Nothing was found, so let's just return the original path.
1623+
return None;
1624+
}
1625+
}
1626+
}
1627+
None
1628+
}
1629+
15171630
fn clean_qpath<'tcx>(hir_ty: &hir::Ty<'tcx>, cx: &mut DocContext<'tcx>) -> Type {
1518-
let hir::Ty { hir_id: _, span, ref kind } = *hir_ty;
1631+
let hir::Ty { hir_id, span, ref kind } = *hir_ty;
15191632
let hir::TyKind::Path(qpath) = kind else { unreachable!() };
15201633

15211634
match qpath {
@@ -1532,7 +1645,12 @@ fn clean_qpath<'tcx>(hir_ty: &hir::Ty<'tcx>, cx: &mut DocContext<'tcx>) -> Type
15321645
if let Some(expanded) = maybe_expand_private_type_alias(cx, path) {
15331646
expanded
15341647
} else {
1535-
let path = clean_path(path, cx);
1648+
// First we check if it's a private re-export.
1649+
let path = if let Some(path) = first_non_private(cx, hir_id, &path) {
1650+
path
1651+
} else {
1652+
clean_path(path, cx)
1653+
};
15361654
resolve_type(cx, path)
15371655
}
15381656
}
@@ -1683,7 +1801,7 @@ fn maybe_expand_private_type_alias<'tcx>(
16831801
}
16841802
}
16851803

1686-
Some(cx.enter_alias(args, def_id.to_def_id(), |cx| clean_ty(ty, cx)))
1804+
Some(cx.enter_alias(args, def_id.to_def_id(), |cx| clean_ty(&ty, cx)))
16871805
}
16881806

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

‎src/librustdoc/clean/types.rs‎

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2212,6 +2212,17 @@ pub(crate) enum GenericArgs {
22122212
Parenthesized { inputs: Box<[Type]>, output: Option<Box<Type>> },
22132213
}
22142214

2215+
impl GenericArgs {
2216+
pub(crate) fn is_empty(&self) -> bool {
2217+
match self {
2218+
GenericArgs::AngleBracketed { args, bindings } => {
2219+
args.is_empty() && bindings.is_empty()
2220+
}
2221+
GenericArgs::Parenthesized { inputs, output } => inputs.is_empty() && output.is_none(),
2222+
}
2223+
}
2224+
}
2225+
22152226
#[derive(Clone, PartialEq, Eq, Debug, Hash)]
22162227
pub(crate) struct PathSegment {
22172228
pub(crate) name: Symbol,
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
pub struct Ident;
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
// edition:2015
2+
3+
#![crate_name = "foo"]
4+
5+
use external::Public as Private;
6+
7+
pub mod external {
8+
pub struct Public;
9+
10+
// @has 'foo/external/fn.make.html'
11+
// @has - '//*[@class="rust item-decl"]/code' 'pub fn make() -> Public'
12+
pub fn make() -> ::Private { super::Private }
13+
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
#![crate_name = "foo"]
2+
3+
use crate::bar::Foo as Alias;
4+
5+
pub mod bar {
6+
pub struct Foo<'a, T>(&'a T);
7+
}
8+
9+
// @has "foo/fn.foo.html"
10+
// @has - '//*[@class="rust item-decl"]/code' "pub fn foo<'a, T>(f: Foo<'a, T>) -> Foo<'a, usize>"
11+
pub fn foo<'a, T>(f: Alias<'a, T>) -> Alias<'a, usize> {
12+
Alias(&0)
13+
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
// compile-flags: -Z unstable-options --document-hidden-items
2+
3+
#![crate_name = "foo"]
4+
5+
#[doc(hidden)]
6+
pub use crate::bar::Bar as Alias;
7+
8+
mod bar {
9+
pub struct Bar;
10+
}
11+
12+
// @has 'foo/fn.bar.html'
13+
// @has - '//*[@class="rust item-decl"]/code' 'pub fn bar() -> Alias'
14+
pub fn bar() -> Alias {
15+
Alias
16+
}
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
// compile-flags: --document-private-items
2+
3+
#![crate_name = "foo"]
4+
5+
use crate::bar::Bar as Alias;
6+
pub(crate) use crate::bar::Bar as CrateAlias;
7+
8+
mod bar {
9+
pub struct Bar;
10+
pub use self::Bar as Inner;
11+
}
12+
13+
// It's a fully private re-export so it should not be displayed.
14+
// @has 'foo/fn.bar.html'
15+
// @has - '//*[@class="rust item-decl"]/code' 'pub fn bar() -> Bar'
16+
pub fn bar() -> Alias {
17+
Alias
18+
}
19+
20+
// It's public re-export inside a private module so it should be visible.
21+
// @has 'foo/fn.bar2.html'
22+
// @has - '//*[@class="rust item-decl"]/code' 'pub fn bar2() -> Inner'
23+
pub fn bar2() -> crate::bar::Inner {
24+
Alias
25+
}
26+
27+
// It's a non-public, so it doesn't appear in documentation so it should not be visible.
28+
// @has 'foo/fn.bar3.html'
29+
// @has - '//*[@class="rust item-decl"]/code' 'pub fn bar3() -> Bar'
30+
pub fn bar3() -> CrateAlias {
31+
Alias
32+
}
Lines changed: 124 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,124 @@
1+
// This test ensures that if a private re-export is present in a public API, it'll be
2+
// replaced by the first public item in the re-export chain or by the private item.
3+
4+
#![crate_name = "foo"]
5+
6+
use crate::bar::Bar as Alias;
7+
8+
pub use crate::bar::Bar as Whatever;
9+
use crate::Whatever as Whatever2;
10+
use crate::Whatever2 as Whatever3;
11+
pub use crate::bar::Inner as Whatever4;
12+
13+
mod bar {
14+
pub struct Bar;
15+
pub use self::Bar as Inner;
16+
}
17+
18+
// @has 'foo/fn.bar.html'
19+
// @has - '//*[@class="rust item-decl"]/code' 'pub fn bar() -> Bar'
20+
pub fn bar() -> Alias {
21+
Alias
22+
}
23+
24+
// @has 'foo/fn.bar2.html'
25+
// @has - '//*[@class="rust item-decl"]/code' 'pub fn bar2() -> Whatever'
26+
pub fn bar2() -> Whatever3 {
27+
Whatever
28+
}
29+
30+
// @has 'foo/fn.bar3.html'
31+
// @has - '//*[@class="rust item-decl"]/code' 'pub fn bar3() -> Whatever4'
32+
pub fn bar3() -> Whatever4 {
33+
Whatever
34+
}
35+
36+
// @has 'foo/fn.bar4.html'
37+
// @has - '//*[@class="rust item-decl"]/code' 'pub fn bar4() -> Bar'
38+
pub fn bar4() -> crate::Alias {
39+
Alias
40+
}
41+
42+
// @has 'foo/fn.bar5.html'
43+
// @has - '//*[@class="rust item-decl"]/code' 'pub fn bar5() -> Whatever'
44+
pub fn bar5() -> crate::Whatever3 {
45+
Whatever
46+
}
47+
48+
// @has 'foo/fn.bar6.html'
49+
// @has - '//*[@class="rust item-decl"]/code' 'pub fn bar6() -> Whatever4'
50+
pub fn bar6() -> crate::Whatever4 {
51+
Whatever
52+
}
53+
54+
55+
// @has 'foo/fn.bar7.html'
56+
// @has - '//*[@class="rust item-decl"]/code' 'pub fn bar7() -> Bar'
57+
pub fn bar7() -> self::Alias {
58+
Alias
59+
}
60+
61+
// @has 'foo/fn.bar8.html'
62+
// @has - '//*[@class="rust item-decl"]/code' 'pub fn bar8() -> Whatever'
63+
pub fn bar8() -> self::Whatever3 {
64+
Whatever
65+
}
66+
67+
// @has 'foo/fn.bar9.html'
68+
// @has - '//*[@class="rust item-decl"]/code' 'pub fn bar9() -> Whatever4'
69+
pub fn bar9() -> self::Whatever4 {
70+
Whatever
71+
}
72+
73+
mod nested {
74+
pub(crate) use crate::Alias;
75+
pub(crate) use crate::Whatever3;
76+
pub(crate) use crate::Whatever4;
77+
pub(crate) use crate::nested as nested2;
78+
}
79+
80+
// @has 'foo/fn.bar10.html'
81+
// @has - '//*[@class="rust item-decl"]/code' 'pub fn bar10() -> Bar'
82+
pub fn bar10() -> nested::Alias {
83+
Alias
84+
}
85+
86+
// @has 'foo/fn.bar11.html'
87+
// @has - '//*[@class="rust item-decl"]/code' 'pub fn bar11() -> Whatever'
88+
pub fn bar11() -> nested::Whatever3 {
89+
Whatever
90+
}
91+
92+
// @has 'foo/fn.bar12.html'
93+
// @has - '//*[@class="rust item-decl"]/code' 'pub fn bar12() -> Whatever4'
94+
pub fn bar12() -> nested::Whatever4 {
95+
Whatever
96+
}
97+
98+
// @has 'foo/fn.bar13.html'
99+
// @has - '//*[@class="rust item-decl"]/code' 'pub fn bar13() -> Bar'
100+
pub fn bar13() -> nested::nested2::Alias {
101+
Alias
102+
}
103+
104+
// @has 'foo/fn.bar14.html'
105+
// @has - '//*[@class="rust item-decl"]/code' 'pub fn bar14() -> Whatever'
106+
pub fn bar14() -> nested::nested2::Whatever3 {
107+
Whatever
108+
}
109+
110+
// @has 'foo/fn.bar15.html'
111+
// @has - '//*[@class="rust item-decl"]/code' 'pub fn bar15() -> Whatever4'
112+
pub fn bar15() -> nested::nested2::Whatever4 {
113+
Whatever
114+
}
115+
116+
use external::Public as Private;
117+
118+
pub mod external {
119+
pub struct Public;
120+
121+
// @has 'foo/external/fn.make.html'
122+
// @has - '//*[@class="rust item-decl"]/code' 'pub fn make() -> Public'
123+
pub fn make() -> super::Private { super::Private }
124+
}

‎tests/rustdoc/private-use.rs‎

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
// Regression test for <https://github.com/rust-lang/rust/pull/113374> to
2+
// ensure it doesn't panic.
3+
4+
mod generics {
5+
pub enum WherePredicate {
6+
EqPredicate,
7+
}
8+
}
9+
pub mod visit {
10+
use *;
11+
pub fn visit_where_predicate<V>(_visitor: &mut V, _i: &WherePredicate) {}
12+
}
13+
pub use generics::*;

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /