Unnamed repository; edit this file 'description' to name the repository.
Merge pull request #18785 from Veykril/push-uvsqposqyvmo
Cleanup toolchain info fetching
Lukas Wirth 2024-12-29
parent 293df4c · parent 98fde69 · commit 90b724a
-rw-r--r--clippy.toml4
-rw-r--r--crates/hir-ty/src/layout/tests.rs6
-rw-r--r--crates/ide/src/expand_macro.rs1
-rw-r--r--crates/proc-macro-api/src/process.rs1
-rw-r--r--crates/proc-macro-srv/build.rs1
-rw-r--r--crates/proc-macro-srv/proc-macro-test/build.rs2
-rw-r--r--crates/project-model/src/build_dependencies.rs14
-rw-r--r--crates/project-model/src/cargo_workspace.rs2
-rw-r--r--crates/project-model/src/env.rs5
-rw-r--r--crates/project-model/src/lib.rs26
-rw-r--r--crates/project-model/src/rustc_cfg.rs99
-rw-r--r--crates/project-model/src/sysroot.rs20
-rw-r--r--crates/project-model/src/target_data_layout.rs67
-rw-r--r--crates/project-model/src/toolchain_info/rustc_cfg.rs78
-rw-r--r--crates/project-model/src/toolchain_info/target_data_layout.rs57
-rw-r--r--crates/project-model/src/toolchain_info/target_triple.rs (renamed from crates/project-model/src/target_triple.rs)54
-rw-r--r--crates/project-model/src/workspace.rs315
-rw-r--r--crates/rust-analyzer/build.rs1
-rw-r--r--crates/rust-analyzer/src/bin/rustc_wrapper.rs1
-rw-r--r--crates/rust-analyzer/src/cli/rustc_tests.rs8
-rw-r--r--crates/rust-analyzer/src/discover.rs10
-rw-r--r--crates/rust-analyzer/src/flycheck.rs20
-rw-r--r--crates/rust-analyzer/src/handlers/request.rs52
-rw-r--r--crates/rust-analyzer/src/main_loop.rs3
-rw-r--r--crates/rust-analyzer/src/test_runner.rs4
-rw-r--r--crates/toolchain/src/lib.rs16
-rw-r--r--xtask/src/main.rs7
27 files changed, 438 insertions, 436 deletions
diff --git a/clippy.toml b/clippy.toml
index 8032c775ab..1046cb3d56 100644
--- a/clippy.toml
+++ b/clippy.toml
@@ -3,3 +3,7 @@ disallowed-types = [
{ path = "std::collections::HashSet", reason = "use FxHashSet" },
{ path = "std::collections::hash_map::RandomState", reason = "use BuildHasherDefault<FxHasher>"}
]
+
+disallowed-methods = [
+ { path = "std::process::Command::new", reason = "use `toolchain::command` instead as it forces the choice of a working directory" },
+]
diff --git a/crates/hir-ty/src/layout/tests.rs b/crates/hir-ty/src/layout/tests.rs
index f40d508f75..2649d88ac2 100644
--- a/crates/hir-ty/src/layout/tests.rs
+++ b/crates/hir-ty/src/layout/tests.rs
@@ -1,7 +1,7 @@
use chalk_ir::{AdtId, TyKind};
use either::Either;
use hir_def::db::DefDatabase;
-use project_model::{target_data_layout::RustcDataLayoutConfig, Sysroot};
+use project_model::{toolchain_info::QueryConfig, Sysroot};
use rustc_hash::FxHashMap;
use syntax::ToSmolStr;
use test_fixture::WithFixture;
@@ -17,8 +17,8 @@ use crate::{
mod closure;
fn current_machine_data_layout() -> String {
- project_model::target_data_layout::get(
- RustcDataLayoutConfig::Rustc(&Sysroot::empty()),
+ project_model::toolchain_info::target_data_layout::get(
+ QueryConfig::Rustc(&Sysroot::empty(), &std::env::current_dir().unwrap()),
None,
&FxHashMap::default(),
)
diff --git a/crates/ide/src/expand_macro.rs b/crates/ide/src/expand_macro.rs
index 10a73edd51..f642db6a71 100644
--- a/crates/ide/src/expand_macro.rs
+++ b/crates/ide/src/expand_macro.rs
@@ -253,6 +253,7 @@ fn _format(
let &crate_id = db.relevant_crates(file_id).iter().next()?;
let edition = db.crate_graph()[crate_id].edition;
+ #[allow(clippy::disallowed_methods)]
let mut cmd = std::process::Command::new(toolchain::Tool::Rustfmt.path());
cmd.arg("--edition");
cmd.arg(edition.to_string());
diff --git a/crates/proc-macro-api/src/process.rs b/crates/proc-macro-api/src/process.rs
index 4045e25fdf..4d62efdd6b 100644
--- a/crates/proc-macro-api/src/process.rs
+++ b/crates/proc-macro-api/src/process.rs
@@ -202,6 +202,7 @@ fn mk_child(
env: impl IntoIterator<Item = (impl AsRef<std::ffi::OsStr>, impl AsRef<std::ffi::OsStr>)>,
null_stderr: bool,
) -> io::Result<Child> {
+ #[allow(clippy::disallowed_methods)]
let mut cmd = Command::new(path);
cmd.envs(env)
.env("RUST_ANALYZER_INTERNALS_DO_NOT_USE", "this is unstable")
diff --git a/crates/proc-macro-srv/build.rs b/crates/proc-macro-srv/build.rs
index 9a17cfc9f3..07a10aaae5 100644
--- a/crates/proc-macro-srv/build.rs
+++ b/crates/proc-macro-srv/build.rs
@@ -7,6 +7,7 @@ fn main() {
println!("cargo::rustc-check-cfg=cfg(rust_analyzer)");
let rustc = env::var("RUSTC").expect("proc-macro-srv's build script expects RUSTC to be set");
+ #[allow(clippy::disallowed_methods)]
let output = Command::new(rustc).arg("--version").output().expect("rustc --version must run");
let version_string = std::str::from_utf8(&output.stdout[..])
.expect("rustc --version output must be UTF-8")
diff --git a/crates/proc-macro-srv/proc-macro-test/build.rs b/crates/proc-macro-srv/proc-macro-test/build.rs
index ff2f5d1863..d3d58a6df0 100644
--- a/crates/proc-macro-srv/proc-macro-test/build.rs
+++ b/crates/proc-macro-srv/proc-macro-test/build.rs
@@ -7,6 +7,8 @@
//! a specific rustup toolchain: this allows testing against older ABIs (e.g.
//! 1.58) and future ABIs (stage1, nightly)
+#![allow(clippy::disallowed_methods)]
+
use std::{
env,
path::{Path, PathBuf},
diff --git a/crates/project-model/src/build_dependencies.rs b/crates/project-model/src/build_dependencies.rs
index 524323b973..b0939229f9 100644
--- a/crates/project-model/src/build_dependencies.rs
+++ b/crates/project-model/src/build_dependencies.rs
@@ -172,19 +172,18 @@ impl WorkspaceBuildScripts {
}
let res = (|| {
let target_libdir = (|| {
- let mut cargo_config = sysroot.tool(Tool::Cargo);
+ let mut cargo_config = sysroot.tool(Tool::Cargo, current_dir);
cargo_config.envs(extra_env);
cargo_config
- .current_dir(current_dir)
.args(["rustc", "-Z", "unstable-options", "--print", "target-libdir"])
.env("RUSTC_BOOTSTRAP", "1");
- if let Ok(it) = utf8_stdout(cargo_config) {
+ if let Ok(it) = utf8_stdout(&mut cargo_config) {
return Ok(it);
}
- let mut cmd = sysroot.tool(Tool::Rustc);
+ let mut cmd = sysroot.tool(Tool::Rustc, current_dir);
cmd.envs(extra_env);
cmd.args(["--print", "target-libdir"]);
- utf8_stdout(cmd)
+ utf8_stdout(&mut cmd)
})()?;
let target_libdir = AbsPathBuf::try_from(Utf8PathBuf::from(target_libdir))
@@ -390,12 +389,12 @@ impl WorkspaceBuildScripts {
) -> io::Result<Command> {
let mut cmd = match config.run_build_script_command.as_deref() {
Some([program, args @ ..]) => {
- let mut cmd = Command::new(program);
+ let mut cmd = toolchain::command(program, current_dir);
cmd.args(args);
cmd
}
_ => {
- let mut cmd = sysroot.tool(Tool::Cargo);
+ let mut cmd = sysroot.tool(Tool::Cargo, current_dir);
cmd.args(["check", "--quiet", "--workspace", "--message-format=json"]);
cmd.args(&config.extra_args);
@@ -448,7 +447,6 @@ impl WorkspaceBuildScripts {
}
};
- cmd.current_dir(current_dir);
cmd.envs(&config.extra_env);
if config.wrap_rustc_in_build_scripts {
// Setup RUSTC_WRAPPER to point to `rust-analyzer` binary itself. We use
diff --git a/crates/project-model/src/cargo_workspace.rs b/crates/project-model/src/cargo_workspace.rs
index 836879c75b..4ffe3a6265 100644
--- a/crates/project-model/src/cargo_workspace.rs
+++ b/crates/project-model/src/cargo_workspace.rs
@@ -294,7 +294,7 @@ impl CargoWorkspace {
no_deps: bool,
progress: &dyn Fn(String),
) -> anyhow::Result<(cargo_metadata::Metadata, Option<anyhow::Error>)> {
- let cargo = sysroot.tool(Tool::Cargo);
+ let cargo = sysroot.tool(Tool::Cargo, current_dir);
let mut meta = MetadataCommand::new();
meta.cargo_path(cargo.get_program());
cargo.get_envs().for_each(|(var, val)| _ = meta.env(var, val.unwrap_or_default()));
diff --git a/crates/project-model/src/env.rs b/crates/project-model/src/env.rs
index ff9d2035f6..b4714b764a 100644
--- a/crates/project-model/src/env.rs
+++ b/crates/project-model/src/env.rs
@@ -74,10 +74,9 @@ pub(crate) fn cargo_config_env(
extra_env: &FxHashMap<String, String>,
sysroot: &Sysroot,
) -> FxHashMap<String, String> {
- let mut cargo_config = sysroot.tool(Tool::Cargo);
+ let mut cargo_config = sysroot.tool(Tool::Cargo, manifest.parent());
cargo_config.envs(extra_env);
cargo_config
- .current_dir(manifest.parent())
.args(["-Z", "unstable-options", "config", "get", "env"])
.env("RUSTC_BOOTSTRAP", "1");
if manifest.is_rust_manifest() {
@@ -85,7 +84,7 @@ pub(crate) fn cargo_config_env(
}
// if successful we receive `env.key.value = "value" per entry
tracing::debug!("Discovering cargo config env by {:?}", cargo_config);
- utf8_stdout(cargo_config)
+ utf8_stdout(&mut cargo_config)
.map(parse_output_cargo_config_env)
.inspect(|env| {
tracing::debug!("Discovered cargo config env: {:?}", env);
diff --git a/crates/project-model/src/lib.rs b/crates/project-model/src/lib.rs
index 9a024f6b96..1913db11fa 100644
--- a/crates/project-model/src/lib.rs
+++ b/crates/project-model/src/lib.rs
@@ -15,15 +15,31 @@
//! procedural macros).
//! * Lowering of concrete model to a [`base_db::CrateGraph`]
+pub mod project_json;
+pub mod toolchain_info {
+ pub mod rustc_cfg;
+ pub mod target_data_layout;
+ pub mod target_triple;
+
+ use std::path::Path;
+
+ use crate::{ManifestPath, Sysroot};
+
+ #[derive(Copy, Clone)]
+ pub enum QueryConfig<'a> {
+ /// Directly invoke `rustc` to query the desired information.
+ Rustc(&'a Sysroot, &'a Path),
+ /// Attempt to use cargo to query the desired information, honoring cargo configurations.
+ /// If this fails, falls back to invoking `rustc` directly.
+ Cargo(&'a Sysroot, &'a ManifestPath),
+ }
+}
+
mod build_dependencies;
mod cargo_workspace;
mod env;
mod manifest_path;
-pub mod project_json;
-mod rustc_cfg;
mod sysroot;
-pub mod target_data_layout;
-mod target_triple;
mod workspace;
#[cfg(test)]
@@ -182,7 +198,7 @@ impl fmt::Display for ProjectManifest {
}
}
-fn utf8_stdout(mut cmd: Command) -> anyhow::Result<String> {
+fn utf8_stdout(cmd: &mut Command) -> anyhow::Result<String> {
let output = cmd.output().with_context(|| format!("{cmd:?} failed"))?;
if !output.status.success() {
match String::from_utf8(output.stderr) {
diff --git a/crates/project-model/src/rustc_cfg.rs b/crates/project-model/src/rustc_cfg.rs
deleted file mode 100644
index bc1f0e6fbf..0000000000
--- a/crates/project-model/src/rustc_cfg.rs
+++ /dev/null
@@ -1,99 +0,0 @@
-//! Runs `rustc --print cfg` to get built-in cfg flags.
-
-use anyhow::Context;
-use cfg::CfgAtom;
-use intern::Symbol;
-use rustc_hash::FxHashMap;
-use toolchain::Tool;
-
-use crate::{utf8_stdout, ManifestPath, Sysroot};
-
-/// Determines how `rustc --print cfg` is discovered and invoked.
-pub(crate) enum RustcCfgConfig<'a> {
- /// Use `rustc --print cfg`, either from with the binary from the sysroot or by discovering via
- /// [`toolchain::rustc`].
- Rustc(&'a Sysroot),
- /// Use `cargo --print cfg`, either from with the binary from the sysroot or by discovering via
- /// [`toolchain::cargo`].
- Cargo(&'a Sysroot, &'a ManifestPath),
-}
-
-pub(crate) fn get(
- target: Option<&str>,
- extra_env: &FxHashMap<String, String>,
- config: RustcCfgConfig<'_>,
-) -> Vec<CfgAtom> {
- let _p = tracing::info_span!("rustc_cfg::get").entered();
- let mut res: Vec<_> = Vec::with_capacity(7 * 2 + 1);
-
- // Some nightly-only cfgs, which are required for stdlib
- res.push(CfgAtom::Flag(Symbol::intern("target_thread_local")));
- for key in ["target_has_atomic", "target_has_atomic_load_store"] {
- for ty in ["8", "16", "32", "64", "cas", "ptr"] {
- res.push(CfgAtom::KeyValue { key: Symbol::intern(key), value: Symbol::intern(ty) });
- }
- res.push(CfgAtom::Flag(Symbol::intern(key)));
- }
-
- let rustc_cfgs = get_rust_cfgs(target, extra_env, config);
-
- let rustc_cfgs = match rustc_cfgs {
- Ok(cfgs) => cfgs,
- Err(e) => {
- tracing::error!(?e, "failed to get rustc cfgs");
- return res;
- }
- };
-
- let rustc_cfgs = rustc_cfgs.lines().map(crate::parse_cfg).collect::<Result<Vec<_>, _>>();
-
- match rustc_cfgs {
- Ok(rustc_cfgs) => {
- tracing::debug!(?rustc_cfgs, "rustc cfgs found");
- res.extend(rustc_cfgs);
- }
- Err(e) => {
- tracing::error!(?e, "failed to get rustc cfgs")
- }
- }
-
- res
-}
-
-fn get_rust_cfgs(
- target: Option<&str>,
- extra_env: &FxHashMap<String, String>,
- config: RustcCfgConfig<'_>,
-) -> anyhow::Result<String> {
- let sysroot = match config {
- RustcCfgConfig::Cargo(sysroot, cargo_toml) => {
- let mut cmd = sysroot.tool(Tool::Cargo);
-
- cmd.envs(extra_env);
- cmd.current_dir(cargo_toml.parent())
- .args(["rustc", "-Z", "unstable-options", "--print", "cfg"])
- .env("RUSTC_BOOTSTRAP", "1");
- if let Some(target) = target {
- cmd.args(["--target", target]);
- }
-
- match utf8_stdout(cmd) {
- Ok(it) => return Ok(it),
- Err(e) => {
- tracing::warn!("failed to run `cargo rustc --print cfg`, falling back to invoking rustc directly: {e}");
- sysroot
- }
- }
- }
- RustcCfgConfig::Rustc(sysroot) => sysroot,
- };
-
- let mut cmd = sysroot.tool(Tool::Rustc);
- cmd.envs(extra_env);
- cmd.args(["--print", "cfg", "-O"]);
- if let Some(target) = target {
- cmd.args(["--target", target]);
- }
-
- utf8_stdout(cmd).context("unable to fetch cfgs via `rustc --print cfg -O`")
-}
diff --git a/crates/project-model/src/sysroot.rs b/crates/project-model/src/sysroot.rs
index d8186a23f7..b0fdd3fa41 100644
--- a/crates/project-model/src/sysroot.rs
+++ b/crates/project-model/src/sysroot.rs
@@ -4,7 +4,7 @@
//! but we can't process `.rlib` and need source code instead. The source code
//! is typically installed with `rustup component add rust-src` command.
-use std::{env, fs, ops, process::Command};
+use std::{env, fs, ops, path::Path, process::Command};
use anyhow::{format_err, Result};
use base_db::CrateName;
@@ -170,7 +170,7 @@ impl Sysroot {
}
/// Returns a command to run a tool preferring the cargo proxies if the sysroot exists.
- pub fn tool(&self, tool: Tool) -> Command {
+ pub fn tool(&self, tool: Tool, current_dir: impl AsRef<Path>) -> Command {
match self.root() {
Some(root) => {
// special case rustc, we can look that up directly in the sysroot's bin folder
@@ -179,15 +179,15 @@ impl Sysroot {
if let Some(path) =
probe_for_binary(root.join("bin").join(Tool::Rustc.name()).into())
{
- return Command::new(path);
+ return toolchain::command(path, current_dir);
}
}
- let mut cmd = Command::new(tool.prefer_proxy());
+ let mut cmd = toolchain::command(tool.prefer_proxy(), current_dir);
cmd.env("RUSTUP_TOOLCHAIN", AsRef::<std::path::Path>::as_ref(root));
cmd
}
- _ => Command::new(tool.path()),
+ _ => toolchain::command(tool.path(), current_dir),
}
}
@@ -436,11 +436,11 @@ fn discover_sysroot_dir(
current_dir: &AbsPath,
extra_env: &FxHashMap<String, String>,
) -> Result<AbsPathBuf> {
- let mut rustc = Command::new(Tool::Rustc.path());
+ let mut rustc = toolchain::command(Tool::Rustc.path(), current_dir);
rustc.envs(extra_env);
rustc.current_dir(current_dir).args(["--print", "sysroot"]);
tracing::debug!("Discovering sysroot by {:?}", rustc);
- let stdout = utf8_stdout(rustc)?;
+ let stdout = utf8_stdout(&mut rustc)?;
Ok(AbsPathBuf::assert(Utf8PathBuf::from(stdout)))
}
@@ -468,11 +468,11 @@ fn discover_sysroot_src_dir_or_add_component(
) -> Result<AbsPathBuf> {
discover_sysroot_src_dir(sysroot_path)
.or_else(|| {
- let mut rustup = Command::new(Tool::Rustup.prefer_proxy());
+ let mut rustup = toolchain::command(Tool::Rustup.prefer_proxy(), current_dir);
rustup.envs(extra_env);
- rustup.current_dir(current_dir).args(["component", "add", "rust-src"]);
+ rustup.args(["component", "add", "rust-src"]);
tracing::info!("adding rust-src component by {:?}", rustup);
- utf8_stdout(rustup).ok()?;
+ utf8_stdout(&mut rustup).ok()?;
get_rust_src(sysroot_path)
})
.ok_or_else(|| {
diff --git a/crates/project-model/src/target_data_layout.rs b/crates/project-model/src/target_data_layout.rs
deleted file mode 100644
index 8a8a2d3255..0000000000
--- a/crates/project-model/src/target_data_layout.rs
+++ /dev/null
@@ -1,67 +0,0 @@
-//! Runs `rustc --print target-spec-json` to get the target_data_layout.
-
-use rustc_hash::FxHashMap;
-use toolchain::Tool;
-
-use crate::{utf8_stdout, ManifestPath, Sysroot};
-
-/// Determines how `rustc --print target-spec-json` is discovered and invoked.
-pub enum RustcDataLayoutConfig<'a> {
- /// Use `rustc --print target-spec-json`, either from with the binary from the sysroot or by discovering via
- /// [`toolchain::rustc`].
- Rustc(&'a Sysroot),
- /// Use `cargo --print target-spec-json`, either from with the binary from the sysroot or by discovering via
- /// [`toolchain::cargo`].
- Cargo(&'a Sysroot, &'a ManifestPath),
-}
-
-pub fn get(
- config: RustcDataLayoutConfig<'_>,
- target: Option<&str>,
- extra_env: &FxHashMap<String, String>,
-) -> anyhow::Result<String> {
- let process = |output: String| {
- (|| Some(output.split_once(r#""data-layout": ""#)?.1.split_once('"')?.0.to_owned()))()
- .ok_or_else(|| {
- anyhow::format_err!("could not fetch target-spec-json from command output")
- })
- };
- let sysroot = match config {
- RustcDataLayoutConfig::Cargo(sysroot, cargo_toml) => {
- let mut cmd = sysroot.tool(Tool::Cargo);
- cmd.envs(extra_env);
- cmd.current_dir(cargo_toml.parent())
- .args([
- "rustc",
- "-Z",
- "unstable-options",
- "--print",
- "target-spec-json",
- "--",
- "-Z",
- "unstable-options",
- ])
- .env("RUSTC_BOOTSTRAP", "1");
- if let Some(target) = target {
- cmd.args(["--target", target]);
- }
- match utf8_stdout(cmd) {
- Ok(output) => return process(output),
- Err(e) => {
- tracing::warn!("failed to run `cargo rustc --print target-spec-json`, falling back to invoking rustc directly: {e}");
- sysroot
- }
- }
- }
- RustcDataLayoutConfig::Rustc(sysroot) => sysroot,
- };
-
- let mut cmd = Sysroot::tool(sysroot, Tool::Rustc);
- cmd.envs(extra_env)
- .args(["-Z", "unstable-options", "--print", "target-spec-json"])
- .env("RUSTC_BOOTSTRAP", "1");
- if let Some(target) = target {
- cmd.args(["--target", target]);
- }
- process(utf8_stdout(cmd)?)
-}
diff --git a/crates/project-model/src/toolchain_info/rustc_cfg.rs b/crates/project-model/src/toolchain_info/rustc_cfg.rs
new file mode 100644
index 0000000000..12e674a6c4
--- /dev/null
+++ b/crates/project-model/src/toolchain_info/rustc_cfg.rs
@@ -0,0 +1,78 @@
+//! Get the built-in cfg flags for the to be compile platform.
+
+use anyhow::Context;
+use cfg::CfgAtom;
+use rustc_hash::FxHashMap;
+use toolchain::Tool;
+
+use crate::{toolchain_info::QueryConfig, utf8_stdout};
+
+/// Uses `rustc --print cfg` to fetch the builtin cfgs.
+pub fn get(
+ config: QueryConfig<'_>,
+ target: Option<&str>,
+ extra_env: &FxHashMap<String, String>,
+) -> Vec<CfgAtom> {
+ let _p = tracing::info_span!("rustc_cfg::get").entered();
+
+ let rustc_cfgs = rustc_print_cfg(target, extra_env, config);
+ let rustc_cfgs = match rustc_cfgs {
+ Ok(cfgs) => cfgs,
+ Err(e) => {
+ tracing::error!(?e, "failed to get rustc cfgs");
+ return vec![];
+ }
+ };
+
+ let rustc_cfgs = rustc_cfgs.lines().map(crate::parse_cfg).collect::<Result<Vec<_>, _>>();
+ match rustc_cfgs {
+ Ok(rustc_cfgs) => {
+ tracing::debug!(?rustc_cfgs, "rustc cfgs found");
+ rustc_cfgs
+ }
+ Err(e) => {
+ tracing::error!(?e, "failed to parse rustc cfgs");
+ vec![]
+ }
+ }
+}
+
+fn rustc_print_cfg(
+ target: Option<&str>,
+ extra_env: &FxHashMap<String, String>,
+ config: QueryConfig<'_>,
+) -> anyhow::Result<String> {
+ const RUSTC_ARGS: [&str; 3] = ["--print", "cfg", "-O"];
+ let (sysroot, current_dir) = match config {
+ QueryConfig::Cargo(sysroot, cargo_toml) => {
+ let mut cmd = sysroot.tool(Tool::Cargo, cargo_toml.parent());
+ cmd.envs(extra_env);
+ cmd.env("RUSTC_BOOTSTRAP", "1");
+ cmd.args(["rustc", "-Z", "unstable-options"]).args(RUSTC_ARGS);
+ if let Some(target) = target {
+ cmd.args(["--target", target]);
+ }
+
+ match utf8_stdout(&mut cmd) {
+ Ok(it) => return Ok(it),
+ Err(e) => {
+ tracing::warn!(
+ %e,
+ "failed to run `{cmd:?}`, falling back to invoking rustc directly"
+ );
+ (sysroot, cargo_toml.parent().as_ref())
+ }
+ }
+ }
+ QueryConfig::Rustc(sysroot, current_dir) => (sysroot, current_dir),
+ };
+
+ let mut cmd = sysroot.tool(Tool::Rustc, current_dir);
+ cmd.envs(extra_env);
+ cmd.args(RUSTC_ARGS);
+ if let Some(target) = target {
+ cmd.args(["--target", target]);
+ }
+
+ utf8_stdout(&mut cmd).with_context(|| format!("unable to fetch cfgs via `{cmd:?}`"))
+}
diff --git a/crates/project-model/src/toolchain_info/target_data_layout.rs b/crates/project-model/src/toolchain_info/target_data_layout.rs
new file mode 100644
index 0000000000..9986c66131
--- /dev/null
+++ b/crates/project-model/src/toolchain_info/target_data_layout.rs
@@ -0,0 +1,57 @@
+//! Runs `rustc --print target-spec-json` to get the target_data_layout.
+
+use anyhow::Context;
+use rustc_hash::FxHashMap;
+use toolchain::Tool;
+
+use crate::{toolchain_info::QueryConfig, utf8_stdout, Sysroot};
+
+/// Uses `rustc --print target-spec-json`.
+pub fn get(
+ config: QueryConfig<'_>,
+ target: Option<&str>,
+ extra_env: &FxHashMap<String, String>,
+) -> anyhow::Result<String> {
+ const RUSTC_ARGS: [&str; 2] = ["--print", "target-spec-json"];
+ let process = |output: String| {
+ (|| Some(output.split_once(r#""data-layout": ""#)?.1.split_once('"')?.0.to_owned()))()
+ .ok_or_else(|| {
+ anyhow::format_err!("could not parse target-spec-json from command output")
+ })
+ };
+ let (sysroot, current_dir) = match config {
+ QueryConfig::Cargo(sysroot, cargo_toml) => {
+ let mut cmd = sysroot.tool(Tool::Cargo, cargo_toml.parent());
+ cmd.envs(extra_env);
+ cmd.env("RUSTC_BOOTSTRAP", "1");
+ cmd.args(["rustc", "-Z", "unstable-options"]).args(RUSTC_ARGS).args([
+ "--",
+ "-Z",
+ "unstable-options",
+ ]);
+ if let Some(target) = target {
+ cmd.args(["--target", target]);
+ }
+ match utf8_stdout(&mut cmd) {
+ Ok(output) => return process(output),
+ Err(e) => {
+ tracing::warn!(%e, "failed to run `{cmd:?}`, falling back to invoking rustc directly");
+ (sysroot, cargo_toml.parent().as_ref())
+ }
+ }
+ }
+ QueryConfig::Rustc(sysroot, current_dir) => (sysroot, current_dir),
+ };
+
+ let mut cmd = Sysroot::tool(sysroot, Tool::Rustc, current_dir);
+ cmd.envs(extra_env)
+ .env("RUSTC_BOOTSTRAP", "1")
+ .args(["-Z", "unstable-options"])
+ .args(RUSTC_ARGS);
+ if let Some(target) = target {
+ cmd.args(["--target", target]);
+ }
+ utf8_stdout(&mut cmd)
+ .with_context(|| format!("unable to fetch target-data-layout via `{cmd:?}`"))
+ .and_then(process)
+}
diff --git a/crates/project-model/src/target_triple.rs b/crates/project-model/src/toolchain_info/target_triple.rs
index 4a32212097..163884e5e8 100644
--- a/crates/project-model/src/target_triple.rs
+++ b/crates/project-model/src/toolchain_info/target_triple.rs
@@ -1,46 +1,46 @@
-//! Runs `rustc --print -vV` to get the host target.
+//! Functionality to discover the current build target(s).
+use std::path::Path;
+
use anyhow::Context;
use rustc_hash::FxHashMap;
use toolchain::Tool;
-use crate::{utf8_stdout, ManifestPath, Sysroot};
-
-pub(super) enum TargetTipleConfig<'a> {
- #[expect(dead_code)]
- Rustc(&'a Sysroot),
- Cargo(&'a Sysroot, &'a ManifestPath),
-}
+use crate::{toolchain_info::QueryConfig, utf8_stdout, ManifestPath, Sysroot};
-pub(super) fn get(
- config: TargetTipleConfig<'_>,
+/// For cargo, runs `cargo -Zunstable-options config get build.target` to get the configured project target(s).
+/// For rustc, runs `rustc --print -vV` to get the host target.
+pub fn get(
+ config: QueryConfig<'_>,
target: Option<&str>,
extra_env: &FxHashMap<String, String>,
) -> anyhow::Result<Vec<String>> {
+ let _p = tracing::info_span!("target_triple::get").entered();
if let Some(target) = target {
return Ok(vec![target.to_owned()]);
}
- let sysroot = match config {
- TargetTipleConfig::Cargo(sysroot, cargo_toml) => {
+ let (sysroot, current_dir) = match config {
+ QueryConfig::Cargo(sysroot, cargo_toml) => {
match cargo_config_build_target(cargo_toml, extra_env, sysroot) {
Some(it) => return Ok(it),
- None => sysroot,
+ None => (sysroot, cargo_toml.parent().as_ref()),
}
}
- TargetTipleConfig::Rustc(sysroot) => sysroot,
+ QueryConfig::Rustc(sysroot, current_dir) => (sysroot, current_dir),
};
- rustc_discover_host_triple(extra_env, sysroot).map(|it| vec![it])
+ rustc_discover_host_triple(extra_env, sysroot, current_dir).map(|it| vec![it])
}
fn rustc_discover_host_triple(
extra_env: &FxHashMap<String, String>,
sysroot: &Sysroot,
+ current_dir: &Path,
) -> anyhow::Result<String> {
- let mut rustc = sysroot.tool(Tool::Rustc);
- rustc.envs(extra_env);
- rustc.arg("-vV");
- tracing::debug!("Discovering host platform by {:?}", rustc);
- let stdout = utf8_stdout(rustc).context("Failed to discover host platform")?;
+ let mut cmd = sysroot.tool(Tool::Rustc, current_dir);
+ cmd.envs(extra_env);
+ cmd.arg("-vV");
+ let stdout = utf8_stdout(&mut cmd)
+ .with_context(|| format!("unable to discover host platform via `{cmd:?}`"))?;
let field = "host: ";
let target = stdout.lines().find_map(|l| l.strip_prefix(field));
if let Some(target) = target {
@@ -56,20 +56,18 @@ fn cargo_config_build_target(
extra_env: &FxHashMap<String, String>,
sysroot: &Sysroot,
) -> Option<Vec<String>> {
- let mut cargo_config = sysroot.tool(Tool::Cargo);
- cargo_config.envs(extra_env);
- cargo_config
- .current_dir(cargo_toml.parent())
- .args(["-Z", "unstable-options", "config", "get", "build.target"])
- .env("RUSTC_BOOTSTRAP", "1");
+ let mut cmd = sysroot.tool(Tool::Cargo, cargo_toml.parent());
+ cmd.envs(extra_env);
+ cmd.current_dir(cargo_toml.parent()).env("RUSTC_BOOTSTRAP", "1");
+ cmd.args(["-Z", "unstable-options", "config", "get", "build.target"]);
// if successful we receive `build.target = "target-triple"`
// or `build.target = ["<target 1>", ..]`
- tracing::debug!("Discovering cargo config target by {:?}", cargo_config);
// this might be `error: config value `build.target` is not set` in which case we
// don't wanna log the error
- utf8_stdout(cargo_config).and_then(parse_output_cargo_config_build_target).ok()
+ utf8_stdout(&mut cmd).and_then(parse_output_cargo_config_build_target).ok()
}
+// Parses `"build.target = [target-triple, target-triple, ...]"` or `"build.target = "target-triple"`
fn parse_output_cargo_config_build_target(stdout: String) -> anyhow::Result<Vec<String>> {
let trimmed = stdout.trim_start_matches("build.target = ").trim_matches('"');
diff --git a/crates/project-model/src/workspace.rs b/crates/project-model/src/workspace.rs
index d747a8086b..233f94203e 100644
--- a/crates/project-model/src/workspace.rs
+++ b/crates/project-model/src/workspace.rs
@@ -25,10 +25,8 @@ use crate::{
cargo_workspace::{CargoMetadataConfig, DepKind, PackageData, RustLibSource},
env::{cargo_config_env, inject_cargo_env, inject_cargo_package_env, inject_rustc_tool_env},
project_json::{Crate, CrateArrayIdx},
- rustc_cfg::{self, RustcCfgConfig},
sysroot::{SysrootCrate, SysrootMode},
- target_data_layout::{self, RustcDataLayoutConfig},
- target_triple::{self, TargetTipleConfig},
+ toolchain_info::{rustc_cfg, target_data_layout, target_triple, QueryConfig},
utf8_stdout, CargoConfig, CargoWorkspace, CfgOverrides, InvocationStrategy, ManifestPath,
Package, ProjectJson, ProjectManifest, Sysroot, TargetData, TargetKind, WorkspaceBuildScripts,
};
@@ -177,10 +175,10 @@ fn get_toolchain_version(
extra_env: &FxHashMap<String, String>,
prefix: &str,
) -> Result<Option<Version>, anyhow::Error> {
- let cargo_version = utf8_stdout({
- let mut cmd = Sysroot::tool(sysroot, tool);
+ let cargo_version = utf8_stdout(&mut {
+ let mut cmd = Sysroot::tool(sysroot, tool, current_dir);
cmd.envs(extra_env);
- cmd.arg("--version").current_dir(current_dir);
+ cmd.arg("--version");
cmd
})
.with_context(|| format!("Failed to query rust toolchain version at {current_dir}, is your toolchain setup correctly?"))?;
@@ -221,155 +219,152 @@ impl ProjectWorkspace {
ProjectWorkspace::load_detached_file(rust_file, config)?
}
ProjectManifest::CargoToml(cargo_toml) => {
- // FIXME: Split sysroot discovery from sysroot loading, as to load the sysroot we
- // want to pass the analysis target, but to discover the target we need to know the
- // sysroot location so we know which cargo to use
- let sysroot = match (&config.sysroot, &config.sysroot_src) {
- (Some(RustLibSource::Discover), None) => Sysroot::discover(
- cargo_toml.parent(),
- &config.extra_env,
- &config.sysroot_query_metadata,
- ),
- (Some(RustLibSource::Discover), Some(sysroot_src)) => {
- Sysroot::discover_with_src_override(
- cargo_toml.parent(),
- &config.extra_env,
- sysroot_src.clone(),
- &config.sysroot_query_metadata,
- )
- }
- (Some(RustLibSource::Path(path)), None) => Sysroot::discover_sysroot_src_dir(
- path.clone(),
- &config.sysroot_query_metadata,
- ),
- (Some(RustLibSource::Path(sysroot)), Some(sysroot_src)) => Sysroot::load(
- Some(sysroot.clone()),
- Some(sysroot_src.clone()),
- &config.sysroot_query_metadata,
- ),
- (None, _) => Sysroot::empty(),
- };
- tracing::info!(workspace = %cargo_toml, src_root = ?sysroot.src_root(), root = ?sysroot.root(), "Using sysroot");
-
- let rustc_dir = match &config.rustc_source {
- Some(RustLibSource::Path(path)) => ManifestPath::try_from(path.clone())
- .map_err(|p| Some(format!("rustc source path is not absolute: {p}"))),
- Some(RustLibSource::Discover) => {
- sysroot.discover_rustc_src().ok_or_else(|| {
- Some("Failed to discover rustc source for sysroot.".to_owned())
- })
- }
- None => Err(None),
- };
- let targets = target_triple::get(
- TargetTipleConfig::Cargo(&sysroot, cargo_toml),
- config.target.as_deref(),
+ ProjectWorkspace::load_cargo(cargo_toml, config, progress)?
+ }
+ };
+
+ Ok(res)
+ }
+
+ fn load_cargo(
+ cargo_toml: &ManifestPath,
+ config: &CargoConfig,
+ progress: &dyn Fn(String),
+ ) -> Result<ProjectWorkspace, anyhow::Error> {
+ // FIXME: Split sysroot discovery from sysroot loading, as to load the sysroot we
+ // want to pass the analysis target, but to discover the target we need to know the
+ // sysroot location so we know which cargo to use
+ let sysroot = match (&config.sysroot, &config.sysroot_src) {
+ (Some(RustLibSource::Discover), None) => Sysroot::discover(
+ cargo_toml.parent(),
+ &config.extra_env,
+ &config.sysroot_query_metadata,
+ ),
+ (Some(RustLibSource::Discover), Some(sysroot_src)) => {
+ Sysroot::discover_with_src_override(
+ cargo_toml.parent(),
&config.extra_env,
+ sysroot_src.clone(),
+ &config.sysroot_query_metadata,
)
- .unwrap_or_default();
- let rustc = rustc_dir.and_then(|rustc_dir| {
- info!(workspace = %cargo_toml, rustc_dir = %rustc_dir, "Using rustc source");
- match CargoWorkspace::fetch_metadata(
- &rustc_dir,
+ }
+ (Some(RustLibSource::Path(path)), None) => {
+ Sysroot::discover_sysroot_src_dir(path.clone(), &config.sysroot_query_metadata)
+ }
+ (Some(RustLibSource::Path(sysroot)), Some(sysroot_src)) => Sysroot::load(
+ Some(sysroot.clone()),
+ Some(sysroot_src.clone()),
+ &config.sysroot_query_metadata,
+ ),
+ (None, _) => Sysroot::empty(),
+ };
+ tracing::info!(workspace = %cargo_toml, src_root = ?sysroot.src_root(), root = ?sysroot.root(), "Using sysroot");
+ let rustc_dir = match &config.rustc_source {
+ Some(RustLibSource::Path(path)) => ManifestPath::try_from(path.clone())
+ .map_err(|p| Some(format!("rustc source path is not absolute: {p}"))),
+ Some(RustLibSource::Discover) => sysroot
+ .discover_rustc_src()
+ .ok_or_else(|| Some("Failed to discover rustc source for sysroot.".to_owned())),
+ None => Err(None),
+ };
+ let targets = target_triple::get(
+ QueryConfig::Cargo(&sysroot, cargo_toml),
+ config.target.as_deref(),
+ &config.extra_env,
+ )
+ .unwrap_or_default();
+ let rustc = rustc_dir.and_then(|rustc_dir| {
+ info!(workspace = %cargo_toml, rustc_dir = %rustc_dir, "Using rustc source");
+ match CargoWorkspace::fetch_metadata(
+ &rustc_dir,
+ cargo_toml.parent(),
+ &CargoMetadataConfig {
+ features: crate::CargoFeatures::default(),
+ targets: targets.clone(),
+ extra_args: config.extra_args.clone(),
+ extra_env: config.extra_env.clone(),
+ },
+ &sysroot,
+ false,
+ progress,
+ ) {
+ Ok((meta, _error)) => {
+ let workspace = CargoWorkspace::new(meta, cargo_toml.clone());
+ let buildscripts = WorkspaceBuildScripts::rustc_crates(
+ &workspace,
cargo_toml.parent(),
- &CargoMetadataConfig {
- features: crate::CargoFeatures::default(),
- targets: targets.clone(),
- extra_args: config.extra_args.clone(),
- extra_env: config.extra_env.clone(),
- },
+ &config.extra_env,
&sysroot,
- false,
- progress,
- ) {
- Ok((meta, _error)) => {
- let workspace = CargoWorkspace::new(meta, cargo_toml.clone());
- let buildscripts = WorkspaceBuildScripts::rustc_crates(
- &workspace,
- cargo_toml.parent(),
- &config.extra_env,
- &sysroot
- );
- Ok(Box::new((workspace, buildscripts)))
- }
- Err(e) => {
- tracing::error!(
- %e,
- "Failed to read Cargo metadata from rustc source at {rustc_dir}",
- );
- Err(Some(format!(
- "Failed to read Cargo metadata from rustc source at {rustc_dir}: {e}"
- )))
- }
- }
- });
-
- let toolchain = get_toolchain_version(
- cargo_toml.parent(),
- &sysroot,
- Tool::Cargo,
- &config.extra_env,
- "cargo ",
- )?;
- let rustc_cfg = rustc_cfg::get(
- targets.first().map(Deref::deref),
- &config.extra_env,
- RustcCfgConfig::Cargo(&sysroot, cargo_toml),
- );
-
- let cfg_overrides = config.cfg_overrides.clone();
- let data_layout = target_data_layout::get(
- RustcDataLayoutConfig::Cargo(&sysroot, cargo_toml),
- targets.first().map(Deref::deref),
- &config.extra_env,
- );
- if let Err(e) = &data_layout {
- tracing::error!(%e, "failed fetching data layout for {cargo_toml:?} workspace");
+ );
+ Ok(Box::new((workspace, buildscripts)))
}
-
- let (meta, error) = CargoWorkspace::fetch_metadata(
- cargo_toml,
- cargo_toml.parent(),
- &CargoMetadataConfig {
- features: config.features.clone(),
- targets,
- extra_args: config.extra_args.clone(),
- extra_env: config.extra_env.clone(),
- },
- &sysroot,
- false,
- progress,
- )
- .with_context(|| {
- format!(
- "Failed to read Cargo metadata from Cargo.toml file {cargo_toml}, {toolchain:?}",
- )
- })?;
- let cargo = CargoWorkspace::new(meta, cargo_toml.clone());
-
- let cargo_config_extra_env =
- cargo_config_env(cargo_toml, &config.extra_env, &sysroot);
- ProjectWorkspace {
- kind: ProjectWorkspaceKind::Cargo {
- cargo,
- build_scripts: WorkspaceBuildScripts::default(),
- rustc,
- cargo_config_extra_env,
- error: error.map(Arc::new),
- set_test: config.set_test,
- },
- sysroot,
- rustc_cfg,
- cfg_overrides,
- toolchain,
- target_layout: data_layout
- .map(Arc::from)
- .map_err(|it| Arc::from(it.to_string())),
+ Err(e) => {
+ tracing::error!(
+ %e,
+ "Failed to read Cargo metadata from rustc source at {rustc_dir}",
+ );
+ Err(Some(format!(
+ "Failed to read Cargo metadata from rustc source at {rustc_dir}: {e}"
+ )))
}
}
- };
-
- Ok(res)
+ });
+ let toolchain = get_toolchain_version(
+ cargo_toml.parent(),
+ &sysroot,
+ Tool::Cargo,
+ &config.extra_env,
+ "cargo ",
+ )?;
+ let rustc_cfg = rustc_cfg::get(
+ QueryConfig::Cargo(&sysroot, cargo_toml),
+ targets.first().map(Deref::deref),
+ &config.extra_env,
+ );
+ let cfg_overrides = config.cfg_overrides.clone();
+ let data_layout = target_data_layout::get(
+ QueryConfig::Cargo(&sysroot, cargo_toml),
+ targets.first().map(Deref::deref),
+ &config.extra_env,
+ );
+ if let Err(e) = &data_layout {
+ tracing::error!(%e, "failed fetching data layout for {cargo_toml:?} workspace");
+ }
+ let (meta, error) = CargoWorkspace::fetch_metadata(
+ cargo_toml,
+ cargo_toml.parent(),
+ &CargoMetadataConfig {
+ features: config.features.clone(),
+ targets,
+ extra_args: config.extra_args.clone(),
+ extra_env: config.extra_env.clone(),
+ },
+ &sysroot,
+ false,
+ progress,
+ )
+ .with_context(|| {
+ format!(
+ "Failed to read Cargo metadata from Cargo.toml file {cargo_toml}, {toolchain:?}",
+ )
+ })?;
+ let cargo = CargoWorkspace::new(meta, cargo_toml.clone());
+ let cargo_config_extra_env = cargo_config_env(cargo_toml, &config.extra_env, &sysroot);
+ Ok(ProjectWorkspace {
+ kind: ProjectWorkspaceKind::Cargo {
+ cargo,
+ build_scripts: WorkspaceBuildScripts::default(),
+ rustc,
+ cargo_config_extra_env,
+ error: error.map(Arc::new),
+ set_test: config.set_test,
+ },
+ sysroot,
+ rustc_cfg,
+ cfg_overrides,
+ toolchain,
+ target_layout: data_layout.map(Arc::from).map_err(|it| Arc::from(it.to_string())),
+ })
}
pub fn load_inline(project_json: ProjectJson, config: &CargoConfig) -> ProjectWorkspace {
@@ -378,8 +373,7 @@ impl ProjectWorkspace {
project_json.sysroot_src.clone(),
&config.sysroot_query_metadata,
);
- let cfg_config = RustcCfgConfig::Rustc(&sysroot);
- let data_layout_config = RustcDataLayoutConfig::Rustc(&sysroot);
+ let query_config = QueryConfig::Rustc(&sysroot, project_json.path().as_ref());
let toolchain = match get_toolchain_version(
project_json.path(),
&sysroot,
@@ -395,8 +389,8 @@ impl ProjectWorkspace {
};
let target = config.target.as_deref();
- let rustc_cfg = rustc_cfg::get(target, &config.extra_env, cfg_config);
- let data_layout = target_data_layout::get(data_layout_config, target, &config.extra_env);
+ let rustc_cfg = rustc_cfg::get(query_config, target, &config.extra_env);
+ let data_layout = target_data_layout::get(query_config, target, &config.extra_env);
ProjectWorkspace {
kind: ProjectWorkspaceKind::Json(project_json),
sysroot,
@@ -432,17 +426,14 @@ impl ProjectWorkspace {
};
let targets = target_triple::get(
- TargetTipleConfig::Cargo(&sysroot, detached_file),
+ QueryConfig::Cargo(&sysroot, detached_file),
config.target.as_deref(),
&config.extra_env,
)
.unwrap_or_default();
- let rustc_cfg = rustc_cfg::get(None, &config.extra_env, RustcCfgConfig::Rustc(&sysroot));
- let data_layout = target_data_layout::get(
- RustcDataLayoutConfig::Rustc(&sysroot),
- None,
- &config.extra_env,
- );
+ let query_config = QueryConfig::Rustc(&sysroot, dir.as_ref());
+ let rustc_cfg = rustc_cfg::get(query_config, None, &config.extra_env);
+ let data_layout = target_data_layout::get(query_config, None, &config.extra_env);
let cargo_script = CargoWorkspace::fetch_metadata(
detached_file,
@@ -954,7 +945,11 @@ fn project_json_to_crate_graph(
let target_cfgs = match target.as_deref() {
Some(target) => cfg_cache.entry(target).or_insert_with(|| {
- rustc_cfg::get(Some(target), extra_env, RustcCfgConfig::Rustc(sysroot))
+ rustc_cfg::get(
+ QueryConfig::Rustc(sysroot, project.project_root().as_ref()),
+ Some(target),
+ extra_env,
+ )
}),
None => &rustc_cfg,
};
diff --git a/crates/rust-analyzer/build.rs b/crates/rust-analyzer/build.rs
index 72b741de00..0fd381d612 100644
--- a/crates/rust-analyzer/build.rs
+++ b/crates/rust-analyzer/build.rs
@@ -32,6 +32,7 @@ fn set_rerun() {
}
fn set_commit_info() {
+ #[allow(clippy::disallowed_methods)]
let output = match Command::new("git")
.arg("log")
.arg("-1")
diff --git a/crates/rust-analyzer/src/bin/rustc_wrapper.rs b/crates/rust-analyzer/src/bin/rustc_wrapper.rs
index 684b3f52af..b9fcd2e187 100644
--- a/crates/rust-analyzer/src/bin/rustc_wrapper.rs
+++ b/crates/rust-analyzer/src/bin/rustc_wrapper.rs
@@ -46,6 +46,7 @@ fn run_rustc_skipping_cargo_checking(
}
fn run_rustc(rustc_executable: OsString, args: Vec<OsString>) -> io::Result<ExitCode> {
+ #[allow(clippy::disallowed_methods)]
let mut child = Command::new(rustc_executable)
.args(args)
.stdin(Stdio::inherit())
diff --git a/crates/rust-analyzer/src/cli/rustc_tests.rs b/crates/rust-analyzer/src/cli/rustc_tests.rs
index db792ade57..dabc71b1b9 100644
--- a/crates/rust-analyzer/src/cli/rustc_tests.rs
+++ b/crates/rust-analyzer/src/cli/rustc_tests.rs
@@ -10,10 +10,10 @@ use ide::{AnalysisHost, DiagnosticCode, DiagnosticsConfig};
use itertools::Either;
use paths::Utf8PathBuf;
use profile::StopWatch;
-use project_model::target_data_layout::RustcDataLayoutConfig;
+use project_model::toolchain_info::{target_data_layout, QueryConfig};
use project_model::{
- target_data_layout, CargoConfig, ManifestPath, ProjectWorkspace, ProjectWorkspaceKind,
- RustLibSource, Sysroot, SysrootQueryMetadata,
+ CargoConfig, ManifestPath, ProjectWorkspace, ProjectWorkspaceKind, RustLibSource, Sysroot,
+ SysrootQueryMetadata,
};
use load_cargo::{load_workspace, LoadCargoConfig, ProcMacroServerChoice};
@@ -80,7 +80,7 @@ impl Tester {
&SysrootQueryMetadata::CargoMetadata(Default::default()),
);
let data_layout = target_data_layout::get(
- RustcDataLayoutConfig::Rustc(&sysroot),
+ QueryConfig::Rustc(&sysroot, tmp_file.parent().unwrap().as_ref()),
None,
&cargo_config.extra_env,
);
diff --git a/crates/rust-analyzer/src/discover.rs b/crates/rust-analyzer/src/discover.rs
index 96b164228e..0c111319bb 100644
--- a/crates/rust-analyzer/src/discover.rs
+++ b/crates/rust-analyzer/src/discover.rs
@@ -1,6 +1,6 @@
//! Infrastructure for lazy project discovery. Currently only support rust-project.json discovery
//! via a custom discover command.
-use std::{io, process::Command};
+use std::{io, path::Path};
use crossbeam_channel::Sender;
use paths::{AbsPathBuf, Utf8Path, Utf8PathBuf};
@@ -43,7 +43,11 @@ impl DiscoverCommand {
}
/// Spawn the command inside [Discover] and report progress, if any.
- pub(crate) fn spawn(&self, discover_arg: DiscoverArgument) -> io::Result<DiscoverHandle> {
+ pub(crate) fn spawn(
+ &self,
+ discover_arg: DiscoverArgument,
+ current_dir: &Path,
+ ) -> io::Result<DiscoverHandle> {
let command = &self.command[0];
let args = &self.command[1..];
@@ -58,7 +62,7 @@ impl DiscoverCommand {
})
.collect();
- let mut cmd = Command::new(command);
+ let mut cmd = toolchain::command(command, current_dir);
cmd.args(args);
Ok(DiscoverHandle {
diff --git a/crates/rust-analyzer/src/flycheck.rs b/crates/rust-analyzer/src/flycheck.rs
index c7bb275c5f..16ed674406 100644
--- a/crates/rust-analyzer/src/flycheck.rs
+++ b/crates/rust-analyzer/src/flycheck.rs
@@ -444,12 +444,11 @@ impl FlycheckActor {
) -> Option<Command> {
match &self.config {
FlycheckConfig::CargoCommand { command, options, ansi_color_output } => {
- let mut cmd = Command::new(Tool::Cargo.path());
+ let mut cmd = toolchain::command(Tool::Cargo.path(), &*self.root);
if let Some(sysroot_root) = &self.sysroot_root {
cmd.env("RUSTUP_TOOLCHAIN", AsRef::<std::path::Path>::as_ref(sysroot_root));
}
cmd.arg(command);
- cmd.current_dir(&*self.root);
match package {
Some(pkg) => cmd.arg("-p").arg(pkg),
@@ -486,18 +485,15 @@ impl FlycheckActor {
Some(cmd)
}
FlycheckConfig::CustomCommand { command, args, extra_env, invocation_strategy } => {
- let mut cmd = Command::new(command);
- cmd.envs(extra_env);
-
- match invocation_strategy {
- InvocationStrategy::Once => {
- cmd.current_dir(&*self.root);
- }
+ let root = match invocation_strategy {
+ InvocationStrategy::Once => &*self.root,
InvocationStrategy::PerWorkspace => {
- // FIXME: cmd.current_dir(&affected_workspace);
- cmd.current_dir(&*self.root);
+ // FIXME: &affected_workspace
+ &*self.root
}
- }
+ };
+ let mut cmd = toolchain::command(command, root);
+ cmd.envs(extra_env);
// If the custom command has a $saved_file placeholder, and
// we're saving a file, replace the placeholder in the arguments.
diff --git a/crates/rust-analyzer/src/handlers/request.rs b/crates/rust-analyzer/src/handlers/request.rs
index 8f2bf80ea2..d2ed43e882 100644
--- a/crates/rust-analyzer/src/handlers/request.rs
+++ b/crates/rust-analyzer/src/handlers/request.rs
@@ -1,12 +1,7 @@
//! This module is responsible for implementing handlers for Language Server
//! Protocol. This module specifically handles requests.
-use std::{
- fs,
- io::Write as _,
- ops::Not,
- process::{self, Stdio},
-};
+use std::{fs, io::Write as _, ops::Not, process::Stdio};
use anyhow::Context;
@@ -2243,10 +2238,31 @@ fn run_rustfmt(
let line_index = snap.file_line_index(file_id)?;
let source_root_id = snap.analysis.source_root_id(file_id).ok();
+ // try to chdir to the file so we can respect `rustfmt.toml`
+ // FIXME: use `rustfmt --config-path` once
+ // https://github.com/rust-lang/rustfmt/issues/4660 gets fixed
+ let current_dir = match text_document.uri.to_file_path() {
+ Ok(mut path) => {
+ // pop off file name
+ if path.pop() && path.is_dir() {
+ path
+ } else {
+ std::env::current_dir()?
+ }
+ }
+ Err(_) => {
+ tracing::error!(
+ text_document = ?text_document.uri,
+ "Unable to get path, rustfmt.toml might be ignored"
+ );
+ std::env::current_dir()?
+ }
+ };
+
let mut command = match snap.config.rustfmt(source_root_id) {
RustfmtConfig::Rustfmt { extra_args, enable_range_formatting } => {
// FIXME: Set RUSTUP_TOOLCHAIN
- let mut cmd = process::Command::new(toolchain::Tool::Rustfmt.path());
+ let mut cmd = toolchain::command(toolchain::Tool::Rustfmt.path(), current_dir);
cmd.envs(snap.config.extra_env(source_root_id));
cmd.args(extra_args);
@@ -2300,9 +2316,9 @@ fn run_rustfmt(
} else {
cmd
};
- process::Command::new(cmd_path)
+ toolchain::command(cmd_path, current_dir)
}
- _ => process::Command::new(cmd),
+ _ => toolchain::command(cmd, current_dir),
};
cmd.envs(snap.config.extra_env(source_root_id));
@@ -2313,24 +2329,6 @@ fn run_rustfmt(
tracing::debug!(?command, "created format command");
- // try to chdir to the file so we can respect `rustfmt.toml`
- // FIXME: use `rustfmt --config-path` once
- // https://github.com/rust-lang/rustfmt/issues/4660 gets fixed
- match text_document.uri.to_file_path() {
- Ok(mut path) => {
- // pop off file name
- if path.pop() && path.is_dir() {
- command.current_dir(path);
- }
- }
- Err(_) => {
- tracing::error!(
- text_document = ?text_document.uri,
- "Unable to get path, rustfmt.toml might be ignored"
- );
- }
- }
-
let mut rustfmt = command
.stdin(Stdio::piped())
.stdout(Stdio::piped())
diff --git a/crates/rust-analyzer/src/main_loop.rs b/crates/rust-analyzer/src/main_loop.rs
index d97d96d54a..97657b9265 100644
--- a/crates/rust-analyzer/src/main_loop.rs
+++ b/crates/rust-analyzer/src/main_loop.rs
@@ -744,7 +744,8 @@ impl GlobalState {
DiscoverProjectParam::Path(it) => DiscoverArgument::Path(it),
};
- let handle = discover.spawn(arg).unwrap();
+ let handle =
+ discover.spawn(arg, &std::env::current_dir().unwrap()).unwrap();
self.discover_handle = Some(handle);
}
}
diff --git a/crates/rust-analyzer/src/test_runner.rs b/crates/rust-analyzer/src/test_runner.rs
index 2fd5254733..503b3ee43a 100644
--- a/crates/rust-analyzer/src/test_runner.rs
+++ b/crates/rust-analyzer/src/test_runner.rs
@@ -1,8 +1,6 @@
//! This module provides the functionality needed to run `cargo test` in a background
//! thread and report the result of each test in a channel.
-use std::process::Command;
-
use crossbeam_channel::Sender;
use paths::AbsPath;
use serde::Deserialize as _;
@@ -78,7 +76,7 @@ impl CargoTestHandle {
test_target: TestTarget,
sender: Sender<CargoTestMessage>,
) -> std::io::Result<Self> {
- let mut cmd = Command::new(Tool::Cargo.path());
+ let mut cmd = toolchain::command(Tool::Cargo.path(), root);
cmd.env("RUSTC_BOOTSTRAP", "1");
cmd.arg("test");
diff --git a/crates/toolchain/src/lib.rs b/crates/toolchain/src/lib.rs
index a0603e35a0..33578e056e 100644
--- a/crates/toolchain/src/lib.rs
+++ b/crates/toolchain/src/lib.rs
@@ -1,6 +1,12 @@
//! Discovery of `cargo` & `rustc` executables.
-use std::{env, iter, path::PathBuf};
+use std::{
+ env,
+ ffi::OsStr,
+ iter,
+ path::{Path, PathBuf},
+ process::Command,
+};
use camino::{Utf8Path, Utf8PathBuf};
@@ -65,6 +71,14 @@ impl Tool {
}
}
+pub fn command(cmd: impl AsRef<OsStr>, working_directory: impl AsRef<Path>) -> Command {
+ // we are `toolchain::command``
+ #[allow(clippy::disallowed_methods)]
+ let mut cmd = Command::new(cmd);
+ cmd.current_dir(working_directory);
+ cmd
+}
+
fn invoke(list: &[fn(&str) -> Option<Utf8PathBuf>], executable: &str) -> Utf8PathBuf {
list.iter().find_map(|it| it(executable)).unwrap_or_else(|| executable.into())
}
diff --git a/xtask/src/main.rs b/xtask/src/main.rs
index 5c312da1dd..1e723b90a5 100644
--- a/xtask/src/main.rs
+++ b/xtask/src/main.rs
@@ -9,7 +9,12 @@
//! `.cargo/config`.
#![warn(rust_2018_idioms, unused_lifetimes)]
-#![allow(clippy::print_stderr, clippy::print_stdout)]
+#![allow(
+ clippy::print_stderr,
+ clippy::print_stdout,
+ clippy::disallowed_methods,
+ clippy::disallowed_types
+)]
mod flags;