Skip to content

Commit ef282ff

Browse files
committed
rustdoc: Reify emission types
1 parent cb40c25 commit ef282ff

10 files changed

Lines changed: 109 additions & 72 deletions

src/librustdoc/config.rs

Lines changed: 68 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ use rustc_session::{EarlyDiagCtxt, getopts};
1818
use rustc_span::edition::Edition;
1919
use rustc_span::{FileName, RemapPathScopeComponents};
2020
use rustc_target::spec::TargetTuple;
21+
use smallvec::SmallVec;
2122

2223
use crate::core::new_dcx;
2324
use crate::externalfiles::ExternalHtml;
@@ -293,7 +294,7 @@ pub(crate) struct RenderOptions {
293294
/// Note: this field is duplicated in `Options` because it's useful to have
294295
/// it in both places.
295296
pub(crate) unstable_features: rustc_feature::UnstableFeatures,
296-
pub(crate) emit: Vec<EmitType>,
297+
pub(crate) emit: SmallVec<[EmitType; 2]>,
297298
/// If `true`, HTML source pages will generate links for items to their definition.
298299
pub(crate) generate_link_to_definition: bool,
299300
/// Set of function-call locations to include as examples
@@ -327,9 +328,22 @@ pub(crate) enum ModuleSorting {
327328
pub(crate) enum EmitType {
328329
HtmlStaticFiles,
329330
HtmlNonStaticFiles,
331+
// not explicitly nameable by the user for now
332+
JsonFiles,
330333
DepInfo(Option<OutFileName>),
331334
}
332335

336+
impl fmt::Display for EmitType {
337+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
338+
f.write_str(match self {
339+
Self::HtmlStaticFiles => "html-static-files",
340+
Self::HtmlNonStaticFiles => "html-non-static-files",
341+
Self::JsonFiles => "json-files",
342+
Self::DepInfo(_) => "dep-info",
343+
})
344+
}
345+
}
346+
333347
impl FromStr for EmitType {
334348
type Err = ();
335349

@@ -352,17 +366,11 @@ impl FromStr for EmitType {
352366
}
353367

354368
impl RenderOptions {
355-
pub(crate) fn should_emit_crate(&self) -> bool {
356-
self.emit.is_empty() || self.emit.contains(&EmitType::HtmlNonStaticFiles)
357-
}
358-
359369
pub(crate) fn dep_info(&self) -> Option<Option<&OutFileName>> {
360-
for emit in &self.emit {
361-
if let EmitType::DepInfo(file) = emit {
362-
return Some(file.as_ref());
363-
}
364-
}
365-
None
370+
self.emit.iter().find_map(|emit| match emit {
371+
EmitType::DepInfo(file) => Some(file.as_ref()),
372+
_ => None,
373+
})
366374
}
367375
}
368376

@@ -469,26 +477,6 @@ impl Options {
469477

470478
let should_test = matches.opt_present("test");
471479

472-
let mut emit = FxIndexMap::<_, EmitType>::default();
473-
for list in matches.opt_strs("emit") {
474-
if should_test {
475-
dcx.fatal("the `--test` flag and the `--emit` flag are not supported together");
476-
}
477-
for kind in list.split(',') {
478-
match kind.parse() {
479-
Ok(kind) => {
480-
// De-duplicate emit types and the last wins.
481-
// Only one instance for each type is allowed
482-
// regardless the actual data it carries.
483-
// This matches rustc's `--emit` behavior.
484-
emit.insert(std::mem::discriminant(&kind), kind);
485-
}
486-
Err(()) => dcx.fatal(format!("unrecognized emission type: {kind}")),
487-
}
488-
}
489-
}
490-
let emit = emit.into_values().collect::<Vec<_>>();
491-
492480
let show_coverage = matches.opt_present("show-coverage");
493481
let output_format_s = matches.opt_str("output-format");
494482
let output_format = match output_format_s {
@@ -527,15 +515,55 @@ impl Options {
527515
}
528516
}
529517

530-
if output_format == OutputFormat::Json {
531-
if let Some(emit_flag) = emit.iter().find_map(|emit| match emit {
532-
EmitType::HtmlStaticFiles => Some("html-static-files"),
533-
EmitType::HtmlNonStaticFiles => Some("html-non-static-files"),
534-
EmitType::DepInfo(_) => None,
535-
}) {
536-
dcx.fatal(format!(
537-
"the `--emit={emit_flag}` flag is not supported with `--output-format=json`",
538-
));
518+
let mut emit = FxIndexMap::default();
519+
for list in matches.opt_strs("emit") {
520+
if should_test {
521+
dcx.fatal("the `--test` flag and the `--emit` flag are not supported together");
522+
}
523+
if let OutputFormat::Doctest = output_format {
524+
dcx.fatal("the `--emit` flag is not supported with `--output-format=doctest`");
525+
}
526+
527+
for typ in list.split(',') {
528+
let Ok(typ) = typ.parse::<EmitType>() else {
529+
dcx.fatal(format!("unrecognized emission type: {typ}"))
530+
};
531+
532+
match typ {
533+
EmitType::DepInfo(_) => match output_format {
534+
OutputFormat::Json | OutputFormat::Html => {}
535+
OutputFormat::Doctest => unreachable!(),
536+
},
537+
EmitType::HtmlStaticFiles | EmitType::HtmlNonStaticFiles => match output_format
538+
{
539+
OutputFormat::Html => {}
540+
OutputFormat::Json => dcx.fatal(format!(
541+
"the `--emit={typ}` flag is not supported with `--output-format=json`",
542+
)),
543+
OutputFormat::Doctest => unreachable!(),
544+
},
545+
EmitType::JsonFiles => unreachable!(),
546+
}
547+
548+
// De-duplicate emit types and the last wins.
549+
// Only one instance for each type is allowed
550+
// regardless the actual data it carries.
551+
// This matches rustc's `--emit` behavior.
552+
emit.insert(std::mem::discriminant(&typ), typ);
553+
}
554+
}
555+
let mut emit: SmallVec<[_; 2]> = emit.into_values().collect();
556+
// If `--emit` is absent we'll register default emission types depending on the requested
557+
// output format. We can safely use `is_empty` for this since `--emit=` ("truly empty")
558+
// will have already been rejected above.
559+
if emit.is_empty() {
560+
match output_format {
561+
OutputFormat::Json => emit.push(EmitType::JsonFiles),
562+
OutputFormat::Html => {
563+
emit.push(EmitType::HtmlStaticFiles);
564+
emit.push(EmitType::HtmlNonStaticFiles);
565+
}
566+
OutputFormat::Doctest => {}
539567
}
540568
}
541569

src/librustdoc/formats/renderer.rs

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2,22 +2,24 @@ use rustc_data_structures::profiling::SelfProfilerRef;
22
use rustc_middle::ty::TyCtxt;
33

44
use crate::clean;
5-
use crate::config::RenderOptions;
5+
use crate::config::{EmitType, RenderOptions};
66
use crate::error::Error;
77
use crate::formats::cache::Cache;
88

99
/// Allows for different backends to rustdoc to be used with the `run_format()` function. Each
1010
/// backend renderer has hooks for initialization, documenting an item, entering and exiting a
1111
/// module, and cleanup/finalizing output.
1212
pub(crate) trait FormatRenderer<'tcx>: Sized {
13-
/// Gives a description of the renderer. Used for performance profiling.
14-
fn descr() -> &'static str;
13+
/// A description of the renderer. Used for performance profiling.
14+
const DESCR: &'static str;
1515

16-
/// Whether to call `item` recursively for modules
16+
/// Whether to call `item` recursively for modules.
1717
///
18-
/// This is true for html, and false for json. See #80664
18+
/// See [#80664](https://github.com/rust-lang/rust/issues/80664).
1919
const RUN_ON_MODULE: bool;
2020

21+
const NON_STATIC_FILE_EMIT_TYPE: EmitType;
22+
2123
/// This associated type is the type where the current module information is stored.
2224
///
2325
/// For each module, we go through their items by calling for each item:
@@ -109,18 +111,18 @@ pub(crate) fn run_format<
109111
) -> Result<(), Error> {
110112
let prof = &tcx.sess.prof;
111113

112-
let emit_crate = options.should_emit_crate();
114+
let emit_non_static_files = options.emit.contains(&T::NON_STATIC_FILE_EMIT_TYPE);
113115
let (mut format_renderer, krate) = prof
114-
.verbose_generic_activity_with_arg("create_renderer", T::descr())
116+
.verbose_generic_activity_with_arg("create_renderer", T::DESCR)
115117
.run(|| init(krate, options, cache, tcx))?;
116118

117-
if !emit_crate {
119+
if !emit_non_static_files {
118120
return Ok(());
119121
}
120122

121123
// Render the crate documentation
122124
run_format_inner(&mut format_renderer, &krate.module, prof)?;
123125

124-
prof.verbose_generic_activity_with_arg("renderer_after_krate", T::descr())
126+
prof.verbose_generic_activity_with_arg("renderer_after_krate", T::DESCR)
125127
.run(|| format_renderer.after_krate())
126128
}

src/librustdoc/html/render/context.rs

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ use super::{AllTypes, LinkFromSrc, StylePath, collect_spans_and_sources, scrape_
2323
use crate::clean::types::ExternalLocation;
2424
use crate::clean::utils::has_doc_flag;
2525
use crate::clean::{self, ExternalCrate};
26-
use crate::config::{ModuleSorting, RenderOptions, ShouldMerge};
26+
use crate::config::{EmitType, ModuleSorting, RenderOptions, ShouldMerge};
2727
use crate::docfs::{DocFS, PathError};
2828
use crate::error::Error;
2929
use crate::formats::FormatRenderer;
@@ -481,7 +481,6 @@ impl<'tcx> Context<'tcx> {
481481
) -> Result<(Self, clean::Crate), Error> {
482482
// need to save a copy of the options for rendering the index page
483483
let md_opts = options.clone();
484-
let emit_crate = options.should_emit_crate();
485484
let RenderOptions {
486485
output,
487486
external_html,
@@ -495,6 +494,7 @@ impl<'tcx> Context<'tcx> {
495494
static_root_path,
496495
generate_redirect_map,
497496
show_type_layout,
497+
emit,
498498
generate_link_to_definition,
499499
call_locations,
500500
no_emit_shared,
@@ -605,7 +605,7 @@ impl<'tcx> Context<'tcx> {
605605
info: ContextInfo::new(include_sources),
606606
};
607607

608-
if emit_crate {
608+
if emit.contains(&EmitType::HtmlNonStaticFiles) {
609609
sources::render(&mut cx, &krate)?;
610610
}
611611

@@ -619,11 +619,10 @@ impl<'tcx> Context<'tcx> {
619619

620620
/// Generates the documentation for `crate` into the directory `dst`
621621
impl<'tcx> FormatRenderer<'tcx> for Context<'tcx> {
622-
fn descr() -> &'static str {
623-
"html"
624-
}
625-
622+
const DESCR: &'static str = "html";
626623
const RUN_ON_MODULE: bool = true;
624+
const NON_STATIC_FILE_EMIT_TYPE: EmitType = EmitType::HtmlNonStaticFiles;
625+
627626
type ModuleData = ContextInfo;
628627

629628
fn save_module_data(&mut self) -> Self::ModuleData {

src/librustdoc/html/render/write_shared.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -165,7 +165,7 @@ fn write_rendered_cross_crate_info(
165165
resource_suffix: &str,
166166
) -> Result<(), Error> {
167167
let m = &opt.should_merge;
168-
if opt.should_emit_crate() {
168+
if opt.emit.contains(&EmitType::HtmlNonStaticFiles) {
169169
if include_sources {
170170
write_rendered_cci::<SourcesPart, _>(SourcesPart::blank, dst, crates, m)?;
171171
}
@@ -190,7 +190,7 @@ fn write_resources(
190190
css_file_extension: Option<&Path>,
191191
resource_suffix: &str,
192192
) -> Result<(), Error> {
193-
if opt.emit.is_empty() || opt.emit.contains(&EmitType::HtmlNonStaticFiles) {
193+
if opt.emit.contains(&EmitType::HtmlNonStaticFiles) {
194194
// Handle added third-party themes
195195
for entry in style_files {
196196
let theme = entry.basename()?;
@@ -218,7 +218,7 @@ fn write_resources(
218218
}
219219
}
220220

221-
if opt.emit.is_empty() || opt.emit.contains(&EmitType::HtmlStaticFiles) {
221+
if opt.emit.contains(&EmitType::HtmlStaticFiles) {
222222
let static_dir = dst.join("static.files");
223223
try_err!(fs::create_dir_all(&static_dir), &static_dir);
224224

src/librustdoc/json/mod.rs

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ use tracing::{debug, trace};
2727

2828
use crate::clean::ItemKind;
2929
use crate::clean::types::{ExternalCrate, ExternalLocation};
30-
use crate::config::RenderOptions;
30+
use crate::config::{EmitType, RenderOptions};
3131
use crate::docfs::PathError;
3232
use crate::error::Error;
3333
use crate::formats::FormatRenderer;
@@ -132,11 +132,10 @@ impl<'tcx> JsonRenderer<'tcx> {
132132
}
133133

134134
impl<'tcx> FormatRenderer<'tcx> for JsonRenderer<'tcx> {
135-
fn descr() -> &'static str {
136-
"json"
137-
}
138-
135+
const DESCR: &'static str = "json";
139136
const RUN_ON_MODULE: bool = false;
137+
const NON_STATIC_FILE_EMIT_TYPE: EmitType = EmitType::JsonFiles;
138+
140139
type ModuleData = ();
141140

142141
fn save_module_data(&mut self) -> Self::ModuleData {

src/librustdoc/lib.rs

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -869,9 +869,7 @@ fn main_args(early_dcx: &mut EarlyDiagCtxt, at_args: &[String]) {
869869
};
870870
rustc_interface::create_and_enter_global_ctxt(compiler, krate, |tcx| {
871871
let has_dep_info = render_options.dep_info().is_some();
872-
if render_options.emit.contains(&EmitType::HtmlNonStaticFiles)
873-
|| render_options.emit.is_empty()
874-
{
872+
if render_options.emit.contains(&EmitType::HtmlNonStaticFiles) {
875873
markdown::render_and_write(file, render_options, edition)?;
876874
}
877875
if has_dep_info {
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
error: the `--emit` flag is not supported with `--output-format=doctest`
2+
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
error: the `--emit` flag is not supported with `--output-format=doctest`
2+
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
// Ensure that `--output-format=doctest` is incompatible with the `--emit` flag (for now at least).
2+
3+
//@ revisions: html-static-files dep-info
4+
//@ compile-flags: -Zunstable-options --output-format doctest
5+
//@[html-static-files] compile-flags: --emit html-static-files
6+
//@[dep-info] compile-flags: --emit dep-info
7+
8+
//~? ERROR the `--emit` flag is not supported with `--output-format=doctest`
Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,7 @@
11
//@ revisions: html_static html_non_static
2-
//@ check-fail
3-
//@[html_static] compile-flags: -Z unstable-options --output-format=json --emit=html-static-files
4-
//@[html_non_static] compile-flags: -Z unstable-options --output-format=json --emit=html-non-static-files
2+
//@ compile-flags: -Zunstable-options --output-format json
3+
//@[html_static] compile-flags: --emit html-static-files
4+
//@[html_non_static] compile-flags: --emit html-non-static-files
5+
56
//[html_static]~? ERROR the `--emit=html-static-files` flag is not supported with `--output-format=json`
67
//[html_non_static]~? ERROR the `--emit=html-non-static-files` flag is not supported with `--output-format=json`
7-
8-
pub struct Foo;

0 commit comments

Comments
 (0)