From 327ee15959949c808da2498f7337a5fa5e415c08 Mon Sep 17 00:00:00 2001 From: Noratrieb <48135649+Noratrieb@users.noreply.github.com> Date: Mon, 28 Jul 2025 20:47:01 +0200 Subject: [PATCH] Ensure external paths passed via flags end up in rustdoc depinfo rustdoc has many flags to pass external HTML/Markdown/CSS files that end up in the build. These need to be recorded in depinfo so that Cargo will rebuild the crate if they change. --- src/librustdoc/config.rs | 20 +++++++++++------- src/librustdoc/externalfiles.rs | 23 ++++++++++++++------- src/librustdoc/lib.rs | 8 ++++++- src/librustdoc/scrape_examples.rs | 2 ++ tests/run-make/rustdoc-dep-info/after.md | 1 + tests/run-make/rustdoc-dep-info/before.html | 0 tests/run-make/rustdoc-dep-info/extend.css | 0 tests/run-make/rustdoc-dep-info/rmake.rs | 15 +++++++++++++- tests/run-make/rustdoc-dep-info/theme.css | 1 + 9 files changed, 53 insertions(+), 17 deletions(-) create mode 100644 tests/run-make/rustdoc-dep-info/after.md create mode 100644 tests/run-make/rustdoc-dep-info/before.html create mode 100644 tests/run-make/rustdoc-dep-info/extend.css create mode 100644 tests/run-make/rustdoc-dep-info/theme.css diff --git a/src/librustdoc/config.rs b/src/librustdoc/config.rs index 986390dbaa084..dfa6bf175d94c 100644 --- a/src/librustdoc/config.rs +++ b/src/librustdoc/config.rs @@ -377,7 +377,7 @@ impl Options { early_dcx: &mut EarlyDiagCtxt, matches: &getopts::Matches, args: Vec, - ) -> Option<(InputMode, Options, RenderOptions)> { + ) -> Option<(InputMode, Options, RenderOptions, Vec)> { // Check for unstable options. nightly_options::check_nightly_options(early_dcx, matches, &opts()); @@ -640,10 +640,13 @@ impl Options { let extension_css = matches.opt_str("e").map(|s| PathBuf::from(&s)); - if let Some(ref p) = extension_css - && !p.is_file() - { - dcx.fatal("option --extend-css argument must be a file"); + let mut loaded_paths = Vec::new(); + + if let Some(ref p) = extension_css { + loaded_paths.push(p.clone()); + if !p.is_file() { + dcx.fatal("option --extend-css argument must be a file"); + } } let mut themes = Vec::new(); @@ -687,6 +690,7 @@ impl Options { )) .emit(); } + loaded_paths.push(theme_file.clone()); themes.push(StylePath { path: theme_file }); } } @@ -705,6 +709,7 @@ impl Options { &mut id_map, edition, &None, + &mut loaded_paths, ) else { dcx.fatal("`ExternalHtml::load` failed"); }; @@ -796,7 +801,8 @@ impl Options { let scrape_examples_options = ScrapeExamplesOptions::new(matches, dcx); let with_examples = matches.opt_strs("with-examples"); - let call_locations = crate::scrape_examples::load_call_locations(with_examples, dcx); + let call_locations = + crate::scrape_examples::load_call_locations(with_examples, dcx, &mut loaded_paths); let doctest_build_args = matches.opt_strs("doctest-build-arg"); let unstable_features = @@ -881,7 +887,7 @@ impl Options { parts_out_dir, disable_minification, }; - Some((input, options, render_options)) + Some((input, options, render_options, loaded_paths)) } } diff --git a/src/librustdoc/externalfiles.rs b/src/librustdoc/externalfiles.rs index ea2aa963eddf3..42ade5b90048b 100644 --- a/src/librustdoc/externalfiles.rs +++ b/src/librustdoc/externalfiles.rs @@ -1,4 +1,4 @@ -use std::path::Path; +use std::path::{Path, PathBuf}; use std::{fs, str}; use rustc_errors::DiagCtxtHandle; @@ -32,12 +32,13 @@ impl ExternalHtml { id_map: &mut IdMap, edition: Edition, playground: &Option, + loaded_paths: &mut Vec, ) -> Option { let codes = ErrorCodes::from(nightly_build); - let ih = load_external_files(in_header, dcx)?; + let ih = load_external_files(in_header, dcx, loaded_paths)?; let bc = { - let mut bc = load_external_files(before_content, dcx)?; - let m_bc = load_external_files(md_before_content, dcx)?; + let mut bc = load_external_files(before_content, dcx, loaded_paths)?; + let m_bc = load_external_files(md_before_content, dcx, loaded_paths)?; Markdown { content: &m_bc, links: &[], @@ -52,8 +53,8 @@ impl ExternalHtml { bc }; let ac = { - let mut ac = load_external_files(after_content, dcx)?; - let m_ac = load_external_files(md_after_content, dcx)?; + let mut ac = load_external_files(after_content, dcx, loaded_paths)?; + let m_ac = load_external_files(md_after_content, dcx, loaded_paths)?; Markdown { content: &m_ac, links: &[], @@ -79,8 +80,10 @@ pub(crate) enum LoadStringError { pub(crate) fn load_string>( file_path: P, dcx: DiagCtxtHandle<'_>, + loaded_paths: &mut Vec, ) -> Result { let file_path = file_path.as_ref(); + loaded_paths.push(file_path.to_owned()); let contents = match fs::read(file_path) { Ok(bytes) => bytes, Err(e) => { @@ -101,10 +104,14 @@ pub(crate) fn load_string>( } } -fn load_external_files(names: &[String], dcx: DiagCtxtHandle<'_>) -> Option { +fn load_external_files( + names: &[String], + dcx: DiagCtxtHandle<'_>, + loaded_paths: &mut Vec, +) -> Option { let mut out = String::new(); for name in names { - let Ok(s) = load_string(name, dcx) else { return None }; + let Ok(s) = load_string(name, dcx, loaded_paths) else { return None }; out.push_str(&s); out.push('\n'); } diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs index a3cdc4f687f2d..7431ff8e1adef 100644 --- a/src/librustdoc/lib.rs +++ b/src/librustdoc/lib.rs @@ -799,7 +799,7 @@ fn main_args(early_dcx: &mut EarlyDiagCtxt, at_args: &[String]) { // Note that we discard any distinction between different non-zero exit // codes from `from_matches` here. - let (input, options, render_options) = + let (input, options, render_options, loaded_paths) = match config::Options::from_matches(early_dcx, &matches, args) { Some(opts) => opts, None => return, @@ -870,6 +870,12 @@ fn main_args(early_dcx: &mut EarlyDiagCtxt, at_args: &[String]) { interface::run_compiler(config, |compiler| { let sess = &compiler.sess; + // Register the loaded external files in the source map so they show up in depinfo. + // We can't load them via the source map because it gets created after we process the options. + for external_path in &loaded_paths { + let _ = sess.source_map().load_file(external_path); + } + if sess.opts.describe_lints { rustc_driver::describe_lints(sess, registered_lints); return; diff --git a/src/librustdoc/scrape_examples.rs b/src/librustdoc/scrape_examples.rs index fceacb69fb55e..4d29c74e1eb53 100644 --- a/src/librustdoc/scrape_examples.rs +++ b/src/librustdoc/scrape_examples.rs @@ -333,9 +333,11 @@ pub(crate) fn run( pub(crate) fn load_call_locations( with_examples: Vec, dcx: DiagCtxtHandle<'_>, + loaded_paths: &mut Vec, ) -> AllCallLocations { let mut all_calls: AllCallLocations = FxIndexMap::default(); for path in with_examples { + loaded_paths.push(path.clone().into()); let bytes = match fs::read(&path) { Ok(bytes) => bytes, Err(e) => dcx.fatal(format!("failed to load examples: {e}")), diff --git a/tests/run-make/rustdoc-dep-info/after.md b/tests/run-make/rustdoc-dep-info/after.md new file mode 100644 index 0000000000000..10d4b4c411640 --- /dev/null +++ b/tests/run-make/rustdoc-dep-info/after.md @@ -0,0 +1 @@ +meow! :3 diff --git a/tests/run-make/rustdoc-dep-info/before.html b/tests/run-make/rustdoc-dep-info/before.html new file mode 100644 index 0000000000000..e69de29bb2d1d diff --git a/tests/run-make/rustdoc-dep-info/extend.css b/tests/run-make/rustdoc-dep-info/extend.css new file mode 100644 index 0000000000000..e69de29bb2d1d diff --git a/tests/run-make/rustdoc-dep-info/rmake.rs b/tests/run-make/rustdoc-dep-info/rmake.rs index db7a00a5ce21c..625f81fd428ef 100644 --- a/tests/run-make/rustdoc-dep-info/rmake.rs +++ b/tests/run-make/rustdoc-dep-info/rmake.rs @@ -9,13 +9,26 @@ use run_make_support::{path, rfs, rustdoc}; fn main() { // We're only emitting dep info, so we shouldn't be running static analysis to // figure out that this program is erroneous. - rustdoc().input("lib.rs").arg("-Zunstable-options").emit("dep-info").run(); + // Ensure that all kinds of input reading flags end up in dep-info. + rustdoc() + .input("lib.rs") + .arg("-Zunstable-options") + .arg("--html-before-content=before.html") + .arg("--markdown-after-content=after.md") + .arg("--extend-css=extend.css") + .arg("--theme=theme.css") + .emit("dep-info") + .run(); let content = rfs::read_to_string("foo.d"); assert_contains(&content, "lib.rs:"); assert_contains(&content, "foo.rs:"); assert_contains(&content, "bar.rs:"); assert_contains(&content, "doc.md:"); + assert_contains(&content, "after.md:"); + assert_contains(&content, "before.html:"); + assert_contains(&content, "extend.css:"); + assert_contains(&content, "theme.css:"); // Now we check that we can provide a file name to the `dep-info` argument. rustdoc().input("lib.rs").arg("-Zunstable-options").emit("dep-info=bla.d").run(); diff --git a/tests/run-make/rustdoc-dep-info/theme.css b/tests/run-make/rustdoc-dep-info/theme.css new file mode 100644 index 0000000000000..459daffa9a19b --- /dev/null +++ b/tests/run-make/rustdoc-dep-info/theme.css @@ -0,0 +1 @@ +/* This is not a valid theme but that doesn't really matter */