]> git.lizzy.rs Git - rust.git/blobdiff - crates/ra_lsp_server/src/server_world.rs
automatically collect garbage
[rust.git] / crates / ra_lsp_server / src / server_world.rs
index ebf2b15ccd80d120f9c05d0e672d00647e2bc4ec..c2167c5d80342c69a2eb283accdfd45f9c4a0eb0 100644 (file)
@@ -1,10 +1,10 @@
 use std::{
-    path::{PathBuf},
+    path::PathBuf,
     sync::Arc,
 };
 
-use languageserver_types::Url;
-use ra_analysis::{
+use lsp_types::Url;
+use ra_ide_api::{
     Analysis, AnalysisChange, AnalysisHost, CrateGraph, FileId, LibraryData,
     SourceRootId
 };
 use rustc_hash::FxHashMap;
 use relative_path::RelativePathBuf;
 use parking_lot::RwLock;
-use failure::{format_err};
+use failure::format_err;
 
 use crate::{
-    project_model::{CargoWorkspace, TargetKind},
+    project_model::{ProjectWorkspace, TargetKind},
     Result,
 };
 
 pub struct ServerWorldState {
     pub roots_to_scan: usize,
     pub root: PathBuf,
-    pub workspaces: Arc<Vec<CargoWorkspace>>,
+    pub workspaces: Arc<Vec<ProjectWorkspace>>,
     pub analysis_host: AnalysisHost,
     pub vfs: Arc<RwLock<Vfs>>,
 }
 
 pub struct ServerWorld {
-    pub workspaces: Arc<Vec<CargoWorkspace>>,
+    pub workspaces: Arc<Vec<ProjectWorkspace>>,
     pub analysis: Analysis,
     pub vfs: Arc<RwLock<Vfs>>,
 }
 
 impl ServerWorldState {
-    pub fn new(root: PathBuf, workspaces: Vec<CargoWorkspace>) -> ServerWorldState {
+    pub fn new(root: PathBuf, workspaces: Vec<ProjectWorkspace>) -> ServerWorldState {
         let mut change = AnalysisChange::new();
 
         let mut roots = Vec::new();
         roots.push(root.clone());
         for ws in workspaces.iter() {
-            for pkg in ws.packages() {
-                roots.push(pkg.root(&ws).to_path_buf());
+            for pkg in ws.cargo.packages() {
+                roots.push(pkg.root(&ws.cargo).to_path_buf());
+            }
+            for krate in ws.sysroot.crates() {
+                roots.push(krate.root_dir(&ws.sysroot).to_path_buf())
             }
         }
+        roots.sort();
+        roots.dedup();
         let roots_to_scan = roots.len();
         let (mut vfs, roots) = Vfs::new(roots);
         for r in roots {
@@ -53,16 +58,45 @@ pub fn new(root: PathBuf, workspaces: Vec<CargoWorkspace>) -> ServerWorldState {
         }
 
         let mut crate_graph = CrateGraph::default();
-        let mut pkg_to_lib_crate = FxHashMap::default();
-        let mut pkg_crates = FxHashMap::default();
         for ws in workspaces.iter() {
-            for pkg in ws.packages() {
-                for tgt in pkg.targets(ws) {
-                    let root = tgt.root(ws);
+            // First, load std
+            let mut sysroot_crates = FxHashMap::default();
+            for krate in ws.sysroot.crates() {
+                if let Some(file_id) = vfs.load(krate.root(&ws.sysroot)) {
+                    let file_id = FileId(file_id.0.into());
+                    sysroot_crates.insert(krate, crate_graph.add_crate_root(file_id));
+                }
+            }
+            for from in ws.sysroot.crates() {
+                for to in from.deps(&ws.sysroot) {
+                    let name = to.name(&ws.sysroot);
+                    if let (Some(&from), Some(&to)) =
+                        (sysroot_crates.get(&from), sysroot_crates.get(&to))
+                    {
+                        if let Err(_) = crate_graph.add_dep(from, name.clone(), to) {
+                            log::error!("cyclic dependency between sysroot crates")
+                        }
+                    }
+                }
+            }
+
+            let libstd = ws
+                .sysroot
+                .std()
+                .and_then(|it| sysroot_crates.get(&it).map(|&it| it));
+
+            let mut pkg_to_lib_crate = FxHashMap::default();
+            let mut pkg_crates = FxHashMap::default();
+            // Next, create crates for each package, target pair
+            for pkg in ws.cargo.packages() {
+                let mut lib_tgt = None;
+                for tgt in pkg.targets(&ws.cargo) {
+                    let root = tgt.root(&ws.cargo);
                     if let Some(file_id) = vfs.load(root) {
                         let file_id = FileId(file_id.0.into());
                         let crate_id = crate_graph.add_crate_root(file_id);
-                        if tgt.kind(ws) == TargetKind::Lib {
+                        if tgt.kind(&ws.cargo) == TargetKind::Lib {
+                            lib_tgt = Some(crate_id);
                             pkg_to_lib_crate.insert(pkg, crate_id);
                         }
                         pkg_crates
@@ -71,12 +105,42 @@ pub fn new(root: PathBuf, workspaces: Vec<CargoWorkspace>) -> ServerWorldState {
                             .push(crate_id);
                     }
                 }
+
+                // Set deps to the std and to the lib target of the current package
+                for &from in pkg_crates.get(&pkg).into_iter().flatten() {
+                    if let Some(to) = lib_tgt {
+                        if to != from {
+                            if let Err(_) =
+                                crate_graph.add_dep(from, pkg.name(&ws.cargo).into(), to)
+                            {
+                                log::error!(
+                                    "cyclic dependency between targets of {}",
+                                    pkg.name(&ws.cargo)
+                                )
+                            }
+                        }
+                    }
+                    if let Some(std) = libstd {
+                        if let Err(_) = crate_graph.add_dep(from, "std".into(), std) {
+                            log::error!("cyclic dependency on std for {}", pkg.name(&ws.cargo))
+                        }
+                    }
+                }
             }
-            for pkg in ws.packages() {
-                for dep in pkg.dependencies(ws) {
+
+            // Now add a dep ednge from all targets of upstream to the lib
+            // target of downstream.
+            for pkg in ws.cargo.packages() {
+                for dep in pkg.dependencies(&ws.cargo) {
                     if let Some(&to) = pkg_to_lib_crate.get(&dep.pkg) {
                         for &from in pkg_crates.get(&pkg).into_iter().flatten() {
-                            crate_graph.add_dep(from, dep.name.clone(), to);
+                            if let Err(_) = crate_graph.add_dep(from, dep.name.clone(), to) {
+                                log::error!(
+                                    "cyclic dependency {} -> {}",
+                                    pkg.name(&ws.cargo),
+                                    dep.pkg.name(&ws.cargo)
+                                )
+                            }
                         }
                     }
                 }
@@ -167,6 +231,14 @@ pub fn snapshot(&self) -> ServerWorld {
             vfs: Arc::clone(&self.vfs),
         }
     }
+
+    pub fn maybe_collect_garbage(&mut self) {
+        self.analysis_host.maybe_collect_garbage()
+    }
+
+    pub fn collect_garbage(&mut self) {
+        self.analysis_host.collect_garbage()
+    }
 }
 
 impl ServerWorld {
@@ -200,4 +272,19 @@ pub fn path_to_uri(&self, root: SourceRootId, path: &RelativePathBuf) -> Result<
             .map_err(|_| format_err!("can't convert path to url: {}", path.display()))?;
         Ok(url)
     }
+
+    pub fn status(&self) -> String {
+        let mut res = String::new();
+        if self.workspaces.is_empty() {
+            res.push_str("no workspaces\n")
+        } else {
+            res.push_str("workspaces:\n");
+            for w in self.workspaces.iter() {
+                res += &format!("{} packages loaded\n", w.cargo.packages().count());
+            }
+        }
+        res.push_str("\nanalysis:\n");
+        res.push_str(&self.analysis.status());
+        res
+    }
 }