Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
76 changes: 36 additions & 40 deletions src/librustdoc/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,33 +29,18 @@ use crate::passes::{self, Condition};
use crate::scrape_examples::{AllCallLocations, ScrapeExamplesOptions};
use crate::{html, opts, theme};

#[derive(Clone, Copy, PartialEq, Eq, Debug, Default)]
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
pub(crate) enum OutputFormat {
Json,
#[default]
/// `--output-format=json` without `--show-coverage`.
///
/// JSON description of crate API.
IrJson,
/// `--output-format=json` with `--show-coverage`.
CoverageJson,
Html,
Doctest,
}

impl OutputFormat {
pub(crate) fn is_json(&self) -> bool {
matches!(self, OutputFormat::Json)
}
}

impl TryFrom<&str> for OutputFormat {
type Error = String;

fn try_from(value: &str) -> Result<Self, Self::Error> {
match value {
"json" => Ok(OutputFormat::Json),
"html" => Ok(OutputFormat::Html),
"doctest" => Ok(OutputFormat::Doctest),
_ => Err(format!("unknown output format `{value}`")),
}
}
}

/// Either an input crate, markdown file, or nothing (--merge=finalize).
pub(crate) enum InputMode {
/// The `--merge=finalize` step does not need an input crate to rustdoc.
Expand Down Expand Up @@ -329,7 +314,8 @@ pub(crate) enum EmitType {
HtmlStaticFiles,
HtmlNonStaticFiles,
// not explicitly nameable by the user for now
JsonFiles,
IrJsonFiles,
CoverageJsonFiles,
DepInfo(Option<OutFileName>),
}

Expand All @@ -338,7 +324,8 @@ impl fmt::Display for EmitType {
f.write_str(match self {
Self::HtmlStaticFiles => "html-static-files",
Self::HtmlNonStaticFiles => "html-non-static-files",
Self::JsonFiles => "json-files",
Self::IrJsonFiles => "ir-json-files",
Self::CoverageJsonFiles => "coverage-json-files",
Self::DepInfo(_) => "dep-info",
})
}
Expand Down Expand Up @@ -479,40 +466,48 @@ impl Options {

let show_coverage = matches.opt_present("show-coverage");
let output_format_s = matches.opt_str("output-format");
let output_format = match output_format_s {
Some(ref s) => match OutputFormat::try_from(s.as_str()) {
Ok(out_fmt) => out_fmt,
Err(e) => dcx.fatal(e),
},
None => OutputFormat::default(),
let output_format = match output_format_s.as_deref() {
None | Some("html") => OutputFormat::Html,
Some("json") => {
if show_coverage {
OutputFormat::CoverageJson
} else {
OutputFormat::IrJson
}
}
Some("doctest") => OutputFormat::Doctest,
Some(other) => dcx.fatal(format!("unknown output format `{other}`")),
};

// check for `--output-format=json`
// check for `--output-format` stability, and compatibility with `--show-coverage`
match (
output_format_s.as_ref().map(|_| output_format),
show_coverage,
nightly_options::is_unstable_enabled(matches),
) {
(None | Some(OutputFormat::Json), true, _) => {}
(None | Some(OutputFormat::CoverageJson), true, _) => {}
(_, true, _) => {
dcx.fatal(format!(
"`--output-format={}` is not supported for the `--show-coverage` option",
output_format_s.unwrap_or_default(),
output_format_s.expect("checked for none above"),
));
}
// If `-Zunstable-options` is used, nothing to check after this point.
(_, false, true) => {}
(None | Some(OutputFormat::Html), false, _) => {}
(Some(OutputFormat::Json), false, false) => {
(Some(OutputFormat::IrJson), false, false) => {
dcx.fatal(
"the -Z unstable-options flag must be passed to enable --output-format for documentation generation (see https://github.com/rust-lang/rust/issues/76578)",
"the -Z unstable-options flag must be passed to enable --output-format=json for documentation generation (see https://github.com/rust-lang/rust/issues/76578)",
);
}
(Some(OutputFormat::Doctest), false, false) => {
dcx.fatal(
"the -Z unstable-options flag must be passed to enable --output-format for documentation generation (see https://github.com/rust-lang/rust/issues/134529)",
"the -Z unstable-options flag must be passed to enable --output-format=doctest (see https://github.com/rust-lang/rust/issues/134529)",
);
}
(Some(OutputFormat::CoverageJson), false, _) => {
unreachable!("CoverageJson is only possible when show_coverage is true")
}
}

let mut emit = FxIndexMap::default();
Expand All @@ -531,18 +526,18 @@ impl Options {

match typ {
EmitType::DepInfo(_) => match output_format {
OutputFormat::Json | OutputFormat::Html => {}
OutputFormat::Html | OutputFormat::IrJson | OutputFormat::CoverageJson => {}

@aDotInTheVoid aDotInTheVoid Jul 7, 2026

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think this is actually correct as --emit=dep-info makes no sense for --show-coverage (which only goes to stdout). I've filed #158929 to track doing this, as that fix should be a separate PR.

View changes since the review

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Indeed this seems weird. I agree that we should probably disallow --emit=dep-info with --show-coverage.

OutputFormat::Doctest => unreachable!(),
},
EmitType::HtmlStaticFiles | EmitType::HtmlNonStaticFiles => match output_format
{
OutputFormat::Html => {}
OutputFormat::Json => dcx.fatal(format!(
OutputFormat::IrJson | OutputFormat::CoverageJson => dcx.fatal(format!(
"the `--emit={typ}` flag is not supported with `--output-format=json`",
)),
OutputFormat::Doctest => unreachable!(),
},
EmitType::JsonFiles => unreachable!(),
EmitType::IrJsonFiles | EmitType::CoverageJsonFiles => unreachable!(),
}

// De-duplicate emit types and the last wins.
Expand All @@ -558,7 +553,8 @@ impl Options {
// will have already been rejected above.
if emit.is_empty() {
match output_format {
OutputFormat::Json => emit.push(EmitType::JsonFiles),
OutputFormat::IrJson => emit.push(EmitType::IrJsonFiles),
OutputFormat::CoverageJson => emit.push(EmitType::CoverageJsonFiles),
OutputFormat::Html => {
emit.push(EmitType::HtmlStaticFiles);
emit.push(EmitType::HtmlNonStaticFiles);
Expand Down
5 changes: 1 addition & 4 deletions src/librustdoc/core.rs
Original file line number Diff line number Diff line change
Expand Up @@ -75,8 +75,6 @@ pub(crate) struct DocContext<'tcx> {
pub(crate) inlined: FxHashSet<ItemId>,
/// Used by `calculate_doc_coverage`.
pub(crate) output_format: OutputFormat,
/// Used by `strip_private`.
pub(crate) show_coverage: bool,
}

impl<'tcx> DocContext<'tcx> {
Expand Down Expand Up @@ -139,7 +137,7 @@ impl<'tcx> DocContext<'tcx> {
///
/// If another option like `--show-coverage` is enabled, it will return `false`.
pub(crate) fn is_json_output(&self) -> bool {
self.output_format.is_json() && !self.show_coverage
self.output_format == OutputFormat::IrJson
}

/// If `--document-private-items` was passed to rustdoc.
Expand Down Expand Up @@ -385,7 +383,6 @@ pub(crate) fn run_global_ctxt(
cache: Cache::new(render_options.document_private, render_options.document_hidden),
inlined: FxHashSet::default(),
output_format,
show_coverage,
};

for cnum in tcx.crates(()) {
Expand Down
2 changes: 1 addition & 1 deletion src/librustdoc/json/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,7 @@ impl<'tcx> JsonRenderer<'tcx> {
impl<'tcx> FormatRenderer<'tcx> for JsonRenderer<'tcx> {
const DESCR: &'static str = "json";
const RUN_ON_MODULE: bool = false;
const NON_STATIC_FILE_EMIT_TYPE: EmitType = EmitType::JsonFiles;
const NON_STATIC_FILE_EMIT_TYPE: EmitType = EmitType::IrJsonFiles;

type ModuleData = ();

Expand Down
8 changes: 5 additions & 3 deletions src/librustdoc/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -984,11 +984,13 @@ fn main_args(early_dcx: &mut EarlyDiagCtxt, at_args: &[String]) {
},
)
}),
config::OutputFormat::Json => sess.time("render_json", || {
config::OutputFormat::IrJson => sess.time("render_json", || {
run_renderer(krate, render_opts, cache, tcx, json::JsonRenderer::init)
}),
// Already handled above with doctest runners.
config::OutputFormat::Doctest => unreachable!(),
// Already handled above with doctest runners or coverage early return
config::OutputFormat::Doctest | config::OutputFormat::CoverageJson => {
unreachable!()
}
}
})
})
Expand Down
4 changes: 2 additions & 2 deletions src/librustdoc/passes/calculate_doc_coverage.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ use serde::Serialize;
use tracing::debug;

use crate::clean;
use crate::config::OutputFormat;
use crate::core::DocContext;
use crate::html::markdown::{ErrorCodes, find_testable_code};
use crate::passes::Pass;
Expand Down Expand Up @@ -131,8 +132,7 @@ impl CoverageCalculator<'_, '_> {

fn print_results(&self) {
let output_format = self.ctx.output_format;
// In this case we want to ensure that the `OutputFormat` is JSON and NOT the `DocContext`.
if output_format.is_json() {
if output_format == OutputFormat::CoverageJson {
println!("{}", self.to_json());
return;
}
Expand Down
3 changes: 0 additions & 3 deletions tests/run-make/unstable-flag-required/README.md

This file was deleted.

This file was deleted.

12 changes: 0 additions & 12 deletions tests/run-make/unstable-flag-required/rmake.rs

This file was deleted.

1 change: 0 additions & 1 deletion tests/run-make/unstable-flag-required/x.rs

This file was deleted.

2 changes: 2 additions & 0 deletions tests/rustdoc-ui/output-format-coveragejson-emit-depinfo.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
//@ compile-flags: --show-coverage --output-format=json --emit=dep-info -Zunstable-options
//@ build-pass
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"$DIR/output-format-coveragejson-emit-depinfo.rs":{"total":1,"with_docs":0,"total_examples":0,"with_examples":0}}
4 changes: 4 additions & 0 deletions tests/rustdoc-ui/output-format-doctests-unstable.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
//@ compile-flags: --output-format=doctest
pub struct Foo;

//~? ERROR the -Z unstable-options flag must be passed to enable --output-format=doctest (see https://github.com/rust-lang/rust/issues/134529)
2 changes: 2 additions & 0 deletions tests/rustdoc-ui/output-format-doctests-unstable.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
error: the -Z unstable-options flag must be passed to enable --output-format=doctest (see https://github.com/rust-lang/rust/issues/134529)

2 changes: 2 additions & 0 deletions tests/rustdoc-ui/output-format-irjson-emit-depinfo.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
//@ compile-flags: --output-format=json --emit=dep-info -Zunstable-options
//@ build-pass
4 changes: 4 additions & 0 deletions tests/rustdoc-ui/output-format-irjson-unstable.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
//@ compile-flags: --output-format=json
pub struct Foo;

//~? ERROR the -Z unstable-options flag must be passed to enable --output-format=json for documentation
2 changes: 2 additions & 0 deletions tests/rustdoc-ui/output-format-irjson-unstable.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
error: the -Z unstable-options flag must be passed to enable --output-format=json for documentation generation (see https://github.com/rust-lang/rust/issues/76578)

Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
error: the `--emit=html-non-static-files` flag is not supported with `--output-format=json`

Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
error: the `--emit=html-static-files` flag is not supported with `--output-format=json`

6 changes: 5 additions & 1 deletion tests/rustdoc-ui/output-format-json-emit-html.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
//@ revisions: html_static html_non_static
//@ revisions: html_static html_non_static html_static_coverage html_non_static_coverage
//@ compile-flags: -Zunstable-options --output-format json
//@[html_static] compile-flags: --emit html-static-files
//@[html_static_coverage] compile-flags: --emit html-static-files --show-coverage
//@[html_non_static] compile-flags: --emit html-non-static-files
//@[html_non_static_coverage] compile-flags: --emit html-non-static-files --show-coverage

//[html_static]~? ERROR the `--emit=html-static-files` flag is not supported with `--output-format=json`
//[html_static_coverage]~? 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`
//[html_non_static_coverage]~? ERROR the `--emit=html-non-static-files` flag is not supported with `--output-format=json`
4 changes: 4 additions & 0 deletions tests/rustdoc-ui/output-format-unknown.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
//@ compile-flags: --output-format=da-doo-ron-ron

pub struct Foo;
//~? ERROR unknown output format `da-doo-ron-ron`
2 changes: 2 additions & 0 deletions tests/rustdoc-ui/output-format-unknown.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
error: unknown output format `da-doo-ron-ron`

Loading