]> git.lizzy.rs Git - rust.git/blob - src/librustdoc/README.md
Rollup merge of #48480 - jethrogb:patch-5, r=alexcrichton
[rust.git] / src / librustdoc / README.md
1 # The walking tour of rustdoc
2
3 Rustdoc is implemented entirely within the crate `librustdoc`. After partially compiling a crate to
4 get its AST (technically the HIR map) from rustc, librustdoc performs two major steps past that to
5 render a set of documentation:
6
7 * "Clean" the AST into a form that's more suited to creating documentation (and slightly more
8   resistant to churn in the compiler).
9 * Use this cleaned AST to render a crate's documentation, one page at a time.
10
11 Naturally, there's more than just this, and those descriptions simplify out lots of details, but
12 that's the high-level overview.
13
14 (Side note: this is a library crate! The `rustdoc` binary is crated using the project in
15 `src/tools/rustdoc`. Note that literally all that does is call the `main()` that's in this crate's
16 `lib.rs`, though.)
17
18 ## Cheat sheet
19
20 * Use `x.py build --stage 1 src/libstd src/tools/rustdoc` to make a useable rustdoc you can run on
21   other projects.
22   * Add `src/libtest` to be able to use `rustdoc --test`.
23   * If you've used `rustup toolchain link local /path/to/build/$TARGET/stage1` previously, then
24     after the previous build command, `cargo +local doc` will Just Work.
25 * Use `x.py doc --stage 1 src/libstd` to use this rustdoc to generate the standard library docs.
26   * The completed docs will be available in `build/$TARGET/doc/std`, though the bundle is meant to
27     be used as though you would copy out the `doc` folder to a web server, since that's where the
28     CSS/JS and landing page are.
29 * Most of the HTML printing code is in `html/format.rs` and `html/render.rs`. It's in a bunch of
30   `fmt::Display` implementations and supplementary functions.
31 * The types that got `Display` impls above are defined in `clean/mod.rs`, right next to the custom
32   `Clean` trait used to process them out of the rustc HIR.
33 * The bits specific to using rustdoc as a test harness are in `test.rs`.
34 * The Markdown renderer is loaded up in `html/markdown.rs`, including functions for extracting
35   doctests from a given block of Markdown.
36 * The tests on rustdoc *output* are located in `src/test/rustdoc`, where they're handled by the test
37   runner of rustbuild and the supplementary script `src/etc/htmldocck.py`.
38 * Tests on search index generation are located in `src/test/rustdoc-js`, as a series of JavaScript
39   files that encode queries on the standard library search index and expected results.
40
41 ## From crate to clean
42
43 In `core.rs` are two central items: the `DocContext` struct, and the `run_core` function. The latter
44 is where rustdoc calls out to rustc to compile a crate to the point where rustdoc can take over. The
45 former is a state container used when crawling through a crate to gather its documentation.
46
47 The main process of crate crawling is done in `clean/mod.rs` through several implementations of the
48 `Clean` trait defined within. This is a conversion trait, which defines one method:
49
50 ```rust
51 pub trait Clean<T> {
52     fn clean(&self, cx: &DocContext) -> T;
53 }
54 ```
55
56 `clean/mod.rs` also defines the types for the "cleaned" AST used later on to render documentation
57 pages. Each usually accompanies an implementation of `Clean` that takes some AST or HIR type from
58 rustc and converts it into the appropriate "cleaned" type. "Big" items like modules or associated
59 items may have some extra processing in its `Clean` implementation, but for the most part these
60 impls are straightforward conversions. The "entry point" to this module is the `impl Clean<Crate>
61 for visit_ast::RustdocVisitor`, which is called by `run_core` above.
62
63 You see, I actually lied a little earlier: There's another AST transformation that happens before
64 the events in `clean/mod.rs`.  In `visit_ast.rs` is the type `RustdocVisitor`, which *actually*
65 crawls a `hir::Crate` to get the first intermediate representation, defined in `doctree.rs`. This
66 pass is mainly to get a few intermediate wrappers around the HIR types and to process visibility
67 and inlining. This is where `#[doc(inline)]`, `#[doc(no_inline)]`, and `#[doc(hidden)]` are
68 processed, as well as the logic for whether a `pub use` should get the full page or a "Reexport"
69 line in the module page.
70
71 The other major thing that happens in `clean/mod.rs` is the collection of doc comments and
72 `#[doc=""]` attributes into a separate field of the Attributes struct, present on anything that gets
73 hand-written documentation. This makes it easier to collect this documentation later in the process.
74
75 The primary output of this process is a clean::Crate with a tree of Items which describe the
76 publicly-documentable items in the target crate.
77
78 ### Hot potato
79
80 Before moving on to the next major step, a few important "passes" occur over the documentation.
81 These do things like combine the separate "attributes" into a single string and strip leading
82 whitespace to make the document easier on the markdown parser, or drop items that are not public or
83 deliberately hidden with `#[doc(hidden)]`. These are all implemented in the `passes/` directory, one
84 file per pass. By default, all of these passes are run on a crate, but the ones regarding dropping
85 private/hidden items can be bypassed by passing `--document-private-items` to rustdoc.
86
87 (Strictly speaking, you can fine-tune the passes run and even add your own, but [we're trying to
88 deprecate that][44136]. If you need finer-grain control over these passes, please let us know!)
89
90 [44136]: https://github.com/rust-lang/rust/issues/44136
91
92 ## From clean to crate
93
94 This is where the "second phase" in rustdoc begins. This phase primarily lives in the `html/`
95 folder, and it all starts with `run()` in `html/render.rs`. This code is responsible for setting up
96 the `Context`, `SharedContext`, and `Cache` which are used during rendering, copying out the static
97 files which live in every rendered set of documentation (things like the fonts, CSS, and JavaScript
98 that live in `html/static/`), creating the search index, and printing out the source code rendering,
99 before beginning the process of rendering all the documentation for the crate.
100
101 Several functions implemented directly on `Context` take the `clean::Crate` and set up some state
102 between rendering items or recursing on a module's child items. From here the "page rendering"
103 begins, via an enormous `write!()` call in `html/layout.rs`. The parts that actually generate HTML
104 from the items and documentation occurs within a series of `std::fmt::Display` implementations and
105 functions that pass around a `&mut std::fmt::Formatter`. The top-level implementation that writes
106 out the page body is the `impl<'a> fmt::Display for Item<'a>` in `html/render.rs`, which switches
107 out to one of several `item_*` functions based on the kind of `Item` being rendered.
108
109 Depending on what kind of rendering code you're looking for, you'll probably find it either in
110 `html/render.rs` for major items like "what sections should I print for a struct page" or
111 `html/format.rs` for smaller component pieces like "how should I print a where clause as part of
112 some other item".
113
114 Whenever rustdoc comes across an item that should print hand-written documentation alongside, it
115 calls out to `html/markdown.rs` which interfaces with the Markdown parser. This is exposed as a
116 series of types that wrap a string of Markdown, and implement `fmt::Display` to emit HTML text. It
117 takes special care to enable certain features like footnotes and tables and add syntax highlighting
118 to Rust code blocks (via `html/highlight.rs`) before running the Markdown parser. There's also a
119 function in here (`find_testable_code`) that specifically scans for Rust code blocks so the
120 test-runner code can find all the doctests in the crate.
121
122 ### From soup to nuts
123
124 (alternate title: ["An unbroken thread that stretches from those first `Cell`s to us"][video])
125
126 [video]: https://www.youtube.com/watch?v=hOLAGYmUQV0
127
128 It's important to note that the AST cleaning can ask the compiler for information (crucially,
129 `DocContext` contains a `TyCtxt`), but page rendering cannot. The `clean::Crate` created within
130 `run_core` is passed outside the compiler context before being handed to `html::render::run`. This
131 means that a lot of the "supplementary data" that isn't immediately available inside an item's
132 definition, like which trait is the `Deref` trait used by the language, needs to be collected during
133 cleaning, stored in the `DocContext`, and passed along to the `SharedContext` during HTML rendering.
134 This manifests as a bunch of shared state, context variables, and `RefCell`s.
135
136 Also of note is that some items that come from "asking the compiler" don't go directly into the
137 `DocContext` - for example, when loading items from a foreign crate, rustdoc will ask about trait
138 implementations and generate new `Item`s for the impls based on that information. This goes directly
139 into the returned `Crate` rather than roundabout through the `DocContext`. This way, these
140 implementations can be collected alongside the others, right before rendering the HTML.
141
142 ## Other tricks up its sleeve
143
144 All this describes the process for generating HTML documentation from a Rust crate, but there are
145 couple other major modes that rustdoc runs in. It can also be run on a standalone Markdown file, or
146 it can run doctests on Rust code or standalone Markdown files. For the former, it shortcuts straight
147 to `html/markdown.rs`, optionally including a mode which inserts a Table of Contents to the output
148 HTML.
149
150 For the latter, rustdoc runs a similar partial-compilation to get relevant documentation in
151 `test.rs`, but instead of going through the full clean and render process, it runs a much simpler
152 crate walk to grab *just* the hand-written documentation. Combined with the aforementioned
153 "`find_testable_code`" in `html/markdown.rs`, it builds up a collection of tests to run before
154 handing them off to the libtest test runner. One notable location in `test.rs` is the function
155 `make_test`, which is where hand-written doctests get transformed into something that can be
156 executed.
157
158 ## Dotting i's and crossing t's
159
160 So that's rustdoc's code in a nutshell, but there's more things in the repo that deal with it. Since
161 we have the full `compiletest` suite at hand, there's a set of tests in `src/test/rustdoc` that make
162 sure the final HTML is what we expect in various situations. These tests also use a supplementary
163 script, `src/etc/htmldocck.py`, that allows it to look through the final HTML using XPath notation
164 to get a precise look at the output. The full description of all the commands available to rustdoc
165 tests is in `htmldocck.py`.
166
167 In addition, there are separate tests for the search index and rustdoc's ability to query it. The
168 files in `src/test/rustdoc-js` each contain a different search query and the expected results,
169 broken out by search tab. These files are processed by a script in `src/tools/rustdoc-js` and the
170 Node.js runtime. These tests don't have as thorough of a writeup, but a broad example that features
171 results in all tabs can be found in `basic.js`. The basic idea is that you match a given `QUERY`
172 with a set of `EXPECTED` results, complete with the full item path of each item.