aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_ide_db/src/symbol_index.rs
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_ide_db/src/symbol_index.rs')
-rw-r--r--crates/ra_ide_db/src/symbol_index.rs127
1 files changed, 76 insertions, 51 deletions
diff --git a/crates/ra_ide_db/src/symbol_index.rs b/crates/ra_ide_db/src/symbol_index.rs
index acc31fe3b..25c99813f 100644
--- a/crates/ra_ide_db/src/symbol_index.rs
+++ b/crates/ra_ide_db/src/symbol_index.rs
@@ -29,18 +29,20 @@ use std::{
29}; 29};
30 30
31use fst::{self, Streamer}; 31use fst::{self, Streamer};
32use hir::db::DefDatabase;
32use ra_db::{ 33use ra_db::{
33 salsa::{self, ParallelDatabase}, 34 salsa::{self, ParallelDatabase},
34 FileId, SourceDatabaseExt, SourceRootId, 35 CrateId, FileId, SourceDatabaseExt, SourceRootId,
35}; 36};
37use ra_prof::profile;
36use ra_syntax::{ 38use ra_syntax::{
37 ast::{self, NameOwner}, 39 ast::{self, NameOwner},
38 match_ast, AstNode, Parse, SmolStr, SourceFile, 40 match_ast, AstNode, Parse, SmolStr, SourceFile,
39 SyntaxKind::{self, *}, 41 SyntaxKind::{self, *},
40 SyntaxNode, SyntaxNodePtr, TextRange, WalkEvent, 42 SyntaxNode, SyntaxNodePtr, TextRange, WalkEvent,
41}; 43};
42#[cfg(not(feature = "wasm"))]
43use rayon::prelude::*; 44use rayon::prelude::*;
45use rustc_hash::FxHashMap;
44 46
45use crate::RootDatabase; 47use crate::RootDatabase;
46 48
@@ -85,10 +87,9 @@ impl Query {
85} 87}
86 88
87#[salsa::query_group(SymbolsDatabaseStorage)] 89#[salsa::query_group(SymbolsDatabaseStorage)]
88pub trait SymbolsDatabase: hir::db::HirDatabase { 90pub trait SymbolsDatabase: hir::db::HirDatabase + SourceDatabaseExt + ParallelDatabase {
89 fn file_symbols(&self, file_id: FileId) -> Arc<SymbolIndex>; 91 fn file_symbols(&self, file_id: FileId) -> Arc<SymbolIndex>;
90 #[salsa::input] 92 fn library_symbols(&self) -> Arc<FxHashMap<SourceRootId, SymbolIndex>>;
91 fn library_symbols(&self, id: SourceRootId) -> Arc<SymbolIndex>;
92 /// The set of "local" (that is, from the current workspace) roots. 93 /// The set of "local" (that is, from the current workspace) roots.
93 /// Files in local roots are assumed to change frequently. 94 /// Files in local roots are assumed to change frequently.
94 #[salsa::input] 95 #[salsa::input]
@@ -99,6 +100,29 @@ pub trait SymbolsDatabase: hir::db::HirDatabase {
99 fn library_roots(&self) -> Arc<Vec<SourceRootId>>; 100 fn library_roots(&self) -> Arc<Vec<SourceRootId>>;
100} 101}
101 102
103fn library_symbols(
104 db: &(impl SymbolsDatabase + ParallelDatabase),
105) -> Arc<FxHashMap<SourceRootId, SymbolIndex>> {
106 let _p = profile("library_symbols");
107
108 let roots = db.library_roots();
109 let res = roots
110 .iter()
111 .map(|&root_id| {
112 let root = db.source_root(root_id);
113 let files = root
114 .walk()
115 .map(|it| (it, SourceDatabaseExt::file_text(db, it)))
116 .collect::<Vec<_>>();
117 let symbol_index = SymbolIndex::for_files(
118 files.into_par_iter().map(|(file, text)| (file, SourceFile::parse(&text))),
119 );
120 (root_id, symbol_index)
121 })
122 .collect();
123 Arc::new(res)
124}
125
102fn file_symbols(db: &impl SymbolsDatabase, file_id: FileId) -> Arc<SymbolIndex> { 126fn file_symbols(db: &impl SymbolsDatabase, file_id: FileId) -> Arc<SymbolIndex> {
103 db.check_canceled(); 127 db.check_canceled();
104 let parse = db.parse(file_id); 128 let parse = db.parse(file_id);
@@ -110,6 +134,14 @@ fn file_symbols(db: &impl SymbolsDatabase, file_id: FileId) -> Arc<SymbolIndex>
110 Arc::new(SymbolIndex::new(symbols)) 134 Arc::new(SymbolIndex::new(symbols))
111} 135}
112 136
137/// Need to wrap Snapshot to provide `Clone` impl for `map_with`
138struct Snap<DB>(DB);
139impl<DB: ParallelDatabase> Clone for Snap<salsa::Snapshot<DB>> {
140 fn clone(&self) -> Snap<salsa::Snapshot<DB>> {
141 Snap(self.0.snapshot())
142 }
143}
144
113// Feature: Workspace Symbol 145// Feature: Workspace Symbol
114// 146//
115// Uses fuzzy-search to find types, modules and functions by name across your 147// Uses fuzzy-search to find types, modules and functions by name across your
@@ -132,27 +164,13 @@ fn file_symbols(db: &impl SymbolsDatabase, file_id: FileId) -> Arc<SymbolIndex>
132// | VS Code | kbd:[Ctrl+T] 164// | VS Code | kbd:[Ctrl+T]
133// |=== 165// |===
134pub fn world_symbols(db: &RootDatabase, query: Query) -> Vec<FileSymbol> { 166pub fn world_symbols(db: &RootDatabase, query: Query) -> Vec<FileSymbol> {
135 /// Need to wrap Snapshot to provide `Clone` impl for `map_with` 167 let _p = ra_prof::profile("world_symbols").detail(|| query.query.clone());
136 struct Snap(salsa::Snapshot<RootDatabase>);
137 impl Clone for Snap {
138 fn clone(&self) -> Snap {
139 Snap(self.0.snapshot())
140 }
141 }
142 168
143 let buf: Vec<Arc<SymbolIndex>> = if query.libs { 169 let tmp1;
144 let snap = Snap(db.snapshot()); 170 let tmp2;
145 #[cfg(not(feature = "wasm"))] 171 let buf: Vec<&SymbolIndex> = if query.libs {
146 let buf = db 172 tmp1 = db.library_symbols();
147 .library_roots() 173 tmp1.values().collect()
148 .par_iter()
149 .map_with(snap, |db, &lib_id| db.0.library_symbols(lib_id))
150 .collect();
151
152 #[cfg(feature = "wasm")]
153 let buf = db.library_roots().iter().map(|&lib_id| snap.0.library_symbols(lib_id)).collect();
154
155 buf
156 } else { 174 } else {
157 let mut files = Vec::new(); 175 let mut files = Vec::new();
158 for &root in db.local_roots().iter() { 176 for &root in db.local_roots().iter() {
@@ -161,15 +179,36 @@ pub fn world_symbols(db: &RootDatabase, query: Query) -> Vec<FileSymbol> {
161 } 179 }
162 180
163 let snap = Snap(db.snapshot()); 181 let snap = Snap(db.snapshot());
164 #[cfg(not(feature = "wasm"))] 182 tmp2 = files
165 let buf = 183 .par_iter()
166 files.par_iter().map_with(snap, |db, &file_id| db.0.file_symbols(file_id)).collect(); 184 .map_with(snap, |db, &file_id| db.0.file_symbols(file_id))
185 .collect::<Vec<_>>();
186 tmp2.iter().map(|it| &**it).collect()
187 };
188 query.search(&buf)
189}
167 190
168 #[cfg(feature = "wasm")] 191pub fn crate_symbols(db: &RootDatabase, krate: CrateId, query: Query) -> Vec<FileSymbol> {
169 let buf = files.iter().map(|&file_id| snap.0.file_symbols(file_id)).collect(); 192 // FIXME(#4842): This now depends on CrateDefMap, why not build the entire symbol index from
193 // that instead?
194
195 let def_map = db.crate_def_map(krate);
196 let mut files = Vec::new();
197 let mut modules = vec![def_map.root];
198 while let Some(module) = modules.pop() {
199 let data = &def_map[module];
200 files.extend(data.origin.file_id());
201 modules.extend(data.children.values());
202 }
203
204 let snap = Snap(db.snapshot());
205
206 let buf = files
207 .par_iter()
208 .map_with(snap, |db, &file_id| db.0.file_symbols(file_id))
209 .collect::<Vec<_>>();
210 let buf = buf.iter().map(|it| &**it).collect::<Vec<_>>();
170 211
171 buf
172 };
173 query.search(&buf) 212 query.search(&buf)
174} 213}
175 214
@@ -215,12 +254,8 @@ impl SymbolIndex {
215 lhs_chars.cmp(rhs_chars) 254 lhs_chars.cmp(rhs_chars)
216 } 255 }
217 256
218 #[cfg(not(feature = "wasm"))]
219 symbols.par_sort_by(cmp); 257 symbols.par_sort_by(cmp);
220 258
221 #[cfg(feature = "wasm")]
222 symbols.sort_by(cmp);
223
224 let mut builder = fst::MapBuilder::memory(); 259 let mut builder = fst::MapBuilder::memory();
225 260
226 let mut last_batch_start = 0; 261 let mut last_batch_start = 0;
@@ -254,7 +289,6 @@ impl SymbolIndex {
254 self.map.as_fst().size() + self.symbols.len() * mem::size_of::<FileSymbol>() 289 self.map.as_fst().size() + self.symbols.len() * mem::size_of::<FileSymbol>()
255 } 290 }
256 291
257 #[cfg(not(feature = "wasm"))]
258 pub(crate) fn for_files( 292 pub(crate) fn for_files(
259 files: impl ParallelIterator<Item = (FileId, Parse<ast::SourceFile>)>, 293 files: impl ParallelIterator<Item = (FileId, Parse<ast::SourceFile>)>,
260 ) -> SymbolIndex { 294 ) -> SymbolIndex {
@@ -264,16 +298,6 @@ impl SymbolIndex {
264 SymbolIndex::new(symbols) 298 SymbolIndex::new(symbols)
265 } 299 }
266 300
267 #[cfg(feature = "wasm")]
268 pub(crate) fn for_files(
269 files: impl Iterator<Item = (FileId, Parse<ast::SourceFile>)>,
270 ) -> SymbolIndex {
271 let symbols = files
272 .flat_map(|(file_id, file)| source_file_to_file_symbols(&file.tree(), file_id))
273 .collect::<Vec<_>>();
274 SymbolIndex::new(symbols)
275 }
276
277 fn range_to_map_value(start: usize, end: usize) -> u64 { 301 fn range_to_map_value(start: usize, end: usize) -> u64 {
278 debug_assert![start <= (std::u32::MAX as usize)]; 302 debug_assert![start <= (std::u32::MAX as usize)];
279 debug_assert![end <= (std::u32::MAX as usize)]; 303 debug_assert![end <= (std::u32::MAX as usize)];
@@ -289,7 +313,7 @@ impl SymbolIndex {
289} 313}
290 314
291impl Query { 315impl Query {
292 pub(crate) fn search(self, indices: &[Arc<SymbolIndex>]) -> Vec<FileSymbol> { 316 pub(crate) fn search(self, indices: &[&SymbolIndex]) -> Vec<FileSymbol> {
293 let mut op = fst::map::OpBuilder::new(); 317 let mut op = fst::map::OpBuilder::new();
294 for file_symbols in indices.iter() { 318 for file_symbols in indices.iter() {
295 let automaton = fst::automaton::Subsequence::new(&self.lowercased); 319 let automaton = fst::automaton::Subsequence::new(&self.lowercased);
@@ -298,9 +322,6 @@ impl Query {
298 let mut stream = op.union(); 322 let mut stream = op.union();
299 let mut res = Vec::new(); 323 let mut res = Vec::new();
300 while let Some((_, indexed_values)) = stream.next() { 324 while let Some((_, indexed_values)) = stream.next() {
301 if res.len() >= self.limit {
302 break;
303 }
304 for indexed_value in indexed_values { 325 for indexed_value in indexed_values {
305 let symbol_index = &indices[indexed_value.index]; 326 let symbol_index = &indices[indexed_value.index];
306 let (start, end) = SymbolIndex::map_value_to_range(indexed_value.value); 327 let (start, end) = SymbolIndex::map_value_to_range(indexed_value.value);
@@ -312,7 +333,11 @@ impl Query {
312 if self.exact && symbol.name != self.query { 333 if self.exact && symbol.name != self.query {
313 continue; 334 continue;
314 } 335 }
336
315 res.push(symbol.clone()); 337 res.push(symbol.clone());
338 if res.len() >= self.limit {
339 return res;
340 }
316 } 341 }
317 } 342 }
318 } 343 }