8034: Implement Crate::transitive_reverse_dependencies r=matklad a=Veykril

changelog internal Implement Crate::transitive_reverse_dependencies

Co-authored-by: Lukas Wirth <lukastw97@gmail.com>
This commit is contained in:
bors[bot] 2021-03-16 14:54:12 +00:00 committed by GitHub
commit 979e788957
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 94 additions and 8 deletions

View file

@ -57,7 +57,7 @@
//! fn insert_source_code_here() {} //! fn insert_source_code_here() {}
//! " //! "
//! ``` //! ```
use std::{str::FromStr, sync::Arc}; use std::{mem, str::FromStr, sync::Arc};
use cfg::CfgOptions; use cfg::CfgOptions;
use rustc_hash::FxHashMap; use rustc_hash::FxHashMap;
@ -148,6 +148,7 @@ impl ChangeFixture {
let mut file_set = FileSet::default(); let mut file_set = FileSet::default();
let source_root_prefix = "/".to_string(); let source_root_prefix = "/".to_string();
let mut file_id = FileId(0); let mut file_id = FileId(0);
let mut roots = Vec::new();
let mut file_position = None; let mut file_position = None;
@ -168,6 +169,10 @@ impl ChangeFixture {
let meta = FileMeta::from(entry); let meta = FileMeta::from(entry);
assert!(meta.path.starts_with(&source_root_prefix)); assert!(meta.path.starts_with(&source_root_prefix));
if meta.introduce_new_source_root {
roots.push(SourceRoot::new_local(mem::take(&mut file_set)));
}
if let Some(krate) = meta.krate { if let Some(krate) = meta.krate {
let crate_name = CrateName::normalize_dashes(&krate); let crate_name = CrateName::normalize_dashes(&krate);
let crate_id = crate_graph.add_crate_root( let crate_id = crate_graph.add_crate_root(
@ -215,7 +220,8 @@ impl ChangeFixture {
} }
} }
change.set_roots(vec![SourceRoot::new_local(file_set)]); roots.push(SourceRoot::new_local(mem::take(&mut file_set)));
change.set_roots(roots);
change.set_crate_graph(crate_graph); change.set_crate_graph(crate_graph);
ChangeFixture { file_position, files, change } ChangeFixture { file_position, files, change }
@ -229,6 +235,7 @@ struct FileMeta {
cfg: CfgOptions, cfg: CfgOptions,
edition: Edition, edition: Edition,
env: Env, env: Env,
introduce_new_source_root: bool,
} }
impl From<Fixture> for FileMeta { impl From<Fixture> for FileMeta {
@ -247,6 +254,7 @@ impl From<Fixture> for FileMeta {
.as_ref() .as_ref()
.map_or(Edition::Edition2018, |v| Edition::from_str(&v).unwrap()), .map_or(Edition::Edition2018, |v| Edition::from_str(&v).unwrap()),
env: f.env.into_iter().collect(), env: f.env.into_iter().collect(),
introduce_new_source_root: f.introduce_new_source_root,
} }
} }
} }

View file

@ -274,6 +274,33 @@ impl CrateGraph {
deps.into_iter() deps.into_iter()
} }
/// Returns an iterator over all transitive reverse dependencies of the given crate.
pub fn transitive_reverse_dependencies(
&self,
of: CrateId,
) -> impl Iterator<Item = CrateId> + '_ {
let mut worklist = vec![of];
let mut rev_deps = FxHashSet::default();
let mut inverted_graph = FxHashMap::<_, Vec<_>>::default();
self.arena.iter().for_each(|(&krate, data)| {
data.dependencies
.iter()
.for_each(|dep| inverted_graph.entry(dep.crate_id).or_default().push(krate))
});
while let Some(krate) = worklist.pop() {
if let Some(krate_rev_deps) = inverted_graph.get(&krate) {
krate_rev_deps
.iter()
.copied()
.filter(|&rev_dep| rev_deps.insert(rev_dep))
.for_each(|rev_dep| worklist.push(rev_dep));
}
}
rev_deps.into_iter()
}
/// Returns all crates in the graph, sorted in topological order (ie. dependencies of a crate /// Returns all crates in the graph, sorted in topological order (ie. dependencies of a crate
/// come before the crate itself). /// come before the crate itself).
pub fn crates_in_topological_order(&self) -> Vec<CrateId> { pub fn crates_in_topological_order(&self) -> Vec<CrateId> {

View file

@ -60,6 +60,7 @@ use hir_ty::{
InEnvironment, Interner, Obligation, ProjectionPredicate, ProjectionTy, Scalar, Substs, Ty, InEnvironment, Interner, Obligation, ProjectionPredicate, ProjectionTy, Scalar, Substs, Ty,
TyDefId, TyKind, TyVariableKind, TyDefId, TyKind, TyVariableKind,
}; };
use itertools::Itertools;
use rustc_hash::FxHashSet; use rustc_hash::FxHashSet;
use stdx::{format_to, impl_from}; use stdx::{format_to, impl_from};
use syntax::{ use syntax::{
@ -141,7 +142,6 @@ impl Crate {
.collect() .collect()
} }
// FIXME: add `transitive_reverse_dependencies`.
pub fn reverse_dependencies(self, db: &dyn HirDatabase) -> Vec<Crate> { pub fn reverse_dependencies(self, db: &dyn HirDatabase) -> Vec<Crate> {
let crate_graph = db.crate_graph(); let crate_graph = db.crate_graph();
crate_graph crate_graph
@ -153,6 +153,14 @@ impl Crate {
.collect() .collect()
} }
pub fn transitive_reverse_dependencies(self, db: &dyn HirDatabase) -> Vec<Crate> {
db.crate_graph()
.transitive_reverse_dependencies(self.id)
.into_iter()
.map(|id| Crate { id })
.collect()
}
pub fn root_module(self, db: &dyn HirDatabase) -> Module { pub fn root_module(self, db: &dyn HirDatabase) -> Module {
let def_map = db.crate_def_map(self.id); let def_map = db.crate_def_map(self.id);
Module { id: def_map.module_id(def_map.root()) } Module { id: def_map.module_id(def_map.root()) }
@ -1541,11 +1549,17 @@ impl Impl {
}; };
let mut all = Vec::new(); let mut all = Vec::new();
def_crates.into_iter().for_each(|id| { def_crates.iter().for_each(|&id| {
all.extend(db.inherent_impls_in_crate(id).all_impls().map(Self::from).filter(filter)) all.extend(db.inherent_impls_in_crate(id).all_impls().map(Self::from).filter(filter))
}); });
let fp = TyFingerprint::for_impl(&ty.value); let fp = TyFingerprint::for_impl(&ty.value);
for id in db.crate_graph().iter() { for id in def_crates
.iter()
.flat_map(|&id| Crate { id }.transitive_reverse_dependencies(db))
.map(|Crate { id }| id)
.chain(def_crates.iter().copied())
.unique()
{
match fp { match fp {
Some(fp) => all.extend( Some(fp) => all.extend(
db.trait_impls_in_crate(id).for_self_ty(fp).map(Self::from).filter(filter), db.trait_impls_in_crate(id).for_self_ty(fp).map(Self::from).filter(filter),
@ -1560,7 +1574,8 @@ impl Impl {
pub fn all_for_trait(db: &dyn HirDatabase, trait_: Trait) -> Vec<Impl> { pub fn all_for_trait(db: &dyn HirDatabase, trait_: Trait) -> Vec<Impl> {
let krate = trait_.module(db).krate(); let krate = trait_.module(db).krate();
let mut all = Vec::new(); let mut all = Vec::new();
for Crate { id } in krate.reverse_dependencies(db).into_iter().chain(Some(krate)) { for Crate { id } in krate.transitive_reverse_dependencies(db).into_iter().chain(Some(krate))
{
let impls = db.trait_impls_in_crate(id); let impls = db.trait_impls_in_crate(id);
all.extend(impls.for_trait(trait_.id).map(Self::from)) all.extend(impls.for_trait(trait_.id).map(Self::from))
} }

View file

@ -1271,4 +1271,27 @@ fn foo(_: bool) -> bo$0ol { true }
"#]], "#]],
); );
} }
#[test]
fn test_transitive() {
check(
r#"
//- /level3.rs new_source_root: crate:level3
pub struct Fo$0o;
//- /level2.rs new_source_root: crate:level2 deps:level3
pub use level3::Foo;
//- /level1.rs new_source_root: crate:level1 deps:level2
pub use level2::Foo;
//- /level0.rs new_source_root: crate:level0 deps:level1
pub use level1::Foo;
"#,
expect![[r#"
Foo Struct FileId(0) 0..15 11..14
FileId(1) 16..19
FileId(2) 16..19
FileId(3) 16..19
"#]],
);
}
} }

View file

@ -260,7 +260,7 @@ impl Definition {
let mut res = source_root.iter().map(|id| (id, None)).collect::<FxHashMap<_, _>>(); let mut res = source_root.iter().map(|id| (id, None)).collect::<FxHashMap<_, _>>();
let krate = module.krate(); let krate = module.krate();
for rev_dep in krate.reverse_dependencies(db) { for rev_dep in krate.transitive_reverse_dependencies(db) {
let root_file = rev_dep.root_file(db); let root_file = rev_dep.root_file(db);
let source_root_id = db.file_source_root(root_file); let source_root_id = db.file_source_root(root_file);
let source_root = db.source_root(source_root_id); let source_root = db.source_root(source_root_id);

View file

@ -14,6 +14,7 @@ pub struct Fixture {
pub cfg_key_values: Vec<(String, String)>, pub cfg_key_values: Vec<(String, String)>,
pub edition: Option<String>, pub edition: Option<String>,
pub env: FxHashMap<String, String>, pub env: FxHashMap<String, String>,
pub introduce_new_source_root: bool,
} }
impl Fixture { impl Fixture {
@ -70,6 +71,7 @@ impl Fixture {
let mut cfg_atoms = Vec::new(); let mut cfg_atoms = Vec::new();
let mut cfg_key_values = Vec::new(); let mut cfg_key_values = Vec::new();
let mut env = FxHashMap::default(); let mut env = FxHashMap::default();
let mut introduce_new_source_root = false;
for component in components[1..].iter() { for component in components[1..].iter() {
let (key, value) = split_once(component, ':').unwrap(); let (key, value) = split_once(component, ':').unwrap();
match key { match key {
@ -91,11 +93,22 @@ impl Fixture {
} }
} }
} }
"new_source_root" => introduce_new_source_root = true,
_ => panic!("bad component: {:?}", component), _ => panic!("bad component: {:?}", component),
} }
} }
Fixture { path, text: String::new(), krate, deps, cfg_atoms, cfg_key_values, edition, env } Fixture {
path,
text: String::new(),
krate,
deps,
cfg_atoms,
cfg_key_values,
edition,
env,
introduce_new_source_root,
}
} }
} }