propagate deps to CrateGraph

This commit is contained in:
Aleksey Kladov 2018-12-08 23:16:11 +03:00
parent 32c067f8c9
commit 9b1356464a
3 changed files with 43 additions and 14 deletions

View file

@ -48,6 +48,9 @@ impl CrateGraph {
assert!(prev.is_none()); assert!(prev.is_none());
crate_id crate_id
} }
//FIXME: check that we don't have cycles here.
// Just a simple depth first search from `to` should work,
// the graph is small.
pub fn add_dep(&mut self, from: CrateId, to: CrateId) { pub fn add_dep(&mut self, from: CrateId, to: CrateId) {
self.arena.get_mut(&from).unwrap().add_dep(to) self.arena.get_mut(&from).unwrap().add_dep(to)
} }

View file

@ -1,6 +1,5 @@
use std::path::{Path, PathBuf}; use std::path::{Path, PathBuf};
use serde_derive::Serialize;
use cargo_metadata::{metadata_run, CargoOpt}; use cargo_metadata::{metadata_run, CargoOpt};
use ra_syntax::SmolStr; use ra_syntax::SmolStr;
use rustc_hash::{FxHashMap, FxHashSet}; use rustc_hash::{FxHashMap, FxHashSet};
@ -11,15 +10,22 @@ use crate::{
thread_watcher::{ThreadWatcher, Worker}, thread_watcher::{ThreadWatcher, Worker},
}; };
/// `CargoWorksapce` represents the logical structure of, well, a Cargo
/// workspace. It pretty closely mirrors `cargo metadata` output.
///
/// Note that internally, rust analyzer uses a differnet structure:
/// `CrateGraph`. `CrateGraph` is lower-level: it knows only about the crates,
/// while this knows about `Pacakges` & `Targets`: purely cargo-related
/// concepts.
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct CargoWorkspace { pub struct CargoWorkspace {
packages: Vec<PackageData>, packages: Vec<PackageData>,
targets: Vec<TargetData>, targets: Vec<TargetData>,
} }
#[derive(Clone, Copy, Debug, Serialize)] #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub struct Package(usize); pub struct Package(usize);
#[derive(Clone, Copy, Debug, Serialize)] #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub struct Target(usize); pub struct Target(usize);
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
@ -62,6 +68,9 @@ impl Package {
pub fn is_member(self, ws: &CargoWorkspace) -> bool { pub fn is_member(self, ws: &CargoWorkspace) -> bool {
ws.pkg(self).is_member ws.pkg(self).is_member
} }
pub fn dependencies<'a>(self, ws: &'a CargoWorkspace) -> impl Iterator<Item = Package> + 'a {
ws.pkg(self).dependencies.iter().cloned()
}
} }
impl Target { impl Target {

View file

@ -13,7 +13,7 @@ use failure::{bail, format_err};
use crate::{ use crate::{
path_map::{PathMap, Root}, path_map::{PathMap, Root},
project_model::CargoWorkspace, project_model::{CargoWorkspace, TargetKind},
vfs::{FileEvent, FileEventKind}, vfs::{FileEvent, FileEventKind},
Result, Result,
}; };
@ -142,17 +142,34 @@ impl ServerWorldState {
} }
pub fn set_workspaces(&mut self, ws: Vec<CargoWorkspace>) { pub fn set_workspaces(&mut self, ws: Vec<CargoWorkspace>) {
let mut crate_graph = CrateGraph::default(); let mut crate_graph = CrateGraph::default();
ws.iter() let mut pkg_to_lib_crate = FxHashMap::default();
.flat_map(|ws| { let mut pkg_crates = FxHashMap::default();
ws.packages() for ws in ws.iter() {
.flat_map(move |pkg| pkg.targets(ws)) for pkg in ws.packages() {
.map(move |tgt| tgt.root(ws)) for tgt in pkg.targets(ws) {
}) let root = tgt.root(ws);
.for_each(|root| {
if let Some(file_id) = self.path_map.get_id(root) { if let Some(file_id) = self.path_map.get_id(root) {
crate_graph.add_crate_root(file_id); let crate_id = crate_graph.add_crate_root(file_id);
if tgt.kind(ws) == TargetKind::Lib {
pkg_to_lib_crate.insert(pkg, crate_id);
}
pkg_crates
.entry(pkg)
.or_insert_with(Vec::new)
.push(crate_id);
}
}
}
for pkg in ws.packages() {
for dep in pkg.dependencies(ws) {
if let Some(&to) = pkg_to_lib_crate.get(&dep) {
for &from in pkg_crates.get(&pkg).into_iter().flatten() {
crate_graph.add_dep(from, to);
}
}
}
}
} }
});
self.workspaces = Arc::new(ws); self.workspaces = Arc::new(ws);
let mut change = AnalysisChange::new(); let mut change = AnalysisChange::new();
change.set_crate_graph(crate_graph); change.set_crate_graph(crate_graph);