Unnamed repository; edit this file 'description' to name the repository.
Diffstat (limited to 'crates/base-db/src/input.rs')
-rw-r--r--crates/base-db/src/input.rs43
1 files changed, 32 insertions, 11 deletions
diff --git a/crates/base-db/src/input.rs b/crates/base-db/src/input.rs
index 246c57edc2..38f9c5a5a1 100644
--- a/crates/base-db/src/input.rs
+++ b/crates/base-db/src/input.rs
@@ -21,7 +21,10 @@ use span::Edition;
use triomphe::Arc;
use vfs::{AbsPathBuf, AnchoredPath, FileId, VfsPath, file_set::FileSet};
-use crate::{CrateWorkspaceData, EditionedFileId, FxIndexSet, RootQueryDb};
+use crate::{
+ CrateWorkspaceData, EditionedFileId, FxIndexSet, SourceDatabase, all_crates,
+ set_all_crates_with_durability,
+};
pub type ProcMacroPaths =
FxHashMap<CrateBuilderId, Result<(String, AbsPathBuf), ProcMacroLoadingError>>;
@@ -490,13 +493,13 @@ impl Crate {
/// including the crate itself.
///
/// **Warning**: do not use this query in `hir-*` crates! It kills incrementality across crate metadata modifications.
- pub fn transitive_rev_deps(self, db: &dyn RootQueryDb) -> Box<[Crate]> {
+ pub fn transitive_rev_deps(self, db: &dyn SourceDatabase) -> Box<[Crate]> {
let mut worklist = vec![self];
let mut rev_deps = FxHashSet::default();
rev_deps.insert(self);
let mut inverted_graph = FxHashMap::<_, Vec<_>>::default();
- db.all_crates().iter().for_each(|&krate| {
+ all_crates(db).iter().for_each(|&krate| {
krate
.data(db)
.dependencies
@@ -586,15 +589,15 @@ impl CrateGraphBuilder {
Ok(())
}
- pub fn set_in_db(self, db: &mut dyn RootQueryDb) -> CratesIdMap {
+ pub fn set_in_db(self, db: &mut dyn SourceDatabase) -> CratesIdMap {
+ let old_all_crates = all_crates(db);
+
// For some reason in some repositories we have duplicate crates, so we use a set and not `Vec`.
// We use an `IndexSet` because the list needs to be topologically sorted.
let mut all_crates = FxIndexSet::with_capacity_and_hasher(self.arena.len(), FxBuildHasher);
let mut visited = FxHashMap::default();
let mut visited_root_files = FxHashSet::default();
- let old_all_crates = db.all_crates();
-
let crates_map = db.crates_map();
// salsa doesn't compare new input to old input to see if they are the same, so here we are doing all the work ourselves.
for krate in self.iter() {
@@ -612,17 +615,14 @@ impl CrateGraphBuilder {
if old_all_crates.len() != all_crates.len()
|| old_all_crates.iter().any(|&krate| !all_crates.contains(&krate))
{
- db.set_all_crates_with_durability(
- Arc::new(Vec::from_iter(all_crates).into_boxed_slice()),
- Durability::MEDIUM,
- );
+ set_all_crates_with_durability(db, all_crates, Durability::MEDIUM);
}
return visited;
fn go(
graph: &CrateGraphBuilder,
- db: &mut dyn RootQueryDb,
+ db: &mut dyn SourceDatabase,
crates_map: &CratesMap,
visited: &mut FxHashMap<CrateBuilderId, Crate>,
visited_root_files: &mut FxHashSet<FileId>,
@@ -929,6 +929,27 @@ impl<'a> IntoIterator for &'a Env {
}
}
+/// The crate graph had a cycle. This is typically a bug, and
+/// rust-analyzer logs a warning when it encounters a cycle. Generally
+/// rust-analyzer will continue working OK in the presence of cycle,
+/// but it's better to have an accurate crate graph.
+///
+/// ## dev-dependencies
+///
+/// Note that it's actually legal for a cargo package (i.e. a thing
+/// with a Cargo.toml) to depend on itself in dev-dependencies. This
+/// can enable additional features, and is typically used when a
+/// project wants features to be enabled in tests. Dev-dependencies
+/// are not propagated, so they aren't visible to package that depend
+/// on this one.
+///
+/// <https://doc.rust-lang.org/cargo/reference/specifying-dependencies.html#development-dependencies>
+///
+/// However, rust-analyzer constructs its crate graph from Cargo
+/// metadata, so it can end up producing a cyclic crate graph from a
+/// well-formed package graph.
+///
+/// <https://github.com/rust-lang/rust-analyzer/issues/14167>
#[derive(Debug)]
pub struct CyclicDependenciesError {
path: Vec<(CrateBuilderId, Option<CrateDisplayName>)>,