From 27ebe5d33e08d92c1a032dc27f19094571bd19cd Mon Sep 17 00:00:00 2001
From: Aleksey Kladov <aleksey.kladov@gmail.com>
Date: Wed, 10 Jun 2020 12:08:35 +0200
Subject: Reduce OUT_DIR special casing

---
 crates/ra_project_model/src/lib.rs         | 20 ++++++----------
 crates/rust-analyzer/src/cli/load_cargo.rs | 38 +++++++++++++++---------------
 crates/rust-analyzer/src/global_state.rs   | 35 +++++++++++++--------------
 3 files changed, 43 insertions(+), 50 deletions(-)

(limited to 'crates')

diff --git a/crates/ra_project_model/src/lib.rs b/crates/ra_project_model/src/lib.rs
index c1f7e3ac5..cb0e27dce 100644
--- a/crates/ra_project_model/src/lib.rs
+++ b/crates/ra_project_model/src/lib.rs
@@ -47,17 +47,21 @@ pub struct PackageRoot {
     path: PathBuf,
     /// Is a member of the current workspace
     is_member: bool,
+    out_dir: Option<PathBuf>,
 }
 impl PackageRoot {
     pub fn new_member(path: PathBuf) -> PackageRoot {
-        Self { path, is_member: true }
+        Self { path, is_member: true, out_dir: None }
     }
     pub fn new_non_member(path: PathBuf) -> PackageRoot {
-        Self { path, is_member: false }
+        Self { path, is_member: false, out_dir: None }
     }
     pub fn path(&self) -> &Path {
         &self.path
     }
+    pub fn out_dir(&self) -> Option<&Path> {
+        self.out_dir.as_deref()
+    }
     pub fn is_member(&self) -> bool {
         self.is_member
     }
@@ -204,6 +208,7 @@ impl ProjectWorkspace {
                 .map(|pkg| PackageRoot {
                     path: cargo[pkg].root().to_path_buf(),
                     is_member: cargo[pkg].is_member,
+                    out_dir: cargo[pkg].out_dir.clone(),
                 })
                 .chain(sysroot.crates().map(|krate| {
                     PackageRoot::new_non_member(sysroot[krate].root_dir().to_path_buf())
@@ -212,17 +217,6 @@ impl ProjectWorkspace {
         }
     }
 
-    pub fn out_dirs(&self) -> Vec<PathBuf> {
-        match self {
-            ProjectWorkspace::Json { project } => {
-                project.crates.iter().filter_map(|krate| krate.out_dir.as_ref()).cloned().collect()
-            }
-            ProjectWorkspace::Cargo { cargo, sysroot: _ } => {
-                cargo.packages().filter_map(|pkg| cargo[pkg].out_dir.as_ref()).cloned().collect()
-            }
-        }
-    }
-
     pub fn proc_macro_dylib_paths(&self) -> Vec<PathBuf> {
         match self {
             ProjectWorkspace::Json { project } => project
diff --git a/crates/rust-analyzer/src/cli/load_cargo.rs b/crates/rust-analyzer/src/cli/load_cargo.rs
index 8f2aeac77..45af96317 100644
--- a/crates/rust-analyzer/src/cli/load_cargo.rs
+++ b/crates/rust-analyzer/src/cli/load_cargo.rs
@@ -36,28 +36,28 @@ pub fn load_cargo(
     )?;
 
     let mut extern_dirs = FxHashSet::default();
-    extern_dirs.extend(ws.out_dirs());
-
-    let mut project_roots = ws.to_roots();
-    project_roots.extend(extern_dirs.iter().cloned().map(PackageRoot::new_non_member));
 
     let (sender, receiver) = unbounded();
     let sender = Box::new(move |t| sender.send(t).unwrap());
-    let (mut vfs, roots) = Vfs::new(
-        project_roots
-            .iter()
-            .map(|pkg_root| {
-                RootEntry::new(
-                    pkg_root.path().to_owned(),
-                    RustPackageFilterBuilder::default()
-                        .set_member(pkg_root.is_member())
-                        .into_vfs_filter(),
-                )
-            })
-            .collect(),
-        sender,
-        Watch(false),
-    );
+
+    let mut roots = Vec::new();
+    let project_roots = ws.to_roots();
+    for root in &project_roots {
+        roots.push(RootEntry::new(
+            root.path().to_owned(),
+            RustPackageFilterBuilder::default().set_member(root.is_member()).into_vfs_filter(),
+        ));
+
+        if let Some(out_dir) = root.out_dir() {
+            extern_dirs.insert(out_dir.to_path_buf());
+            roots.push(RootEntry::new(
+                out_dir.to_owned(),
+                RustPackageFilterBuilder::default().set_member(root.is_member()).into_vfs_filter(),
+            ))
+        }
+    }
+
+    let (mut vfs, roots) = Vfs::new(roots, sender, Watch(false));
 
     let source_roots = roots
         .into_iter()
diff --git a/crates/rust-analyzer/src/global_state.rs b/crates/rust-analyzer/src/global_state.rs
index 73b0f881d..96d91b12d 100644
--- a/crates/rust-analyzer/src/global_state.rs
+++ b/crates/rust-analyzer/src/global_state.rs
@@ -89,8 +89,7 @@ impl GlobalState {
     ) -> GlobalState {
         let mut change = AnalysisChange::new();
 
-        let extern_dirs: FxHashSet<_> =
-            workspaces.iter().flat_map(ProjectWorkspace::out_dirs).collect();
+        let mut extern_dirs: FxHashSet<PathBuf> = FxHashSet::default();
 
         let mut local_roots = Vec::new();
         let roots: Vec<_> = {
@@ -100,22 +99,22 @@ impl GlobalState {
                     .exclude(exclude_globs.iter().cloned())
                     .into_vfs_filter()
             };
-            workspaces
-                .iter()
-                .flat_map(ProjectWorkspace::to_roots)
-                .map(|pkg_root| {
-                    let path = pkg_root.path().to_owned();
-                    if pkg_root.is_member() {
-                        local_roots.push(path.clone());
-                    }
-                    RootEntry::new(path, create_filter(pkg_root.is_member()))
-                })
-                .chain(
-                    extern_dirs
-                        .iter()
-                        .map(|path| RootEntry::new(path.to_owned(), create_filter(false))),
-                )
-                .collect()
+            let mut roots = Vec::new();
+            for root in workspaces.iter().flat_map(ProjectWorkspace::to_roots) {
+                let path = root.path().to_owned();
+                if root.is_member() {
+                    local_roots.push(path.clone());
+                }
+                roots.push(RootEntry::new(path, create_filter(root.is_member())));
+                if let Some(out_dir) = root.out_dir() {
+                    extern_dirs.insert(out_dir.to_path_buf());
+                    roots.push(RootEntry::new(
+                        out_dir.to_path_buf(),
+                        create_filter(root.is_member()),
+                    ))
+                }
+            }
+            roots
         };
 
         let (task_sender, task_receiver) = unbounded();
-- 
cgit v1.2.3