forked from rust-lang/rust
-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathrenderer.rs
More file actions
137 lines (115 loc) · 4.81 KB
/
Copy pathrenderer.rs
File metadata and controls
137 lines (115 loc) · 4.81 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
use rustc_middle::ty::TyCtxt;
use rustc_span::Symbol;
use crate::clean::{self, Item};
use crate::config::RenderOptions;
use crate::error::Error;
use crate::formats::cache::Cache;
/// Allows for different backends to rustdoc to be used with the `run_format()` function. Each
/// backend renderer has hooks for initialization, documenting an item, entering and exiting a
/// module, and cleanup/finalizing output.
pub(crate) trait FormatRenderer<'tcx>: Sized {
/// Gives a description of the renderer. Used for performance profiling.
fn descr() -> &'static str;
/// Whether to call `item` recursively for modules
///
/// This is true for html, and false for json. See #80664
const RUN_ON_MODULE: bool;
/// Sets up any state required for the renderer. When this is called the cache has already been
/// populated.
fn init(
krate: clean::Crate,
options: RenderOptions,
cache: Cache,
tcx: TyCtxt<'tcx>,
) -> Result<(Self, clean::Crate), Error>;
/// Renders a single non-module item. This means no recursive sub-item rendering is required.
fn item(&mut self, item: clean::Item) -> Result<(), Error>;
/// Runs before rendering an item (not a module)
fn before_item(&mut self, _item: &clean::Item) -> Result<(), Error> {
Ok(())
}
/// Runs after rendering an item (not a module)
fn after_item(&mut self) -> Result<(), Error> {
Ok(())
}
/// Renders a module (should not handle recursing into children).
fn mod_item_in(&mut self, item: &clean::Item) -> Result<(), Error>;
/// Runs after recursively rendering all sub-items of a module.
fn mod_item_out(&mut self) -> Result<(), Error> {
Ok(())
}
/// Post processing hook for cleanup and dumping output to files.
fn after_krate(&mut self) -> Result<(), Error>;
fn cache(&self) -> &Cache;
}
/// Main method for rendering a crate.
pub(crate) fn run_format<'tcx, T: FormatRenderer<'tcx>>(
krate: clean::Crate,
options: RenderOptions,
cache: Cache,
tcx: TyCtxt<'tcx>,
) -> Result<(), Error> {
let prof = &tcx.sess.prof;
let emit_crate = options.should_emit_crate();
let (mut format_renderer, krate) = prof
.extra_verbose_generic_activity("create_renderer", T::descr())
.run(|| T::init(krate, options, cache, tcx))?;
if !emit_crate {
return Ok(());
}
enum WorkUnit {
Module { item: Item, current_index: usize },
Single(Item),
}
let mut work_units: Vec<WorkUnit> =
vec![WorkUnit::Module { item: krate.module, current_index: 0 }];
let unknown = Symbol::intern("<unknown item>");
while let Some(work_unit) = work_units.pop() {
match work_unit {
WorkUnit::Module { item, current_index } if T::RUN_ON_MODULE => {
let (clean::StrippedItem(box clean::ModuleItem(module)) | clean::ModuleItem(module)) = item.kind.as_ref()
else { unreachable!() };
if current_index == 0 {
// just enter the module
format_renderer.mod_item_in(&item)?;
}
if current_index < module.items.len() {
// get the next item
let next_item = module.items[current_index].clone();
// stay in the module
work_units.push(WorkUnit::Module { item, current_index: current_index + 1 });
// push the next item
if next_item.is_mod() {
work_units.push(WorkUnit::Module { item: next_item, current_index: 0 });
} else {
work_units.push(WorkUnit::Single(next_item));
}
} else {
// the last item of the module has been rendered
// -> exit the module
format_renderer.mod_item_out()?;
}
}
// FIXME: checking `item.name.is_some()` is very implicit and leads to lots of special
// cases. Use an explicit match instead.
WorkUnit::Module { item, .. } | WorkUnit::Single(item)
if item.name.is_some() && !item.is_extern_crate() =>
{
// render the item
prof.generic_activity_with_arg(
"render_item",
item.name.unwrap_or(unknown).as_str(),
)
.run(|| {
format_renderer.before_item(&item)?;
let result = format_renderer.item(item)?;
format_renderer.after_item()?;
Ok(result)
})?;
}
_ => {}
}
}
prof.extra_verbose_generic_activity("renderer_after_krate", T::descr())
.run(|| format_renderer.after_krate())
}