aboutsummaryrefslogtreecommitdiff
path: root/crates/libanalysis/src
diff options
context:
space:
mode:
authorAleksey Kladov <[email protected]>2018-09-03 17:46:30 +0100
committerAleksey Kladov <[email protected]>2018-09-03 17:46:30 +0100
commitb04c14d4ad51433b0055e2e5799f98da20d15d58 (patch)
tree18bd67e27c515d48be6725230b274b2eb55c740d /crates/libanalysis/src
parent2f2feef9afe8f1c75f743a56f945a1560ca85af4 (diff)
dispatch acros roots
Diffstat (limited to 'crates/libanalysis/src')
-rw-r--r--crates/libanalysis/src/imp.rs65
-rw-r--r--crates/libanalysis/src/lib.rs8
-rw-r--r--crates/libanalysis/src/module_map.rs4
-rw-r--r--crates/libanalysis/src/roots.rs143
-rw-r--r--crates/libanalysis/src/symbol_index.rs35
5 files changed, 180 insertions, 75 deletions
diff --git a/crates/libanalysis/src/imp.rs b/crates/libanalysis/src/imp.rs
index 73a6f4306..c1e144025 100644
--- a/crates/libanalysis/src/imp.rs
+++ b/crates/libanalysis/src/imp.rs
@@ -17,8 +17,8 @@ use libsyntax2::{
17use { 17use {
18 FileId, FileResolver, Query, Diagnostic, SourceChange, SourceFileEdit, Position, FileSystemEdit, 18 FileId, FileResolver, Query, Diagnostic, SourceChange, SourceFileEdit, Position, FileSystemEdit,
19 JobToken, CrateGraph, CrateId, 19 JobToken, CrateGraph, CrateId,
20 module_map::Problem, 20 module_map::{ModuleMap, Problem},
21 roots::SourceRoot, 21 roots::{SourceRoot, ReadonlySourceRoot, WritableSourceRoot},
22}; 22};
23 23
24#[derive(Debug)] 24#[derive(Debug)]
@@ -57,6 +57,10 @@ impl AnalysisHostImpl {
57 } 57 }
58 self.data_mut().crate_graph = graph; 58 self.data_mut().crate_graph = graph;
59 } 59 }
60 pub fn set_libraries(&mut self, libs: impl Iterator<Item=impl Iterator<Item=(FileId, String)>>) {
61 let libs = libs.map(ReadonlySourceRoot::new).collect::<Vec<_>>();
62 self.data_mut().libs = Arc::new(libs);
63 }
60 fn data_mut(&mut self) -> &mut WorldData { 64 fn data_mut(&mut self) -> &mut WorldData {
61 Arc::make_mut(&mut self.data) 65 Arc::make_mut(&mut self.data)
62 } 66 }
@@ -85,19 +89,33 @@ impl Clone for AnalysisImpl {
85} 89}
86 90
87impl AnalysisImpl { 91impl AnalysisImpl {
92 fn root(&self, file_id: FileId) -> &SourceRoot {
93 if self.data.root.contains(file_id) {
94 return &self.data.root;
95 }
96 self.data.libs.iter().find(|it| it.contains(file_id)).unwrap()
97 }
88 pub fn file_syntax(&self, file_id: FileId) -> &File { 98 pub fn file_syntax(&self, file_id: FileId) -> &File {
89 self.data.root.syntax(file_id) 99 self.root(file_id).syntax(file_id)
90 } 100 }
91 pub fn file_line_index(&self, file_id: FileId) -> &LineIndex { 101 pub fn file_line_index(&self, file_id: FileId) -> &LineIndex {
92 self.data.root.lines(file_id) 102 self.root(file_id).lines(file_id)
93 } 103 }
94 pub fn world_symbols(&self, query: Query, token: &JobToken) -> Vec<(FileId, FileSymbol)> { 104 pub fn world_symbols(&self, query: Query, token: &JobToken) -> Vec<(FileId, FileSymbol)> {
95 self.reindex(); 105 self.reindex();
96 query.search(&self.data.root.symbols(), token) 106 let mut buf = Vec::new();
107 if query.libs {
108 self.data.libs.iter()
109 .for_each(|it| it.symbols(&mut buf));
110 } else {
111 self.data.root.symbols(&mut buf);
112 }
113 query.search(&buf, token)
114
97 } 115 }
98 pub fn parent_module(&self, id: FileId) -> Vec<(FileId, FileSymbol)> { 116 pub fn parent_module(&self, file_id: FileId) -> Vec<(FileId, FileSymbol)> {
99 let module_map = self.data.root.module_map(); 117 let module_map = self.root(file_id).module_map();
100 let id = module_map.file2module(id); 118 let id = module_map.file2module(file_id);
101 module_map 119 module_map
102 .parent_modules( 120 .parent_modules(
103 id, 121 id,
@@ -117,12 +135,12 @@ impl AnalysisImpl {
117 .collect() 135 .collect()
118 } 136 }
119 137
120 pub fn crate_for(&self, id: FileId) -> Vec<CrateId> { 138 pub fn crate_for(&self, file_id: FileId) -> Vec<CrateId> {
121 let module_map = self.data.root.module_map(); 139 let module_map = self.root(file_id).module_map();
122 let crate_graph = &self.data.crate_graph; 140 let crate_graph = &self.data.crate_graph;
123 let mut res = Vec::new(); 141 let mut res = Vec::new();
124 let mut work = VecDeque::new(); 142 let mut work = VecDeque::new();
125 work.push_back(id); 143 work.push_back(file_id);
126 let mut visited = HashSet::new(); 144 let mut visited = HashSet::new();
127 while let Some(id) = work.pop_front() { 145 while let Some(id) = work.pop_front() {
128 if let Some(crate_id) = crate_graph.crate_id_for_crate_root(id) { 146 if let Some(crate_id) = crate_graph.crate_id_for_crate_root(id) {
@@ -148,11 +166,13 @@ impl AnalysisImpl {
148 } 166 }
149 pub fn approximately_resolve_symbol( 167 pub fn approximately_resolve_symbol(
150 &self, 168 &self,
151 id: FileId, 169 file_id: FileId,
152 offset: TextUnit, 170 offset: TextUnit,
153 token: &JobToken, 171 token: &JobToken,
154 ) -> Vec<(FileId, FileSymbol)> { 172 ) -> Vec<(FileId, FileSymbol)> {
155 let file = self.file_syntax(id); 173 let root = self.root(file_id);
174 let module_map = root.module_map();
175 let file = root.syntax(file_id);
156 let syntax = file.syntax(); 176 let syntax = file.syntax();
157 if let Some(name_ref) = find_node_at_offset::<ast::NameRef>(syntax, offset) { 177 if let Some(name_ref) = find_node_at_offset::<ast::NameRef>(syntax, offset) {
158 return self.index_resolve(name_ref, token); 178 return self.index_resolve(name_ref, token);
@@ -160,7 +180,7 @@ impl AnalysisImpl {
160 if let Some(name) = find_node_at_offset::<ast::Name>(syntax, offset) { 180 if let Some(name) = find_node_at_offset::<ast::Name>(syntax, offset) {
161 if let Some(module) = name.syntax().parent().and_then(ast::Module::cast) { 181 if let Some(module) = name.syntax().parent().and_then(ast::Module::cast) {
162 if module.has_semi() { 182 if module.has_semi() {
163 let file_ids = self.resolve_module(id, module); 183 let file_ids = self.resolve_module(module_map, file_id, module);
164 184
165 let res = file_ids.into_iter().map(|id| { 185 let res = file_ids.into_iter().map(|id| {
166 let name = module.name() 186 let name = module.name()
@@ -182,13 +202,16 @@ impl AnalysisImpl {
182 } 202 }
183 203
184 pub fn diagnostics(&self, file_id: FileId) -> Vec<Diagnostic> { 204 pub fn diagnostics(&self, file_id: FileId) -> Vec<Diagnostic> {
185 let syntax = self.file_syntax(file_id); 205 let root = self.root(file_id);
206 let module_map = root.module_map();
207 let syntax = root.syntax(file_id);
208
186 let mut res = libeditor::diagnostics(&syntax) 209 let mut res = libeditor::diagnostics(&syntax)
187 .into_iter() 210 .into_iter()
188 .map(|d| Diagnostic { range: d.range, message: d.msg, fix: None }) 211 .map(|d| Diagnostic { range: d.range, message: d.msg, fix: None })
189 .collect::<Vec<_>>(); 212 .collect::<Vec<_>>();
190 213
191 self.data.root.module_map().problems( 214 module_map.problems(
192 file_id, 215 file_id,
193 &*self.file_resolver, 216 &*self.file_resolver,
194 &|file_id| self.file_syntax(file_id), 217 &|file_id| self.file_syntax(file_id),
@@ -257,13 +280,12 @@ impl AnalysisImpl {
257 self.world_symbols(query, token) 280 self.world_symbols(query, token)
258 } 281 }
259 282
260 fn resolve_module(&self, id: FileId, module: ast::Module) -> Vec<FileId> { 283 fn resolve_module(&self, module_map: &ModuleMap, file_id: FileId, module: ast::Module) -> Vec<FileId> {
261 let name = match module.name() { 284 let name = match module.name() {
262 Some(name) => name.text(), 285 Some(name) => name.text(),
263 None => return Vec::new(), 286 None => return Vec::new(),
264 }; 287 };
265 let module_map = self.data.root.module_map(); 288 let id = module_map.file2module(file_id);
266 let id = module_map.file2module(id);
267 module_map 289 module_map
268 .child_module_by_name( 290 .child_module_by_name(
269 id, name.as_str(), 291 id, name.as_str(),
@@ -285,7 +307,8 @@ impl AnalysisImpl {
285#[derive(Clone, Default, Debug)] 307#[derive(Clone, Default, Debug)]
286struct WorldData { 308struct WorldData {
287 crate_graph: CrateGraph, 309 crate_graph: CrateGraph,
288 root: SourceRoot, 310 root: WritableSourceRoot,
311 libs: Arc<Vec<ReadonlySourceRoot>>,
289} 312}
290 313
291impl SourceChange { 314impl SourceChange {
diff --git a/crates/libanalysis/src/lib.rs b/crates/libanalysis/src/lib.rs
index b044fdae8..9ae87d46c 100644
--- a/crates/libanalysis/src/lib.rs
+++ b/crates/libanalysis/src/lib.rs
@@ -68,6 +68,9 @@ impl AnalysisHost {
68 pub fn set_crate_graph(&mut self, graph: CrateGraph) { 68 pub fn set_crate_graph(&mut self, graph: CrateGraph) {
69 self.imp.set_crate_graph(graph) 69 self.imp.set_crate_graph(graph)
70 } 70 }
71 pub fn set_libraries(&mut self, libs: impl Iterator<Item=impl Iterator<Item=(FileId, String)>>) {
72 self.imp.set_libraries(libs)
73 }
71} 74}
72 75
73#[derive(Debug)] 76#[derive(Debug)]
@@ -114,6 +117,7 @@ pub struct Query {
114 query: String, 117 query: String,
115 lowercased: String, 118 lowercased: String,
116 only_types: bool, 119 only_types: bool,
120 libs: bool,
117 exact: bool, 121 exact: bool,
118 limit: usize, 122 limit: usize,
119} 123}
@@ -125,6 +129,7 @@ impl Query {
125 query, 129 query,
126 lowercased, 130 lowercased,
127 only_types: false, 131 only_types: false,
132 libs: false,
128 exact: false, 133 exact: false,
129 limit: usize::max_value() 134 limit: usize::max_value()
130 } 135 }
@@ -132,6 +137,9 @@ impl Query {
132 pub fn only_types(&mut self) { 137 pub fn only_types(&mut self) {
133 self.only_types = true; 138 self.only_types = true;
134 } 139 }
140 pub fn libs(&mut self) {
141 self.libs = true;
142 }
135 pub fn exact(&mut self) { 143 pub fn exact(&mut self) {
136 self.exact = true; 144 self.exact = true;
137 } 145 }
diff --git a/crates/libanalysis/src/module_map.rs b/crates/libanalysis/src/module_map.rs
index 5ceb71817..1b225ecee 100644
--- a/crates/libanalysis/src/module_map.rs
+++ b/crates/libanalysis/src/module_map.rs
@@ -56,6 +56,10 @@ pub enum Problem {
56} 56}
57 57
58impl ModuleMap { 58impl ModuleMap {
59 pub fn new() -> ModuleMap {
60 Default::default()
61 }
62
59 pub fn update_file(&mut self, file: FileId, change_kind: ChangeKind) { 63 pub fn update_file(&mut self, file: FileId, change_kind: ChangeKind) {
60 self.state.get_mut().changes.push((file, change_kind)); 64 self.state.get_mut().changes.push((file, change_kind));
61 } 65 }
diff --git a/crates/libanalysis/src/roots.rs b/crates/libanalysis/src/roots.rs
index 01de3e128..a65668c9b 100644
--- a/crates/libanalysis/src/roots.rs
+++ b/crates/libanalysis/src/roots.rs
@@ -13,16 +13,24 @@ use libsyntax2::File;
13use { 13use {
14 FileId, 14 FileId,
15 module_map::{ModuleMap, ChangeKind}, 15 module_map::{ModuleMap, ChangeKind},
16 symbol_index::FileSymbols, 16 symbol_index::SymbolIndex,
17}; 17};
18 18
19pub(crate) trait SourceRoot {
20 fn contains(&self, file_id: FileId) -> bool;
21 fn module_map(&self) -> &ModuleMap;
22 fn lines(&self, file_id: FileId) -> &LineIndex;
23 fn syntax(&self, file_id: FileId) -> &File;
24 fn symbols<'a>(&'a self, acc: &mut Vec<&'a SymbolIndex>);
25}
26
19#[derive(Clone, Default, Debug)] 27#[derive(Clone, Default, Debug)]
20pub(crate) struct SourceRoot { 28pub(crate) struct WritableSourceRoot {
21 file_map: HashMap<FileId, Arc<(FileData, OnceCell<FileSymbols>)>>, 29 file_map: HashMap<FileId, Arc<(FileData, OnceCell<SymbolIndex>)>>,
22 module_map: ModuleMap, 30 module_map: ModuleMap,
23} 31}
24 32
25impl SourceRoot { 33impl WritableSourceRoot {
26 pub fn update(&mut self, file_id: FileId, text: Option<String>) { 34 pub fn update(&mut self, file_id: FileId, text: Option<String>) {
27 let change_kind = if self.file_map.remove(&file_id).is_some() { 35 let change_kind = if self.file_map.remove(&file_id).is_some() {
28 if text.is_some() { 36 if text.is_some() {
@@ -40,31 +48,6 @@ impl SourceRoot {
40 self.file_map.insert(file_id, Arc::new((file_data, Default::default()))); 48 self.file_map.insert(file_id, Arc::new((file_data, Default::default())));
41 } 49 }
42 } 50 }
43 pub fn module_map(&self) -> &ModuleMap {
44 &self.module_map
45 }
46 pub fn lines(&self, file_id: FileId) -> &LineIndex {
47 let data = self.data(file_id);
48 data.lines.get_or_init(|| LineIndex::new(&data.text))
49 }
50 pub fn syntax(&self, file_id: FileId) -> &File {
51 let data = self.data(file_id);
52 let text = &data.text;
53 let syntax = &data.syntax;
54 match panic::catch_unwind(panic::AssertUnwindSafe(|| syntax.get_or_init(|| File::parse(text)))) {
55 Ok(file) => file,
56 Err(err) => {
57 error!("Parser paniced on:\n------\n{}\n------\n", &data.text);
58 panic::resume_unwind(err)
59 }
60 }
61 }
62 pub(crate) fn symbols(&self) -> Vec<&FileSymbols> {
63 self.file_map
64 .iter()
65 .map(|(&file_id, data)| symbols(file_id, data))
66 .collect()
67 }
68 pub fn reindex(&self) { 51 pub fn reindex(&self) {
69 let now = Instant::now(); 52 let now = Instant::now();
70 self.file_map 53 self.file_map
@@ -83,9 +66,31 @@ impl SourceRoot {
83 } 66 }
84} 67}
85 68
86fn symbols(file_id: FileId, (data, symbols): &(FileData, OnceCell<FileSymbols>)) -> &FileSymbols { 69impl SourceRoot for WritableSourceRoot {
70 fn contains(&self, file_id: FileId) -> bool {
71 self.file_map.contains_key(&file_id)
72 }
73 fn module_map(&self) -> &ModuleMap {
74 &self.module_map
75 }
76 fn lines(&self, file_id: FileId) -> &LineIndex {
77 self.data(file_id).lines()
78 }
79 fn syntax(&self, file_id: FileId) -> &File {
80 self.data(file_id).syntax()
81 }
82 fn symbols<'a>(&'a self, acc: &mut Vec<&'a SymbolIndex>) {
83 acc.extend(
84 self.file_map
85 .iter()
86 .map(|(&file_id, data)| symbols(file_id, data))
87 )
88 }
89}
90
91fn symbols(file_id: FileId, (data, symbols): &(FileData, OnceCell<SymbolIndex>)) -> &SymbolIndex {
87 let syntax = data.syntax_transient(); 92 let syntax = data.syntax_transient();
88 symbols.get_or_init(|| FileSymbols::new(file_id, &syntax)) 93 symbols.get_or_init(|| SymbolIndex::for_file(file_id, syntax))
89} 94}
90 95
91#[derive(Debug)] 96#[derive(Debug)]
@@ -103,19 +108,77 @@ impl FileData {
103 lines: OnceCell::new(), 108 lines: OnceCell::new(),
104 } 109 }
105 } 110 }
111 fn lines(&self) -> &LineIndex {
112 self.lines.get_or_init(|| LineIndex::new(&self.text))
113 }
114 fn syntax(&self) -> &File {
115 let text = &self.text;
116 let syntax = &self.syntax;
117 match panic::catch_unwind(panic::AssertUnwindSafe(|| syntax.get_or_init(|| File::parse(text)))) {
118 Ok(file) => file,
119 Err(err) => {
120 error!("Parser paniced on:\n------\n{}\n------\n", text);
121 panic::resume_unwind(err)
122 }
123 }
124 }
106 fn syntax_transient(&self) -> File { 125 fn syntax_transient(&self) -> File {
107 self.syntax.get().map(|s| s.clone()) 126 self.syntax.get().map(|s| s.clone())
108 .unwrap_or_else(|| File::parse(&self.text)) 127 .unwrap_or_else(|| File::parse(&self.text))
109 } 128 }
110} 129}
111 130
112// #[derive(Clone, Default, Debug)] 131#[derive(Debug)]
113// pub(crate) struct ReadonlySourceRoot { 132pub(crate) struct ReadonlySourceRoot {
114// data: Arc<ReadonlySourceRoot> 133 symbol_index: SymbolIndex,
115// } 134 file_map: HashMap<FileId, FileData>,
135 module_map: ModuleMap,
136}
116 137
117// #[derive(Clone, Default, Debug)] 138impl ReadonlySourceRoot {
118// pub(crate) struct ReadonlySourceRootInner { 139 pub fn new(files: impl Iterator<Item=(FileId, String)>) -> ReadonlySourceRoot {
119// file_map: HashMap<FileId, FileData>, 140 let mut module_map = ModuleMap::new();
120// module_map: ModuleMap, 141 let file_map: HashMap<FileId, FileData> = files
121// } 142 .map(|(id, text)| {
143 module_map.update_file(id, ChangeKind::Insert);
144 (id, FileData::new(text))
145 })
146 .collect();
147 let symbol_index = SymbolIndex::for_files(
148 file_map.par_iter().map(|(&file_id, file_data)| {
149 (file_id, file_data.syntax_transient())
150 })
151 );
152
153 ReadonlySourceRoot {
154 symbol_index,
155 file_map,
156 module_map,
157 }
158 }
159
160 fn data(&self, file_id: FileId) -> &FileData {
161 match self.file_map.get(&file_id) {
162 Some(data) => data,
163 None => panic!("unknown file: {:?}", file_id),
164 }
165 }
166}
167
168impl SourceRoot for ReadonlySourceRoot {
169 fn contains(&self, file_id: FileId) -> bool {
170 self.file_map.contains_key(&file_id)
171 }
172 fn module_map(&self) -> &ModuleMap {
173 &self.module_map
174 }
175 fn lines(&self, file_id: FileId) -> &LineIndex {
176 self.data(file_id).lines()
177 }
178 fn syntax(&self, file_id: FileId) -> &File {
179 self.data(file_id).syntax()
180 }
181 fn symbols<'a>(&'a self, acc: &mut Vec<&'a SymbolIndex>) {
182 acc.push(&self.symbol_index)
183 }
184}
diff --git a/crates/libanalysis/src/symbol_index.rs b/crates/libanalysis/src/symbol_index.rs
index 54952cb94..8fef326ab 100644
--- a/crates/libanalysis/src/symbol_index.rs
+++ b/crates/libanalysis/src/symbol_index.rs
@@ -4,39 +4,46 @@ use libsyntax2::{
4 SyntaxKind::{self, *}, 4 SyntaxKind::{self, *},
5}; 5};
6use fst::{self, Streamer}; 6use fst::{self, Streamer};
7use rayon::prelude::*;
7use {Query, FileId, JobToken}; 8use {Query, FileId, JobToken};
8 9
9#[derive(Debug)] 10#[derive(Debug)]
10pub(crate) struct FileSymbols { 11pub(crate) struct SymbolIndex {
11 symbols: Vec<(FileId, FileSymbol)>, 12 symbols: Vec<(FileId, FileSymbol)>,
12 map: fst::Map, 13 map: fst::Map,
13} 14}
14 15
15impl FileSymbols { 16impl SymbolIndex {
16 pub(crate) fn new(file_id: FileId, file: &File) -> FileSymbols { 17 pub(crate) fn for_files(files: impl ParallelIterator<Item=(FileId, File)>) -> SymbolIndex {
17 let mut symbols = file_symbols(file) 18 let mut symbols = files
18 .into_iter() 19 .flat_map(|(file_id, file)| {
19 .map(|s| (s.name.as_str().to_lowercase(), s)) 20 file_symbols(&file)
21 .into_iter()
22 .map(move |symbol| {
23 (symbol.name.as_str().to_lowercase(), (file_id, symbol))
24 })
25 .collect::<Vec<_>>()
26 })
20 .collect::<Vec<_>>(); 27 .collect::<Vec<_>>();
21 28 symbols.par_sort_by(|s1, s2| s1.0.cmp(&s2.0));
22 symbols.sort_by(|s1, s2| s1.0.cmp(&s2.0));
23 symbols.dedup_by(|s1, s2| s1.0 == s2.0); 29 symbols.dedup_by(|s1, s2| s1.0 == s2.0);
24 let (names, symbols): (Vec<String>, Vec<(FileId, FileSymbol)>) = 30 let (names, symbols): (Vec<String>, Vec<(FileId, FileSymbol)>) =
25 symbols.into_iter() 31 symbols.into_iter().unzip();
26 .map(|(name, symbol)| (name, (file_id, symbol)))
27 .unzip();
28
29 let map = fst::Map::from_iter( 32 let map = fst::Map::from_iter(
30 names.into_iter().zip(0u64..) 33 names.into_iter().zip(0u64..)
31 ).unwrap(); 34 ).unwrap();
32 FileSymbols { symbols, map } 35 SymbolIndex { symbols, map }
36 }
37
38 pub(crate) fn for_file(file_id: FileId, file: File) -> SymbolIndex {
39 SymbolIndex::for_files(::rayon::iter::once((file_id, file)))
33 } 40 }
34} 41}
35 42
36impl Query { 43impl Query {
37 pub(crate) fn search( 44 pub(crate) fn search(
38 mut self, 45 mut self,
39 indices: &[&FileSymbols], 46 indices: &[&SymbolIndex],
40 token: &JobToken, 47 token: &JobToken,
41 ) -> Vec<(FileId, FileSymbol)> { 48 ) -> Vec<(FileId, FileSymbol)> {
42 49