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.rs | 43 |
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>)>, |