Unnamed repository; edit this file 'description' to name the repository.
Diffstat (limited to 'crates/project-model/src/workspace.rs')
-rw-r--r--crates/project-model/src/workspace.rs143
1 files changed, 38 insertions, 105 deletions
diff --git a/crates/project-model/src/workspace.rs b/crates/project-model/src/workspace.rs
index 6a063905ca..0baf90e54e 100644
--- a/crates/project-model/src/workspace.rs
+++ b/crates/project-model/src/workspace.rs
@@ -2,7 +2,7 @@
//! metadata` or `rust-project.json`) into representation stored in the salsa
//! database -- `CrateGraph`.
-use std::{collections::VecDeque, fmt, fs, iter, str::FromStr, sync};
+use std::{collections::VecDeque, fmt, fs, iter, sync};
use anyhow::{format_err, Context};
use base_db::{
@@ -21,7 +21,8 @@ use triomphe::Arc;
use crate::{
build_scripts::BuildScriptOutput,
cargo_workspace::{DepKind, PackageData, RustLibSource},
- cfg_flag::CfgFlag,
+ cfg::{CfgFlag, CfgOverrides},
+ 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},
@@ -30,29 +31,7 @@ use crate::{
ProjectJson, ProjectManifest, Sysroot, TargetData, TargetKind, WorkspaceBuildScripts,
};
-/// A set of cfg-overrides per crate.
-#[derive(Default, Debug, Clone, Eq, PartialEq)]
-pub struct CfgOverrides {
- /// A global set of overrides matching all crates.
- pub global: CfgDiff,
- /// A set of overrides matching specific crates.
- pub selective: FxHashMap<String, CfgDiff>,
-}
-
-impl CfgOverrides {
- pub fn len(&self) -> usize {
- self.global.len() + self.selective.values().map(|it| it.len()).sum::<usize>()
- }
-
- fn apply(&self, cfg_options: &mut CfgOptions, name: &str) {
- if !self.global.is_empty() {
- cfg_options.apply_diff(self.global.clone());
- };
- if let Some(diff) = self.selective.get(name) {
- cfg_options.apply_diff(diff.clone());
- };
- }
-}
+pub type FileLoader<'a> = &'a mut dyn for<'b> FnMut(&'b AbsPath) -> Option<FileId>;
/// `PackageRoot` describes a package root folder.
/// Which may be an external dependency, or a member of
@@ -69,29 +48,43 @@ pub struct PackageRoot {
pub enum ProjectWorkspace {
/// Project workspace was discovered by running `cargo metadata` and `rustc --print sysroot`.
Cargo {
+ /// The workspace as returned by `cargo metadata`.
cargo: CargoWorkspace,
+ /// The build script results for the workspace.
build_scripts: WorkspaceBuildScripts,
+ /// The sysroot loaded for this workspace.
sysroot: Result<Sysroot, Option<String>>,
+ /// The rustc workspace loaded for this workspace. An `Err(None)` means loading has been
+ /// disabled or was otherwise not requested.
rustc: Result<Box<(CargoWorkspace, WorkspaceBuildScripts)>, Option<String>>,
/// Holds cfg flags for the current target. We get those by running
/// `rustc --print cfg`.
- ///
- /// FIXME: make this a per-crate map, as, eg, build.rs might have a
- /// different target.
+ // FIXME: make this a per-crate map, as, eg, build.rs might have a
+ // different target.
rustc_cfg: Vec<CfgFlag>,
+ /// A set of cfg overrides for this workspace.
cfg_overrides: CfgOverrides,
+ /// The toolchain version used by this workspace.
toolchain: Option<Version>,
+ /// The target data layout queried for workspace.
target_layout: TargetLayoutLoadResult,
+ /// Environment variables set in the `.cargo/config` file.
cargo_config_extra_env: FxHashMap<String, String>,
},
/// Project workspace was manually specified using a `rust-project.json` file.
Json {
+ /// The loaded project json file.
project: ProjectJson,
+ /// The sysroot loaded for this workspace.
sysroot: Result<Sysroot, Option<String>>,
/// Holds cfg flags for the current target. We get those by running
/// `rustc --print cfg`.
+ // FIXME: make this a per-crate map, as, eg, build.rs might have a
+ // different target.
rustc_cfg: Vec<CfgFlag>,
+ /// The toolchain version used by this workspace.
toolchain: Option<Version>,
+ /// The target data layout queried for workspace.
target_layout: TargetLayoutLoadResult,
},
// FIXME: The primary limitation of this approach is that the set of detached files needs to be fixed at the beginning.
@@ -105,12 +98,18 @@ pub enum ProjectWorkspace {
/// Project with a set of disjoint files, not belonging to any particular workspace.
/// Backed by basic sysroot crates for basic completion and highlighting.
DetachedFiles {
+ /// The set of detached files.
files: Vec<AbsPathBuf>,
+ /// The sysroot loaded for this workspace.
sysroot: Result<Sysroot, Option<String>>,
/// Holds cfg flags for the current target. We get those by running
/// `rustc --print cfg`.
+ // FIXME: make this a per-crate map, as, eg, build.rs might have a
+ // different target.
rustc_cfg: Vec<CfgFlag>,
+ /// The toolchain version used by this workspace.
toolchain: Option<Version>,
+ /// The target data layout queried for workspace.
target_layout: TargetLayoutLoadResult,
},
}
@@ -723,7 +722,7 @@ impl ProjectWorkspace {
pub fn to_crate_graph(
&self,
- load: &mut dyn FnMut(&AbsPath) -> Option<FileId>,
+ load: FileLoader<'_>,
extra_env: &FxHashMap<String, String>,
) -> (CrateGraph, ProcMacroPaths) {
let _p = tracing::span!(tracing::Level::INFO, "ProjectWorkspace::to_crate_graph").entered();
@@ -874,7 +873,7 @@ impl ProjectWorkspace {
fn project_json_to_crate_graph(
rustc_cfg: Vec<CfgFlag>,
- load: &mut dyn FnMut(&AbsPath) -> Option<FileId>,
+ load: FileLoader<'_>,
project: &ProjectJson,
sysroot: Option<&Sysroot>,
extra_env: &FxHashMap<String, String>,
@@ -976,7 +975,7 @@ fn project_json_to_crate_graph(
}
fn cargo_to_crate_graph(
- load: &mut dyn FnMut(&AbsPath) -> Option<FileId>,
+ load: FileLoader<'_>,
rustc: Option<&(CargoWorkspace, WorkspaceBuildScripts)>,
cargo: &CargoWorkspace,
sysroot: Option<&Sysroot>,
@@ -1166,7 +1165,7 @@ fn cargo_to_crate_graph(
fn detached_files_to_crate_graph(
rustc_cfg: Vec<CfgFlag>,
- load: &mut dyn FnMut(&AbsPath) -> Option<FileId>,
+ load: FileLoader<'_>,
detached_files: &[AbsPathBuf],
sysroot: Option<&Sysroot>,
) -> (CrateGraph, ProcMacroPaths) {
@@ -1216,7 +1215,7 @@ fn handle_rustc_crates(
crate_graph: &mut CrateGraph,
proc_macros: &mut ProcMacroPaths,
pkg_to_lib_crate: &mut FxHashMap<Package, CrateId>,
- load: &mut dyn FnMut(&AbsPath) -> Option<FileId>,
+ load: FileLoader<'_>,
rustc_workspace: &CargoWorkspace,
cargo: &CargoWorkspace,
public_deps: &SysrootPublicDeps,
@@ -1350,23 +1349,19 @@ fn add_target_crate_root(
};
let mut env = Env::default();
- inject_cargo_env(pkg, &mut env);
- if let Ok(cname) = String::from_str(cargo_name) {
- // CARGO_CRATE_NAME is the name of the Cargo target with - converted to _, such as the name of the library, binary, example, integration test, or benchmark.
- env.set("CARGO_CRATE_NAME", cname.replace('-', "_"));
- }
+ inject_cargo_package_env(&mut env, pkg);
+ inject_cargo_env(&mut env);
+ inject_rustc_tool_env(&mut env, cargo_name, kind);
if let Some(envs) = build_data.map(|it| &it.envs) {
for (k, v) in envs {
env.set(k, v.clone());
}
}
-
- let display_name = CrateDisplayName::from_canonical_name(cargo_name.to_owned());
let crate_id = crate_graph.add_crate_root(
file_id,
edition,
- Some(display_name),
+ Some(CrateDisplayName::from_canonical_name(cargo_name.to_owned())),
Some(pkg.version.to_string()),
Arc::new(cfg_options),
potential_cfg_options.map(Arc::new),
@@ -1405,7 +1400,7 @@ fn sysroot_to_crate_graph(
crate_graph: &mut CrateGraph,
sysroot: &Sysroot,
rustc_cfg: Vec<CfgFlag>,
- load: &mut dyn FnMut(&AbsPath) -> Option<FileId>,
+ load: FileLoader<'_>,
) -> (SysrootPublicDeps, Option<CrateId>) {
let _p = tracing::span!(tracing::Level::INFO, "sysroot_to_crate_graph").entered();
match sysroot.mode() {
@@ -1480,7 +1475,6 @@ fn sysroot_to_crate_graph(
.filter_map(|krate| {
let file_id = load(&stitched[krate].root)?;
- let env = Env::default();
let display_name =
CrateDisplayName::from_canonical_name(stitched[krate].name.clone());
let crate_id = crate_graph.add_crate_root(
@@ -1490,7 +1484,7 @@ fn sysroot_to_crate_graph(
None,
cfg_options.clone(),
None,
- env,
+ Env::default(),
false,
CrateOrigin::Lang(LangCrateOrigin::from(&*stitched[krate].name)),
);
@@ -1549,70 +1543,9 @@ fn add_dep_inner(graph: &mut CrateGraph, from: CrateId, dep: Dependency) {
}
}
-/// Recreates the compile-time environment variables that Cargo sets.
-///
-/// Should be synced with
-/// <https://doc.rust-lang.org/cargo/reference/environment-variables.html#environment-variables-cargo-sets-for-crates>
-///
-/// FIXME: ask Cargo to provide this data instead of re-deriving.
-fn inject_cargo_env(package: &PackageData, env: &mut Env) {
- // FIXME: Missing variables:
- // CARGO_BIN_NAME, CARGO_BIN_EXE_<name>
-
- let manifest_dir = package.manifest.parent();
- env.set("CARGO_MANIFEST_DIR", manifest_dir.as_str().to_owned());
-
- // Not always right, but works for common cases.
- env.set("CARGO", "cargo".into());
-
- env.set("CARGO_PKG_VERSION", package.version.to_string());
- env.set("CARGO_PKG_VERSION_MAJOR", package.version.major.to_string());
- env.set("CARGO_PKG_VERSION_MINOR", package.version.minor.to_string());
- env.set("CARGO_PKG_VERSION_PATCH", package.version.patch.to_string());
- env.set("CARGO_PKG_VERSION_PRE", package.version.pre.to_string());
-
- env.set("CARGO_PKG_AUTHORS", String::new());
-
- env.set("CARGO_PKG_NAME", package.name.clone());
- // FIXME: This isn't really correct (a package can have many crates with different names), but
- // it's better than leaving the variable unset.
- env.set("CARGO_CRATE_NAME", CrateName::normalize_dashes(&package.name).to_string());
- env.set("CARGO_PKG_DESCRIPTION", String::new());
- env.set("CARGO_PKG_HOMEPAGE", String::new());
- env.set("CARGO_PKG_REPOSITORY", String::new());
- env.set("CARGO_PKG_LICENSE", String::new());
-
- env.set("CARGO_PKG_LICENSE_FILE", String::new());
-}
-
fn create_cfg_options(rustc_cfg: Vec<CfgFlag>) -> CfgOptions {
let mut cfg_options = CfgOptions::default();
cfg_options.extend(rustc_cfg);
cfg_options.insert_atom("debug_assertions".into());
cfg_options
}
-
-fn cargo_config_env(
- cargo_toml: &ManifestPath,
- extra_env: &FxHashMap<String, String>,
- sysroot: Option<&Sysroot>,
-) -> FxHashMap<String, String> {
- let mut cargo_config = Sysroot::tool(sysroot, Tool::Cargo);
- cargo_config.envs(extra_env);
- cargo_config
- .current_dir(cargo_toml.parent())
- .args(["-Z", "unstable-options", "config", "get", "env"])
- .env("RUSTC_BOOTSTRAP", "1");
- // if successful we receive `env.key.value = "value" per entry
- tracing::debug!("Discovering cargo config env by {:?}", cargo_config);
- utf8_stdout(cargo_config).map(parse_output_cargo_config_env).unwrap_or_default()
-}
-
-fn parse_output_cargo_config_env(stdout: String) -> FxHashMap<String, String> {
- stdout
- .lines()
- .filter_map(|l| l.strip_prefix("env."))
- .filter_map(|l| l.split_once(".value = "))
- .map(|(key, value)| (key.to_owned(), value.trim_matches('"').to_owned()))
- .collect()
-}