aboutsummaryrefslogtreecommitdiff
path: root/crates/libanalysis/src/lib.rs
diff options
context:
space:
mode:
Diffstat (limited to 'crates/libanalysis/src/lib.rs')
-rw-r--r--crates/libanalysis/src/lib.rs124
1 files changed, 84 insertions, 40 deletions
diff --git a/crates/libanalysis/src/lib.rs b/crates/libanalysis/src/lib.rs
index 63c4c77cf..d01144627 100644
--- a/crates/libanalysis/src/lib.rs
+++ b/crates/libanalysis/src/lib.rs
@@ -10,16 +10,18 @@ extern crate fst;
10extern crate rayon; 10extern crate rayon;
11 11
12mod symbol_index; 12mod symbol_index;
13mod module_map;
13 14
14use once_cell::sync::OnceCell; 15use once_cell::sync::OnceCell;
15use rayon::prelude::*; 16use rayon::prelude::*;
16 17
17use std::{ 18use std::{
18 fmt, 19 fmt,
19 path::{Path, PathBuf}, 20 mem,
21 path::{Path},
20 sync::{ 22 sync::{
21 Arc, 23 Arc,
22 atomic::{AtomicUsize, Ordering::SeqCst}, 24 atomic::{AtomicBool, Ordering::SeqCst},
23 }, 25 },
24 collections::hash_map::HashMap, 26 collections::hash_map::HashMap,
25 time::Instant, 27 time::Instant,
@@ -32,7 +34,10 @@ use libsyntax2::{
32}; 34};
33use libeditor::{LineIndex, FileSymbol, find_node}; 35use libeditor::{LineIndex, FileSymbol, find_node};
34 36
35use self::symbol_index::FileSymbols; 37use self::{
38 symbol_index::FileSymbols,
39 module_map::ModuleMap,
40};
36pub use self::symbol_index::Query; 41pub use self::symbol_index::Query;
37 42
38pub type Result<T> = ::std::result::Result<T, ::failure::Error>; 43pub type Result<T> = ::std::result::Result<T, ::failure::Error>;
@@ -42,11 +47,12 @@ pub type FileResolver = dyn Fn(FileId, &Path) -> Option<FileId> + Send + Sync;
42 47
43#[derive(Debug)] 48#[derive(Debug)]
44pub struct WorldState { 49pub struct WorldState {
50 updates: Vec<FileId>,
45 data: Arc<WorldData> 51 data: Arc<WorldData>
46} 52}
47 53
48#[derive(Clone)]
49pub struct World { 54pub struct World {
55 needs_reindex: AtomicBool,
50 file_resolver: Arc<FileResolver>, 56 file_resolver: Arc<FileResolver>,
51 data: Arc<WorldData>, 57 data: Arc<WorldData>,
52} 58}
@@ -57,18 +63,48 @@ impl fmt::Debug for World {
57 } 63 }
58} 64}
59 65
66impl Clone for World {
67 fn clone(&self) -> World {
68 World {
69 needs_reindex: AtomicBool::new(self.needs_reindex.load(SeqCst)),
70 file_resolver: Arc::clone(&self.file_resolver),
71 data: Arc::clone(&self.data),
72 }
73 }
74}
75
60#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] 76#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
61pub struct FileId(pub u32); 77pub struct FileId(pub u32);
62 78
63impl WorldState { 79impl WorldState {
64 pub fn new() -> WorldState { 80 pub fn new() -> WorldState {
65 WorldState { 81 WorldState {
66 data: Arc::new(WorldData::default()) 82 updates: Vec::new(),
83 data: Arc::new(WorldData::default()),
67 } 84 }
68 } 85 }
69 86
70 pub fn snapshot(&self, file_resolver: impl Fn(FileId, &Path) -> Option<FileId> + 'static + Send + Sync) -> World { 87 pub fn snapshot(
88 &mut self,
89 file_resolver: impl Fn(FileId, &Path) -> Option<FileId> + 'static + Send + Sync,
90 ) -> World {
91 let needs_reindex = self.updates.len() >= INDEXING_THRESHOLD;
92 if !self.updates.is_empty() {
93 let updates = mem::replace(&mut self.updates, Vec::new());
94 let data = self.data_mut();
95 for file_id in updates {
96 let syntax = data.file_map
97 .get(&file_id)
98 .map(|it| it.syntax());
99 data.module_map.update_file(
100 file_id,
101 syntax,
102 &file_resolver,
103 );
104 }
105 }
71 World { 106 World {
107 needs_reindex: AtomicBool::new(needs_reindex),
72 file_resolver: Arc::new(file_resolver), 108 file_resolver: Arc::new(file_resolver),
73 data: self.data.clone() 109 data: self.data.clone()
74 } 110 }
@@ -79,28 +115,28 @@ impl WorldState {
79 } 115 }
80 116
81 pub fn change_files(&mut self, changes: impl Iterator<Item=(FileId, Option<String>)>) { 117 pub fn change_files(&mut self, changes: impl Iterator<Item=(FileId, Option<String>)>) {
82 let data = self.data_mut(); 118 let mut updates = Vec::new();
83 let mut cnt = 0; 119 {
84 for (id, text) in changes { 120 let data = self.data_mut();
85 cnt += 1; 121 for (file_id, text) in changes {
86 data.file_map.remove(&id); 122 data.file_map.remove(&file_id);
87 if let Some(text) = text { 123 if let Some(text) = text {
88 let file_data = FileData::new(text); 124 let file_data = FileData::new(text);
89 data.file_map.insert(id, Arc::new(file_data)); 125 data.file_map.insert(file_id, Arc::new(file_data));
90 } else { 126 } else {
91 data.file_map.remove(&id); 127 data.file_map.remove(&file_id);
128 }
129 updates.push(file_id);
92 } 130 }
93 } 131 }
94 *data.unindexed.get_mut() += cnt; 132 self.updates.extend(updates)
95 } 133 }
96 134
97 fn data_mut(&mut self) -> &mut WorldData { 135 fn data_mut(&mut self) -> &mut WorldData {
98 if Arc::get_mut(&mut self.data).is_none() { 136 if Arc::get_mut(&mut self.data).is_none() {
99 self.data = Arc::new(WorldData { 137 self.data = Arc::new(WorldData {
100 unindexed: AtomicUsize::new(
101 self.data.unindexed.load(SeqCst)
102 ),
103 file_map: self.data.file_map.clone(), 138 file_map: self.data.file_map.clone(),
139 module_map: self.data.module_map.clone(),
104 }); 140 });
105 } 141 }
106 Arc::get_mut(&mut self.data).unwrap() 142 Arc::get_mut(&mut self.data).unwrap()
@@ -131,6 +167,24 @@ impl World {
131 .collect() 167 .collect()
132 } 168 }
133 169
170 pub fn parent_module(&self, id: FileId) -> Vec<(FileId, FileSymbol)> {
171 let module_map = &self.data.module_map;
172 let id = module_map.file2module(id);
173 module_map
174 .parent_modules(id)
175 .into_iter()
176 .map(|(id, m)| {
177 let id = module_map.module2file(id);
178 let sym = FileSymbol {
179 name: m.name().unwrap().text(),
180 node_range: m.syntax().range(),
181 kind: MODULE,
182 };
183 (id, sym)
184 })
185 .collect()
186 }
187
134 pub fn approximately_resolve_symbol( 188 pub fn approximately_resolve_symbol(
135 &self, 189 &self,
136 id: FileId, 190 id: FileId,
@@ -178,32 +232,22 @@ impl World {
178 Some(name) => name.text(), 232 Some(name) => name.text(),
179 None => return Vec::new(), 233 None => return Vec::new(),
180 }; 234 };
181 let paths = &[ 235 let module_map = &self.data.module_map;
182 PathBuf::from(format!("../{}.rs", name)), 236 let id = module_map.file2module(id);
183 PathBuf::from(format!("../{}/mod.rs", name)), 237 module_map
184 ]; 238 .child_module_by_name(id, name.as_str())
185 paths.iter() 239 .into_iter()
186 .filter_map(|path| self.resolve_relative_path(id, path)) 240 .map(|id| module_map.module2file(id))
187 .collect() 241 .collect()
188 } 242 }
189 243
190 fn resolve_relative_path(&self, id: FileId, path: &Path) -> Option<FileId> {
191 (self.file_resolver)(id, path)
192 }
193
194 fn reindex(&self) { 244 fn reindex(&self) {
195 let data = &*self.data; 245 if self.needs_reindex.compare_and_swap(false, true, SeqCst) {
196 let unindexed = data.unindexed.load(SeqCst);
197 if unindexed < INDEXING_THRESHOLD {
198 return;
199 }
200 if unindexed == data.unindexed.compare_and_swap(unindexed, 0, SeqCst) {
201 let now = Instant::now(); 246 let now = Instant::now();
247 let data = &*self.data;
202 data.file_map 248 data.file_map
203 .par_iter() 249 .par_iter()
204 .for_each(|(_, data)| { 250 .for_each(|(_, data)| drop(data.symbols()));
205 data.symbols();
206 });
207 info!("parallel indexing took {:?}", now.elapsed()); 251 info!("parallel indexing took {:?}", now.elapsed());
208 } 252 }
209 } 253 }
@@ -218,8 +262,8 @@ impl World {
218 262
219#[derive(Default, Debug)] 263#[derive(Default, Debug)]
220struct WorldData { 264struct WorldData {
221 unindexed: AtomicUsize,
222 file_map: HashMap<FileId, Arc<FileData>>, 265 file_map: HashMap<FileId, Arc<FileData>>,
266 module_map: ModuleMap,
223} 267}
224 268
225#[derive(Debug)] 269#[derive(Debug)]