aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_batch/src
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_batch/src')
-rw-r--r--crates/ra_batch/src/lib.rs176
-rw-r--r--crates/ra_batch/src/vfs_filter.rs108
2 files changed, 134 insertions, 150 deletions
diff --git a/crates/ra_batch/src/lib.rs b/crates/ra_batch/src/lib.rs
index 96b32d9fe..43d3fb7e3 100644
--- a/crates/ra_batch/src/lib.rs
+++ b/crates/ra_batch/src/lib.rs
@@ -1,36 +1,19 @@
1mod vfs_filter; 1mod vfs_filter;
2 2
3use std::{sync::Arc, path::Path, collections::HashSet, error::Error}; 3use std::{path::Path, collections::HashSet, error::Error};
4 4
5use rustc_hash::FxHashMap; 5use rustc_hash::FxHashMap;
6 6
7use ra_db::{ 7use ra_db::{
8 CrateGraph, FileId, SourceRoot, SourceRootId, SourceDatabase, salsa::{self, Database}, 8 CrateGraph, FileId, SourceRootId,
9}; 9};
10use ra_hir::db; 10use ra_ide_api::{AnalysisHost, AnalysisChange};
11use ra_project_model::ProjectWorkspace; 11use ra_project_model::{ProjectWorkspace, ProjectRoot};
12use ra_vfs::{Vfs, VfsChange}; 12use ra_vfs::{Vfs, VfsChange};
13use vfs_filter::IncludeRustFiles; 13use vfs_filter::IncludeRustFiles;
14 14
15type Result<T> = std::result::Result<T, Box<dyn Error + Send + Sync>>; 15type Result<T> = std::result::Result<T, Box<dyn Error + Send + Sync>>;
16 16
17#[salsa::database(
18 ra_db::SourceDatabaseStorage,
19 db::AstDatabaseStorage,
20 db::DefDatabaseStorage,
21 db::HirDatabaseStorage
22)]
23#[derive(Debug)]
24pub struct BatchDatabase {
25 runtime: salsa::Runtime<BatchDatabase>,
26}
27
28impl salsa::Database for BatchDatabase {
29 fn salsa_runtime(&self) -> &salsa::Runtime<BatchDatabase> {
30 &self.runtime
31 }
32}
33
34fn vfs_file_to_id(f: ra_vfs::VfsFile) -> FileId { 17fn vfs_file_to_id(f: ra_vfs::VfsFile) -> FileId {
35 FileId(f.0) 18 FileId(f.0)
36} 19}
@@ -38,86 +21,87 @@ fn vfs_root_to_id(r: ra_vfs::VfsRoot) -> SourceRootId {
38 SourceRootId(r.0) 21 SourceRootId(r.0)
39} 22}
40 23
41impl BatchDatabase { 24pub fn load_cargo(root: &Path) -> Result<(AnalysisHost, FxHashMap<SourceRootId, ProjectRoot>)> {
42 pub fn load(crate_graph: CrateGraph, vfs: &mut Vfs) -> BatchDatabase { 25 let root = std::env::current_dir()?.join(root);
43 let mut db = BatchDatabase { runtime: salsa::Runtime::default() }; 26 let ws = ProjectWorkspace::discover(root.as_ref())?;
44 let lru_cap = std::env::var("RA_LRU_CAP") 27 let project_roots = ws.to_roots();
45 .ok() 28 let (mut vfs, roots) = Vfs::new(IncludeRustFiles::from_roots(project_roots.clone()).collect());
46 .and_then(|it| it.parse::<usize>().ok()) 29 let crate_graph = ws.to_crate_graph(&mut |path: &Path| {
47 .unwrap_or(ra_db::DEFAULT_LRU_CAP); 30 let vfs_file = vfs.load(path);
48 db.query_mut(ra_db::ParseQuery).set_lru_capacity(lru_cap); 31 log::debug!("vfs file {:?} -> {:?}", path, vfs_file);
49 db.query_mut(ra_hir::db::ParseMacroQuery).set_lru_capacity(lru_cap); 32 vfs_file.map(vfs_file_to_id)
50 db.set_crate_graph(Arc::new(crate_graph)); 33 });
34 log::debug!("crate graph: {:?}", crate_graph);
35
36 let source_roots = roots
37 .iter()
38 .map(|&vfs_root| {
39 let source_root_id = vfs_root_to_id(vfs_root);
40 let project_root = project_roots
41 .iter()
42 .find(|it| it.path() == &vfs.root2path(vfs_root))
43 .unwrap()
44 .clone();
45 (source_root_id, project_root)
46 })
47 .collect::<FxHashMap<_, _>>();
48 let host = load(&source_roots, crate_graph, &mut vfs);
49 Ok((host, source_roots))
50}
51 51
52 // wait until Vfs has loaded all roots 52pub fn load(
53 let receiver = vfs.task_receiver().clone(); 53 source_roots: &FxHashMap<SourceRootId, ProjectRoot>,
54 let mut roots_loaded = HashSet::new(); 54 crate_graph: CrateGraph,
55 for task in receiver { 55 vfs: &mut Vfs,
56 vfs.handle_task(task); 56) -> AnalysisHost {
57 let mut done = false; 57 let lru_cap = std::env::var("RA_LRU_CAP").ok().and_then(|it| it.parse::<usize>().ok());
58 for change in vfs.commit_changes() { 58 let mut host = AnalysisHost::new(lru_cap);
59 match change { 59 let mut analysis_change = AnalysisChange::new();
60 VfsChange::AddRoot { root, files } => { 60 analysis_change.set_crate_graph(crate_graph);
61 let source_root_id = vfs_root_to_id(root); 61
62 log::debug!( 62 // wait until Vfs has loaded all roots
63 "loaded source root {:?} with path {:?}", 63 let receiver = vfs.task_receiver().clone();
64 source_root_id, 64 let mut roots_loaded = HashSet::new();
65 vfs.root2path(root) 65 for task in receiver {
66 ); 66 vfs.handle_task(task);
67 let mut file_map = FxHashMap::default(); 67 let mut done = false;
68 for (vfs_file, path, text) in files { 68 for change in vfs.commit_changes() {
69 let file_id = vfs_file_to_id(vfs_file); 69 match change {
70 db.set_file_text(file_id, text); 70 VfsChange::AddRoot { root, files } => {
71 db.set_file_relative_path(file_id, path.clone()); 71 let source_root_id = vfs_root_to_id(root);
72 db.set_file_source_root(file_id, source_root_id); 72 let is_local = source_roots[&source_root_id].is_member();
73 file_map.insert(path, file_id); 73 log::debug!(
74 } 74 "loaded source root {:?} with path {:?}",
75 let source_root = SourceRoot { files: file_map }; 75 source_root_id,
76 db.set_source_root(source_root_id, Arc::new(source_root)); 76 vfs.root2path(root)
77 roots_loaded.insert(source_root_id); 77 );
78 if roots_loaded.len() == vfs.n_roots() { 78 analysis_change.add_root(source_root_id, is_local);
79 done = true; 79
80 } 80 let mut file_map = FxHashMap::default();
81 for (vfs_file, path, text) in files {
82 let file_id = vfs_file_to_id(vfs_file);
83 analysis_change.add_file(source_root_id, file_id, path.clone(), text);
84 file_map.insert(path, file_id);
81 } 85 }
82 VfsChange::AddFile { .. } 86 roots_loaded.insert(source_root_id);
83 | VfsChange::RemoveFile { .. } 87 if roots_loaded.len() == vfs.n_roots() {
84 | VfsChange::ChangeFile { .. } => { 88 done = true;
85 // We just need the first scan, so just ignore these
86 } 89 }
87 } 90 }
88 } 91 VfsChange::AddFile { .. }
89 if done { 92 | VfsChange::RemoveFile { .. }
90 break; 93 | VfsChange::ChangeFile { .. } => {
94 // We just need the first scan, so just ignore these
95 }
91 } 96 }
92 } 97 }
93 98 if done {
94 db 99 break;
100 }
95 } 101 }
96 102
97 pub fn load_cargo(root: impl AsRef<Path>) -> Result<(BatchDatabase, Vec<SourceRootId>)> { 103 host.apply_change(analysis_change);
98 let root = std::env::current_dir()?.join(root); 104 host
99 let ws = ProjectWorkspace::discover(root.as_ref())?;
100 let mut roots = Vec::new();
101 roots.push(IncludeRustFiles::member(root.clone()));
102 roots.extend(IncludeRustFiles::from_roots(ws.to_roots()));
103 let (mut vfs, roots) = Vfs::new(roots);
104 let mut load = |path: &Path| {
105 let vfs_file = vfs.load(path);
106 log::debug!("vfs file {:?} -> {:?}", path, vfs_file);
107 vfs_file.map(vfs_file_to_id)
108 };
109 let crate_graph = ws.to_crate_graph(&mut load);
110 log::debug!("crate graph: {:?}", crate_graph);
111
112 let local_roots = roots
113 .into_iter()
114 .filter(|r| vfs.root2path(*r).starts_with(&root))
115 .map(vfs_root_to_id)
116 .collect();
117
118 let db = BatchDatabase::load(crate_graph, &mut vfs);
119 Ok((db, local_roots))
120 }
121} 105}
122 106
123#[cfg(test)] 107#[cfg(test)]
@@ -128,10 +112,10 @@ mod tests {
128 #[test] 112 #[test]
129 fn test_loading_rust_analyzer() { 113 fn test_loading_rust_analyzer() {
130 let path = Path::new(env!("CARGO_MANIFEST_DIR")).parent().unwrap().parent().unwrap(); 114 let path = Path::new(env!("CARGO_MANIFEST_DIR")).parent().unwrap().parent().unwrap();
131 let (db, roots) = BatchDatabase::load_cargo(path).unwrap(); 115 let (host, roots) = load_cargo(path).unwrap();
132 let mut n_crates = 0; 116 let mut n_crates = 0;
133 for root in roots { 117 for (root, _) in roots {
134 for _krate in Crate::source_root_crates(&db, root) { 118 for _krate in Crate::source_root_crates(host.raw_database(), root) {
135 n_crates += 1; 119 n_crates += 1;
136 } 120 }
137 } 121 }
diff --git a/crates/ra_batch/src/vfs_filter.rs b/crates/ra_batch/src/vfs_filter.rs
index dd20c1203..8552ac999 100644
--- a/crates/ra_batch/src/vfs_filter.rs
+++ b/crates/ra_batch/src/vfs_filter.rs
@@ -1,54 +1,54 @@
1use std::path::PathBuf; 1use std::path::PathBuf;
2use ra_project_model::ProjectRoot; 2use ra_project_model::ProjectRoot;
3use ra_vfs::{RootEntry, Filter, RelativePath}; 3use ra_vfs::{RootEntry, Filter, RelativePath};
4 4
5/// `IncludeRustFiles` is used to convert 5/// `IncludeRustFiles` is used to convert
6/// from `ProjectRoot` to `RootEntry` for VFS 6/// from `ProjectRoot` to `RootEntry` for VFS
7pub struct IncludeRustFiles { 7pub struct IncludeRustFiles {
8 root: ProjectRoot, 8 root: ProjectRoot,
9} 9}
10 10
11impl IncludeRustFiles { 11impl IncludeRustFiles {
12 pub fn from_roots<R>(roots: R) -> impl Iterator<Item = RootEntry> 12 pub fn from_roots<R>(roots: R) -> impl Iterator<Item = RootEntry>
13 where 13 where
14 R: IntoIterator<Item = ProjectRoot>, 14 R: IntoIterator<Item = ProjectRoot>,
15 { 15 {
16 roots.into_iter().map(IncludeRustFiles::from_root) 16 roots.into_iter().map(IncludeRustFiles::from_root)
17 } 17 }
18 18
19 pub fn from_root(root: ProjectRoot) -> RootEntry { 19 pub fn from_root(root: ProjectRoot) -> RootEntry {
20 IncludeRustFiles::from(root).into() 20 IncludeRustFiles::from(root).into()
21 } 21 }
22 22
23 #[allow(unused)] 23 #[allow(unused)]
24 pub fn external(path: PathBuf) -> RootEntry { 24 pub fn external(path: PathBuf) -> RootEntry {
25 IncludeRustFiles::from_root(ProjectRoot::new(path, false)) 25 IncludeRustFiles::from_root(ProjectRoot::new(path, false))
26 } 26 }
27 27
28 pub fn member(path: PathBuf) -> RootEntry { 28 pub fn member(path: PathBuf) -> RootEntry {
29 IncludeRustFiles::from_root(ProjectRoot::new(path, true)) 29 IncludeRustFiles::from_root(ProjectRoot::new(path, true))
30 } 30 }
31} 31}
32 32
33impl Filter for IncludeRustFiles { 33impl Filter for IncludeRustFiles {
34 fn include_dir(&self, dir_path: &RelativePath) -> bool { 34 fn include_dir(&self, dir_path: &RelativePath) -> bool {
35 self.root.include_dir(dir_path) 35 self.root.include_dir(dir_path)
36 } 36 }
37 37
38 fn include_file(&self, file_path: &RelativePath) -> bool { 38 fn include_file(&self, file_path: &RelativePath) -> bool {
39 self.root.include_file(file_path) 39 self.root.include_file(file_path)
40 } 40 }
41} 41}
42 42
43impl std::convert::From<ProjectRoot> for IncludeRustFiles { 43impl From<ProjectRoot> for IncludeRustFiles {
44 fn from(v: ProjectRoot) -> IncludeRustFiles { 44 fn from(v: ProjectRoot) -> IncludeRustFiles {
45 IncludeRustFiles { root: v } 45 IncludeRustFiles { root: v }
46 } 46 }
47} 47}
48 48
49impl std::convert::From<IncludeRustFiles> for RootEntry { 49impl From<IncludeRustFiles> for RootEntry {
50 fn from(v: IncludeRustFiles) -> RootEntry { 50 fn from(v: IncludeRustFiles) -> RootEntry {
51 let path = v.root.path().clone(); 51 let path = v.root.path().clone();
52 RootEntry::new(path, Box::new(v)) 52 RootEntry::new(path, Box::new(v))
53 } 53 }
54} 54}