mirror of
https://github.com/rust-lang/rust
synced 2024-10-01 22:34:35 +00:00
Rollup merge of #112304 - GuillaumeGomez:re-exports, r=notriddle
Add chapter in rustdoc book for re-exports and add a regression test for `#[doc(hidden)]` behaviour Fixes https://github.com/rust-lang/rust/issues/109449. Fixes https://github.com/rust-lang/rust/issues/53417. After the discussion in #109697, I made a few PRs to fix a few corner cases: * https://github.com/rust-lang/rust/pull/112178 * https://github.com/rust-lang/rust/pull/112108 * https://github.com/rust-lang/rust/pull/111997 With this I think I covered all cases. Only thing missing at this point was a chapter covering re-exports in the rustdoc book. r? `@notriddle`
This commit is contained in:
commit
9bc95a4bc9
|
@ -7,6 +7,7 @@
|
|||
- [How to write documentation](how-to-write-documentation.md)
|
||||
- [What to include (and exclude)](write-documentation/what-to-include.md)
|
||||
- [The `#[doc]` attribute](write-documentation/the-doc-attribute.md)
|
||||
- [Re-exports](write-documentation/re-exports.md)
|
||||
- [Linking to items by name](write-documentation/linking-to-items-by-name.md)
|
||||
- [Documentation tests](write-documentation/documentation-tests.md)
|
||||
- [Rustdoc-specific lints](lints.md)
|
||||
|
|
172
src/doc/rustdoc/src/write-documentation/re-exports.md
Normal file
172
src/doc/rustdoc/src/write-documentation/re-exports.md
Normal file
|
@ -0,0 +1,172 @@
|
|||
# Re-exports
|
||||
|
||||
Let's start by explaining what are re-exports. To do so, we will use an example where we are
|
||||
writing a library (named `lib`) with some types dispatched in sub-modules:
|
||||
|
||||
```rust
|
||||
pub mod sub_module1 {
|
||||
pub struct Foo;
|
||||
}
|
||||
pub mod sub_module2 {
|
||||
pub struct AnotherFoo;
|
||||
}
|
||||
```
|
||||
|
||||
Users can import them like this:
|
||||
|
||||
```rust,ignore (inline)
|
||||
use lib::sub_module1::Foo;
|
||||
use lib::sub_module2::AnotherFoo;
|
||||
```
|
||||
|
||||
But what if you want the types to be available directly at the crate root or if we don't want the
|
||||
modules to be visible for users? That's where re-exports come in:
|
||||
|
||||
```rust,ignore (inline)
|
||||
// `sub_module1` and `sub_module2` are not visible outside.
|
||||
mod sub_module1 {
|
||||
pub struct Foo;
|
||||
}
|
||||
mod sub_module2 {
|
||||
pub struct AnotherFoo;
|
||||
}
|
||||
// We re-export both types:
|
||||
pub use crate::sub_module1::Foo;
|
||||
pub use crate::sub_module2::AnotherFoo;
|
||||
```
|
||||
|
||||
And now users will be able to do:
|
||||
|
||||
```rust,ignore (inline)
|
||||
use lib::{Foo, AnotherFoo};
|
||||
```
|
||||
|
||||
And since both `sub_module1` and `sub_module2` are private, users won't be able to import them.
|
||||
|
||||
Now what's interesting is that the generated documentation for this crate will show both `Foo` and
|
||||
`AnotherFoo` directly at the crate root, meaning they have been inlined. There are a few rules to
|
||||
know whether or not a re-exported item will be inlined.
|
||||
|
||||
## Inlining rules
|
||||
|
||||
If a public item comes from a private module, it will be inlined:
|
||||
|
||||
```rust,ignore (inline)
|
||||
mod private_module {
|
||||
pub struct Public;
|
||||
}
|
||||
pub mod public_mod {
|
||||
// `Public` will inlined here since `private_module` is private.
|
||||
pub use super::private_module::Public;
|
||||
}
|
||||
// `Public` will not be inlined here since `public_mod` is public.
|
||||
pub use self::public_mod::Public;
|
||||
```
|
||||
|
||||
Likewise, if an item inherits `#[doc(hidden)]` from any of its ancestors, it will be inlined:
|
||||
|
||||
```rust,ignore (inline)
|
||||
#[doc(hidden)]
|
||||
pub mod public_mod {
|
||||
pub struct Public;
|
||||
}
|
||||
// `Public` be inlined since its parent (`public_mod`) has `#[doc(hidden)]`.
|
||||
pub use self::public_mod::Public;
|
||||
```
|
||||
|
||||
If an item has `#[doc(hidden)]`, it won't be inlined (nor visible in the generated documentation):
|
||||
|
||||
```rust,ignore (inline)
|
||||
// This struct won't be visible.
|
||||
#[doc(hidden)]
|
||||
pub struct Hidden;
|
||||
|
||||
// This re-export won't be visible.
|
||||
pub use self::Hidden as InlinedHidden;
|
||||
```
|
||||
|
||||
The same applies on re-exports themselves: if you have multiple re-exports and some of them have
|
||||
`#[doc(hidden)]`, then these ones (and only these) own't appear in the documentation:
|
||||
|
||||
```rust,ignore (inline)
|
||||
mod private_mod {
|
||||
/// First
|
||||
pub struct InPrivate;
|
||||
}
|
||||
|
||||
/// Second
|
||||
#[doc(hidden)]
|
||||
pub use self::private_mod::InPrivate as Hidden;
|
||||
/// Third
|
||||
pub use self::Hidden as Visible;
|
||||
```
|
||||
|
||||
In this case, `InPrivate` will be inlined as `Visible`. However, its documentation will be
|
||||
`First Third` and not `First Second Third` because the re-export with `Second` as documentation has
|
||||
`#[doc(hidden)]`, therefore, all its attributes are ignored.
|
||||
|
||||
## Inlining with `#[doc(inline)]`
|
||||
|
||||
You can use the `#[doc(inline)]` attribute if you want to force an item to be inlined:
|
||||
|
||||
```rust,ignore (inline)
|
||||
pub mod public_mod {
|
||||
pub struct Public;
|
||||
}
|
||||
#[doc(inline)]
|
||||
pub use self::public_mod::Public;
|
||||
```
|
||||
|
||||
With this code, even though `public_mod::Public` is public and present in the documentation, the
|
||||
`Public` type will be present both at the crate root and in the `public_mod` module.
|
||||
|
||||
## Preventing inlining with `#[doc(no_inline)]`
|
||||
|
||||
On the opposite of the `#[doc(inline)]` attribute, if you want to prevent an item from being
|
||||
inlined, you can use `#[doc(no_inline)]`:
|
||||
|
||||
```rust,ignore (inline)
|
||||
mod private_mod {
|
||||
pub struct Public;
|
||||
}
|
||||
#[doc(no_inline)]
|
||||
pub use self::private_mod::Public;
|
||||
```
|
||||
|
||||
In the generated documentation, you will see a re-export at the crate root and not the type
|
||||
directly.
|
||||
|
||||
## Attributes
|
||||
|
||||
When an item is inlined, its doc comments and most of its attributes will be inlined along with it:
|
||||
|
||||
```rust,ignore (inline)
|
||||
mod private_mod {
|
||||
/// First
|
||||
#[cfg(a)]
|
||||
pub struct InPrivate;
|
||||
/// Second
|
||||
#[cfg(b)]
|
||||
pub use self::InPrivate as Second;
|
||||
}
|
||||
|
||||
/// Third
|
||||
#[doc(inline)]
|
||||
#[cfg(c)]
|
||||
pub use self::private_mod::Second as Visible;
|
||||
```
|
||||
|
||||
In this case, `Visible` will have as documentation `First Second Third` and will also have as `cfg`:
|
||||
`#[cfg(a, b, c)]`.
|
||||
|
||||
[Intra-doc links](./linking-to-items-by-name.md) are resolved relative to where the doc comment is
|
||||
defined.
|
||||
|
||||
There are a few attributes which are not inlined though:
|
||||
* `#[doc(alias="")]`
|
||||
* `#[doc(inline)]`
|
||||
* `#[doc(no_inline)]`
|
||||
* `#[doc(hidden)]` (because the re-export itself and its attributes are ignored).
|
||||
|
||||
All other attributes are inherited when inlined, so that the documentation matches the behavior if
|
||||
the inlined item was directly defined at the spot where it's shown.
|
|
@ -223,12 +223,18 @@ Now we'll have a `Re-exports` line, and `Bar` will not link to anywhere.
|
|||
One special case: In Rust 2018 and later, if you `pub use` one of your dependencies, `rustdoc` will
|
||||
not eagerly inline it as a module unless you add `#[doc(inline)]`.
|
||||
|
||||
If you want to know more about inlining rules, take a look at the
|
||||
[`re-exports` chapter](./re-exports.md).
|
||||
|
||||
### `hidden`
|
||||
|
||||
<span id="dochidden"></span>
|
||||
|
||||
Any item annotated with `#[doc(hidden)]` will not appear in the documentation, unless
|
||||
the `strip-hidden` pass is removed.
|
||||
the `strip-hidden` pass is removed. Re-exported items where one of its ancestors has
|
||||
`#[doc(hidden)]` will be considered the same as private.
|
||||
|
||||
You can find more information in the [`re-exports` chapter](./re-exports.md).
|
||||
|
||||
### `alias`
|
||||
|
||||
|
|
143
tests/rustdoc/issue-109449-doc-hidden-reexports.rs
Normal file
143
tests/rustdoc/issue-109449-doc-hidden-reexports.rs
Normal file
|
@ -0,0 +1,143 @@
|
|||
// Test to enforce rules over re-exports inlining from
|
||||
// <https://github.com/rust-lang/rust/issues/109449>.
|
||||
|
||||
#![crate_name = "foo"]
|
||||
|
||||
mod private_module {
|
||||
#[doc(hidden)]
|
||||
pub struct Public;
|
||||
#[doc(hidden)]
|
||||
pub type Bar = ();
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
mod module {
|
||||
pub struct Public2;
|
||||
pub type Bar2 = ();
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
pub type Bar3 = ();
|
||||
#[doc(hidden)]
|
||||
pub struct FooFoo;
|
||||
|
||||
// Checking that re-exporting a `#[doc(hidden)]` item will NOT inline it.
|
||||
pub mod single_reexport {
|
||||
// @has 'foo/single_reexport/index.html'
|
||||
|
||||
// First we check that we have 4 type aliases.
|
||||
// @count - '//*[@id="main-content"]/*[@class="item-table"]//code' 4
|
||||
|
||||
// Then we check that we have the correct link for each re-export.
|
||||
|
||||
// @!has - '//*[@href="struct.Foo.html"]' 'Foo'
|
||||
// @has - '//*[@id="reexport.Foo"]/code' 'pub use crate::private_module::Public as Foo;'
|
||||
pub use crate::private_module::Public as Foo;
|
||||
// @!has - '//*[@href="type.Foo2.html"]' 'Foo2'
|
||||
// @has - '//*[@id="reexport.Foo2"]/code' 'pub use crate::private_module::Bar as Foo2;'
|
||||
pub use crate::private_module::Bar as Foo2;
|
||||
// @!has - '//*[@href="type.Yo.html"]' 'Yo'
|
||||
// @has - '//*[@id="reexport.Yo"]/code' 'pub use crate::Bar3 as Yo;'
|
||||
pub use crate::Bar3 as Yo;
|
||||
// @!has - '//*[@href="struct.Yo2.html"]' 'Yo2'
|
||||
// @has - '//*[@id="reexport.Yo2"]/code' 'pub use crate::FooFoo as Yo2;'
|
||||
pub use crate::FooFoo as Yo2;
|
||||
|
||||
// Checking that each file is also created as expected.
|
||||
// @!has 'foo/single_reexport/struct.Foo.html'
|
||||
// @!has 'foo/single_reexport/type.Foo2.html'
|
||||
// @!has 'foo/single_reexport/type.Yo.html'
|
||||
// @!has 'foo/single_reexport/struct.Yo2.html'
|
||||
}
|
||||
|
||||
// However, re-exporting an item inheriting `#[doc(hidden)]` will inline it.
|
||||
pub mod single_reexport_inherit_hidden {
|
||||
// @has 'foo/single_reexport_inherit_hidden/index.html'
|
||||
|
||||
// @has - '//*[@href="struct.Foo3.html"]' 'Foo3'
|
||||
pub use crate::module::Public2 as Foo3;
|
||||
// @has - '//*[@href="type.Foo4.html"]' 'Foo4'
|
||||
pub use crate::module::Bar2 as Foo4;
|
||||
|
||||
// @has 'foo/single_reexport_inherit_hidden/struct.Foo3.html'
|
||||
// @has 'foo/single_reexport_inherit_hidden/type.Foo4.html'
|
||||
}
|
||||
|
||||
pub mod single_reexport_no_inline {
|
||||
// First we ensure that we only have re-exports and no inlined items.
|
||||
// @has 'foo/single_reexport_no_inline/index.html'
|
||||
// @count - '//*[@id="main-content"]/*[@class="small-section-header"]' 1
|
||||
// @has - '//*[@id="main-content"]/*[@class="small-section-header"]' 'Re-exports'
|
||||
|
||||
// Now we check that we don't have links to the items, just `pub use`.
|
||||
// @has - '//*[@id="main-content"]//*' 'pub use crate::private_module::Public as XFoo;'
|
||||
// @!has - '//*[@id="main-content"]//a' 'XFoo'
|
||||
#[doc(no_inline)]
|
||||
pub use crate::private_module::Public as XFoo;
|
||||
// @has - '//*[@id="main-content"]//*' 'pub use crate::private_module::Bar as Foo2;'
|
||||
// @!has - '//*[@id="main-content"]//a' 'Foo2'
|
||||
#[doc(no_inline)]
|
||||
pub use crate::private_module::Bar as Foo2;
|
||||
// @has - '//*[@id="main-content"]//*' 'pub use crate::Bar3 as Yo;'
|
||||
// @!has - '//*[@id="main-content"]//a' 'Yo'
|
||||
#[doc(no_inline)]
|
||||
pub use crate::Bar3 as Yo;
|
||||
// @has - '//*[@id="main-content"]//*' 'pub use crate::FooFoo as Yo2;'
|
||||
// @!has - '//*[@id="main-content"]//a' 'Yo2'
|
||||
#[doc(no_inline)]
|
||||
pub use crate::FooFoo as Yo2;
|
||||
// @has - '//*[@id="main-content"]//*' 'pub use crate::module::Public2 as Foo3;'
|
||||
// @!has - '//*[@id="main-content"]//a' 'Foo3'
|
||||
#[doc(no_inline)]
|
||||
pub use crate::module::Public2 as Foo3;
|
||||
// @has - '//*[@id="main-content"]//*' 'pub use crate::module::Bar2 as Foo4;'
|
||||
// @!has - '//*[@id="main-content"]//a' 'Foo4'
|
||||
#[doc(no_inline)]
|
||||
pub use crate::module::Bar2 as Foo4;
|
||||
}
|
||||
|
||||
// Checking that glob re-exports don't inline `#[doc(hidden)]` items.
|
||||
pub mod glob_reexport {
|
||||
// With glob re-exports, we don't inline `#[doc(hidden)]` items so only `module` items
|
||||
// should be inlined.
|
||||
// @has 'foo/glob_reexport/index.html'
|
||||
// @count - '//*[@id="main-content"]/*[@class="small-section-header"]' 3
|
||||
// @has - '//*[@id="main-content"]/*[@class="small-section-header"]' 'Re-exports'
|
||||
// @has - '//*[@id="main-content"]/*[@class="small-section-header"]' 'Structs'
|
||||
// @has - '//*[@id="main-content"]/*[@class="small-section-header"]' 'Type Definitions'
|
||||
|
||||
// Now we check we have 1 re-export and 2 inlined items.
|
||||
// If not item from a glob re-export is visible, we don't show the re-export.
|
||||
// @!has - '//*[@id="main-content"]//*' 'pub use crate::private_module::*;'
|
||||
pub use crate::private_module::*;
|
||||
// @has - '//*[@id="main-content"]//*' 'pub use crate::*;'
|
||||
pub use crate::*;
|
||||
// This one should be inlined.
|
||||
// @!has - '//*[@id="main-content"]//*' 'pub use crate::module::*;'
|
||||
// @has - '//*[@id="main-content"]//a[@href="struct.Public2.html"]' 'Public2'
|
||||
// @has - '//*[@id="main-content"]//a[@href="type.Bar2.html"]' 'Bar2'
|
||||
// And we check that the two files were created too.
|
||||
// @has 'foo/glob_reexport/struct.Public2.html'
|
||||
// @has 'foo/glob_reexport/type.Bar2.html'
|
||||
pub use crate::module::*;
|
||||
}
|
||||
|
||||
mod private {
|
||||
/// Original.
|
||||
pub struct Bar3;
|
||||
}
|
||||
|
||||
// Checking that `#[doc(hidden)]` re-exports documentation isn't generated.
|
||||
pub mod doc_hidden_reexport {
|
||||
// @has 'foo/doc_hidden_reexport/index.html'
|
||||
// Ensure there is only one item in this page and that it's a struct.
|
||||
// @count - '//*[@class="item-name"]' 1
|
||||
// @has - '//a[@class="struct"]' 'Reexport'
|
||||
// Check that the `#[doc(hidden)]` re-export's attributes are not taken into account.
|
||||
// @has - '//*[@class="desc docblock-short"]' 'Visible. Original.'
|
||||
/// Hidden.
|
||||
#[doc(hidden)]
|
||||
pub use crate::private::Bar3;
|
||||
/// Visible.
|
||||
pub use self::Bar3 as Reexport;
|
||||
}
|
Loading…
Reference in a new issue