assert!(prev.is_none());
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) {
self.arena.get_mut(&from).unwrap().add_dep(to)
}
use std::path::{Path, PathBuf};
-use serde_derive::Serialize;
use cargo_metadata::{metadata_run, CargoOpt};
use ra_syntax::SmolStr;
use rustc_hash::{FxHashMap, FxHashSet};
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)]
pub struct CargoWorkspace {
packages: Vec<PackageData>,
targets: Vec<TargetData>,
}
-#[derive(Clone, Copy, Debug, Serialize)]
+#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub struct Package(usize);
-#[derive(Clone, Copy, Debug, Serialize)]
+#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub struct Target(usize);
#[derive(Debug, Clone)]
pub fn is_member(self, ws: &CargoWorkspace) -> bool {
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 {
use crate::{
path_map::{PathMap, Root},
- project_model::CargoWorkspace,
+ project_model::{CargoWorkspace, TargetKind},
vfs::{FileEvent, FileEventKind},
Result,
};
}
pub fn set_workspaces(&mut self, ws: Vec<CargoWorkspace>) {
let mut crate_graph = CrateGraph::default();
- ws.iter()
- .flat_map(|ws| {
- ws.packages()
- .flat_map(move |pkg| pkg.targets(ws))
- .map(move |tgt| tgt.root(ws))
- })
- .for_each(|root| {
- if let Some(file_id) = self.path_map.get_id(root) {
- crate_graph.add_crate_root(file_id);
+ let mut pkg_to_lib_crate = FxHashMap::default();
+ let mut pkg_crates = FxHashMap::default();
+ for ws in ws.iter() {
+ for pkg in ws.packages() {
+ for tgt in pkg.targets(ws) {
+ let root = tgt.root(ws);
+ if let Some(file_id) = self.path_map.get_id(root) {
+ 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);
let mut change = AnalysisChange::new();
change.set_crate_graph(crate_graph);