aboutsummaryrefslogtreecommitdiff
path: root/crates
diff options
context:
space:
mode:
Diffstat (limited to 'crates')
-rw-r--r--crates/libanalysis/src/imp.rs121
-rw-r--r--crates/libanalysis/src/lib.rs5
-rw-r--r--crates/libanalysis/src/module_map.rs2
-rw-r--r--crates/libanalysis/src/roots.rs113
-rw-r--r--crates/libanalysis/src/symbol_index.rs58
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
12use rayon::prelude::*;
13use once_cell::sync::OnceCell;
14use libeditor::{self, FileSymbol, LineIndex, find_node_at_offset, LocalEdit}; 10use libeditor::{self, FileSymbol, LineIndex, find_node_at_offset, LocalEdit};
15use libsyntax2::{ 11use libsyntax2::{
16 TextUnit, TextRange, SmolStr, File, AstNode, 12 TextUnit, TextRange, SmolStr, File, AstNode,
@@ -20,10 +16,9 @@ use libsyntax2::{
20 16
21use { 17use {
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
108impl AnalysisImpl { 87impl 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)]
332struct WorldData { 286struct 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)]
339struct FileData {
340 text: String,
341 symbols: OnceCell<FileSymbols>,
342 syntax: OnceCell<File>,
343 lines: OnceCell<LineIndex>,
344}
345
346impl 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
380impl SourceChange { 291impl 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;
14mod module_map; 14mod module_map;
15mod imp; 15mod imp;
16mod job; 16mod job;
17mod roots;
17 18
18use std::{ 19use std::{
19 sync::Arc, 20 sync::Arc,
@@ -146,10 +147,10 @@ pub struct Analysis {
146 147
147impl Analysis { 148impl 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};
9use {FileId, FileResolver}; 9use {FileId, FileResolver};
10 10
11type SyntaxProvider<'a> = dyn Fn(FileId) -> File + 'a; 11type 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)]
14pub struct ModuleId(FileId); 14pub 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 @@
1use std::{
2 collections::HashMap,
3 time::Instant,
4 sync::Arc,
5 panic,
6};
7
8use once_cell::sync::OnceCell;
9use rayon::prelude::*;
10use libeditor::LineIndex;
11use libsyntax2::File;
12
13use {
14 FileId,
15 module_map::{ModuleMap, ChangeKind},
16 symbol_index::FileSymbols,
17};
18
19#[derive(Clone, Default, Debug)]
20pub(crate) struct SourceRoot {
21 file_map: HashMap<FileId, Arc<FileData>>,
22 module_map: ModuleMap,
23}
24
25impl 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)]
89struct FileData {
90 text: String,
91 lines: OnceCell<LineIndex>,
92 syntax: OnceCell<File>,
93 symbols: OnceCell<FileSymbols>,
94}
95
96impl 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};
6use fst::{self, IntoStreamer, Streamer}; 6use fst::{self, Streamer};
7use Query; 7use {Query, FileId, JobToken};
8 8
9#[derive(Debug)] 9#[derive(Debug)]
10pub(crate) struct FileSymbols { 10pub(crate) struct FileSymbols {
@@ -32,35 +32,45 @@ impl FileSymbols {
32} 32}
33 33
34impl Query { 34impl 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
71fn is_type(kind: SyntaxKind) -> bool {
72 match kind {
73 STRUCT_DEF | ENUM_DEF | TRAIT_DEF | TYPE_DEF => true,
74 _ => false,
75 }
76}