diff options
author | Aleksey Kladov <[email protected]> | 2020-06-11 10:04:09 +0100 |
---|---|---|
committer | Aleksey Kladov <[email protected]> | 2020-06-23 16:51:06 +0100 |
commit | dad1333b48c38bc7a5628fc0ff5304d003776a85 (patch) | |
tree | 29be52a980b4cae72f46a48c48135a15e31641e0 /crates/rust-analyzer/src/cli/load_cargo.rs | |
parent | 7aa66371ee3e8b31217513204c8b4f683584419d (diff) |
New VFS
Diffstat (limited to 'crates/rust-analyzer/src/cli/load_cargo.rs')
-rw-r--r-- | crates/rust-analyzer/src/cli/load_cargo.rs | 166 |
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 | 3 | use std::{convert::TryFrom, path::Path, sync::Arc}; | |
4 | use std::path::{Path, PathBuf}; | ||
5 | 4 | ||
6 | use anyhow::Result; | 5 | use anyhow::Result; |
7 | use crossbeam_channel::{unbounded, Receiver}; | 6 | use crossbeam_channel::{unbounded, Receiver}; |
8 | use ra_db::{ExternSourceId, FileId, SourceRootId}; | 7 | use ra_db::{AbsPathBuf, CrateGraph}; |
9 | use ra_ide::{AnalysisChange, AnalysisHost}; | 8 | use ra_ide::{AnalysisChange, AnalysisHost}; |
10 | use ra_project_model::{ | 9 | use ra_project_model::{CargoConfig, ProcMacroClient, ProjectManifest, ProjectWorkspace}; |
11 | CargoConfig, PackageRoot, ProcMacroClient, ProjectManifest, ProjectWorkspace, | 10 | use vfs::loader::Handle; |
12 | }; | ||
13 | use ra_vfs::{RootEntry, Vfs, VfsChange, VfsTask, Watch}; | ||
14 | use rustc_hash::{FxHashMap, FxHashSet}; | ||
15 | |||
16 | use crate::vfs_glob::RustPackageFilterBuilder; | ||
17 | 11 | ||
18 | fn vfs_file_to_id(f: ra_vfs::VfsFile) -> FileId { | 12 | use crate::global_state::{ProjectFolders, SourceRootConfig}; |
19 | FileId(f.0) | ||
20 | } | ||
21 | fn vfs_root_to_id(r: ra_vfs::VfsRoot) -> SourceRootId { | ||
22 | SourceRootId(r.0) | ||
23 | } | ||
24 | 13 | ||
25 | pub fn load_cargo( | 14 | pub 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 | ||
85 | pub(crate) fn load( | 58 | pub(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); |