| use rustc_data_structures::profiling::SelfProfilerRef; |
| use rustc_middle::ty::TyCtxt; |
| |
| use crate::clean; |
| 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; |
| |
| /// This associated type is the type where the current module information is stored. |
| /// |
| /// For each module, we go through their items by calling for each item: |
| /// |
| /// 1. `save_module_data` |
| /// 2. `item` |
| /// 3. `restore_module_data` |
| /// |
| /// This is because the `item` method might update information in `self` (for example if the child |
| /// is a module). To prevent it from impacting the other children of the current module, we need to |
| /// reset the information between each call to `item` by using `restore_module_data`. |
| type ModuleData; |
| |
| /// This method is called right before call [`Self::item`]. This method returns a type |
| /// containing information that needs to be reset after the [`Self::item`] method has been |
| /// called with the [`Self::restore_module_data`] method. |
| /// |
| /// In short it goes like this: |
| /// |
| /// ```ignore (not valid code) |
| /// let reset_data = renderer.save_module_data(); |
| /// renderer.item(item)?; |
| /// renderer.restore_module_data(reset_data); |
| /// ``` |
| fn save_module_data(&mut self) -> Self::ModuleData; |
| /// Used to reset current module's information. |
| fn restore_module_data(&mut self, info: Self::ModuleData); |
| |
| /// Renders a single non-module item. This means no recursive sub-item rendering is required. |
| fn item(&mut self, item: &clean::Item) -> Result<(), Error>; |
| |
| /// 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(self) -> Result<(), Error>; |
| } |
| |
| fn run_format_inner<'tcx, T: FormatRenderer<'tcx>>( |
| cx: &mut T, |
| item: &clean::Item, |
| prof: &SelfProfilerRef, |
| ) -> Result<(), Error> { |
| if item.is_mod() && T::RUN_ON_MODULE { |
| // modules are special because they add a namespace. We also need to |
| // recurse into the items of the module as well. |
| let _timer = |
| prof.generic_activity_with_arg("render_mod_item", item.name.unwrap().to_string()); |
| |
| cx.mod_item_in(item)?; |
| let (clean::StrippedItem(box clean::ModuleItem(ref module)) |
| | clean::ModuleItem(ref module)) = item.inner.kind |
| else { |
| unreachable!() |
| }; |
| for it in module.items.iter() { |
| let info = cx.save_module_data(); |
| run_format_inner(cx, it, prof)?; |
| cx.restore_module_data(info); |
| } |
| |
| cx.mod_item_out()?; |
| // FIXME: checking `item.name.is_some()` is very implicit and leads to lots of special |
| // cases. Use an explicit match instead. |
| } else if let Some(item_name) = item.name |
| && !item.is_extern_crate() |
| { |
| prof.generic_activity_with_arg("render_item", item_name.as_str()).run(|| cx.item(item))?; |
| } |
| Ok(()) |
| } |
| |
| /// Main method for rendering a crate. |
| pub(crate) fn run_format< |
| 'tcx, |
| T: FormatRenderer<'tcx>, |
| F: FnOnce(clean::Crate, RenderOptions, Cache, TyCtxt<'tcx>) -> Result<(T, clean::Crate), Error>, |
| >( |
| krate: clean::Crate, |
| options: RenderOptions, |
| cache: Cache, |
| tcx: TyCtxt<'tcx>, |
| init: F, |
| ) -> Result<(), Error> { |
| let prof = &tcx.sess.prof; |
| |
| let emit_crate = options.should_emit_crate(); |
| let (mut format_renderer, krate) = prof |
| .verbose_generic_activity_with_arg("create_renderer", T::descr()) |
| .run(|| init(krate, options, cache, tcx))?; |
| |
| if !emit_crate { |
| return Ok(()); |
| } |
| |
| // Render the crate documentation |
| run_format_inner(&mut format_renderer, &krate.module, prof)?; |
| |
| prof.verbose_generic_activity_with_arg("renderer_after_krate", T::descr()) |
| .run(|| format_renderer.after_krate()) |
| } |