mirror of
https://github.com/rust-lang/rust.git
synced 2026-05-16 04:55:22 +03:00
rustdoc: Reify emission types
This commit is contained in:
+68
-40
@@ -18,6 +18,7 @@
|
||||
use rustc_span::edition::Edition;
|
||||
use rustc_span::{FileName, RemapPathScopeComponents};
|
||||
use rustc_target::spec::TargetTuple;
|
||||
use smallvec::SmallVec;
|
||||
|
||||
use crate::core::new_dcx;
|
||||
use crate::externalfiles::ExternalHtml;
|
||||
@@ -293,7 +294,7 @@ pub(crate) struct RenderOptions {
|
||||
/// Note: this field is duplicated in `Options` because it's useful to have
|
||||
/// it in both places.
|
||||
pub(crate) unstable_features: rustc_feature::UnstableFeatures,
|
||||
pub(crate) emit: Vec<EmitType>,
|
||||
pub(crate) emit: SmallVec<[EmitType; 2]>,
|
||||
/// If `true`, HTML source pages will generate links for items to their definition.
|
||||
pub(crate) generate_link_to_definition: bool,
|
||||
/// Set of function-call locations to include as examples
|
||||
@@ -327,9 +328,22 @@ pub(crate) enum ModuleSorting {
|
||||
pub(crate) enum EmitType {
|
||||
HtmlStaticFiles,
|
||||
HtmlNonStaticFiles,
|
||||
// not explicitly nameable by the user for now
|
||||
JsonFiles,
|
||||
DepInfo(Option<OutFileName>),
|
||||
}
|
||||
|
||||
impl fmt::Display for EmitType {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
f.write_str(match self {
|
||||
Self::HtmlStaticFiles => "html-static-files",
|
||||
Self::HtmlNonStaticFiles => "html-non-static-files",
|
||||
Self::JsonFiles => "json-files",
|
||||
Self::DepInfo(_) => "dep-info",
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl FromStr for EmitType {
|
||||
type Err = ();
|
||||
|
||||
@@ -352,17 +366,11 @@ fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||
}
|
||||
|
||||
impl RenderOptions {
|
||||
pub(crate) fn should_emit_crate(&self) -> bool {
|
||||
self.emit.is_empty() || self.emit.contains(&EmitType::HtmlNonStaticFiles)
|
||||
}
|
||||
|
||||
pub(crate) fn dep_info(&self) -> Option<Option<&OutFileName>> {
|
||||
for emit in &self.emit {
|
||||
if let EmitType::DepInfo(file) = emit {
|
||||
return Some(file.as_ref());
|
||||
}
|
||||
}
|
||||
None
|
||||
self.emit.iter().find_map(|emit| match emit {
|
||||
EmitType::DepInfo(file) => Some(file.as_ref()),
|
||||
_ => None,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -469,26 +477,6 @@ fn println_condition(condition: Condition) {
|
||||
|
||||
let should_test = matches.opt_present("test");
|
||||
|
||||
let mut emit = FxIndexMap::<_, EmitType>::default();
|
||||
for list in matches.opt_strs("emit") {
|
||||
if should_test {
|
||||
dcx.fatal("the `--test` flag and the `--emit` flag are not supported together");
|
||||
}
|
||||
for kind in list.split(',') {
|
||||
match kind.parse() {
|
||||
Ok(kind) => {
|
||||
// De-duplicate emit types and the last wins.
|
||||
// Only one instance for each type is allowed
|
||||
// regardless the actual data it carries.
|
||||
// This matches rustc's `--emit` behavior.
|
||||
emit.insert(std::mem::discriminant(&kind), kind);
|
||||
}
|
||||
Err(()) => dcx.fatal(format!("unrecognized emission type: {kind}")),
|
||||
}
|
||||
}
|
||||
}
|
||||
let emit = emit.into_values().collect::<Vec<_>>();
|
||||
|
||||
let show_coverage = matches.opt_present("show-coverage");
|
||||
let output_format_s = matches.opt_str("output-format");
|
||||
let output_format = match output_format_s {
|
||||
@@ -527,15 +515,55 @@ fn println_condition(condition: Condition) {
|
||||
}
|
||||
}
|
||||
|
||||
if output_format == OutputFormat::Json {
|
||||
if let Some(emit_flag) = emit.iter().find_map(|emit| match emit {
|
||||
EmitType::HtmlStaticFiles => Some("html-static-files"),
|
||||
EmitType::HtmlNonStaticFiles => Some("html-non-static-files"),
|
||||
EmitType::DepInfo(_) => None,
|
||||
}) {
|
||||
dcx.fatal(format!(
|
||||
"the `--emit={emit_flag}` flag is not supported with `--output-format=json`",
|
||||
));
|
||||
let mut emit = FxIndexMap::default();
|
||||
for list in matches.opt_strs("emit") {
|
||||
if should_test {
|
||||
dcx.fatal("the `--test` flag and the `--emit` flag are not supported together");
|
||||
}
|
||||
if let OutputFormat::Doctest = output_format {
|
||||
dcx.fatal("the `--emit` flag is not supported with `--output-format=doctest`");
|
||||
}
|
||||
|
||||
for typ in list.split(',') {
|
||||
let Ok(typ) = typ.parse::<EmitType>() else {
|
||||
dcx.fatal(format!("unrecognized emission type: {typ}"))
|
||||
};
|
||||
|
||||
match typ {
|
||||
EmitType::DepInfo(_) => match output_format {
|
||||
OutputFormat::Json | OutputFormat::Html => {}
|
||||
OutputFormat::Doctest => unreachable!(),
|
||||
},
|
||||
EmitType::HtmlStaticFiles | EmitType::HtmlNonStaticFiles => match output_format
|
||||
{
|
||||
OutputFormat::Html => {}
|
||||
OutputFormat::Json => dcx.fatal(format!(
|
||||
"the `--emit={typ}` flag is not supported with `--output-format=json`",
|
||||
)),
|
||||
OutputFormat::Doctest => unreachable!(),
|
||||
},
|
||||
EmitType::JsonFiles => unreachable!(),
|
||||
}
|
||||
|
||||
// De-duplicate emit types and the last wins.
|
||||
// Only one instance for each type is allowed
|
||||
// regardless the actual data it carries.
|
||||
// This matches rustc's `--emit` behavior.
|
||||
emit.insert(std::mem::discriminant(&typ), typ);
|
||||
}
|
||||
}
|
||||
let mut emit: SmallVec<[_; 2]> = emit.into_values().collect();
|
||||
// If `--emit` is absent we'll register default emission types depending on the requested
|
||||
// output format. We can safely use `is_empty` for this since `--emit=` ("truly empty")
|
||||
// will have already been rejected above.
|
||||
if emit.is_empty() {
|
||||
match output_format {
|
||||
OutputFormat::Json => emit.push(EmitType::JsonFiles),
|
||||
OutputFormat::Html => {
|
||||
emit.push(EmitType::HtmlStaticFiles);
|
||||
emit.push(EmitType::HtmlNonStaticFiles);
|
||||
}
|
||||
OutputFormat::Doctest => {}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
use rustc_middle::ty::TyCtxt;
|
||||
|
||||
use crate::clean;
|
||||
use crate::config::RenderOptions;
|
||||
use crate::config::{EmitType, RenderOptions};
|
||||
use crate::error::Error;
|
||||
use crate::formats::cache::Cache;
|
||||
|
||||
@@ -10,14 +10,16 @@
|
||||
/// 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;
|
||||
/// A description of the renderer. Used for performance profiling.
|
||||
const DESCR: &'static str;
|
||||
|
||||
/// Whether to call `item` recursively for modules
|
||||
/// Whether to call `item` recursively for modules.
|
||||
///
|
||||
/// This is true for html, and false for json. See #80664
|
||||
/// See [#80664](https://github.com/rust-lang/rust/issues/80664).
|
||||
const RUN_ON_MODULE: bool;
|
||||
|
||||
const NON_STATIC_FILE_EMIT_TYPE: EmitType;
|
||||
|
||||
/// 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:
|
||||
@@ -109,18 +111,18 @@ pub(crate) fn run_format<
|
||||
) -> Result<(), Error> {
|
||||
let prof = &tcx.sess.prof;
|
||||
|
||||
let emit_crate = options.should_emit_crate();
|
||||
let emit_non_static_files = options.emit.contains(&T::NON_STATIC_FILE_EMIT_TYPE);
|
||||
let (mut format_renderer, krate) = prof
|
||||
.verbose_generic_activity_with_arg("create_renderer", T::descr())
|
||||
.verbose_generic_activity_with_arg("create_renderer", T::DESCR)
|
||||
.run(|| init(krate, options, cache, tcx))?;
|
||||
|
||||
if !emit_crate {
|
||||
if !emit_non_static_files {
|
||||
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())
|
||||
prof.verbose_generic_activity_with_arg("renderer_after_krate", T::DESCR)
|
||||
.run(|| format_renderer.after_krate())
|
||||
}
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
use crate::clean::types::ExternalLocation;
|
||||
use crate::clean::utils::has_doc_flag;
|
||||
use crate::clean::{self, ExternalCrate};
|
||||
use crate::config::{ModuleSorting, RenderOptions, ShouldMerge};
|
||||
use crate::config::{EmitType, ModuleSorting, RenderOptions, ShouldMerge};
|
||||
use crate::docfs::{DocFS, PathError};
|
||||
use crate::error::Error;
|
||||
use crate::formats::FormatRenderer;
|
||||
@@ -481,7 +481,6 @@ pub(crate) fn init(
|
||||
) -> Result<(Self, clean::Crate), Error> {
|
||||
// need to save a copy of the options for rendering the index page
|
||||
let md_opts = options.clone();
|
||||
let emit_crate = options.should_emit_crate();
|
||||
let RenderOptions {
|
||||
output,
|
||||
external_html,
|
||||
@@ -495,6 +494,7 @@ pub(crate) fn init(
|
||||
static_root_path,
|
||||
generate_redirect_map,
|
||||
show_type_layout,
|
||||
emit,
|
||||
generate_link_to_definition,
|
||||
call_locations,
|
||||
no_emit_shared,
|
||||
@@ -605,7 +605,7 @@ pub(crate) fn init(
|
||||
info: ContextInfo::new(include_sources),
|
||||
};
|
||||
|
||||
if emit_crate {
|
||||
if emit.contains(&EmitType::HtmlNonStaticFiles) {
|
||||
sources::render(&mut cx, &krate)?;
|
||||
}
|
||||
|
||||
@@ -619,11 +619,10 @@ pub(crate) fn init(
|
||||
|
||||
/// Generates the documentation for `crate` into the directory `dst`
|
||||
impl<'tcx> FormatRenderer<'tcx> for Context<'tcx> {
|
||||
fn descr() -> &'static str {
|
||||
"html"
|
||||
}
|
||||
|
||||
const DESCR: &'static str = "html";
|
||||
const RUN_ON_MODULE: bool = true;
|
||||
const NON_STATIC_FILE_EMIT_TYPE: EmitType = EmitType::HtmlNonStaticFiles;
|
||||
|
||||
type ModuleData = ContextInfo;
|
||||
|
||||
fn save_module_data(&mut self) -> Self::ModuleData {
|
||||
|
||||
@@ -165,7 +165,7 @@ fn write_rendered_cross_crate_info(
|
||||
resource_suffix: &str,
|
||||
) -> Result<(), Error> {
|
||||
let m = &opt.should_merge;
|
||||
if opt.should_emit_crate() {
|
||||
if opt.emit.contains(&EmitType::HtmlNonStaticFiles) {
|
||||
if include_sources {
|
||||
write_rendered_cci::<SourcesPart, _>(SourcesPart::blank, dst, crates, m)?;
|
||||
}
|
||||
@@ -190,7 +190,7 @@ fn write_resources(
|
||||
css_file_extension: Option<&Path>,
|
||||
resource_suffix: &str,
|
||||
) -> Result<(), Error> {
|
||||
if opt.emit.is_empty() || opt.emit.contains(&EmitType::HtmlNonStaticFiles) {
|
||||
if opt.emit.contains(&EmitType::HtmlNonStaticFiles) {
|
||||
// Handle added third-party themes
|
||||
for entry in style_files {
|
||||
let theme = entry.basename()?;
|
||||
@@ -218,7 +218,7 @@ fn write_resources(
|
||||
}
|
||||
}
|
||||
|
||||
if opt.emit.is_empty() || opt.emit.contains(&EmitType::HtmlStaticFiles) {
|
||||
if opt.emit.contains(&EmitType::HtmlStaticFiles) {
|
||||
let static_dir = dst.join("static.files");
|
||||
try_err!(fs::create_dir_all(&static_dir), &static_dir);
|
||||
|
||||
|
||||
@@ -27,7 +27,7 @@
|
||||
|
||||
use crate::clean::ItemKind;
|
||||
use crate::clean::types::{ExternalCrate, ExternalLocation};
|
||||
use crate::config::RenderOptions;
|
||||
use crate::config::{EmitType, RenderOptions};
|
||||
use crate::docfs::PathError;
|
||||
use crate::error::Error;
|
||||
use crate::formats::FormatRenderer;
|
||||
@@ -132,11 +132,10 @@ pub(crate) fn init(
|
||||
}
|
||||
|
||||
impl<'tcx> FormatRenderer<'tcx> for JsonRenderer<'tcx> {
|
||||
fn descr() -> &'static str {
|
||||
"json"
|
||||
}
|
||||
|
||||
const DESCR: &'static str = "json";
|
||||
const RUN_ON_MODULE: bool = false;
|
||||
const NON_STATIC_FILE_EMIT_TYPE: EmitType = EmitType::JsonFiles;
|
||||
|
||||
type ModuleData = ();
|
||||
|
||||
fn save_module_data(&mut self) -> Self::ModuleData {
|
||||
|
||||
@@ -869,9 +869,7 @@ fn main_args(early_dcx: &mut EarlyDiagCtxt, at_args: &[String]) {
|
||||
};
|
||||
rustc_interface::create_and_enter_global_ctxt(compiler, krate, |tcx| {
|
||||
let has_dep_info = render_options.dep_info().is_some();
|
||||
if render_options.emit.contains(&EmitType::HtmlNonStaticFiles)
|
||||
|| render_options.emit.is_empty()
|
||||
{
|
||||
if render_options.emit.contains(&EmitType::HtmlNonStaticFiles) {
|
||||
markdown::render_and_write(file, render_options, edition)?;
|
||||
}
|
||||
if has_dep_info {
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
error: the `--emit` flag is not supported with `--output-format=doctest`
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
error: the `--emit` flag is not supported with `--output-format=doctest`
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
// Ensure that `--output-format=doctest` is incompatible with the `--emit` flag (for now at least).
|
||||
|
||||
//@ revisions: html-static-files dep-info
|
||||
//@ compile-flags: -Zunstable-options --output-format doctest
|
||||
//@[html-static-files] compile-flags: --emit html-static-files
|
||||
//@[dep-info] compile-flags: --emit dep-info
|
||||
|
||||
//~? ERROR the `--emit` flag is not supported with `--output-format=doctest`
|
||||
@@ -1,8 +1,7 @@
|
||||
//@ revisions: html_static html_non_static
|
||||
//@ check-fail
|
||||
//@[html_static] compile-flags: -Z unstable-options --output-format=json --emit=html-static-files
|
||||
//@[html_non_static] compile-flags: -Z unstable-options --output-format=json --emit=html-non-static-files
|
||||
//@ compile-flags: -Zunstable-options --output-format json
|
||||
//@[html_static] compile-flags: --emit html-static-files
|
||||
//@[html_non_static] compile-flags: --emit html-non-static-files
|
||||
|
||||
//[html_static]~? ERROR the `--emit=html-static-files` flag is not supported with `--output-format=json`
|
||||
//[html_non_static]~? ERROR the `--emit=html-non-static-files` flag is not supported with `--output-format=json`
|
||||
|
||||
pub struct Foo;
|
||||
|
||||
Reference in New Issue
Block a user