From 991eb2dbb152e9228c043c3fd8a71ee4a90d7d14 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Fri, 13 Nov 2020 22:32:54 +0100 Subject: [PATCH] Add --check for rustdoc --- src/bin/cargo/commands/check.rs | 12 +++++ src/bin/cargo/commands/doc.rs | 54 ++++++++++++++++--- src/cargo/core/compiler/build_config.rs | 9 +++- .../compiler/build_context/target_info.rs | 5 +- .../compiler/context/compilation_files.rs | 2 +- src/cargo/core/compiler/mod.rs | 20 +++++-- src/cargo/core/compiler/timings.rs | 4 +- src/cargo/core/profiles.rs | 5 +- src/cargo/ops/cargo_compile.rs | 28 +++++----- 9 files changed, 107 insertions(+), 32 deletions(-) diff --git a/src/bin/cargo/commands/check.rs b/src/bin/cargo/commands/check.rs index 6d26ef2d765..ed57d779244 100644 --- a/src/bin/cargo/commands/check.rs +++ b/src/bin/cargo/commands/check.rs @@ -1,5 +1,7 @@ use crate::command_prelude::*; +use crate::commands::doc; +use cargo::core::features; use cargo::ops; pub fn cli() -> App { @@ -55,5 +57,15 @@ pub fn exec(config: &mut Config, args: &ArgMatches<'_>) -> CliResult { let compile_opts = args.compile_options(config, mode, Some(&ws), ProfileChecking::Unchecked)?; ops::compile(&ws, &compile_opts)?; + + if features::nightly_features_allowed() { + doc::exec_doc( + config, + args, + CompileMode::DocCheck, + ProfileChecking::Checked, + )?; + } + Ok(()) } diff --git a/src/bin/cargo/commands/doc.rs b/src/bin/cargo/commands/doc.rs index d82dc0ec3f6..cf3ef5eec16 100644 --- a/src/bin/cargo/commands/doc.rs +++ b/src/bin/cargo/commands/doc.rs @@ -1,5 +1,6 @@ use crate::command_prelude::*; +use cargo::core::features; use cargo::ops::{self, DocOptions}; pub fn cli() -> App { @@ -23,6 +24,7 @@ pub fn cli() -> App { "Document only the specified binary", "Document all binaries", ) + .arg(opt("check", "Runs `rustdoc --check` (nightly only)")) .arg_release("Build artifacts in release mode, with optimizations") .arg_profile("Build artifacts with the specified profile") .arg_features() @@ -35,18 +37,54 @@ pub fn cli() -> App { } pub fn exec(config: &mut Config, args: &ArgMatches<'_>) -> CliResult { + if args.is_present("check") { + if !features::nightly_features_allowed() { + Err(CliError::new( + anyhow::format_err!("This option is only available in nightly"), + 1, + ))?; + } + exec_doc( + config, + args, + CompileMode::DocCheck, + ProfileChecking::Unchecked, + ) + } else { + exec_doc( + config, + args, + CompileMode::Doc { + deps: !args.is_present("no-deps"), + }, + ProfileChecking::Checked, + ) + } +} + +pub fn exec_doc( + config: &mut Config, + args: &ArgMatches<'_>, + mode: CompileMode, + profile: ProfileChecking, +) -> CliResult { let ws = args.workspace(config)?; - let mode = CompileMode::Doc { - deps: !args.is_present("no-deps"), - }; - let mut compile_opts = - args.compile_options(config, mode, Some(&ws), ProfileChecking::Checked)?; - compile_opts.rustdoc_document_private_items = args.is_present("document-private-items"); - let doc_opts = DocOptions { - open_result: args.is_present("open"), + let mut compile_opts = args.compile_options(config, mode, Some(&ws), profile)?; + + if !mode.is_check() { + compile_opts.rustdoc_document_private_items = args.is_present("document-private-items"); + } + + let mut doc_opts = DocOptions { + open_result: false, compile_opts, }; + + if !mode.is_check() { + doc_opts.open_result = args.is_present("open"); + } + ops::doc(&ws, &doc_opts)?; Ok(()) } diff --git a/src/cargo/core/compiler/build_config.rs b/src/cargo/core/compiler/build_config.rs index d0f5431a47e..16136a34e57 100644 --- a/src/cargo/core/compiler/build_config.rs +++ b/src/cargo/core/compiler/build_config.rs @@ -132,6 +132,8 @@ pub enum CompileMode { /// Building a target with `rustc` to emit `rmeta` metadata only. If /// `test` is true, then it is also compiled with `--test` to check it like /// a test. + /// + /// It then runs `rustdoc --check`. Check { test: bool }, /// Used to indicate benchmarks should be built. This is not used in /// `Unit`, because it is essentially the same as `Test` (indicating @@ -143,6 +145,8 @@ pub enum CompileMode { Doc { deps: bool }, /// A target that will be tested with `rustdoc`. Doctest, + /// Runs `rustdoc --check`. + DocCheck, /// A marker for Units that represent the execution of a `build.rs` script. RunCustomBuild, } @@ -160,6 +164,7 @@ impl ser::Serialize for CompileMode { Bench => "bench".serialize(s), Doc { .. } => "doc".serialize(s), Doctest => "doctest".serialize(s), + DocCheck => "doccheck".serialize(s), RunCustomBuild => "run-custom-build".serialize(s), } } @@ -168,12 +173,12 @@ impl ser::Serialize for CompileMode { impl CompileMode { /// Returns `true` if the unit is being checked. pub fn is_check(self) -> bool { - matches!(self, CompileMode::Check { .. }) + matches!(self, CompileMode::Check { .. } | CompileMode::DocCheck) } /// Returns `true` if this is generating documentation. pub fn is_doc(self) -> bool { - matches!(self, CompileMode::Doc { .. }) + matches!(self, CompileMode::Doc { .. } | CompileMode::DocCheck) } /// Returns `true` if this a doc test. diff --git a/src/cargo/core/compiler/build_context/target_info.rs b/src/cargo/core/compiler/build_context/target_info.rs index 53fe197707c..d4f285a286e 100644 --- a/src/cargo/core/compiler/build_context/target_info.rs +++ b/src/cargo/core/compiler/build_context/target_info.rs @@ -436,7 +436,10 @@ impl TargetInfo { } } CompileMode::Check { .. } => Ok((vec![FileType::new_rmeta()], Vec::new())), - CompileMode::Doc { .. } | CompileMode::Doctest | CompileMode::RunCustomBuild => { + CompileMode::Doc { .. } + | CompileMode::Doctest + | CompileMode::RunCustomBuild + | CompileMode::DocCheck => { panic!("asked for rustc output for non-rustc mode") } } diff --git a/src/cargo/core/compiler/context/compilation_files.rs b/src/cargo/core/compiler/context/compilation_files.rs index 37b11da8471..4f40f612ebd 100644 --- a/src/cargo/core/compiler/context/compilation_files.rs +++ b/src/cargo/core/compiler/context/compilation_files.rs @@ -395,7 +395,7 @@ impl<'a, 'cfg: 'a> CompilationFiles<'a, 'cfg> { // outputs. vec![] } - CompileMode::Doctest => { + CompileMode::Doctest | CompileMode::DocCheck => { // Doctests are built in a temporary directory and then // deleted. There is the `--persist-doctests` unstable flag, // but Cargo does not know about that. diff --git a/src/cargo/core/compiler/mod.rs b/src/cargo/core/compiler/mod.rs index addf5ec7c3f..f1294bcaa43 100644 --- a/src/cargo/core/compiler/mod.rs +++ b/src/cargo/core/compiler/mod.rs @@ -562,12 +562,14 @@ fn rustdoc(cx: &mut Context<'_, '_>, unit: &Unit) -> CargoResult { let doc_dir = cx.files().out_dir(unit); - // Create the documentation directory ahead of time as rustdoc currently has - // a bug where concurrent invocations will race to create this directory if - // it doesn't already exist. - paths::create_dir_all(&doc_dir)?; + if !unit.mode.is_check() { + // Create the documentation directory ahead of time as rustdoc currently has + // a bug where concurrent invocations will race to create this directory if + // it doesn't already exist. + paths::create_dir_all(&doc_dir)?; - rustdoc.arg("-o").arg(doc_dir); + rustdoc.arg("-o").arg(doc_dir); + } for feat in &unit.features { rustdoc.arg("--cfg").arg(&format!("feature=\"{}\"", feat)); @@ -596,6 +598,14 @@ fn rustdoc(cx: &mut Context<'_, '_>, unit: &Unit) -> CargoResult { let pkg_id = unit.pkg.package_id(); let script_metadata = cx.find_build_script_metadata(unit.clone()); + if unit.mode.is_check() { + rustdoc.arg("-Z"); + rustdoc.arg("unstable-options"); + rustdoc.arg("--check"); + // rustdoc.arg("--warn"); + // rustdoc.arg("rustdoc"); + } + Ok(Work::new(move |state| { if let Some(script_metadata) = script_metadata { if let Some(output) = build_script_outputs diff --git a/src/cargo/core/compiler/timings.rs b/src/cargo/core/compiler/timings.rs index a206023a99e..1e9ee4e7932 100644 --- a/src/cargo/core/compiler/timings.rs +++ b/src/cargo/core/compiler/timings.rs @@ -170,7 +170,9 @@ impl<'cfg> Timings<'cfg> { CompileMode::Test => target.push_str(" (test)"), CompileMode::Build => {} CompileMode::Check { test: true } => target.push_str(" (check-test)"), - CompileMode::Check { test: false } => target.push_str(" (check)"), + CompileMode::Check { test: false } | CompileMode::DocCheck => { + target.push_str(" (check)") + } CompileMode::Bench => target.push_str(" (bench)"), CompileMode::Doc { .. } => target.push_str(" (doc)"), CompileMode::Doctest => target.push_str(" (doc test)"), diff --git a/src/cargo/core/profiles.rs b/src/cargo/core/profiles.rs index 0dc7266feaa..b0eabf46318 100644 --- a/src/cargo/core/profiles.rs +++ b/src/cargo/core/profiles.rs @@ -312,7 +312,10 @@ impl Profiles { ) } } - CompileMode::Build | CompileMode::Check { .. } | CompileMode::RunCustomBuild => { + CompileMode::Build + | CompileMode::Check { .. } + | CompileMode::RunCustomBuild + | CompileMode::DocCheck => { // Note: `RunCustomBuild` doesn't normally use this code path. // `build_unit_profiles` normally ensures that it selects the // ancestor's profile. However, `cargo clean -p` can hit this diff --git a/src/cargo/ops/cargo_compile.rs b/src/cargo/ops/cargo_compile.rs index 68ed8625e91..59f74df2c49 100644 --- a/src/cargo/ops/cargo_compile.rs +++ b/src/cargo/ops/cargo_compile.rs @@ -315,7 +315,8 @@ pub fn create_bcx<'a, 'cfg>( | CompileMode::Build | CompileMode::Check { .. } | CompileMode::Bench - | CompileMode::RunCustomBuild => { + | CompileMode::RunCustomBuild + | CompileMode::DocCheck => { if std::env::var("RUST_FLAGS").is_ok() { config.shell().warn( "Cargo does not read `RUST_FLAGS` environment variable. Did you mean `RUSTFLAGS`?", @@ -678,17 +679,18 @@ impl CompileFilter { match mode { CompileMode::Test | CompileMode::Doctest | CompileMode::Bench => true, CompileMode::Check { test: true } => true, - CompileMode::Build | CompileMode::Doc { .. } | CompileMode::Check { test: false } => { - match *self { - CompileFilter::Default { .. } => false, - CompileFilter::Only { - ref examples, - ref tests, - ref benches, - .. - } => examples.is_specific() || tests.is_specific() || benches.is_specific(), - } - } + CompileMode::Build + | CompileMode::Doc { .. } + | CompileMode::Check { test: false } + | CompileMode::DocCheck => match *self { + CompileFilter::Default { .. } => false, + CompileFilter::Only { + ref examples, + ref tests, + ref benches, + .. + } => examples.is_specific() || tests.is_specific() || benches.is_specific(), + }, CompileMode::RunCustomBuild => panic!("Invalid mode"), } } @@ -1177,7 +1179,7 @@ fn filter_default_targets(targets: &[Target], mode: CompileMode) -> Vec<&Target> .iter() .filter(|t| t.tested() || t.is_example()) .collect(), - CompileMode::Build | CompileMode::Check { .. } => targets + CompileMode::Build | CompileMode::Check { .. } | CompileMode::DocCheck => targets .iter() .filter(|t| t.is_bin() || t.is_lib()) .collect(),