Unnamed repository; edit this file 'description' to name the repository.
Diffstat (limited to 'crates/project-model/src/cargo_workspace.rs')
-rw-r--r--crates/project-model/src/cargo_workspace.rs57
1 files changed, 53 insertions, 4 deletions
diff --git a/crates/project-model/src/cargo_workspace.rs b/crates/project-model/src/cargo_workspace.rs
index e613fd590c..adc0cc5094 100644
--- a/crates/project-model/src/cargo_workspace.rs
+++ b/crates/project-model/src/cargo_workspace.rs
@@ -5,7 +5,7 @@ use std::str::from_utf8;
use anyhow::Context;
use base_db::Env;
-use cargo_metadata::{CargoOpt, MetadataCommand};
+use cargo_metadata::{CargoOpt, MetadataCommand, PackageId};
use la_arena::{Arena, Idx};
use paths::{AbsPath, AbsPathBuf, Utf8Path, Utf8PathBuf};
use rustc_hash::{FxHashMap, FxHashSet};
@@ -14,6 +14,7 @@ use serde_json::from_value;
use span::Edition;
use stdx::process::spawn_with_streaming_output;
use toolchain::Tool;
+use triomphe::Arc;
use crate::cargo_config_file::make_lockfile_copy;
use crate::{CfgOverrides, InvocationStrategy};
@@ -155,8 +156,8 @@ pub struct PackageData {
pub features: FxHashMap<String, Vec<String>>,
/// List of features enabled on this package
pub active_features: Vec<String>,
- /// String representation of package id
- pub id: String,
+ /// Package id
+ pub id: Arc<PackageId>,
/// Authors as given in the `Cargo.toml`
pub authors: Vec<String>,
/// Description as given in the `Cargo.toml`
@@ -173,6 +174,10 @@ pub struct PackageData {
pub rust_version: Option<semver::Version>,
/// The contents of [package.metadata.rust-analyzer]
pub metadata: RustAnalyzerPackageMetaData,
+ /// If this package is a member of the workspace, store all direct and transitive
+ /// dependencies as long as they are workspace members, to track dependency relationships
+ /// between members.
+ pub all_member_deps: Option<FxHashSet<Package>>,
}
#[derive(Deserialize, Default, Debug, Clone, Eq, PartialEq)]
@@ -334,6 +339,8 @@ impl CargoWorkspace {
let mut is_virtual_workspace = true;
let mut requires_rustc_private = false;
+ let mut members = FxHashSet::default();
+
meta.packages.sort_by(|a, b| a.id.cmp(&b.id));
for meta_pkg in meta.packages {
let cargo_metadata::Package {
@@ -356,6 +363,7 @@ impl CargoWorkspace {
rust_version,
..
} = meta_pkg;
+ let id = Arc::new(id);
let meta = from_value::<PackageMetadata>(metadata).unwrap_or_default();
let edition = match edition {
cargo_metadata::Edition::E2015 => Edition::Edition2015,
@@ -375,7 +383,7 @@ impl CargoWorkspace {
let manifest = ManifestPath::try_from(AbsPathBuf::assert(manifest_path)).unwrap();
is_virtual_workspace &= manifest != ws_manifest_path;
let pkg = packages.alloc(PackageData {
- id: id.repr.clone(),
+ id: id.clone(),
name: name.to_string(),
version,
manifest: manifest.clone(),
@@ -395,7 +403,11 @@ impl CargoWorkspace {
features: features.into_iter().collect(),
active_features: Vec::new(),
metadata: meta.rust_analyzer.unwrap_or_default(),
+ all_member_deps: None,
});
+ if is_member {
+ members.insert(pkg);
+ }
let pkg_data = &mut packages[pkg];
requires_rustc_private |= pkg_data.metadata.rustc_private;
pkg_by_id.insert(id, pkg);
@@ -440,6 +452,43 @@ impl CargoWorkspace {
.extend(node.features.into_iter().map(|it| it.to_string()));
}
+ fn saturate_all_member_deps(
+ packages: &mut Arena<PackageData>,
+ to_visit: Package,
+ visited: &mut FxHashSet<Package>,
+ members: &FxHashSet<Package>,
+ ) {
+ let pkg_data = &mut packages[to_visit];
+
+ if !visited.insert(to_visit) {
+ return;
+ }
+
+ let deps: Vec<_> = pkg_data
+ .dependencies
+ .iter()
+ .filter_map(|dep| {
+ let pkg = dep.pkg;
+ if members.contains(&pkg) { Some(pkg) } else { None }
+ })
+ .collect();
+
+ let mut all_member_deps = FxHashSet::from_iter(deps.iter().copied());
+ for dep in deps {
+ saturate_all_member_deps(packages, dep, visited, members);
+ if let Some(transitives) = &packages[dep].all_member_deps {
+ all_member_deps.extend(transitives);
+ }
+ }
+
+ packages[to_visit].all_member_deps = Some(all_member_deps);
+ }
+
+ let mut visited = FxHashSet::default();
+ for member in members.iter() {
+ saturate_all_member_deps(&mut packages, *member, &mut visited, &members);
+ }
+
CargoWorkspace {
packages,
targets,