]> git.lizzy.rs Git - rust.git/commitdiff
propagate deps to CrateGraph
authorAleksey Kladov <aleksey.kladov@gmail.com>
Sat, 8 Dec 2018 20:16:11 +0000 (23:16 +0300)
committerAleksey Kladov <aleksey.kladov@gmail.com>
Sun, 9 Dec 2018 10:33:16 +0000 (13:33 +0300)
crates/ra_db/src/input.rs
crates/ra_lsp_server/src/project_model.rs
crates/ra_lsp_server/src/server_world.rs

index 7d9faa43c20fd5644805174c243184e106dddf2e..a48d05b98a19059d19418a6dd1ccd8b04dd8d2f5 100644 (file)
@@ -48,6 +48,9 @@ pub fn add_crate_root(&mut self, file_id: FileId) -> CrateId {
         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)
     }
index 22495f49cb5ef38d6b3837d3e138cb0263bf51b1..5da71b9f54f4104d0f4a55e1479763e3d3af0e9f 100644 (file)
@@ -1,6 +1,5 @@
 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)]
@@ -62,6 +68,9 @@ pub fn targets<'a>(self, ws: &'a CargoWorkspace) -> impl Iterator<Item = Target>
     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 {
index c3f89ad5f0f4db7c48ef1c69e33e1326ed41519a..f2d602dc7856b6f8cb3880e96a5d9b37c4165bb3 100644 (file)
@@ -13,7 +13,7 @@
 
 use crate::{
     path_map::{PathMap, Root},
-    project_model::CargoWorkspace,
+    project_model::{CargoWorkspace, TargetKind},
     vfs::{FileEvent, FileEventKind},
     Result,
 };
@@ -142,17 +142,34 @@ pub fn remove_mem_file(&mut self, path: &Path) -> Result<FileId> {
     }
     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);