Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(trim-paths): rustdoc supports trim-paths for diagnostics #14389

Merged
merged 3 commits into from
Aug 12, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
156 changes: 95 additions & 61 deletions src/cargo/core/compiler/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,7 @@ use crate::util::{add_path_args, internal};
use cargo_util::{paths, ProcessBuilder, ProcessError};
use cargo_util_schemas::manifest::TomlDebugInfo;
use cargo_util_schemas::manifest::TomlTrimPaths;
use cargo_util_schemas::manifest::TomlTrimPathsValue;
use rustfix::diagnostics::Applicability;

const RUSTDOC_CRATE_VERSION_FLAG: &str = "--crate-version";
Expand Down Expand Up @@ -737,6 +738,10 @@ fn prepare_rustdoc(build_runner: &BuildRunner<'_, '_>, unit: &Unit) -> CargoResu
add_error_format_and_color(build_runner, &mut rustdoc);
add_allow_features(build_runner, &mut rustdoc);

if let Some(trim_paths) = unit.profile.trim_paths.as_ref() {
trim_paths_args_rustdoc(&mut rustdoc, build_runner, unit, trim_paths)?;
}

rustdoc.args(unit.pkg.manifest().lint_rustflags());
if let Some(args) = build_runner.bcx.extra_args_for(unit) {
rustdoc.args(args);
Expand Down Expand Up @@ -1223,6 +1228,32 @@ fn features_args(unit: &Unit) -> Vec<OsString> {
args
}

/// Like [`trim_paths_args`] but for rustdoc invocations.
fn trim_paths_args_rustdoc(
cmd: &mut ProcessBuilder,
build_runner: &BuildRunner<'_, '_>,
unit: &Unit,
trim_paths: &TomlTrimPaths,
) -> CargoResult<()> {
match trim_paths {
// rustdoc supports diagnostics trimming only.
TomlTrimPaths::Values(values) if !values.contains(&TomlTrimPathsValue::Diagnostics) => {
return Ok(())
}
_ => {}
}

// feature gate was checked during manifest/config parsing.
cmd.arg("-Zunstable-options");

// Order of `--remap-path-prefix` flags is important for `-Zbuild-std`.
// We want to show `/rustc/<hash>/library/std` instead of `std-0.0.0`.
cmd.arg(package_remap(build_runner, unit));
cmd.arg(sysroot_remap(build_runner, unit));

Ok(())
}

/// Generates the `--remap-path-scope` and `--remap-path-prefix` for [RFC 3127].
/// See also unstable feature [`-Ztrim-paths`].
///
Expand All @@ -1242,73 +1273,76 @@ fn trim_paths_args(
cmd.arg("-Zunstable-options");
cmd.arg(format!("-Zremap-path-scope={trim_paths}"));

let sysroot_remap = {
let sysroot = &build_runner.bcx.target_data.info(unit.kind).sysroot;
let mut remap = OsString::from("--remap-path-prefix=");
remap.push(sysroot);
remap.push("/lib/rustlib/src/rust"); // See also `detect_sysroot_src_path()`.
remap.push("=");
remap.push("/rustc/");
// This remap logic aligns with rustc:
// <https://github.com/rust-lang/rust/blob/c2ef3516/src/bootstrap/src/lib.rs#L1113-L1116>
if let Some(commit_hash) = build_runner.bcx.rustc().commit_hash.as_ref() {
remap.push(commit_hash);
} else {
remap.push(build_runner.bcx.rustc().version.to_string());
}
remap
};
let package_remap = {
let pkg_root = unit.pkg.root();
let ws_root = build_runner.bcx.ws.root();
let mut remap = OsString::from("--remap-path-prefix=");
// Remap rules for dependencies
//
// * Git dependencies: remove ~/.cargo/git/checkouts prefix.
// * Registry dependencies: remove ~/.cargo/registry/src prefix.
// * Others (e.g. path dependencies):
// * relative paths to workspace root if inside the workspace directory.
// * otherwise remapped to `<pkg>-<version>`.
let source_id = unit.pkg.package_id().source_id();
if source_id.is_git() {
remap.push(
build_runner
.bcx
.gctx
.git_checkouts_path()
.as_path_unlocked(),
);
remap.push("=");
} else if source_id.is_registry() {
remap.push(
build_runner
.bcx
.gctx
.registry_source_path()
.as_path_unlocked(),
);
remap.push("=");
} else if pkg_root.strip_prefix(ws_root).is_ok() {
remap.push(ws_root);
remap.push("=."); // remap to relative rustc work dir explicitly
} else {
remap.push(pkg_root);
remap.push("=");
remap.push(unit.pkg.name());
remap.push("-");
remap.push(unit.pkg.version().to_string());
}
remap
};

// Order of `--remap-path-prefix` flags is important for `-Zbuild-std`.
// We want to show `/rustc/<hash>/library/std` instead of `std-0.0.0`.
cmd.arg(package_remap);
cmd.arg(sysroot_remap);
cmd.arg(package_remap(build_runner, unit));
cmd.arg(sysroot_remap(build_runner, unit));

Ok(())
}

/// Path prefix remap rules for sysroot.
///
/// This remap logic aligns with rustc:
/// <https://github.com/rust-lang/rust/blob/c2ef3516/src/bootstrap/src/lib.rs#L1113-L1116>
fn sysroot_remap(build_runner: &BuildRunner<'_, '_>, unit: &Unit) -> OsString {
let sysroot = &build_runner.bcx.target_data.info(unit.kind).sysroot;
let mut remap = OsString::from("--remap-path-prefix=");
remap.push(sysroot);
remap.push("/lib/rustlib/src/rust"); // See also `detect_sysroot_src_path()`.
remap.push("=");
remap.push("/rustc/");
if let Some(commit_hash) = build_runner.bcx.rustc().commit_hash.as_ref() {
remap.push(commit_hash);
} else {
remap.push(build_runner.bcx.rustc().version.to_string());
}
remap
}

/// Path prefix remap rules for dependencies.
///
/// * Git dependencies: remove `~/.cargo/git/checkouts` prefix.
/// * Registry dependencies: remove `~/.cargo/registry/src` prefix.
/// * Others (e.g. path dependencies):
/// * relative paths to workspace root if inside the workspace directory.
/// * otherwise remapped to `<pkg>-<version>`.
fn package_remap(build_runner: &BuildRunner<'_, '_>, unit: &Unit) -> OsString {
let pkg_root = unit.pkg.root();
let ws_root = build_runner.bcx.ws.root();
let mut remap = OsString::from("--remap-path-prefix=");
let source_id = unit.pkg.package_id().source_id();
if source_id.is_git() {
remap.push(
build_runner
.bcx
.gctx
.git_checkouts_path()
.as_path_unlocked(),
);
remap.push("=");
} else if source_id.is_registry() {
remap.push(
build_runner
.bcx
.gctx
.registry_source_path()
.as_path_unlocked(),
);
remap.push("=");
} else if pkg_root.strip_prefix(ws_root).is_ok() {
remap.push(ws_root);
remap.push("=."); // remap to relative rustc work dir explicitly
} else {
remap.push(pkg_root);
remap.push("=");
remap.push(unit.pkg.name());
remap.push("-");
remap.push(unit.pkg.version().to_string());
}
remap
}

/// Generates the `--check-cfg` arguments for the `unit`.
fn check_cfg_args(unit: &Unit) -> CargoResult<Vec<OsString>> {
// The routine below generates the --check-cfg arguments. Our goals here are to
Expand Down
87 changes: 87 additions & 0 deletions tests/testsuite/profile_trim_paths.rs
Original file line number Diff line number Diff line change
Expand Up @@ -752,3 +752,90 @@ Hello, Ferris!
"#]],
);
}

#[cargo_test(nightly, reason = "rustdoc --remap-path-prefix is unstable")]
fn rustdoc_without_diagnostics_scope() {
Package::new("bar", "0.0.1")
.file("Cargo.toml", &basic_manifest("bar", "0.0.1"))
.file(
"src/lib.rs",
r#"
/// </script>
pub struct Bar;
"#,
)
.publish();
let p = project()
.file(
"Cargo.toml",
r#"
[package]
name = "foo"
version = "0.0.1"
edition = "2015"

[dependencies]
bar = "0.0.1"

[profile.dev]
trim-paths = "object"
"#,
)
.file("src/lib.rs", "")
.build();

p.cargo("doc -vv -Ztrim-paths")
.masquerade_as_nightly_cargo(&["-Ztrim-paths"])
.with_stderr_data(str![[r#"
...
[WARNING] unopened HTML tag `script`
--> [ROOT]/home/.cargo/registry/src/-[HASH]/bar-0.0.1/src/lib.rs:2:17
...
"#]])
.run();
}

#[cargo_test(nightly, reason = "rustdoc --remap-path-prefix is unstable")]
fn rustdoc_diagnostics_works() {
// This is expected to work after rust-lang/rust#128736
Package::new("bar", "0.0.1")
.file("Cargo.toml", &basic_manifest("bar", "0.0.1"))
.file(
"src/lib.rs",
r#"
/// </script>
pub struct Bar;
"#,
)
.publish();
let p = project()
.file(
"Cargo.toml",
r#"
[package]
name = "foo"
version = "0.0.1"
edition = "2015"

[dependencies]
bar = "0.0.1"

[profile.dev]
trim-paths = "diagnostics"
"#,
)
.file("src/lib.rs", "")
.build();

p.cargo("doc -vv -Ztrim-paths")
.masquerade_as_nightly_cargo(&["-Ztrim-paths"])
.with_stderr_data(str![[r#"
...
[RUNNING] `[..]rustc [..]-Zremap-path-scope=diagnostics --remap-path-prefix=[ROOT]/home/.cargo/registry/src= --remap-path-prefix=[..]/lib/rustlib/src/rust=/rustc/[..]`
...
[WARNING] unopened HTML tag `script`
--> -[..]/bar-0.0.1/src/lib.rs:2:17
...
"#]])
.run();
}