Skip to content

Commit d66718c

Browse files
committed
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.
1 parent c03ea3d commit d66718c

10 files changed

+139
-18
lines changed

src/librustdoc/config.rs

+26
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,8 @@ pub(crate) struct Options {
125125
pub(crate) enable_per_target_ignores: bool,
126126
/// Do not run doctests, compile them if should_test is active.
127127
pub(crate) no_run: bool,
128+
/// What sources are being mapped.
129+
pub(crate) remap_path_prefix: Vec<(PathBuf, PathBuf)>,
128130

129131
/// The path to a rustc-like binary to build tests with. If not set, we
130132
/// default to loading from `$sysroot/bin/rustc`.
@@ -208,6 +210,7 @@ impl fmt::Debug for Options {
208210
.field("run_check", &self.run_check)
209211
.field("no_run", &self.no_run)
210212
.field("test_builder_wrappers", &self.test_builder_wrappers)
213+
.field("remap-file-prefix", &self.remap_path_prefix)
211214
.field("nocapture", &self.nocapture)
212215
.field("scrape_examples_options", &self.scrape_examples_options)
213216
.field("unstable_features", &self.unstable_features)
@@ -355,6 +358,13 @@ impl Options {
355358
let unstable_opts = UnstableOptions::build(early_dcx, matches);
356359
let force_unstable_if_unmarked = unstable_opts.force_unstable_if_unmarked;
357360

361+
let remap_path_prefix = match parse_remap_path_prefix(&matches) {
362+
Ok(prefix_mappings) => prefix_mappings,
363+
Err(err) => {
364+
early_dcx.early_fatal(err);
365+
}
366+
};
367+
358368
let dcx = new_dcx(error_format, None, diagnostic_width, &unstable_opts);
359369

360370
// check for deprecated options
@@ -734,6 +744,7 @@ impl Options {
734744
run_check,
735745
no_run,
736746
test_builder_wrappers,
747+
remap_path_prefix,
737748
nocapture,
738749
crate_name,
739750
output_format,
@@ -781,6 +792,21 @@ impl Options {
781792
}
782793
}
783794

795+
fn parse_remap_path_prefix(
796+
matches: &getopts::Matches,
797+
) -> Result<Vec<(PathBuf, PathBuf)>, &'static str> {
798+
matches
799+
.opt_strs("remap-path-prefix")
800+
.into_iter()
801+
.map(|remap| {
802+
remap
803+
.rsplit_once('=')
804+
.ok_or("--remap-path-prefix must contain '=' between FROM and TO")
805+
.map(|(from, to)| (PathBuf::from(from), PathBuf::from(to)))
806+
})
807+
.collect()
808+
}
809+
784810
/// Prints deprecation warnings for deprecated options
785811
fn check_deprecated_options(matches: &getopts::Matches, dcx: &rustc_errors::DiagCtxt) {
786812
let deprecated_flags = [];

src/librustdoc/doctest.rs

+14-18
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ use rustc_session::config::{self, CrateType, ErrorOutputType};
1616
use rustc_session::parse::ParseSess;
1717
use rustc_session::{lint, Session};
1818
use rustc_span::edition::Edition;
19-
use rustc_span::source_map::SourceMap;
19+
use rustc_span::source_map::{FilePathMapping, SourceMap};
2020
use rustc_span::symbol::sym;
2121
use rustc_span::{BytePos, FileName, Pos, Span, DUMMY_SP};
2222
use rustc_target::spec::{Target, TargetTriple};
@@ -86,6 +86,7 @@ pub(crate) fn run(options: RustdocOptions) -> Result<(), ErrorGuaranteed> {
8686
edition: options.edition,
8787
target_triple: options.target.clone(),
8888
crate_name: options.crate_name.clone(),
89+
remap_path_prefix: options.remap_path_prefix.clone(),
8990
..config::Options::default()
9091
};
9192

@@ -577,7 +578,6 @@ pub(crate) fn make_test(
577578
use rustc_errors::emitter::{Emitter, HumanEmitter};
578579
use rustc_errors::DiagCtxt;
579580
use rustc_parse::parser::ForceCollect;
580-
use rustc_span::source_map::FilePathMapping;
581581

582582
let filename = FileName::anon_source_code(s);
583583
let source = crates + everything_else;
@@ -768,7 +768,6 @@ fn check_if_attr_is_complete(source: &str, edition: Edition) -> bool {
768768
rustc_span::create_session_if_not_set_then(edition, |_| {
769769
use rustc_errors::emitter::HumanEmitter;
770770
use rustc_errors::DiagCtxt;
771-
use rustc_span::source_map::FilePathMapping;
772771

773772
let filename = FileName::anon_source_code(source);
774773
// Any errors in parsing should also appear when the doctest is compiled for real, so just
@@ -976,7 +975,7 @@ impl Collector {
976975
if !item_path.is_empty() {
977976
item_path.push(' ');
978977
}
979-
format!("{} - {item_path}(line {line})", filename.prefer_local())
978+
format!("{} - {item_path}(line {line})", filename.prefer_remapped_unconditionaly())
980979
}
981980

982981
pub(crate) fn set_position(&mut self, position: Span) {
@@ -986,11 +985,15 @@ impl Collector {
986985
fn get_filename(&self) -> FileName {
987986
if let Some(ref source_map) = self.source_map {
988987
let filename = source_map.span_to_filename(self.position);
989-
if let FileName::Real(ref filename) = filename
990-
&& let Ok(cur_dir) = env::current_dir()
991-
&& let Some(local_path) = filename.local_path()
992-
&& let Ok(path) = local_path.strip_prefix(&cur_dir)
993-
{
988+
if let FileName::Real(ref filename) = filename {
989+
let path = filename.remapped_path_if_available();
990+
991+
// Strip the cwd prefix from the path. This will likely exist if
992+
// the path was not remapped.
993+
let path = env::current_dir()
994+
.map(|cur_dir| path.strip_prefix(&cur_dir).unwrap_or(path))
995+
.unwrap_or(path);
996+
994997
return path.to_owned().into();
995998
}
996999
filename
@@ -1021,20 +1024,13 @@ impl Tester for Collector {
10211024
}
10221025

10231026
let path = match &filename {
1024-
FileName::Real(path) => {
1025-
if let Some(local_path) = path.local_path() {
1026-
local_path.to_path_buf()
1027-
} else {
1028-
// Somehow we got the filename from the metadata of another crate, should never happen
1029-
unreachable!("doctest from a different crate");
1030-
}
1031-
}
1027+
FileName::Real(path) => path.remapped_path_if_available().to_path_buf(),
10321028
_ => PathBuf::from(r"doctest.rs"),
10331029
};
10341030

10351031
// For example `module/file.rs` would become `module_file_rs`
10361032
let file = filename
1037-
.prefer_local()
1033+
.prefer_remapped_unconditionaly()
10381034
.to_string_lossy()
10391035
.chars()
10401036
.map(|c| if c.is_ascii_alphanumeric() { c } else { '_' })

src/librustdoc/lib.rs

+8
Original file line numberDiff line numberDiff line change
@@ -557,6 +557,14 @@ fn opts() -> Vec<RustcOptGroup> {
557557
unstable("no-run", |o| {
558558
o.optflagmulti("", "no-run", "Compile doctests without running them")
559559
}),
560+
unstable("remap-path-prefix", |o| {
561+
o.optmulti(
562+
"",
563+
"remap-path-prefix",
564+
"Remap source names in compiler messages",
565+
"FROM=TO",
566+
)
567+
}),
560568
unstable("show-type-layout", |o| {
561569
o.optflagmulti("", "show-type-layout", "Include the memory layout of types in the docs")
562570
}),

tests/run-make/issue-88756-default-output/output-default.stdout

+2
Original file line numberDiff line numberDiff line change
@@ -157,6 +157,8 @@ Options:
157157
Comma separated list of types of output for rustdoc to
158158
emit
159159
--no-run Compile doctests without running them
160+
--remap-path-prefix FROM=TO
161+
Remap source names in compiler messages
160162
--show-type-layout
161163
Include the memory layout of types in the docs
162164
--nocapture Don't capture stdout and stderr of tests
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
// FIXME: if/when the output of the test harness can be tested on its own, this test should be
2+
// adapted to use that, and that normalize line can go away
3+
4+
//@ compile-flags:--test -Z unstable-options --remap-path-prefix={{src-base}}=remapped_path --test-args --test-threads=1
5+
//@ rustc-env:RUST_BACKTRACE=0
6+
//@ normalize-stdout-test "finished in \d+\.\d+s" -> "finished in $$TIME"
7+
//@ failure-status: 101
8+
9+
// doctest fails at runtime
10+
/// ```
11+
/// panic!("oh no");
12+
/// ```
13+
pub struct SomeStruct;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
2+
running 1 test
3+
test remapped_path/remap-path-prefix-failed-doctest-output.rs - SomeStruct (line 10) ... FAILED
4+
5+
failures:
6+
7+
---- remapped_path/remap-path-prefix-failed-doctest-output.rs - SomeStruct (line 10) stdout ----
8+
Test executable failed (exit status: 101).
9+
10+
stderr:
11+
thread 'main' panicked at remapped_path/remap-path-prefix-failed-doctest-output.rs:3:1:
12+
oh no
13+
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
14+
15+
16+
17+
failures:
18+
remapped_path/remap-path-prefix-failed-doctest-output.rs - SomeStruct (line 10)
19+
20+
test result: FAILED. 0 passed; 1 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME
21+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
// FIXME: if/when the output of the test harness can be tested on its own, this test should be
2+
// adapted to use that, and that normalize line can go away
3+
4+
//@ compile-flags:--test -Z unstable-options --remap-path-prefix={{src-base}}=remapped_path --test-args --test-threads=1
5+
//@ rustc-env:RUST_BACKTRACE=0
6+
//@ normalize-stdout-test "finished in \d+\.\d+s" -> "finished in $$TIME"
7+
//@ failure-status: 101
8+
9+
// doctest fails to compile
10+
/// ```
11+
/// this is not real code
12+
/// ```
13+
pub struct SomeStruct;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
2+
running 1 test
3+
test remapped_path/remap-path-prefix-invalid-doctest.rs - SomeStruct (line 10) ... FAILED
4+
5+
failures:
6+
7+
---- remapped_path/remap-path-prefix-invalid-doctest.rs - SomeStruct (line 10) stdout ----
8+
error: expected one of `!`, `.`, `::`, `;`, `?`, `{`, `}`, or an operator, found `is`
9+
--> remapped_path/remap-path-prefix-invalid-doctest.rs:11:6
10+
|
11+
LL | this is not real code
12+
| ^^ expected one of 8 possible tokens
13+
14+
error: aborting due to 1 previous error
15+
16+
Couldn't compile the test.
17+
18+
failures:
19+
remapped_path/remap-path-prefix-invalid-doctest.rs - SomeStruct (line 10)
20+
21+
test result: FAILED. 0 passed; 1 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME
22+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
//@ check-pass
2+
//@ check-run-results
3+
4+
// FIXME: if/when the output of the test harness can be tested on its own, this test should be
5+
// adapted to use that, and that normalize line can go away
6+
7+
//@ compile-flags:--test -Z unstable-options --remap-path-prefix={{src-base}}=remapped_path --test-args --test-threads=1
8+
//@ normalize-stdout-test "finished in \d+\.\d+s" -> "finished in $$TIME"
9+
10+
// doctest passes at runtime
11+
/// ```
12+
/// assert!(true);
13+
/// ```
14+
pub struct SomeStruct;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
2+
running 1 test
3+
test remapped_path/remap-path-prefix-passed-doctest-output.rs - SomeStruct (line 11) ... ok
4+
5+
test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME
6+

0 commit comments

Comments
 (0)