]> git.lizzy.rs Git - rust.git/blob - src/librustdoc/formats/renderer.rs
Use empty Cache for methods requiring it when filling Cache itself
[rust.git] / src / librustdoc / formats / renderer.rs
1 use rustc_middle::ty;
2 use rustc_span::edition::Edition;
3
4 use crate::clean;
5 use crate::config::{RenderInfo, RenderOptions};
6 use crate::error::Error;
7 use crate::formats::cache::Cache;
8
9 /// Allows for different backends to rustdoc to be used with the `run_format()` function. Each
10 /// backend renderer has hooks for initialization, documenting an item, entering and exiting a
11 /// module, and cleanup/finalizing output.
12 crate trait FormatRenderer<'tcx>: Clone {
13     /// Gives a description of the renderer. Used for performance profiling.
14     fn descr() -> &'static str;
15
16     /// Sets up any state required for the renderer. When this is called the cache has already been
17     /// populated.
18     fn init(
19         krate: clean::Crate,
20         options: RenderOptions,
21         render_info: RenderInfo,
22         edition: Edition,
23         cache: Cache,
24         tcx: ty::TyCtxt<'tcx>,
25     ) -> Result<(Self, clean::Crate), Error>;
26
27     /// Renders a single non-module item. This means no recursive sub-item rendering is required.
28     fn item(&mut self, item: clean::Item) -> Result<(), Error>;
29
30     /// Renders a module (should not handle recursing into children).
31     fn mod_item_in(&mut self, item: &clean::Item, item_name: &str) -> Result<(), Error>;
32
33     /// Runs after recursively rendering all sub-items of a module.
34     fn mod_item_out(&mut self, item_name: &str) -> Result<(), Error>;
35
36     /// Post processing hook for cleanup and dumping output to files.
37     ///
38     /// A handler is available if the renderer wants to report errors.
39     fn after_krate(
40         &mut self,
41         krate: &clean::Crate,
42         diag: &rustc_errors::Handler,
43     ) -> Result<(), Error>;
44
45     fn cache(&self) -> &Cache;
46 }
47
48 /// Main method for rendering a crate.
49 crate fn run_format<'tcx, T: FormatRenderer<'tcx>>(
50     krate: clean::Crate,
51     options: RenderOptions,
52     render_info: RenderInfo,
53     diag: &rustc_errors::Handler,
54     edition: Edition,
55     tcx: TyCtxt<'tcx>,
56 ) -> Result<(), Error> {
57     let (krate, cache) = tcx.sess.time("create_format_cache", || {
58         Cache::from_krate(
59             render_info.clone(),
60             options.document_private,
61             &options.extern_html_root_urls,
62             &options.output,
63             krate,
64         )
65     });
66     let prof = &tcx.sess.prof;
67
68     let (mut format_renderer, mut krate) = prof
69         .extra_verbose_generic_activity("create_renderer", T::descr())
70         .run(|| T::init(krate, options, render_info, edition, cache, tcx))?;
71
72     let (mut format_renderer, mut krate) =
73         T::init(krate, options, render_info, edition, cache, tcx)?;
74
75     let mut item = match krate.module.take() {
76         Some(i) => i,
77         None => return Ok(()),
78     };
79
80     item.name = Some(krate.name);
81
82     // Render the crate documentation
83     let mut work = vec![(format_renderer.clone(), item)];
84
85     let unknown = rustc_span::Symbol::intern("<unknown item>");
86     while let Some((mut cx, item)) = work.pop() {
87         if item.is_mod() {
88             // modules are special because they add a namespace. We also need to
89             // recurse into the items of the module as well.
90             let name = item.name.as_ref().unwrap().to_string();
91             if name.is_empty() {
92                 panic!("Unexpected module with empty name");
93             }
94             let _timer = prof.generic_activity_with_arg("render_mod_item", name.as_str());
95
96             cx.mod_item_in(&item, &name)?;
97             let module = match *item.kind {
98                 clean::StrippedItem(box clean::ModuleItem(m)) | clean::ModuleItem(m) => m,
99                 _ => unreachable!(),
100             };
101             for it in module.items {
102                 debug!("Adding {:?} to worklist", it.name);
103                 work.push((cx.clone(), it));
104             }
105
106             cx.mod_item_out(&name)?;
107         } else if item.name.is_some() {
108             prof.generic_activity_with_arg("render_item", &*item.name.unwrap_or(unknown).as_str())
109                 .run(|| cx.item(item))?;
110         }
111     }
112     prof.extra_verbose_generic_activity("renderer_after_krate", T::descr())
113         .run(|| format_renderer.after_krate(&krate, diag))
114 }