Skip to content

Commit

Permalink
Rollup merge of rust-lang#107099 - edward-shen:edward-shen/rustdoc-re…
Browse files Browse the repository at this point in the history
…map-path-prefix, r=GuillaumeGomez

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`.

This flag similarly takes in two paths, a prefix to replace and a replacement string.

This is useful for build tools (e.g. Buck) other than cargo that can run doc tests.

cc: `@dtolnay`
  • Loading branch information
matthiaskrgr committed May 29, 2024
2 parents f2e1a3a + d66718c commit 014e4f3
Show file tree
Hide file tree
Showing 10 changed files with 139 additions and 18 deletions.
26 changes: 26 additions & 0 deletions src/librustdoc/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,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`.
Expand Down Expand Up @@ -211,6 +213,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)
Expand Down Expand Up @@ -372,6 +375,13 @@ impl Options {
let codegen_options = CodegenOptions::build(early_dcx, matches);
let unstable_opts = UnstableOptions::build(early_dcx, matches);

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
Expand Down Expand Up @@ -772,6 +782,7 @@ impl Options {
run_check,
no_run,
test_builder_wrappers,
remap_path_prefix,
nocapture,
crate_name,
output_format,
Expand Down Expand Up @@ -820,6 +831,21 @@ impl Options {
}
}

fn parse_remap_path_prefix(
matches: &getopts::Matches,
) -> Result<Vec<(PathBuf, PathBuf)>, &'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 = [];
Expand Down
32 changes: 14 additions & 18 deletions src/librustdoc/doctest.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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};
Expand Down Expand Up @@ -128,6 +128,7 @@ pub(crate) fn run(
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()
};

Expand Down Expand Up @@ -612,7 +613,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;
Expand Down Expand Up @@ -803,7 +803,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
Expand Down Expand Up @@ -1066,7 +1065,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) {
Expand All @@ -1076,11 +1075,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
Expand All @@ -1107,20 +1110,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 { '_' })
Expand Down
8 changes: 8 additions & 0 deletions src/librustdoc/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -556,6 +556,14 @@ fn opts() -> Vec<RustcOptGroup> {
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")
}),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
13 changes: 13 additions & 0 deletions tests/rustdoc-ui/remap-path-prefix-failed-doctest-output.rs
Original file line number Diff line number Diff line change
@@ -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;
21 changes: 21 additions & 0 deletions tests/rustdoc-ui/remap-path-prefix-failed-doctest-output.stdout
Original file line number Diff line number Diff line change
@@ -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

13 changes: 13 additions & 0 deletions tests/rustdoc-ui/remap-path-prefix-invalid-doctest.rs
Original file line number Diff line number Diff line change
@@ -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;
22 changes: 22 additions & 0 deletions tests/rustdoc-ui/remap-path-prefix-invalid-doctest.stdout
Original file line number Diff line number Diff line change
@@ -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

14 changes: 14 additions & 0 deletions tests/rustdoc-ui/remap-path-prefix-passed-doctest-output.rs
Original file line number Diff line number Diff line change
@@ -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;
Original file line number Diff line number Diff line change
@@ -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

0 comments on commit 014e4f3

Please sign in to comment.