about summary refs log tree commit diff
diff options
context:
space:
mode:
authorLukas Wirth <lukastw97@gmail.com>2024-12-29 12:25:51 +0100
committerLukas Wirth <lukastw97@gmail.com>2024-12-29 12:25:51 +0100
commitd5f7e78f69d9cbb8f4477b1004e433913a475ef0 (patch)
tree72eae0e7c96b0114101a86fa49470d9167a1b863
parent47f497d6365f28bf165cef24bcb728c7f3b4ab36 (diff)
downloadrust-d5f7e78f69d9cbb8f4477b1004e433913a475ef0.tar.gz
rust-d5f7e78f69d9cbb8f4477b1004e433913a475ef0.zip
Cleanup toolchain info fetching
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/layout/tests.rs6
-rw-r--r--src/tools/rust-analyzer/crates/project-model/src/build_dependencies.rs4
-rw-r--r--src/tools/rust-analyzer/crates/project-model/src/env.rs2
-rw-r--r--src/tools/rust-analyzer/crates/project-model/src/lib.rs9
-rw-r--r--src/tools/rust-analyzer/crates/project-model/src/rustc_cfg.rs99
-rw-r--r--src/tools/rust-analyzer/crates/project-model/src/sysroot.rs4
-rw-r--r--src/tools/rust-analyzer/crates/project-model/src/target_data_layout.rs67
-rw-r--r--src/tools/rust-analyzer/crates/project-model/src/toolchain_info.rs13
-rw-r--r--src/tools/rust-analyzer/crates/project-model/src/toolchain_info/rustc_cfg.rs78
-rw-r--r--src/tools/rust-analyzer/crates/project-model/src/toolchain_info/target_data_layout.rs57
-rw-r--r--src/tools/rust-analyzer/crates/project-model/src/toolchain_info/target_triple.rs (renamed from src/tools/rust-analyzer/crates/project-model/src/target_triple.rs)44
-rw-r--r--src/tools/rust-analyzer/crates/project-model/src/workspace.rs31
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/src/cli/rustc_tests.rs13
13 files changed, 197 insertions, 230 deletions
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/layout/tests.rs b/src/tools/rust-analyzer/crates/hir-ty/src/layout/tests.rs
index f40d508f755..78f2c16517d 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/layout/tests.rs
+++ b/src/tools/rust-analyzer/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()),
         None,
         &FxHashMap::default(),
     )
diff --git a/src/tools/rust-analyzer/crates/project-model/src/build_dependencies.rs b/src/tools/rust-analyzer/crates/project-model/src/build_dependencies.rs
index 524323b9736..65348622a4a 100644
--- a/src/tools/rust-analyzer/crates/project-model/src/build_dependencies.rs
+++ b/src/tools/rust-analyzer/crates/project-model/src/build_dependencies.rs
@@ -178,13 +178,13 @@ impl WorkspaceBuildScripts {
                     .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);
                 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))
diff --git a/src/tools/rust-analyzer/crates/project-model/src/env.rs b/src/tools/rust-analyzer/crates/project-model/src/env.rs
index ff9d2035f60..a3ff51e6087 100644
--- a/src/tools/rust-analyzer/crates/project-model/src/env.rs
+++ b/src/tools/rust-analyzer/crates/project-model/src/env.rs
@@ -85,7 +85,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/src/tools/rust-analyzer/crates/project-model/src/lib.rs b/src/tools/rust-analyzer/crates/project-model/src/lib.rs
index 9a024f6b962..2dd9c54e0c7 100644
--- a/src/tools/rust-analyzer/crates/project-model/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/project-model/src/lib.rs
@@ -15,15 +15,14 @@
 //!   procedural macros).
 //! * Lowering of concrete model to a [`base_db::CrateGraph`]
 
+pub mod project_json;
+pub mod toolchain_info;
+
 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 +181,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/src/tools/rust-analyzer/crates/project-model/src/rustc_cfg.rs b/src/tools/rust-analyzer/crates/project-model/src/rustc_cfg.rs
deleted file mode 100644
index bc1f0e6fbf2..00000000000
--- a/src/tools/rust-analyzer/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/src/tools/rust-analyzer/crates/project-model/src/sysroot.rs b/src/tools/rust-analyzer/crates/project-model/src/sysroot.rs
index d8186a23f76..ffe6c06fa58 100644
--- a/src/tools/rust-analyzer/crates/project-model/src/sysroot.rs
+++ b/src/tools/rust-analyzer/crates/project-model/src/sysroot.rs
@@ -440,7 +440,7 @@ fn discover_sysroot_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)))
 }
 
@@ -472,7 +472,7 @@ fn discover_sysroot_src_dir_or_add_component(
             rustup.envs(extra_env);
             rustup.current_dir(current_dir).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/src/tools/rust-analyzer/crates/project-model/src/target_data_layout.rs b/src/tools/rust-analyzer/crates/project-model/src/target_data_layout.rs
deleted file mode 100644
index 8a8a2d32558..00000000000
--- a/src/tools/rust-analyzer/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/src/tools/rust-analyzer/crates/project-model/src/toolchain_info.rs b/src/tools/rust-analyzer/crates/project-model/src/toolchain_info.rs
new file mode 100644
index 00000000000..ad6f3fae8e6
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/project-model/src/toolchain_info.rs
@@ -0,0 +1,13 @@
+pub mod rustc_cfg;
+pub mod target_data_layout;
+pub mod target_triple;
+
+use crate::{ManifestPath, Sysroot};
+
+pub enum QueryConfig<'a> {
+    /// Directly invoke `rustc` to query the desired information.
+    Rustc(&'a Sysroot),
+    /// 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),
+}
diff --git a/src/tools/rust-analyzer/crates/project-model/src/toolchain_info/rustc_cfg.rs b/src/tools/rust-analyzer/crates/project-model/src/toolchain_info/rustc_cfg.rs
new file mode 100644
index 00000000000..82cb73bc357
--- /dev/null
+++ b/src/tools/rust-analyzer/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 = match config {
+        QueryConfig::Cargo(sysroot, cargo_toml) => {
+            let mut cmd = sysroot.tool(Tool::Cargo);
+            cmd.envs(extra_env);
+            cmd.current_dir(cargo_toml.parent()).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
+                }
+            }
+        }
+        QueryConfig::Rustc(sysroot) => sysroot,
+    };
+
+    let mut cmd = sysroot.tool(Tool::Rustc);
+    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/src/tools/rust-analyzer/crates/project-model/src/toolchain_info/target_data_layout.rs b/src/tools/rust-analyzer/crates/project-model/src/toolchain_info/target_data_layout.rs
new file mode 100644
index 00000000000..65e96f060ad
--- /dev/null
+++ b/src/tools/rust-analyzer/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 = match config {
+        QueryConfig::Cargo(sysroot, cargo_toml) => {
+            let mut cmd = sysroot.tool(Tool::Cargo);
+            cmd.envs(extra_env);
+            cmd.current_dir(cargo_toml.parent()).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
+                }
+            }
+        }
+        QueryConfig::Rustc(sysroot) => sysroot,
+    };
+
+    let mut cmd = Sysroot::tool(sysroot, Tool::Rustc);
+    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/src/tools/rust-analyzer/crates/project-model/src/target_triple.rs b/src/tools/rust-analyzer/crates/project-model/src/toolchain_info/target_triple.rs
index 4a32212097d..1c36e3863a8 100644
--- a/src/tools/rust-analyzer/crates/project-model/src/target_triple.rs
+++ b/src/tools/rust-analyzer/crates/project-model/src/toolchain_info/target_triple.rs
@@ -1,33 +1,29 @@
-//! Runs `rustc --print -vV` to get the host target.
 use anyhow::Context;
 use rustc_hash::FxHashMap;
 use toolchain::Tool;
 
-use crate::{utf8_stdout, ManifestPath, Sysroot};
+use crate::{toolchain_info::QueryConfig, utf8_stdout, ManifestPath, Sysroot};
 
-pub(super) enum TargetTipleConfig<'a> {
-    #[expect(dead_code)]
-    Rustc(&'a Sysroot),
-    Cargo(&'a Sysroot, &'a ManifestPath),
-}
-
-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) => {
+        QueryConfig::Cargo(sysroot, cargo_toml) => {
             match cargo_config_build_target(cargo_toml, extra_env, sysroot) {
                 Some(it) => return Ok(it),
                 None => sysroot,
             }
         }
-        TargetTipleConfig::Rustc(sysroot) => sysroot,
+        QueryConfig::Rustc(sysroot) => sysroot,
     };
     rustc_discover_host_triple(extra_env, sysroot).map(|it| vec![it])
 }
@@ -36,11 +32,11 @@ fn rustc_discover_host_triple(
     extra_env: &FxHashMap<String, String>,
     sysroot: &Sysroot,
 ) -> 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);
+    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 +52,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);
+    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/src/tools/rust-analyzer/crates/project-model/src/workspace.rs b/src/tools/rust-analyzer/crates/project-model/src/workspace.rs
index d747a8086b4..05721b3af1d 100644
--- a/src/tools/rust-analyzer/crates/project-model/src/workspace.rs
+++ b/src/tools/rust-analyzer/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,7 +175,7 @@ fn get_toolchain_version(
     extra_env: &FxHashMap<String, String>,
     prefix: &str,
 ) -> Result<Option<Version>, anyhow::Error> {
-    let cargo_version = utf8_stdout({
+    let cargo_version = utf8_stdout(&mut {
         let mut cmd = Sysroot::tool(sysroot, tool);
         cmd.envs(extra_env);
         cmd.arg("--version").current_dir(current_dir);
@@ -262,7 +260,7 @@ impl ProjectWorkspace {
                     None => Err(None),
                 };
                 let targets = target_triple::get(
-                    TargetTipleConfig::Cargo(&sysroot, cargo_toml),
+                    QueryConfig::Cargo(&sysroot, cargo_toml),
                     config.target.as_deref(),
                     &config.extra_env,
                 )
@@ -312,14 +310,14 @@ impl ProjectWorkspace {
                     "cargo ",
                 )?;
                 let rustc_cfg = rustc_cfg::get(
+                    QueryConfig::Cargo(&sysroot, cargo_toml),
                     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),
+                    QueryConfig::Cargo(&sysroot, cargo_toml),
                     targets.first().map(Deref::deref),
                     &config.extra_env,
                 );
@@ -378,8 +376,8 @@ 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 cfg_config = QueryConfig::Rustc(&sysroot);
+        let data_layout_config = QueryConfig::Rustc(&sysroot);
         let toolchain = match get_toolchain_version(
             project_json.path(),
             &sysroot,
@@ -395,7 +393,7 @@ impl ProjectWorkspace {
         };
 
         let target = config.target.as_deref();
-        let rustc_cfg = rustc_cfg::get(target, &config.extra_env, cfg_config);
+        let rustc_cfg = rustc_cfg::get(cfg_config, target, &config.extra_env);
         let data_layout = target_data_layout::get(data_layout_config, target, &config.extra_env);
         ProjectWorkspace {
             kind: ProjectWorkspaceKind::Json(project_json),
@@ -432,17 +430,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 rustc_cfg = rustc_cfg::get(QueryConfig::Rustc(&sysroot), None, &config.extra_env);
+        let data_layout =
+            target_data_layout::get(QueryConfig::Rustc(&sysroot), None, &config.extra_env);
 
         let cargo_script = CargoWorkspace::fetch_metadata(
             detached_file,
@@ -954,7 +949,7 @@ 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), Some(target), extra_env)
                     }),
                     None => &rustc_cfg,
                 };
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/rustc_tests.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/rustc_tests.rs
index db792ade574..4da916080ca 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/rustc_tests.rs
+++ b/src/tools/rust-analyzer/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};
@@ -79,11 +79,8 @@ impl Tester {
             &cargo_config.extra_env,
             &SysrootQueryMetadata::CargoMetadata(Default::default()),
         );
-        let data_layout = target_data_layout::get(
-            RustcDataLayoutConfig::Rustc(&sysroot),
-            None,
-            &cargo_config.extra_env,
-        );
+        let data_layout =
+            target_data_layout::get(QueryConfig::Rustc(&sysroot), None, &cargo_config.extra_env);
 
         let workspace = ProjectWorkspace {
             kind: ProjectWorkspaceKind::DetachedFile {