From d66718c107d4663cb68cdf9d07e73bd9c87c2ca9 Mon Sep 17 00:00:00 2001 From: Edward Shen Date: Fri, 15 Mar 2024 22:07:40 -0700 Subject: [PATCH] rustdoc: Add support for --remap-path-prefix Adds --remap-path-prefix as an unstable option. This is implemented to mimic the behavior of rustc's --remap-path-prefix but with minor adjustments. This flag similarly takes in two paths, a prefix to replace and a replacement string. --- src/librustdoc/config.rs | 26 +++++++++++++++ src/librustdoc/doctest.rs | 32 ++++++++----------- src/librustdoc/lib.rs | 8 +++++ .../output-default.stdout | 2 ++ ...remap-path-prefix-failed-doctest-output.rs | 13 ++++++++ ...p-path-prefix-failed-doctest-output.stdout | 21 ++++++++++++ .../remap-path-prefix-invalid-doctest.rs | 13 ++++++++ .../remap-path-prefix-invalid-doctest.stdout | 22 +++++++++++++ ...remap-path-prefix-passed-doctest-output.rs | 14 ++++++++ ...p-path-prefix-passed-doctest-output.stdout | 6 ++++ 10 files changed, 139 insertions(+), 18 deletions(-) create mode 100644 tests/rustdoc-ui/remap-path-prefix-failed-doctest-output.rs create mode 100644 tests/rustdoc-ui/remap-path-prefix-failed-doctest-output.stdout create mode 100644 tests/rustdoc-ui/remap-path-prefix-invalid-doctest.rs create mode 100644 tests/rustdoc-ui/remap-path-prefix-invalid-doctest.stdout create mode 100644 tests/rustdoc-ui/remap-path-prefix-passed-doctest-output.rs create mode 100644 tests/rustdoc-ui/remap-path-prefix-passed-doctest-output.stdout diff --git a/src/librustdoc/config.rs b/src/librustdoc/config.rs index be7e319bc79f4..62e35e69a0897 100644 --- a/src/librustdoc/config.rs +++ b/src/librustdoc/config.rs @@ -125,6 +125,8 @@ pub(crate) struct Options { pub(crate) enable_per_target_ignores: bool, /// Do not run doctests, compile them if should_test is active. pub(crate) no_run: bool, + /// What sources are being mapped. + pub(crate) remap_path_prefix: Vec<(PathBuf, PathBuf)>, /// The path to a rustc-like binary to build tests with. If not set, we /// default to loading from `$sysroot/bin/rustc`. @@ -208,6 +210,7 @@ impl fmt::Debug for Options { .field("run_check", &self.run_check) .field("no_run", &self.no_run) .field("test_builder_wrappers", &self.test_builder_wrappers) + .field("remap-file-prefix", &self.remap_path_prefix) .field("nocapture", &self.nocapture) .field("scrape_examples_options", &self.scrape_examples_options) .field("unstable_features", &self.unstable_features) @@ -355,6 +358,13 @@ impl Options { let unstable_opts = UnstableOptions::build(early_dcx, matches); let force_unstable_if_unmarked = unstable_opts.force_unstable_if_unmarked; + let remap_path_prefix = match parse_remap_path_prefix(&matches) { + Ok(prefix_mappings) => prefix_mappings, + Err(err) => { + early_dcx.early_fatal(err); + } + }; + let dcx = new_dcx(error_format, None, diagnostic_width, &unstable_opts); // check for deprecated options @@ -734,6 +744,7 @@ impl Options { run_check, no_run, test_builder_wrappers, + remap_path_prefix, nocapture, crate_name, output_format, @@ -781,6 +792,21 @@ impl Options { } } +fn parse_remap_path_prefix( + matches: &getopts::Matches, +) -> Result, &'static str> { + matches + .opt_strs("remap-path-prefix") + .into_iter() + .map(|remap| { + remap + .rsplit_once('=') + .ok_or("--remap-path-prefix must contain '=' between FROM and TO") + .map(|(from, to)| (PathBuf::from(from), PathBuf::from(to))) + }) + .collect() +} + /// Prints deprecation warnings for deprecated options fn check_deprecated_options(matches: &getopts::Matches, dcx: &rustc_errors::DiagCtxt) { let deprecated_flags = []; diff --git a/src/librustdoc/doctest.rs b/src/librustdoc/doctest.rs index c6eb7be08cd81..d391fb429b9bd 100644 --- a/src/librustdoc/doctest.rs +++ b/src/librustdoc/doctest.rs @@ -16,7 +16,7 @@ use rustc_session::config::{self, CrateType, ErrorOutputType}; use rustc_session::parse::ParseSess; use rustc_session::{lint, Session}; use rustc_span::edition::Edition; -use rustc_span::source_map::SourceMap; +use rustc_span::source_map::{FilePathMapping, SourceMap}; use rustc_span::symbol::sym; use rustc_span::{BytePos, FileName, Pos, Span, DUMMY_SP}; use rustc_target::spec::{Target, TargetTriple}; @@ -86,6 +86,7 @@ pub(crate) fn run(options: RustdocOptions) -> Result<(), ErrorGuaranteed> { edition: options.edition, target_triple: options.target.clone(), crate_name: options.crate_name.clone(), + remap_path_prefix: options.remap_path_prefix.clone(), ..config::Options::default() }; @@ -577,7 +578,6 @@ pub(crate) fn make_test( use rustc_errors::emitter::{Emitter, HumanEmitter}; use rustc_errors::DiagCtxt; use rustc_parse::parser::ForceCollect; - use rustc_span::source_map::FilePathMapping; let filename = FileName::anon_source_code(s); let source = crates + everything_else; @@ -768,7 +768,6 @@ fn check_if_attr_is_complete(source: &str, edition: Edition) -> bool { rustc_span::create_session_if_not_set_then(edition, |_| { use rustc_errors::emitter::HumanEmitter; use rustc_errors::DiagCtxt; - use rustc_span::source_map::FilePathMapping; let filename = FileName::anon_source_code(source); // Any errors in parsing should also appear when the doctest is compiled for real, so just @@ -976,7 +975,7 @@ impl Collector { if !item_path.is_empty() { item_path.push(' '); } - format!("{} - {item_path}(line {line})", filename.prefer_local()) + format!("{} - {item_path}(line {line})", filename.prefer_remapped_unconditionaly()) } pub(crate) fn set_position(&mut self, position: Span) { @@ -986,11 +985,15 @@ impl Collector { fn get_filename(&self) -> FileName { if let Some(ref source_map) = self.source_map { let filename = source_map.span_to_filename(self.position); - if let FileName::Real(ref filename) = filename - && let Ok(cur_dir) = env::current_dir() - && let Some(local_path) = filename.local_path() - && let Ok(path) = local_path.strip_prefix(&cur_dir) - { + if let FileName::Real(ref filename) = filename { + let path = filename.remapped_path_if_available(); + + // Strip the cwd prefix from the path. This will likely exist if + // the path was not remapped. + let path = env::current_dir() + .map(|cur_dir| path.strip_prefix(&cur_dir).unwrap_or(path)) + .unwrap_or(path); + return path.to_owned().into(); } filename @@ -1021,20 +1024,13 @@ impl Tester for Collector { } let path = match &filename { - FileName::Real(path) => { - if let Some(local_path) = path.local_path() { - local_path.to_path_buf() - } else { - // Somehow we got the filename from the metadata of another crate, should never happen - unreachable!("doctest from a different crate"); - } - } + FileName::Real(path) => path.remapped_path_if_available().to_path_buf(), _ => PathBuf::from(r"doctest.rs"), }; // For example `module/file.rs` would become `module_file_rs` let file = filename - .prefer_local() + .prefer_remapped_unconditionaly() .to_string_lossy() .chars() .map(|c| if c.is_ascii_alphanumeric() { c } else { '_' }) diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs index 18651875130fc..80108e5466160 100644 --- a/src/librustdoc/lib.rs +++ b/src/librustdoc/lib.rs @@ -557,6 +557,14 @@ fn opts() -> Vec { unstable("no-run", |o| { o.optflagmulti("", "no-run", "Compile doctests without running them") }), + unstable("remap-path-prefix", |o| { + o.optmulti( + "", + "remap-path-prefix", + "Remap source names in compiler messages", + "FROM=TO", + ) + }), unstable("show-type-layout", |o| { o.optflagmulti("", "show-type-layout", "Include the memory layout of types in the docs") }), diff --git a/tests/run-make/issue-88756-default-output/output-default.stdout b/tests/run-make/issue-88756-default-output/output-default.stdout index 12c1b389fb340..bc38d9e9dc6b3 100644 --- a/tests/run-make/issue-88756-default-output/output-default.stdout +++ b/tests/run-make/issue-88756-default-output/output-default.stdout @@ -157,6 +157,8 @@ Options: Comma separated list of types of output for rustdoc to emit --no-run Compile doctests without running them + --remap-path-prefix FROM=TO + Remap source names in compiler messages --show-type-layout Include the memory layout of types in the docs --nocapture Don't capture stdout and stderr of tests diff --git a/tests/rustdoc-ui/remap-path-prefix-failed-doctest-output.rs b/tests/rustdoc-ui/remap-path-prefix-failed-doctest-output.rs new file mode 100644 index 0000000000000..134ec67589ad7 --- /dev/null +++ b/tests/rustdoc-ui/remap-path-prefix-failed-doctest-output.rs @@ -0,0 +1,13 @@ +// FIXME: if/when the output of the test harness can be tested on its own, this test should be +// adapted to use that, and that normalize line can go away + +//@ compile-flags:--test -Z unstable-options --remap-path-prefix={{src-base}}=remapped_path --test-args --test-threads=1 +//@ rustc-env:RUST_BACKTRACE=0 +//@ normalize-stdout-test "finished in \d+\.\d+s" -> "finished in $$TIME" +//@ failure-status: 101 + +// doctest fails at runtime +/// ``` +/// panic!("oh no"); +/// ``` +pub struct SomeStruct; diff --git a/tests/rustdoc-ui/remap-path-prefix-failed-doctest-output.stdout b/tests/rustdoc-ui/remap-path-prefix-failed-doctest-output.stdout new file mode 100644 index 0000000000000..0ba6d01bf0f80 --- /dev/null +++ b/tests/rustdoc-ui/remap-path-prefix-failed-doctest-output.stdout @@ -0,0 +1,21 @@ + +running 1 test +test remapped_path/remap-path-prefix-failed-doctest-output.rs - SomeStruct (line 10) ... FAILED + +failures: + +---- remapped_path/remap-path-prefix-failed-doctest-output.rs - SomeStruct (line 10) stdout ---- +Test executable failed (exit status: 101). + +stderr: +thread 'main' panicked at remapped_path/remap-path-prefix-failed-doctest-output.rs:3:1: +oh no +note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace + + + +failures: + remapped_path/remap-path-prefix-failed-doctest-output.rs - SomeStruct (line 10) + +test result: FAILED. 0 passed; 1 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME + diff --git a/tests/rustdoc-ui/remap-path-prefix-invalid-doctest.rs b/tests/rustdoc-ui/remap-path-prefix-invalid-doctest.rs new file mode 100644 index 0000000000000..758843dbf3dc9 --- /dev/null +++ b/tests/rustdoc-ui/remap-path-prefix-invalid-doctest.rs @@ -0,0 +1,13 @@ +// FIXME: if/when the output of the test harness can be tested on its own, this test should be +// adapted to use that, and that normalize line can go away + +//@ compile-flags:--test -Z unstable-options --remap-path-prefix={{src-base}}=remapped_path --test-args --test-threads=1 +//@ rustc-env:RUST_BACKTRACE=0 +//@ normalize-stdout-test "finished in \d+\.\d+s" -> "finished in $$TIME" +//@ failure-status: 101 + +// doctest fails to compile +/// ``` +/// this is not real code +/// ``` +pub struct SomeStruct; diff --git a/tests/rustdoc-ui/remap-path-prefix-invalid-doctest.stdout b/tests/rustdoc-ui/remap-path-prefix-invalid-doctest.stdout new file mode 100644 index 0000000000000..a05b51699894b --- /dev/null +++ b/tests/rustdoc-ui/remap-path-prefix-invalid-doctest.stdout @@ -0,0 +1,22 @@ + +running 1 test +test remapped_path/remap-path-prefix-invalid-doctest.rs - SomeStruct (line 10) ... FAILED + +failures: + +---- remapped_path/remap-path-prefix-invalid-doctest.rs - SomeStruct (line 10) stdout ---- +error: expected one of `!`, `.`, `::`, `;`, `?`, `{`, `}`, or an operator, found `is` + --> remapped_path/remap-path-prefix-invalid-doctest.rs:11:6 + | +LL | this is not real code + | ^^ expected one of 8 possible tokens + +error: aborting due to 1 previous error + +Couldn't compile the test. + +failures: + remapped_path/remap-path-prefix-invalid-doctest.rs - SomeStruct (line 10) + +test result: FAILED. 0 passed; 1 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME + diff --git a/tests/rustdoc-ui/remap-path-prefix-passed-doctest-output.rs b/tests/rustdoc-ui/remap-path-prefix-passed-doctest-output.rs new file mode 100644 index 0000000000000..c58f3faeb5323 --- /dev/null +++ b/tests/rustdoc-ui/remap-path-prefix-passed-doctest-output.rs @@ -0,0 +1,14 @@ +//@ check-pass +//@ check-run-results + +// FIXME: if/when the output of the test harness can be tested on its own, this test should be +// adapted to use that, and that normalize line can go away + +//@ compile-flags:--test -Z unstable-options --remap-path-prefix={{src-base}}=remapped_path --test-args --test-threads=1 +//@ normalize-stdout-test "finished in \d+\.\d+s" -> "finished in $$TIME" + +// doctest passes at runtime +/// ``` +/// assert!(true); +/// ``` +pub struct SomeStruct; diff --git a/tests/rustdoc-ui/remap-path-prefix-passed-doctest-output.stdout b/tests/rustdoc-ui/remap-path-prefix-passed-doctest-output.stdout new file mode 100644 index 0000000000000..8ffb569488563 --- /dev/null +++ b/tests/rustdoc-ui/remap-path-prefix-passed-doctest-output.stdout @@ -0,0 +1,6 @@ + +running 1 test +test remapped_path/remap-path-prefix-passed-doctest-output.rs - SomeStruct (line 11) ... ok + +test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME +