Unnamed repository; edit this file 'description' to name the repository.
Auto merge of #15754 - alibektas:15656/linked_projects_are_local_too, r=Veykril
fix: Dedup duplicate crates with differing origins in CrateGraph construction Partially fixes #15656 . Until now the condition for deduplication in crate graphs were the strict equality of two crates. One problem that arises from this is that in certain conditions when we see the same crate having different `CrateOrigin`s the first occurrence would be kept. This approach however results in some unwanted results such as making renaming forbidden as this has been recently only made available for local crates. The given example in #15656 can still not be resolved with this PR as that involves taking inconsistencies between dependencies into consideration. This will be addressed in a future PR.
bors 2023-11-23
parent 7ceefc7 · parent ba1b080 · commit cccc7ca
-rw-r--r--crates/base-db/src/fixture.rs28
-rw-r--r--crates/base-db/src/input.rs189
-rw-r--r--crates/base-db/src/lib.rs1
-rw-r--r--crates/cfg/src/lib.rs7
-rw-r--r--crates/project-model/src/project_json.rs3
-rw-r--r--crates/project-model/src/tests.rs52
-rw-r--r--crates/project-model/src/workspace.rs67
-rw-r--r--crates/project-model/test_data/deduplication_crate_graph_A.json140
-rw-r--r--crates/project-model/test_data/deduplication_crate_graph_B.json66
-rw-r--r--crates/project-model/test_data/output/cargo_hello_world_project_model.txt7
-rw-r--r--crates/project-model/test_data/output/cargo_hello_world_project_model_with_selective_overrides.txt7
-rw-r--r--crates/project-model/test_data/output/cargo_hello_world_project_model_with_wildcard_overrides.txt7
-rw-r--r--crates/project-model/test_data/output/rust_project_hello_world_project_model.txt16
13 files changed, 542 insertions, 48 deletions
diff --git a/crates/base-db/src/fixture.rs b/crates/base-db/src/fixture.rs
index 3f5ccb621c..3da555a47a 100644
--- a/crates/base-db/src/fixture.rs
+++ b/crates/base-db/src/fixture.rs
@@ -13,9 +13,9 @@ use vfs::{file_set::FileSet, VfsPath};
use crate::{
input::{CrateName, CrateOrigin, LangCrateOrigin},
- Change, CrateDisplayName, CrateGraph, CrateId, Dependency, Edition, Env, FileId, FilePosition,
- FileRange, ProcMacro, ProcMacroExpander, ProcMacroExpansionError, ProcMacros, ReleaseChannel,
- SourceDatabaseExt, SourceRoot, SourceRootId,
+ Change, CrateDisplayName, CrateGraph, CrateId, Dependency, DependencyKind, Edition, Env,
+ FileId, FilePosition, FileRange, ProcMacro, ProcMacroExpander, ProcMacroExpansionError,
+ ProcMacros, ReleaseChannel, SourceDatabaseExt, SourceRoot, SourceRootId,
};
pub const WORKSPACE: SourceRootId = SourceRootId(0);
@@ -237,7 +237,12 @@ impl ChangeFixture {
crate_graph
.add_dep(
from_id,
- Dependency::with_prelude(CrateName::new(&to).unwrap(), to_id, prelude),
+ Dependency::with_prelude(
+ CrateName::new(&to).unwrap(),
+ to_id,
+ prelude,
+ DependencyKind::Normal,
+ ),
)
.unwrap();
}
@@ -275,7 +280,14 @@ impl ChangeFixture {
for krate in all_crates {
crate_graph
- .add_dep(krate, Dependency::new(CrateName::new("core").unwrap(), core_crate))
+ .add_dep(
+ krate,
+ Dependency::new(
+ CrateName::new("core").unwrap(),
+ core_crate,
+ DependencyKind::Normal,
+ ),
+ )
.unwrap();
}
}
@@ -317,7 +329,11 @@ impl ChangeFixture {
crate_graph
.add_dep(
krate,
- Dependency::new(CrateName::new("proc_macros").unwrap(), proc_macros_crate),
+ Dependency::new(
+ CrateName::new("proc_macros").unwrap(),
+ proc_macros_crate,
+ DependencyKind::Normal,
+ ),
)
.unwrap();
}
diff --git a/crates/base-db/src/input.rs b/crates/base-db/src/input.rs
index 65db5c0fc7..e4f78321e2 100644
--- a/crates/base-db/src/input.rs
+++ b/crates/base-db/src/input.rs
@@ -155,6 +155,10 @@ impl CrateOrigin {
pub fn is_local(&self) -> bool {
matches!(self, CrateOrigin::Local { .. })
}
+
+ pub fn is_lib(&self) -> bool {
+ matches!(self, CrateOrigin::Library { .. })
+ }
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
@@ -324,6 +328,62 @@ pub struct CrateData {
pub channel: Option<ReleaseChannel>,
}
+impl CrateData {
+ /// Check if [`other`] is almost equal to [`self`] ignoring `CrateOrigin` value.
+ pub fn eq_ignoring_origin_and_deps(&self, other: &CrateData, ignore_dev_deps: bool) -> bool {
+ // This method has some obscure bits. These are mostly there to be compliant with
+ // some patches. References to the patches are given.
+ if self.root_file_id != other.root_file_id {
+ return false;
+ }
+
+ if self.display_name != other.display_name {
+ return false;
+ }
+
+ if self.is_proc_macro != other.is_proc_macro {
+ return false;
+ }
+
+ if self.edition != other.edition {
+ return false;
+ }
+
+ if self.version != other.version {
+ return false;
+ }
+
+ let mut opts = self.cfg_options.difference(&other.cfg_options);
+ if let Some(it) = opts.next() {
+ // Don't care if rust_analyzer CfgAtom is the only cfg in the difference set of self's and other's cfgs.
+ // https://github.com/rust-lang/rust-analyzer/blob/0840038f02daec6ba3238f05d8caa037d28701a0/crates/project-model/src/workspace.rs#L894
+ if it.to_string() != "rust_analyzer" {
+ return false;
+ }
+
+ if let Some(_) = opts.next() {
+ return false;
+ }
+ }
+
+ if self.env != other.env {
+ return false;
+ }
+
+ let slf_deps = self.dependencies.iter();
+ let other_deps = other.dependencies.iter();
+
+ if ignore_dev_deps {
+ return slf_deps
+ .clone()
+ .filter(|it| it.kind != DependencyKind::Dev)
+ .eq(other_deps.clone().filter(|it| it.kind != DependencyKind::Dev));
+ }
+
+ slf_deps.eq(other_deps)
+ }
+}
+
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub enum Edition {
Edition2015,
@@ -351,26 +411,43 @@ impl Env {
}
}
+#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
+pub enum DependencyKind {
+ Normal,
+ Dev,
+ Build,
+}
+
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct Dependency {
pub crate_id: CrateId,
pub name: CrateName,
+ kind: DependencyKind,
prelude: bool,
}
impl Dependency {
- pub fn new(name: CrateName, crate_id: CrateId) -> Self {
- Self { name, crate_id, prelude: true }
+ pub fn new(name: CrateName, crate_id: CrateId, kind: DependencyKind) -> Self {
+ Self { name, crate_id, prelude: true, kind }
}
- pub fn with_prelude(name: CrateName, crate_id: CrateId, prelude: bool) -> Self {
- Self { name, crate_id, prelude }
+ pub fn with_prelude(
+ name: CrateName,
+ crate_id: CrateId,
+ prelude: bool,
+ kind: DependencyKind,
+ ) -> Self {
+ Self { name, crate_id, prelude, kind }
}
/// Whether this dependency is to be added to the depending crate's extern prelude.
pub fn is_prelude(&self) -> bool {
self.prelude
}
+
+ pub fn kind(&self) -> DependencyKind {
+ self.kind
+ }
}
impl CrateGraph {
@@ -574,23 +651,46 @@ impl CrateGraph {
pub fn extend(&mut self, mut other: CrateGraph, proc_macros: &mut ProcMacroPaths) {
let topo = other.crates_in_topological_order();
let mut id_map: FxHashMap<CrateId, CrateId> = FxHashMap::default();
-
for topo in topo {
let crate_data = &mut other.arena[topo];
+
crate_data.dependencies.iter_mut().for_each(|dep| dep.crate_id = id_map[&dep.crate_id]);
crate_data.dependencies.sort_by_key(|dep| dep.crate_id);
-
- let res = self.arena.iter().find_map(
- |(id, data)| {
- if data == crate_data {
- Some(id)
- } else {
- None
+ let res = self.arena.iter().find_map(|(id, data)| {
+ match (&data.origin, &crate_data.origin) {
+ (a, b) if a == b => {
+ if data.eq_ignoring_origin_and_deps(&crate_data, false) {
+ return Some((id, false));
+ }
+ }
+ (a @ CrateOrigin::Local { .. }, CrateOrigin::Library { .. })
+ | (a @ CrateOrigin::Library { .. }, CrateOrigin::Local { .. }) => {
+ // If the origins differ, check if the two crates are equal without
+ // considering the dev dependencies, if they are, they most likely are in
+ // different loaded workspaces which may cause issues. We keep the local
+ // version and discard the library one as the local version may have
+ // dev-dependencies that we want to keep resolving. See #15656 for more
+ // information.
+ if data.eq_ignoring_origin_and_deps(&crate_data, true) {
+ return Some((id, if a.is_local() { false } else { true }));
+ }
}
- },
- );
- if let Some(res) = res {
+ (_, _) => return None,
+ }
+
+ None
+ });
+
+ if let Some((res, should_update_lib_to_local)) = res {
id_map.insert(topo, res);
+ if should_update_lib_to_local {
+ assert!(self.arena[res].origin.is_lib());
+ assert!(crate_data.origin.is_local());
+ self.arena[res].origin = crate_data.origin.clone();
+
+ // Move local's dev dependencies into the newly-local-formerly-lib crate.
+ self.arena[res].dependencies = crate_data.dependencies.clone();
+ }
} else {
let id = self.arena.alloc(crate_data.clone());
id_map.insert(topo, id);
@@ -636,9 +736,11 @@ impl CrateGraph {
match (cfg_if, std) {
(Some(cfg_if), Some(std)) => {
self.arena[cfg_if].dependencies.clear();
- self.arena[std]
- .dependencies
- .push(Dependency::new(CrateName::new("cfg_if").unwrap(), cfg_if));
+ self.arena[std].dependencies.push(Dependency::new(
+ CrateName::new("cfg_if").unwrap(),
+ cfg_if,
+ DependencyKind::Normal,
+ ));
true
}
_ => false,
@@ -658,6 +760,8 @@ impl ops::Index<CrateId> for CrateGraph {
}
impl CrateData {
+ /// Add a dependency to `self` without checking if the dependency
+ // is existent among `self.dependencies`.
fn add_dep(&mut self, dep: Dependency) {
self.dependencies.push(dep)
}
@@ -759,7 +863,7 @@ impl fmt::Display for CyclicDependenciesError {
#[cfg(test)]
mod tests {
- use crate::CrateOrigin;
+ use crate::{CrateOrigin, DependencyKind};
use super::{CrateGraph, CrateName, Dependency, Edition::Edition2018, Env, FileId};
@@ -806,13 +910,22 @@ mod tests {
None,
);
assert!(graph
- .add_dep(crate1, Dependency::new(CrateName::new("crate2").unwrap(), crate2))
+ .add_dep(
+ crate1,
+ Dependency::new(CrateName::new("crate2").unwrap(), crate2, DependencyKind::Normal)
+ )
.is_ok());
assert!(graph
- .add_dep(crate2, Dependency::new(CrateName::new("crate3").unwrap(), crate3))
+ .add_dep(
+ crate2,
+ Dependency::new(CrateName::new("crate3").unwrap(), crate3, DependencyKind::Normal)
+ )
.is_ok());
assert!(graph
- .add_dep(crate3, Dependency::new(CrateName::new("crate1").unwrap(), crate1))
+ .add_dep(
+ crate3,
+ Dependency::new(CrateName::new("crate1").unwrap(), crate1, DependencyKind::Normal)
+ )
.is_err());
}
@@ -846,10 +959,16 @@ mod tests {
None,
);
assert!(graph
- .add_dep(crate1, Dependency::new(CrateName::new("crate2").unwrap(), crate2))
+ .add_dep(
+ crate1,
+ Dependency::new(CrateName::new("crate2").unwrap(), crate2, DependencyKind::Normal)
+ )
.is_ok());
assert!(graph
- .add_dep(crate2, Dependency::new(CrateName::new("crate2").unwrap(), crate2))
+ .add_dep(
+ crate2,
+ Dependency::new(CrateName::new("crate2").unwrap(), crate2, DependencyKind::Normal)
+ )
.is_err());
}
@@ -896,10 +1015,16 @@ mod tests {
None,
);
assert!(graph
- .add_dep(crate1, Dependency::new(CrateName::new("crate2").unwrap(), crate2))
+ .add_dep(
+ crate1,
+ Dependency::new(CrateName::new("crate2").unwrap(), crate2, DependencyKind::Normal)
+ )
.is_ok());
assert!(graph
- .add_dep(crate2, Dependency::new(CrateName::new("crate3").unwrap(), crate3))
+ .add_dep(
+ crate2,
+ Dependency::new(CrateName::new("crate3").unwrap(), crate3, DependencyKind::Normal)
+ )
.is_ok());
}
@@ -935,12 +1060,20 @@ mod tests {
assert!(graph
.add_dep(
crate1,
- Dependency::new(CrateName::normalize_dashes("crate-name-with-dashes"), crate2)
+ Dependency::new(
+ CrateName::normalize_dashes("crate-name-with-dashes"),
+ crate2,
+ DependencyKind::Normal
+ )
)
.is_ok());
assert_eq!(
graph[crate1].dependencies,
- vec![Dependency::new(CrateName::new("crate_name_with_dashes").unwrap(), crate2)]
+ vec![Dependency::new(
+ CrateName::new("crate_name_with_dashes").unwrap(),
+ crate2,
+ DependencyKind::Normal
+ )]
);
}
}
diff --git a/crates/base-db/src/lib.rs b/crates/base-db/src/lib.rs
index c5c4afa30f..40cfab88af 100644
--- a/crates/base-db/src/lib.rs
+++ b/crates/base-db/src/lib.rs
@@ -12,6 +12,7 @@ use rustc_hash::FxHashSet;
use syntax::{ast, Parse, SourceFile, TextRange, TextSize};
use triomphe::Arc;
+pub use crate::input::DependencyKind;
pub use crate::{
change::Change,
input::{
diff --git a/crates/cfg/src/lib.rs b/crates/cfg/src/lib.rs
index 0aeb0b0505..8bbe5e2a8c 100644
--- a/crates/cfg/src/lib.rs
+++ b/crates/cfg/src/lib.rs
@@ -58,6 +58,13 @@ impl CfgOptions {
self.enabled.insert(CfgAtom::KeyValue { key, value });
}
+ pub fn difference<'a>(
+ &'a self,
+ other: &'a CfgOptions,
+ ) -> impl Iterator<Item = &'a CfgAtom> + 'a {
+ self.enabled.difference(&other.enabled)
+ }
+
pub fn apply_diff(&mut self, diff: CfgDiff) {
for atom in diff.enable {
self.enabled.insert(atom);
diff --git a/crates/project-model/src/project_json.rs b/crates/project-model/src/project_json.rs
index 80897f7478..931eba1157 100644
--- a/crates/project-model/src/project_json.rs
+++ b/crates/project-model/src/project_json.rs
@@ -49,7 +49,7 @@
//! user explores them belongs to that extension (it's totally valid to change
//! rust-project.json over time via configuration request!)
-use base_db::{CrateDisplayName, CrateId, CrateName, Dependency, Edition};
+use base_db::{CrateDisplayName, CrateId, CrateName, Dependency, DependencyKind, Edition};
use la_arena::RawIdx;
use paths::{AbsPath, AbsPathBuf};
use rustc_hash::FxHashMap;
@@ -135,6 +135,7 @@ impl ProjectJson {
Dependency::new(
dep_data.name,
CrateId::from_raw(RawIdx::from(dep_data.krate as u32)),
+ DependencyKind::Normal,
)
})
.collect::<Vec<_>>(),
diff --git a/crates/project-model/src/tests.rs b/crates/project-model/src/tests.rs
index 7815b9dda7..98f3063bb9 100644
--- a/crates/project-model/src/tests.rs
+++ b/crates/project-model/src/tests.rs
@@ -249,3 +249,55 @@ fn crate_graph_dedup() {
crate_graph.extend(regex_crate_graph, &mut regex_proc_macros);
assert_eq!(crate_graph.iter().count(), 118);
}
+
+#[test]
+fn test_deduplicate_origin_dev() {
+ let path_map = &mut Default::default();
+ let (mut crate_graph, _proc_macros) =
+ load_cargo_with_sysroot(path_map, "deduplication_crate_graph_A.json");
+ crate_graph.sort_deps();
+ let (crate_graph_1, mut _proc_macros_2) =
+ load_cargo_with_sysroot(path_map, "deduplication_crate_graph_B.json");
+
+ crate_graph.extend(crate_graph_1, &mut _proc_macros_2);
+
+ let mut crates_named_p2 = vec![];
+ for id in crate_graph.iter() {
+ let krate = &crate_graph[id];
+ if let Some(name) = krate.display_name.as_ref() {
+ if name.to_string() == "p2" {
+ crates_named_p2.push(krate);
+ }
+ }
+ }
+
+ assert!(crates_named_p2.len() == 1);
+ let p2 = crates_named_p2[0];
+ assert!(p2.origin.is_local());
+}
+
+#[test]
+fn test_deduplicate_origin_dev_rev() {
+ let path_map = &mut Default::default();
+ let (mut crate_graph, _proc_macros) =
+ load_cargo_with_sysroot(path_map, "deduplication_crate_graph_B.json");
+ crate_graph.sort_deps();
+ let (crate_graph_1, mut _proc_macros_2) =
+ load_cargo_with_sysroot(path_map, "deduplication_crate_graph_A.json");
+
+ crate_graph.extend(crate_graph_1, &mut _proc_macros_2);
+
+ let mut crates_named_p2 = vec![];
+ for id in crate_graph.iter() {
+ let krate = &crate_graph[id];
+ if let Some(name) = krate.display_name.as_ref() {
+ if name.to_string() == "p2" {
+ crates_named_p2.push(krate);
+ }
+ }
+ }
+
+ assert!(crates_named_p2.len() == 1);
+ let p2 = crates_named_p2[0];
+ assert!(p2.origin.is_local());
+}
diff --git a/crates/project-model/src/workspace.rs b/crates/project-model/src/workspace.rs
index e0209ca15a..9333570354 100644
--- a/crates/project-model/src/workspace.rs
+++ b/crates/project-model/src/workspace.rs
@@ -6,8 +6,8 @@ use std::{collections::VecDeque, fmt, fs, iter, process::Command, str::FromStr,
use anyhow::{format_err, Context};
use base_db::{
- CrateDisplayName, CrateGraph, CrateId, CrateName, CrateOrigin, Dependency, Edition, Env,
- FileId, LangCrateOrigin, ProcMacroPaths, ReleaseChannel, TargetLayoutLoadResult,
+ CrateDisplayName, CrateGraph, CrateId, CrateName, CrateOrigin, Dependency, DependencyKind,
+ Edition, Env, FileId, LangCrateOrigin, ProcMacroPaths, ReleaseChannel, TargetLayoutLoadResult,
};
use cfg::{CfgDiff, CfgOptions};
use paths::{AbsPath, AbsPathBuf};
@@ -834,7 +834,7 @@ fn project_json_to_crate_graph(
for dep in &krate.deps {
if let Some(&to) = crates.get(&dep.crate_id) {
- add_dep(crate_graph, from, dep.name.clone(), to)
+ add_dep(crate_graph, from, dep.name.clone(), to, dep.kind().to_owned())
}
}
}
@@ -979,7 +979,7 @@ fn cargo_to_crate_graph(
// cargo metadata does not do any normalization,
// so we do it ourselves currently
let name = CrateName::normalize_dashes(&name);
- add_dep(crate_graph, from, name, to);
+ add_dep(crate_graph, from, name, to, DependencyKind::Normal);
}
}
}
@@ -999,7 +999,17 @@ fn cargo_to_crate_graph(
continue;
}
- add_dep(crate_graph, from, name.clone(), to)
+ add_dep(
+ crate_graph,
+ from,
+ name.clone(),
+ to,
+ match dep.kind {
+ DepKind::Normal => DependencyKind::Normal,
+ DepKind::Dev => DependencyKind::Dev,
+ DepKind::Build => DependencyKind::Build,
+ },
+ )
}
}
}
@@ -1187,7 +1197,17 @@ fn handle_rustc_crates(
let name = CrateName::new(&dep.name).unwrap();
if let Some(&to) = pkg_to_lib_crate.get(&dep.pkg) {
for &from in rustc_pkg_crates.get(&pkg).into_iter().flatten() {
- add_dep(crate_graph, from, name.clone(), to);
+ add_dep(
+ crate_graph,
+ from,
+ name.clone(),
+ to,
+ match dep.kind {
+ DepKind::Normal => DependencyKind::Normal,
+ DepKind::Dev => DependencyKind::Dev,
+ DepKind::Build => DependencyKind::Build,
+ },
+ );
}
}
}
@@ -1209,7 +1229,7 @@ fn handle_rustc_crates(
// `rust_analyzer` thinks that it should use the one from the `rustc_source`
// instead of the one from `crates.io`
if !crate_graph[*from].dependencies.iter().any(|d| d.name == name) {
- add_dep(crate_graph, *from, name.clone(), to);
+ add_dep(crate_graph, *from, name.clone(), to, DependencyKind::Normal);
}
}
}
@@ -1308,7 +1328,14 @@ impl SysrootPublicDeps {
/// Makes `from` depend on the public sysroot crates.
fn add_to_crate_graph(&self, crate_graph: &mut CrateGraph, from: CrateId) {
for (name, krate, prelude) in &self.deps {
- add_dep_with_prelude(crate_graph, from, name.clone(), *krate, *prelude);
+ add_dep_with_prelude(
+ crate_graph,
+ from,
+ name.clone(),
+ *krate,
+ *prelude,
+ DependencyKind::Normal,
+ );
}
}
}
@@ -1363,7 +1390,7 @@ fn sysroot_to_crate_graph(
for &to in sysroot[from].deps.iter() {
let name = CrateName::new(&sysroot[to].name).unwrap();
if let (Some(&from), Some(&to)) = (sysroot_crates.get(&from), sysroot_crates.get(&to)) {
- add_dep(crate_graph, from, name, to);
+ add_dep(crate_graph, from, name, to, DependencyKind::Normal);
}
}
}
@@ -1442,8 +1469,14 @@ fn handle_hack_cargo_workspace(
.collect()
}
-fn add_dep(graph: &mut CrateGraph, from: CrateId, name: CrateName, to: CrateId) {
- add_dep_inner(graph, from, Dependency::new(name, to))
+fn add_dep(
+ graph: &mut CrateGraph,
+ from: CrateId,
+ name: CrateName,
+ to: CrateId,
+ kind: DependencyKind,
+) {
+ add_dep_inner(graph, from, Dependency::new(name, to, kind))
}
fn add_dep_with_prelude(
@@ -1452,12 +1485,20 @@ fn add_dep_with_prelude(
name: CrateName,
to: CrateId,
prelude: bool,
+ kind: DependencyKind,
) {
- add_dep_inner(graph, from, Dependency::with_prelude(name, to, prelude))
+ add_dep_inner(graph, from, Dependency::with_prelude(name, to, prelude, kind))
}
fn add_proc_macro_dep(crate_graph: &mut CrateGraph, from: CrateId, to: CrateId, prelude: bool) {
- add_dep_with_prelude(crate_graph, from, CrateName::new("proc_macro").unwrap(), to, prelude);
+ add_dep_with_prelude(
+ crate_graph,
+ from,
+ CrateName::new("proc_macro").unwrap(),
+ to,
+ prelude,
+ DependencyKind::Normal,
+ );
}
fn add_dep_inner(graph: &mut CrateGraph, from: CrateId, dep: Dependency) {
diff --git a/crates/project-model/test_data/deduplication_crate_graph_A.json b/crates/project-model/test_data/deduplication_crate_graph_A.json
new file mode 100644
index 0000000000..b0fb5845ce
--- /dev/null
+++ b/crates/project-model/test_data/deduplication_crate_graph_A.json
@@ -0,0 +1,140 @@
+{
+ "packages": [
+ {
+ "name": "p1",
+ "version": "0.1.0",
+ "id": "p1 0.1.0 (path+file:///example_project/p1)",
+ "license": null,
+ "license_file": null,
+ "description": null,
+ "source": null,
+ "dependencies": [
+ {
+ "name": "p2",
+ "source": null,
+ "req": "*",
+ "kind": null,
+ "rename": null,
+ "optional": false,
+ "uses_default_features": true,
+ "features": [],
+ "target": null,
+ "registry": null,
+ "path": "$ROOT$example_project/p2"
+ }
+ ],
+ "targets": [
+ {
+ "kind": [
+ "lib"
+ ],
+ "crate_types": [
+ "lib"
+ ],
+ "name": "p1",
+ "src_path": "$ROOT$example_project/p1/src/lib.rs",
+ "edition": "2021",
+ "doc": true,
+ "doctest": true,
+ "test": true
+ }
+ ],
+ "features": {},
+ "manifest_path": "$ROOT$example_project/p1/Cargo.toml",
+ "metadata": null,
+ "publish": null,
+ "authors": [],
+ "categories": [],
+ "keywords": [],
+ "readme": null,
+ "repository": null,
+ "homepage": null,
+ "documentation": null,
+ "edition": "2021",
+ "links": null,
+ "default_run": null,
+ "rust_version": null
+ },
+ {
+ "name": "p2",
+ "version": "0.1.0",
+ "id": "p2 0.1.0 (path+file:///example_project/p2)",
+ "license": null,
+ "license_file": null,
+ "description": null,
+ "source": null,
+ "dependencies": [],
+ "targets": [
+ {
+ "kind": [
+ "lib"
+ ],
+ "crate_types": [
+ "lib"
+ ],
+ "name": "p2",
+ "src_path": "$ROOT$example_project/p2/src/lib.rs",
+ "edition": "2021",
+ "doc": true,
+ "doctest": true,
+ "test": true
+ }
+ ],
+ "features": {},
+ "manifest_path": "$ROOT$example_project/p2/Cargo.toml",
+ "metadata": null,
+ "publish": null,
+ "authors": [],
+ "categories": [],
+ "keywords": [],
+ "readme": null,
+ "repository": null,
+ "homepage": null,
+ "documentation": null,
+ "edition": "2021",
+ "links": null,
+ "default_run": null,
+ "rust_version": null
+ }
+ ],
+ "workspace_members": [
+ "p1 0.1.0 (path+file:///example_project/p1)"
+ ],
+ "workspace_default_members": [
+ "p1 0.1.0 (path+file:///example_project/p1)"
+ ],
+ "resolve": {
+ "nodes": [
+ {
+ "id": "p1 0.1.0 (path+file:///example_project/p1)",
+ "dependencies": [
+ "p2 0.1.0 (path+file:///example_project/p2)"
+ ],
+ "deps": [
+ {
+ "name": "p2",
+ "pkg": "p2 0.1.0 (path+file:///example_project/p2)",
+ "dep_kinds": [
+ {
+ "kind": null,
+ "target": null
+ }
+ ]
+ }
+ ],
+ "features": []
+ },
+ {
+ "id": "p2 0.1.0 (path+file:///example_project/p2)",
+ "dependencies": [],
+ "deps": [],
+ "features": []
+ }
+ ],
+ "root": "p1 0.1.0 (path+file:///example_project/p1)"
+ },
+ "target_directory": "$ROOT$example_project/p1/target",
+ "version": 1,
+ "workspace_root": "$ROOT$example_project/p1",
+ "metadata": null
+} \ No newline at end of file
diff --git a/crates/project-model/test_data/deduplication_crate_graph_B.json b/crates/project-model/test_data/deduplication_crate_graph_B.json
new file mode 100644
index 0000000000..b5d1e16e62
--- /dev/null
+++ b/crates/project-model/test_data/deduplication_crate_graph_B.json
@@ -0,0 +1,66 @@
+{
+ "packages": [
+ {
+ "name": "p2",
+ "version": "0.1.0",
+ "id": "p2 0.1.0 (path+file:///example_project/p2)",
+ "license": null,
+ "license_file": null,
+ "description": null,
+ "source": null,
+ "dependencies": [],
+ "targets": [
+ {
+ "kind": [
+ "lib"
+ ],
+ "crate_types": [
+ "lib"
+ ],
+ "name": "p2",
+ "src_path": "$ROOT$example_project/p2/src/lib.rs",
+ "edition": "2021",
+ "doc": true,
+ "doctest": true,
+ "test": true
+ }
+ ],
+ "features": {},
+ "manifest_path": "$ROOT$example_project/p2/Cargo.toml",
+ "metadata": null,
+ "publish": null,
+ "authors": [],
+ "categories": [],
+ "keywords": [],
+ "readme": null,
+ "repository": null,
+ "homepage": null,
+ "documentation": null,
+ "edition": "2021",
+ "links": null,
+ "default_run": null,
+ "rust_version": null
+ }
+ ],
+ "workspace_members": [
+ "p2 0.1.0 (path+file:///example_project/p2)"
+ ],
+ "workspace_default_members": [
+ "p2 0.1.0 (path+file:///example_project/p2)"
+ ],
+ "resolve": {
+ "nodes": [
+ {
+ "id": "p2 0.1.0 (path+file:///example_project/p2)",
+ "dependencies": [],
+ "deps": [],
+ "features": []
+ }
+ ],
+ "root": "p2 0.1.0 (path+file:///example_project/p2)"
+ },
+ "target_directory": "$ROOT$example_project/p2/target",
+ "version": 1,
+ "workspace_root": "$ROOT$example_project/p2",
+ "metadata": null
+} \ No newline at end of file
diff --git a/crates/project-model/test_data/output/cargo_hello_world_project_model.txt b/crates/project-model/test_data/output/cargo_hello_world_project_model.txt
index 727d39a307..e98f016ca7 100644
--- a/crates/project-model/test_data/output/cargo_hello_world_project_model.txt
+++ b/crates/project-model/test_data/output/cargo_hello_world_project_model.txt
@@ -48,6 +48,7 @@
name: CrateName(
"libc",
),
+ kind: Normal,
prelude: true,
},
],
@@ -112,6 +113,7 @@
name: CrateName(
"hello_world",
),
+ kind: Normal,
prelude: true,
},
Dependency {
@@ -119,6 +121,7 @@
name: CrateName(
"libc",
),
+ kind: Normal,
prelude: true,
},
],
@@ -183,6 +186,7 @@
name: CrateName(
"hello_world",
),
+ kind: Normal,
prelude: true,
},
Dependency {
@@ -190,6 +194,7 @@
name: CrateName(
"libc",
),
+ kind: Normal,
prelude: true,
},
],
@@ -254,6 +259,7 @@
name: CrateName(
"hello_world",
),
+ kind: Normal,
prelude: true,
},
Dependency {
@@ -261,6 +267,7 @@
name: CrateName(
"libc",
),
+ kind: Normal,
prelude: true,
},
],
diff --git a/crates/project-model/test_data/output/cargo_hello_world_project_model_with_selective_overrides.txt b/crates/project-model/test_data/output/cargo_hello_world_project_model_with_selective_overrides.txt
index 727d39a307..e98f016ca7 100644
--- a/crates/project-model/test_data/output/cargo_hello_world_project_model_with_selective_overrides.txt
+++ b/crates/project-model/test_data/output/cargo_hello_world_project_model_with_selective_overrides.txt
@@ -48,6 +48,7 @@
name: CrateName(
"libc",
),
+ kind: Normal,
prelude: true,
},
],
@@ -112,6 +113,7 @@
name: CrateName(
"hello_world",
),
+ kind: Normal,
prelude: true,
},
Dependency {
@@ -119,6 +121,7 @@
name: CrateName(
"libc",
),
+ kind: Normal,
prelude: true,
},
],
@@ -183,6 +186,7 @@
name: CrateName(
"hello_world",
),
+ kind: Normal,
prelude: true,
},
Dependency {
@@ -190,6 +194,7 @@
name: CrateName(
"libc",
),
+ kind: Normal,
prelude: true,
},
],
@@ -254,6 +259,7 @@
name: CrateName(
"hello_world",
),
+ kind: Normal,
prelude: true,
},
Dependency {
@@ -261,6 +267,7 @@
name: CrateName(
"libc",
),
+ kind: Normal,
prelude: true,
},
],
diff --git a/crates/project-model/test_data/output/cargo_hello_world_project_model_with_wildcard_overrides.txt b/crates/project-model/test_data/output/cargo_hello_world_project_model_with_wildcard_overrides.txt
index 89728babd8..7ecd53572e 100644
--- a/crates/project-model/test_data/output/cargo_hello_world_project_model_with_wildcard_overrides.txt
+++ b/crates/project-model/test_data/output/cargo_hello_world_project_model_with_wildcard_overrides.txt
@@ -47,6 +47,7 @@
name: CrateName(
"libc",
),
+ kind: Normal,
prelude: true,
},
],
@@ -110,6 +111,7 @@
name: CrateName(
"hello_world",
),
+ kind: Normal,
prelude: true,
},
Dependency {
@@ -117,6 +119,7 @@
name: CrateName(
"libc",
),
+ kind: Normal,
prelude: true,
},
],
@@ -180,6 +183,7 @@
name: CrateName(
"hello_world",
),
+ kind: Normal,
prelude: true,
},
Dependency {
@@ -187,6 +191,7 @@
name: CrateName(
"libc",
),
+ kind: Normal,
prelude: true,
},
],
@@ -250,6 +255,7 @@
name: CrateName(
"hello_world",
),
+ kind: Normal,
prelude: true,
},
Dependency {
@@ -257,6 +263,7 @@
name: CrateName(
"libc",
),
+ kind: Normal,
prelude: true,
},
],
diff --git a/crates/project-model/test_data/output/rust_project_hello_world_project_model.txt b/crates/project-model/test_data/output/rust_project_hello_world_project_model.txt
index b7bf6cb277..581a6afc14 100644
--- a/crates/project-model/test_data/output/rust_project_hello_world_project_model.txt
+++ b/crates/project-model/test_data/output/rust_project_hello_world_project_model.txt
@@ -28,6 +28,7 @@
name: CrateName(
"core",
),
+ kind: Normal,
prelude: true,
},
],
@@ -168,6 +169,7 @@
name: CrateName(
"std",
),
+ kind: Normal,
prelude: true,
},
Dependency {
@@ -175,6 +177,7 @@
name: CrateName(
"core",
),
+ kind: Normal,
prelude: true,
},
],
@@ -249,6 +252,7 @@
name: CrateName(
"alloc",
),
+ kind: Normal,
prelude: true,
},
Dependency {
@@ -256,6 +260,7 @@
name: CrateName(
"panic_unwind",
),
+ kind: Normal,
prelude: true,
},
Dependency {
@@ -263,6 +268,7 @@
name: CrateName(
"panic_abort",
),
+ kind: Normal,
prelude: true,
},
Dependency {
@@ -270,6 +276,7 @@
name: CrateName(
"core",
),
+ kind: Normal,
prelude: true,
},
Dependency {
@@ -277,6 +284,7 @@
name: CrateName(
"profiler_builtins",
),
+ kind: Normal,
prelude: true,
},
Dependency {
@@ -284,6 +292,7 @@
name: CrateName(
"unwind",
),
+ kind: Normal,
prelude: true,
},
Dependency {
@@ -291,6 +300,7 @@
name: CrateName(
"std_detect",
),
+ kind: Normal,
prelude: true,
},
Dependency {
@@ -298,6 +308,7 @@
name: CrateName(
"test",
),
+ kind: Normal,
prelude: true,
},
],
@@ -438,6 +449,7 @@
name: CrateName(
"core",
),
+ kind: Normal,
prelude: true,
},
Dependency {
@@ -445,6 +457,7 @@
name: CrateName(
"alloc",
),
+ kind: Normal,
prelude: true,
},
Dependency {
@@ -452,6 +465,7 @@
name: CrateName(
"std",
),
+ kind: Normal,
prelude: true,
},
Dependency {
@@ -459,6 +473,7 @@
name: CrateName(
"test",
),
+ kind: Normal,
prelude: false,
},
Dependency {
@@ -466,6 +481,7 @@
name: CrateName(
"proc_macro",
),
+ kind: Normal,
prelude: false,
},
],