diff options
author | Aleksey Kladov <[email protected]> | 2018-09-02 18:08:58 +0100 |
---|---|---|
committer | Aleksey Kladov <[email protected]> | 2018-09-02 20:51:59 +0100 |
commit | 440dc41dd8f53876d0949272e76b1f560e10ec69 (patch) | |
tree | 55daf3b6e687be992e84845e813151daaec64267 | |
parent | e98d8cd255ab5c2fee873a58af6c2c3ad561dab4 (diff) |
Add source root
-rw-r--r-- | crates/libanalysis/src/imp.rs | 121 | ||||
-rw-r--r-- | crates/libanalysis/src/lib.rs | 5 | ||||
-rw-r--r-- | crates/libanalysis/src/module_map.rs | 2 | ||||
-rw-r--r-- | crates/libanalysis/src/roots.rs | 113 | ||||
-rw-r--r-- | crates/libanalysis/src/symbol_index.rs | 58 |
5 files changed, 167 insertions, 132 deletions
diff --git a/crates/libanalysis/src/imp.rs b/crates/libanalysis/src/imp.rs index b80ce1ab5..73a6f4306 100644 --- a/crates/libanalysis/src/imp.rs +++ b/crates/libanalysis/src/imp.rs | |||
@@ -4,13 +4,9 @@ use std::{ | |||
4 | atomic::{AtomicBool, Ordering::SeqCst}, | 4 | atomic::{AtomicBool, Ordering::SeqCst}, |
5 | }, | 5 | }, |
6 | fmt, | 6 | fmt, |
7 | time::Instant, | 7 | collections::{HashSet, VecDeque}, |
8 | collections::{HashMap, HashSet, VecDeque}, | ||
9 | panic, | ||
10 | }; | 8 | }; |
11 | 9 | ||
12 | use rayon::prelude::*; | ||
13 | use once_cell::sync::OnceCell; | ||
14 | use libeditor::{self, FileSymbol, LineIndex, find_node_at_offset, LocalEdit}; | 10 | use libeditor::{self, FileSymbol, LineIndex, find_node_at_offset, LocalEdit}; |
15 | use libsyntax2::{ | 11 | use libsyntax2::{ |
16 | TextUnit, TextRange, SmolStr, File, AstNode, | 12 | TextUnit, TextRange, SmolStr, File, AstNode, |
@@ -20,10 +16,9 @@ use libsyntax2::{ | |||
20 | 16 | ||
21 | use { | 17 | use { |
22 | FileId, FileResolver, Query, Diagnostic, SourceChange, SourceFileEdit, Position, FileSystemEdit, | 18 | FileId, FileResolver, Query, Diagnostic, SourceChange, SourceFileEdit, Position, FileSystemEdit, |
23 | module_map::Problem, | ||
24 | symbol_index::FileSymbols, | ||
25 | module_map::{ModuleMap, ChangeKind}, | ||
26 | JobToken, CrateGraph, CrateId, | 19 | JobToken, CrateGraph, CrateId, |
20 | module_map::Problem, | ||
21 | roots::SourceRoot, | ||
27 | }; | 22 | }; |
28 | 23 | ||
29 | #[derive(Debug)] | 24 | #[derive(Debug)] |
@@ -50,23 +45,7 @@ impl AnalysisHostImpl { | |||
50 | pub fn change_files(&mut self, changes: &mut dyn Iterator<Item=(FileId, Option<String>)>) { | 45 | pub fn change_files(&mut self, changes: &mut dyn Iterator<Item=(FileId, Option<String>)>) { |
51 | let data = self.data_mut(); | 46 | let data = self.data_mut(); |
52 | for (file_id, text) in changes { | 47 | for (file_id, text) in changes { |
53 | let change_kind = if data.file_map.remove(&file_id).is_some() { | 48 | data.root.update(file_id, text); |
54 | if text.is_some() { | ||
55 | ChangeKind::Update | ||
56 | } else { | ||
57 | ChangeKind::Delete | ||
58 | } | ||
59 | } else { | ||
60 | ChangeKind::Insert | ||
61 | }; | ||
62 | data.module_map.update_file(file_id, change_kind); | ||
63 | data.file_map.remove(&file_id); | ||
64 | if let Some(text) = text { | ||
65 | let file_data = FileData::new(text); | ||
66 | data.file_map.insert(file_id, Arc::new(file_data)); | ||
67 | } else { | ||
68 | data.file_map.remove(&file_id); | ||
69 | } | ||
70 | } | 49 | } |
71 | } | 50 | } |
72 | pub fn set_crate_graph(&mut self, graph: CrateGraph) { | 51 | pub fn set_crate_graph(&mut self, graph: CrateGraph) { |
@@ -106,31 +85,18 @@ impl Clone for AnalysisImpl { | |||
106 | } | 85 | } |
107 | 86 | ||
108 | impl AnalysisImpl { | 87 | impl AnalysisImpl { |
109 | pub fn file_syntax(&self, file_id: FileId) -> File { | 88 | pub fn file_syntax(&self, file_id: FileId) -> &File { |
110 | self.file_data(file_id).syntax().clone() | 89 | self.data.root.syntax(file_id) |
111 | } | 90 | } |
112 | 91 | pub fn file_line_index(&self, file_id: FileId) -> &LineIndex { | |
113 | pub fn file_line_index(&self, id: FileId) -> LineIndex { | 92 | self.data.root.lines(file_id) |
114 | let data = self.file_data(id); | ||
115 | data | ||
116 | .lines | ||
117 | .get_or_init(|| LineIndex::new(&data.text)) | ||
118 | .clone() | ||
119 | } | 93 | } |
120 | 94 | pub fn world_symbols(&self, query: Query, token: &JobToken) -> Vec<(FileId, FileSymbol)> { | |
121 | pub fn world_symbols(&self, mut query: Query, token: &JobToken) -> Vec<(FileId, FileSymbol)> { | ||
122 | self.reindex(); | 95 | self.reindex(); |
123 | self.data.file_map.iter() | 96 | query.search(&self.data.root.symbols(), token) |
124 | .take_while(move |_| !token.is_canceled()) | ||
125 | .flat_map(move |(id, data)| { | ||
126 | let symbols = data.symbols(); | ||
127 | query.process(symbols).into_iter().map(move |s| (*id, s)) | ||
128 | }) | ||
129 | .collect() | ||
130 | } | 97 | } |
131 | |||
132 | pub fn parent_module(&self, id: FileId) -> Vec<(FileId, FileSymbol)> { | 98 | pub fn parent_module(&self, id: FileId) -> Vec<(FileId, FileSymbol)> { |
133 | let module_map = &self.data.module_map; | 99 | let module_map = self.data.root.module_map(); |
134 | let id = module_map.file2module(id); | 100 | let id = module_map.file2module(id); |
135 | module_map | 101 | module_map |
136 | .parent_modules( | 102 | .parent_modules( |
@@ -152,7 +118,7 @@ impl AnalysisImpl { | |||
152 | } | 118 | } |
153 | 119 | ||
154 | pub fn crate_for(&self, id: FileId) -> Vec<CrateId> { | 120 | pub fn crate_for(&self, id: FileId) -> Vec<CrateId> { |
155 | let module_map = &self.data.module_map; | 121 | let module_map = self.data.root.module_map(); |
156 | let crate_graph = &self.data.crate_graph; | 122 | let crate_graph = &self.data.crate_graph; |
157 | let mut res = Vec::new(); | 123 | let mut res = Vec::new(); |
158 | let mut work = VecDeque::new(); | 124 | let mut work = VecDeque::new(); |
@@ -222,7 +188,7 @@ impl AnalysisImpl { | |||
222 | .map(|d| Diagnostic { range: d.range, message: d.msg, fix: None }) | 188 | .map(|d| Diagnostic { range: d.range, message: d.msg, fix: None }) |
223 | .collect::<Vec<_>>(); | 189 | .collect::<Vec<_>>(); |
224 | 190 | ||
225 | self.data.module_map.problems( | 191 | self.data.root.module_map().problems( |
226 | file_id, | 192 | file_id, |
227 | &*self.file_resolver, | 193 | &*self.file_resolver, |
228 | &|file_id| self.file_syntax(file_id), | 194 | &|file_id| self.file_syntax(file_id), |
@@ -296,7 +262,7 @@ impl AnalysisImpl { | |||
296 | Some(name) => name.text(), | 262 | Some(name) => name.text(), |
297 | None => return Vec::new(), | 263 | None => return Vec::new(), |
298 | }; | 264 | }; |
299 | let module_map = &self.data.module_map; | 265 | let module_map = self.data.root.module_map(); |
300 | let id = module_map.file2module(id); | 266 | let id = module_map.file2module(id); |
301 | module_map | 267 | module_map |
302 | .child_module_by_name( | 268 | .child_module_by_name( |
@@ -311,19 +277,7 @@ impl AnalysisImpl { | |||
311 | 277 | ||
312 | fn reindex(&self) { | 278 | fn reindex(&self) { |
313 | if self.needs_reindex.compare_and_swap(true, false, SeqCst) { | 279 | if self.needs_reindex.compare_and_swap(true, false, SeqCst) { |
314 | let now = Instant::now(); | 280 | self.data.root.reindex(); |
315 | let data = &*self.data; | ||
316 | data.file_map | ||
317 | .par_iter() | ||
318 | .for_each(|(_, data)| drop(data.symbols())); | ||
319 | info!("parallel indexing took {:?}", now.elapsed()); | ||
320 | } | ||
321 | } | ||
322 | |||
323 | fn file_data(&self, file_id: FileId) -> Arc<FileData> { | ||
324 | match self.data.file_map.get(&file_id) { | ||
325 | Some(data) => data.clone(), | ||
326 | None => panic!("unknown file: {:?}", file_id), | ||
327 | } | 281 | } |
328 | } | 282 | } |
329 | } | 283 | } |
@@ -331,50 +285,7 @@ impl AnalysisImpl { | |||
331 | #[derive(Clone, Default, Debug)] | 285 | #[derive(Clone, Default, Debug)] |
332 | struct WorldData { | 286 | struct WorldData { |
333 | crate_graph: CrateGraph, | 287 | crate_graph: CrateGraph, |
334 | file_map: HashMap<FileId, Arc<FileData>>, | 288 | root: SourceRoot, |
335 | module_map: ModuleMap, | ||
336 | } | ||
337 | |||
338 | #[derive(Debug)] | ||
339 | struct FileData { | ||
340 | text: String, | ||
341 | symbols: OnceCell<FileSymbols>, | ||
342 | syntax: OnceCell<File>, | ||
343 | lines: OnceCell<LineIndex>, | ||
344 | } | ||
345 | |||
346 | impl FileData { | ||
347 | fn new(text: String) -> FileData { | ||
348 | FileData { | ||
349 | text, | ||
350 | symbols: OnceCell::new(), | ||
351 | syntax: OnceCell::new(), | ||
352 | lines: OnceCell::new(), | ||
353 | } | ||
354 | } | ||
355 | |||
356 | fn syntax(&self) -> &File { | ||
357 | let text = &self.text; | ||
358 | let syntax = &self.syntax; | ||
359 | match panic::catch_unwind(panic::AssertUnwindSafe(|| syntax.get_or_init(|| File::parse(text)))) { | ||
360 | Ok(file) => file, | ||
361 | Err(err) => { | ||
362 | error!("Parser paniced on:\n------\n{}\n------\n", &self.text); | ||
363 | panic::resume_unwind(err) | ||
364 | } | ||
365 | } | ||
366 | } | ||
367 | |||
368 | fn syntax_transient(&self) -> File { | ||
369 | self.syntax.get().map(|s| s.clone()) | ||
370 | .unwrap_or_else(|| File::parse(&self.text)) | ||
371 | } | ||
372 | |||
373 | fn symbols(&self) -> &FileSymbols { | ||
374 | let syntax = self.syntax_transient(); | ||
375 | self.symbols | ||
376 | .get_or_init(|| FileSymbols::new(&syntax)) | ||
377 | } | ||
378 | } | 289 | } |
379 | 290 | ||
380 | impl SourceChange { | 291 | impl SourceChange { |
diff --git a/crates/libanalysis/src/lib.rs b/crates/libanalysis/src/lib.rs index ba290f1e0..b044fdae8 100644 --- a/crates/libanalysis/src/lib.rs +++ b/crates/libanalysis/src/lib.rs | |||
@@ -14,6 +14,7 @@ mod symbol_index; | |||
14 | mod module_map; | 14 | mod module_map; |
15 | mod imp; | 15 | mod imp; |
16 | mod job; | 16 | mod job; |
17 | mod roots; | ||
17 | 18 | ||
18 | use std::{ | 19 | use std::{ |
19 | sync::Arc, | 20 | sync::Arc, |
@@ -146,10 +147,10 @@ pub struct Analysis { | |||
146 | 147 | ||
147 | impl Analysis { | 148 | impl Analysis { |
148 | pub fn file_syntax(&self, file_id: FileId) -> File { | 149 | pub fn file_syntax(&self, file_id: FileId) -> File { |
149 | self.imp.file_syntax(file_id) | 150 | self.imp.file_syntax(file_id).clone() |
150 | } | 151 | } |
151 | pub fn file_line_index(&self, file_id: FileId) -> LineIndex { | 152 | pub fn file_line_index(&self, file_id: FileId) -> LineIndex { |
152 | self.imp.file_line_index(file_id) | 153 | self.imp.file_line_index(file_id).clone() |
153 | } | 154 | } |
154 | pub fn extend_selection(&self, file: &File, range: TextRange) -> TextRange { | 155 | pub fn extend_selection(&self, file: &File, range: TextRange) -> TextRange { |
155 | libeditor::extend_selection(file, range).unwrap_or(range) | 156 | libeditor::extend_selection(file, range).unwrap_or(range) |
diff --git a/crates/libanalysis/src/module_map.rs b/crates/libanalysis/src/module_map.rs index 38935807d..5ceb71817 100644 --- a/crates/libanalysis/src/module_map.rs +++ b/crates/libanalysis/src/module_map.rs | |||
@@ -8,7 +8,7 @@ use libsyntax2::{ | |||
8 | }; | 8 | }; |
9 | use {FileId, FileResolver}; | 9 | use {FileId, FileResolver}; |
10 | 10 | ||
11 | type SyntaxProvider<'a> = dyn Fn(FileId) -> File + 'a; | 11 | type SyntaxProvider<'a> = dyn Fn(FileId) -> &'a File + 'a; |
12 | 12 | ||
13 | #[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)] | 13 | #[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)] |
14 | pub struct ModuleId(FileId); | 14 | pub struct ModuleId(FileId); |
diff --git a/crates/libanalysis/src/roots.rs b/crates/libanalysis/src/roots.rs new file mode 100644 index 000000000..675bce54c --- /dev/null +++ b/crates/libanalysis/src/roots.rs | |||
@@ -0,0 +1,113 @@ | |||
1 | use std::{ | ||
2 | collections::HashMap, | ||
3 | time::Instant, | ||
4 | sync::Arc, | ||
5 | panic, | ||
6 | }; | ||
7 | |||
8 | use once_cell::sync::OnceCell; | ||
9 | use rayon::prelude::*; | ||
10 | use libeditor::LineIndex; | ||
11 | use libsyntax2::File; | ||
12 | |||
13 | use { | ||
14 | FileId, | ||
15 | module_map::{ModuleMap, ChangeKind}, | ||
16 | symbol_index::FileSymbols, | ||
17 | }; | ||
18 | |||
19 | #[derive(Clone, Default, Debug)] | ||
20 | pub(crate) struct SourceRoot { | ||
21 | file_map: HashMap<FileId, Arc<FileData>>, | ||
22 | module_map: ModuleMap, | ||
23 | } | ||
24 | |||
25 | impl SourceRoot { | ||
26 | pub fn update(&mut self, file_id: FileId, text: Option<String>) { | ||
27 | let change_kind = if self.file_map.remove(&file_id).is_some() { | ||
28 | if text.is_some() { | ||
29 | ChangeKind::Update | ||
30 | } else { | ||
31 | ChangeKind::Delete | ||
32 | } | ||
33 | } else { | ||
34 | ChangeKind::Insert | ||
35 | }; | ||
36 | self.module_map.update_file(file_id, change_kind); | ||
37 | self.file_map.remove(&file_id); | ||
38 | if let Some(text) = text { | ||
39 | let file_data = FileData::new(text); | ||
40 | self.file_map.insert(file_id, Arc::new(file_data)); | ||
41 | } else { | ||
42 | self.file_map.remove(&file_id); | ||
43 | } | ||
44 | } | ||
45 | pub fn module_map(&self) -> &ModuleMap { | ||
46 | &self.module_map | ||
47 | } | ||
48 | pub fn lines(&self, file_id: FileId) -> &LineIndex { | ||
49 | let data = self.data(file_id); | ||
50 | data.lines.get_or_init(|| LineIndex::new(&data.text)) | ||
51 | } | ||
52 | pub fn syntax(&self, file_id: FileId) -> &File { | ||
53 | let data = self.data(file_id); | ||
54 | let text = &data.text; | ||
55 | let syntax = &data.syntax; | ||
56 | match panic::catch_unwind(panic::AssertUnwindSafe(|| syntax.get_or_init(|| File::parse(text)))) { | ||
57 | Ok(file) => file, | ||
58 | Err(err) => { | ||
59 | error!("Parser paniced on:\n------\n{}\n------\n", &data.text); | ||
60 | panic::resume_unwind(err) | ||
61 | } | ||
62 | } | ||
63 | } | ||
64 | pub(crate) fn symbols(&self) -> Vec<(FileId, &FileSymbols)> { | ||
65 | self.file_map | ||
66 | .iter() | ||
67 | .map(|(&file_id, data)| (file_id, data.symbols())) | ||
68 | .collect() | ||
69 | } | ||
70 | pub fn reindex(&self) { | ||
71 | let now = Instant::now(); | ||
72 | self.file_map | ||
73 | .par_iter() | ||
74 | .for_each(|(_, data)| { | ||
75 | data.symbols(); | ||
76 | }); | ||
77 | info!("parallel indexing took {:?}", now.elapsed()); | ||
78 | |||
79 | } | ||
80 | fn data(&self, file_id: FileId) -> &FileData { | ||
81 | match self.file_map.get(&file_id) { | ||
82 | Some(data) => data, | ||
83 | None => panic!("unknown file: {:?}", file_id), | ||
84 | } | ||
85 | } | ||
86 | } | ||
87 | |||
88 | #[derive(Debug)] | ||
89 | struct FileData { | ||
90 | text: String, | ||
91 | lines: OnceCell<LineIndex>, | ||
92 | syntax: OnceCell<File>, | ||
93 | symbols: OnceCell<FileSymbols>, | ||
94 | } | ||
95 | |||
96 | impl FileData { | ||
97 | fn new(text: String) -> FileData { | ||
98 | FileData { | ||
99 | text, | ||
100 | symbols: OnceCell::new(), | ||
101 | syntax: OnceCell::new(), | ||
102 | lines: OnceCell::new(), | ||
103 | } | ||
104 | } | ||
105 | fn syntax_transient(&self) -> File { | ||
106 | self.syntax.get().map(|s| s.clone()) | ||
107 | .unwrap_or_else(|| File::parse(&self.text)) | ||
108 | } | ||
109 | fn symbols(&self) -> &FileSymbols { | ||
110 | let syntax = self.syntax_transient(); | ||
111 | self.symbols.get_or_init(|| FileSymbols::new(&syntax)) | ||
112 | } | ||
113 | } | ||
diff --git a/crates/libanalysis/src/symbol_index.rs b/crates/libanalysis/src/symbol_index.rs index cb35ab1d1..2cad3f6eb 100644 --- a/crates/libanalysis/src/symbol_index.rs +++ b/crates/libanalysis/src/symbol_index.rs | |||
@@ -3,8 +3,8 @@ use libsyntax2::{ | |||
3 | File, | 3 | File, |
4 | SyntaxKind::{self, *}, | 4 | SyntaxKind::{self, *}, |
5 | }; | 5 | }; |
6 | use fst::{self, IntoStreamer, Streamer}; | 6 | use fst::{self, Streamer}; |
7 | use Query; | 7 | use {Query, FileId, JobToken}; |
8 | 8 | ||
9 | #[derive(Debug)] | 9 | #[derive(Debug)] |
10 | pub(crate) struct FileSymbols { | 10 | pub(crate) struct FileSymbols { |
@@ -32,35 +32,45 @@ impl FileSymbols { | |||
32 | } | 32 | } |
33 | 33 | ||
34 | impl Query { | 34 | impl Query { |
35 | pub(crate) fn process( | 35 | pub(crate) fn search( |
36 | &mut self, | 36 | mut self, |
37 | file: &FileSymbols, | 37 | indices: &[(FileId, &FileSymbols)], |
38 | ) -> Vec<FileSymbol> { | 38 | token: &JobToken, |
39 | fn is_type(kind: SyntaxKind) -> bool { | 39 | ) -> Vec<(FileId, FileSymbol)> { |
40 | match kind { | 40 | |
41 | STRUCT_DEF | ENUM_DEF | TRAIT_DEF | TYPE_DEF => true, | 41 | let mut op = fst::map::OpBuilder::new(); |
42 | _ => false, | 42 | for (_, file_symbols) in indices.iter() { |
43 | } | 43 | let automaton = fst::automaton::Subsequence::new(&self.lowercased); |
44 | op = op.add(file_symbols.map.search(automaton)) | ||
44 | } | 45 | } |
45 | let automaton = fst::automaton::Subsequence::new(&self.lowercased); | 46 | let mut stream = op.union(); |
46 | let mut stream = file.map.search(automaton).into_stream(); | ||
47 | let mut res = Vec::new(); | 47 | let mut res = Vec::new(); |
48 | while let Some((_, idx)) = stream.next() { | 48 | while let Some((_, indexed_values)) = stream.next() { |
49 | if self.limit == 0 { | 49 | if self.limit == 0 || token.is_canceled() { |
50 | break; | 50 | break; |
51 | } | 51 | } |
52 | let idx = idx as usize; | 52 | for indexed_value in indexed_values { |
53 | let symbol = &file.symbols[idx]; | 53 | let (file_id, file_symbols) = &indices[indexed_value.index]; |
54 | if self.only_types && !is_type(symbol.kind) { | 54 | let idx = indexed_value.value as usize; |
55 | continue; | 55 | |
56 | } | 56 | let symbol = &file_symbols.symbols[idx]; |
57 | if self.exact && symbol.name != self.query { | 57 | if self.only_types && !is_type(symbol.kind) { |
58 | continue; | 58 | continue; |
59 | } | ||
60 | if self.exact && symbol.name != self.query { | ||
61 | continue; | ||
62 | } | ||
63 | res.push((*file_id, symbol.clone())); | ||
64 | self.limit -= 1; | ||
59 | } | 65 | } |
60 | res.push(symbol.clone()); | ||
61 | self.limit -= 1; | ||
62 | } | 66 | } |
63 | res | 67 | res |
64 | } | 68 | } |
65 | } | 69 | } |
66 | 70 | ||
71 | fn is_type(kind: SyntaxKind) -> bool { | ||
72 | match kind { | ||
73 | STRUCT_DEF | ENUM_DEF | TRAIT_DEF | TYPE_DEF => true, | ||
74 | _ => false, | ||
75 | } | ||
76 | } | ||