aboutsummaryrefslogtreecommitdiff
path: root/crates/rust-analyzer/src/cli/load_cargo.rs
diff options
context:
space:
mode:
authorAleksey Kladov <[email protected]>2020-06-11 10:04:09 +0100
committerAleksey Kladov <[email protected]>2020-06-23 16:51:06 +0100
commitdad1333b48c38bc7a5628fc0ff5304d003776a85 (patch)
tree29be52a980b4cae72f46a48c48135a15e31641e0 /crates/rust-analyzer/src/cli/load_cargo.rs
parent7aa66371ee3e8b31217513204c8b4f683584419d (diff)
New VFS
Diffstat (limited to 'crates/rust-analyzer/src/cli/load_cargo.rs')
-rw-r--r--crates/rust-analyzer/src/cli/load_cargo.rs166
1 files changed, 53 insertions, 113 deletions
diff --git a/crates/rust-analyzer/src/cli/load_cargo.rs b/crates/rust-analyzer/src/cli/load_cargo.rs
index 97367d7c6..00bbbaf40 100644
--- a/crates/rust-analyzer/src/cli/load_cargo.rs
+++ b/crates/rust-analyzer/src/cli/load_cargo.rs
@@ -1,32 +1,21 @@
1//! Loads a Cargo project into a static instance of analysis, without support 1//! Loads a Cargo project into a static instance of analysis, without support
2//! for incorporating changes. 2//! for incorporating changes.
3 3use std::{convert::TryFrom, path::Path, sync::Arc};
4use std::path::{Path, PathBuf};
5 4
6use anyhow::Result; 5use anyhow::Result;
7use crossbeam_channel::{unbounded, Receiver}; 6use crossbeam_channel::{unbounded, Receiver};
8use ra_db::{ExternSourceId, FileId, SourceRootId}; 7use ra_db::{AbsPathBuf, CrateGraph};
9use ra_ide::{AnalysisChange, AnalysisHost}; 8use ra_ide::{AnalysisChange, AnalysisHost};
10use ra_project_model::{ 9use ra_project_model::{CargoConfig, ProcMacroClient, ProjectManifest, ProjectWorkspace};
11 CargoConfig, PackageRoot, ProcMacroClient, ProjectManifest, ProjectWorkspace, 10use vfs::loader::Handle;
12};
13use ra_vfs::{RootEntry, Vfs, VfsChange, VfsTask, Watch};
14use rustc_hash::{FxHashMap, FxHashSet};
15
16use crate::vfs_glob::RustPackageFilterBuilder;
17 11
18fn vfs_file_to_id(f: ra_vfs::VfsFile) -> FileId { 12use crate::global_state::{ProjectFolders, SourceRootConfig};
19 FileId(f.0)
20}
21fn vfs_root_to_id(r: ra_vfs::VfsRoot) -> SourceRootId {
22 SourceRootId(r.0)
23}
24 13
25pub fn load_cargo( 14pub fn load_cargo(
26 root: &Path, 15 root: &Path,
27 load_out_dirs_from_check: bool, 16 load_out_dirs_from_check: bool,
28 with_proc_macro: bool, 17 with_proc_macro: bool,
29) -> Result<(AnalysisHost, FxHashMap<SourceRootId, PackageRoot>)> { 18) -> Result<(AnalysisHost, vfs::Vfs)> {
30 let root = std::env::current_dir()?.join(root); 19 let root = std::env::current_dir()?.join(root);
31 let root = ProjectManifest::discover_single(&root)?; 20 let root = ProjectManifest::discover_single(&root)?;
32 let ws = ProjectWorkspace::load( 21 let ws = ProjectWorkspace::load(
@@ -35,123 +24,74 @@ pub fn load_cargo(
35 true, 24 true,
36 )?; 25 )?;
37 26
38 let mut extern_dirs = FxHashSet::default();
39
40 let (sender, receiver) = unbounded(); 27 let (sender, receiver) = unbounded();
41 let sender = Box::new(move |t| sender.send(t).unwrap()); 28 let mut vfs = vfs::Vfs::default();
42 29 let mut loader = {
43 let mut roots = Vec::new(); 30 let loader =
44 let project_roots = ws.to_roots(); 31 vfs_notify::LoaderHandle::spawn(Box::new(move |msg| sender.send(msg).unwrap()));
45 for root in &project_roots { 32 Box::new(loader)
46 roots.push(RootEntry::new( 33 };
47 root.path().to_owned(),
48 RustPackageFilterBuilder::default().set_member(root.is_member()).into_vfs_filter(),
49 ));
50
51 if let Some(out_dir) = root.out_dir() {
52 extern_dirs.insert(out_dir.to_path_buf());
53 roots.push(RootEntry::new(
54 out_dir.to_owned(),
55 RustPackageFilterBuilder::default().set_member(root.is_member()).into_vfs_filter(),
56 ))
57 }
58 }
59
60 let (mut vfs, roots) = Vfs::new(roots, sender, Watch(false));
61
62 let source_roots = roots
63 .into_iter()
64 .map(|vfs_root| {
65 let source_root_id = vfs_root_to_id(vfs_root);
66 let project_root = project_roots
67 .iter()
68 .find(|it| it.path() == vfs.root2path(vfs_root))
69 .unwrap()
70 .clone();
71 (source_root_id, project_root)
72 })
73 .collect::<FxHashMap<_, _>>();
74 34
75 let proc_macro_client = if !with_proc_macro { 35 let proc_macro_client = if with_proc_macro {
76 ProcMacroClient::dummy()
77 } else {
78 let path = std::env::current_exe()?; 36 let path = std::env::current_exe()?;
79 ProcMacroClient::extern_process(path, &["proc-macro"]).unwrap() 37 ProcMacroClient::extern_process(path, &["proc-macro"]).unwrap()
38 } else {
39 ProcMacroClient::dummy()
80 }; 40 };
81 let host = load(&source_roots, ws, &mut vfs, receiver, extern_dirs, &proc_macro_client); 41
82 Ok((host, source_roots)) 42 let crate_graph = ws.to_crate_graph(None, &proc_macro_client, &mut |path: &Path| {
43 let path = AbsPathBuf::try_from(path.to_path_buf()).unwrap();
44 let contents = loader.load_sync(&path);
45 let path = vfs::VfsPath::from(path);
46 vfs.set_file_contents(path.clone(), contents);
47 vfs.file_id(&path)
48 });
49
50 let project_folders = ProjectFolders::new(&[ws]);
51 loader.set_config(vfs::loader::Config { load: project_folders.load, watch: vec![] });
52
53 log::debug!("crate graph: {:?}", crate_graph);
54 let host = load(crate_graph, project_folders.source_root_config, &mut vfs, &receiver);
55 Ok((host, vfs))
83} 56}
84 57
85pub(crate) fn load( 58pub(crate) fn load(
86 source_roots: &FxHashMap<SourceRootId, PackageRoot>, 59 crate_graph: CrateGraph,
87 ws: ProjectWorkspace, 60 source_root_config: SourceRootConfig,
88 vfs: &mut Vfs, 61 vfs: &mut vfs::Vfs,
89 receiver: Receiver<VfsTask>, 62 receiver: &Receiver<vfs::loader::Message>,
90 extern_dirs: FxHashSet<PathBuf>,
91 proc_macro_client: &ProcMacroClient,
92) -> AnalysisHost { 63) -> AnalysisHost {
93 let lru_cap = std::env::var("RA_LRU_CAP").ok().and_then(|it| it.parse::<usize>().ok()); 64 let lru_cap = std::env::var("RA_LRU_CAP").ok().and_then(|it| it.parse::<usize>().ok());
94 let mut host = AnalysisHost::new(lru_cap); 65 let mut host = AnalysisHost::new(lru_cap);
95 let mut analysis_change = AnalysisChange::new(); 66 let mut analysis_change = AnalysisChange::new();
96 67
97 // wait until Vfs has loaded all roots 68 // wait until Vfs has loaded all roots
98 let mut roots_loaded = FxHashSet::default();
99 let mut extern_source_roots = FxHashMap::default();
100 for task in receiver { 69 for task in receiver {
101 vfs.handle_task(task); 70 match task {
102 let mut done = false; 71 vfs::loader::Message::Progress { n_entries_done, n_entries_total } => {
103 for change in vfs.commit_changes() { 72 if n_entries_done == n_entries_total {
104 match change { 73 break;
105 VfsChange::AddRoot { root, files } => {
106 let source_root_id = vfs_root_to_id(root);
107 let is_local = source_roots[&source_root_id].is_member();
108 log::debug!(
109 "loaded source root {:?} with path {:?}",
110 source_root_id,
111 vfs.root2path(root)
112 );
113 analysis_change.add_root(source_root_id, is_local);
114
115 let vfs_root_path = vfs.root2path(root);
116 if extern_dirs.contains(&vfs_root_path) {
117 extern_source_roots.insert(vfs_root_path, ExternSourceId(root.0));
118 }
119
120 let mut file_map = FxHashMap::default();
121 for (vfs_file, path, text) in files {
122 let file_id = vfs_file_to_id(vfs_file);
123 analysis_change.add_file(source_root_id, file_id, path.clone(), text);
124 file_map.insert(path, file_id);
125 }
126 roots_loaded.insert(source_root_id);
127 if roots_loaded.len() == vfs.n_roots() {
128 done = true;
129 }
130 }
131 VfsChange::AddFile { root, file, path, text } => {
132 let source_root_id = vfs_root_to_id(root);
133 let file_id = vfs_file_to_id(file);
134 analysis_change.add_file(source_root_id, file_id, path, text);
135 } 74 }
136 VfsChange::RemoveFile { .. } | VfsChange::ChangeFile { .. } => { 75 }
137 // We just need the first scan, so just ignore these 76 vfs::loader::Message::Loaded { files } => {
77 for (path, contents) in files {
78 vfs.set_file_contents(path.into(), contents)
138 } 79 }
139 } 80 }
140 } 81 }
141 if done { 82 }
142 break; 83 let changes = vfs.take_changes();
84 for file in changes {
85 if file.exists() {
86 let contents = vfs.file_contents(file.file_id).to_vec();
87 if let Ok(text) = String::from_utf8(contents) {
88 analysis_change.change_file(file.file_id, Some(Arc::new(text)))
89 }
143 } 90 }
144 } 91 }
92 let source_roots = source_root_config.partition(&vfs);
93 analysis_change.set_roots(source_roots);
145 94
146 let crate_graph =
147 ws.to_crate_graph(None, &extern_source_roots, proc_macro_client, &mut |path: &Path| {
148 // Some path from metadata will be non canonicalized, e.g. /foo/../bar/lib.rs
149 let path = path.canonicalize().ok()?;
150 let vfs_file = vfs.load(&path);
151 log::debug!("vfs file {:?} -> {:?}", path, vfs_file);
152 vfs_file.map(vfs_file_to_id)
153 });
154 log::debug!("crate graph: {:?}", crate_graph);
155 analysis_change.set_crate_graph(crate_graph); 95 analysis_change.set_crate_graph(crate_graph);
156 96
157 host.apply_change(analysis_change); 97 host.apply_change(analysis_change);
@@ -167,7 +107,7 @@ mod tests {
167 #[test] 107 #[test]
168 fn test_loading_rust_analyzer() { 108 fn test_loading_rust_analyzer() {
169 let path = Path::new(env!("CARGO_MANIFEST_DIR")).parent().unwrap().parent().unwrap(); 109 let path = Path::new(env!("CARGO_MANIFEST_DIR")).parent().unwrap().parent().unwrap();
170 let (host, _roots) = load_cargo(path, false, false).unwrap(); 110 let (host, _vfs) = load_cargo(path, false, false).unwrap();
171 let n_crates = Crate::all(host.raw_database()).len(); 111 let n_crates = Crate::all(host.raw_database()).len();
172 // RA has quite a few crates, but the exact count doesn't matter 112 // RA has quite a few crates, but the exact count doesn't matter
173 assert!(n_crates > 20); 113 assert!(n_crates > 20);