aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_ide_db
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_ide_db')
-rw-r--r--crates/ra_ide_db/src/change.rs86
-rw-r--r--crates/ra_ide_db/src/defs.rs9
-rw-r--r--crates/ra_ide_db/src/imports_locator.rs46
-rw-r--r--crates/ra_ide_db/src/lib.rs20
-rw-r--r--crates/ra_ide_db/src/source_change.rs6
-rw-r--r--crates/ra_ide_db/src/symbol_index.rs127
6 files changed, 117 insertions, 177 deletions
diff --git a/crates/ra_ide_db/src/change.rs b/crates/ra_ide_db/src/change.rs
index 5dbe1c1b7..78ee6a515 100644
--- a/crates/ra_ide_db/src/change.rs
+++ b/crates/ra_ide_db/src/change.rs
@@ -9,24 +9,16 @@ use ra_db::{
9 SourceRootId, 9 SourceRootId,
10}; 10};
11use ra_prof::{memory_usage, profile, Bytes}; 11use ra_prof::{memory_usage, profile, Bytes};
12use ra_syntax::SourceFile;
13#[cfg(not(feature = "wasm"))]
14use rayon::prelude::*;
15use rustc_hash::FxHashMap; 12use rustc_hash::FxHashMap;
16 13
17use crate::{ 14use crate::{symbol_index::SymbolsDatabase, RootDatabase};
18 symbol_index::{SymbolIndex, SymbolsDatabase},
19 DebugData, RootDatabase,
20};
21 15
22#[derive(Default)] 16#[derive(Default)]
23pub struct AnalysisChange { 17pub struct AnalysisChange {
24 new_roots: Vec<(SourceRootId, bool)>, 18 new_roots: Vec<(SourceRootId, bool)>,
25 roots_changed: FxHashMap<SourceRootId, RootChange>, 19 roots_changed: FxHashMap<SourceRootId, RootChange>,
26 files_changed: Vec<(FileId, Arc<String>)>, 20 files_changed: Vec<(FileId, Arc<String>)>,
27 libraries_added: Vec<LibraryData>,
28 crate_graph: Option<CrateGraph>, 21 crate_graph: Option<CrateGraph>,
29 debug_data: DebugData,
30} 22}
31 23
32impl fmt::Debug for AnalysisChange { 24impl fmt::Debug for AnalysisChange {
@@ -41,9 +33,6 @@ impl fmt::Debug for AnalysisChange {
41 if !self.files_changed.is_empty() { 33 if !self.files_changed.is_empty() {
42 d.field("files_changed", &self.files_changed.len()); 34 d.field("files_changed", &self.files_changed.len());
43 } 35 }
44 if !self.libraries_added.is_empty() {
45 d.field("libraries_added", &self.libraries_added.len());
46 }
47 if self.crate_graph.is_some() { 36 if self.crate_graph.is_some() {
48 d.field("crate_graph", &self.crate_graph); 37 d.field("crate_graph", &self.crate_graph);
49 } 38 }
@@ -80,17 +69,9 @@ impl AnalysisChange {
80 self.roots_changed.entry(root_id).or_default().removed.push(file); 69 self.roots_changed.entry(root_id).or_default().removed.push(file);
81 } 70 }
82 71
83 pub fn add_library(&mut self, data: LibraryData) {
84 self.libraries_added.push(data)
85 }
86
87 pub fn set_crate_graph(&mut self, graph: CrateGraph) { 72 pub fn set_crate_graph(&mut self, graph: CrateGraph) {
88 self.crate_graph = Some(graph); 73 self.crate_graph = Some(graph);
89 } 74 }
90
91 pub fn set_debug_root_path(&mut self, source_root_id: SourceRootId, path: String) {
92 self.debug_data.root_paths.insert(source_root_id, path);
93 }
94} 75}
95 76
96#[derive(Debug)] 77#[derive(Debug)]
@@ -121,47 +102,6 @@ impl fmt::Debug for RootChange {
121 } 102 }
122} 103}
123 104
124pub struct LibraryData {
125 root_id: SourceRootId,
126 root_change: RootChange,
127 symbol_index: SymbolIndex,
128}
129
130impl fmt::Debug for LibraryData {
131 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
132 f.debug_struct("LibraryData")
133 .field("root_id", &self.root_id)
134 .field("root_change", &self.root_change)
135 .field("n_symbols", &self.symbol_index.len())
136 .finish()
137 }
138}
139
140impl LibraryData {
141 pub fn prepare(
142 root_id: SourceRootId,
143 files: Vec<(FileId, RelativePathBuf, Arc<String>)>,
144 ) -> LibraryData {
145 let _p = profile("LibraryData::prepare");
146
147 #[cfg(not(feature = "wasm"))]
148 let iter = files.par_iter();
149 #[cfg(feature = "wasm")]
150 let iter = files.iter();
151
152 let symbol_index = SymbolIndex::for_files(iter.map(|(file_id, _, text)| {
153 let parse = SourceFile::parse(text);
154 (*file_id, parse)
155 }));
156 let mut root_change = RootChange::default();
157 root_change.added = files
158 .into_iter()
159 .map(|(file_id, path, text)| AddFile { file_id, path, text })
160 .collect();
161 LibraryData { root_id, root_change, symbol_index }
162 }
163}
164
165const GC_COOLDOWN: time::Duration = time::Duration::from_millis(100); 105const GC_COOLDOWN: time::Duration = time::Duration::from_millis(100);
166 106
167impl RootDatabase { 107impl RootDatabase {
@@ -176,6 +116,7 @@ impl RootDatabase {
176 log::info!("apply_change {:?}", change); 116 log::info!("apply_change {:?}", change);
177 if !change.new_roots.is_empty() { 117 if !change.new_roots.is_empty() {
178 let mut local_roots = Vec::clone(&self.local_roots()); 118 let mut local_roots = Vec::clone(&self.local_roots());
119 let mut libraries = Vec::clone(&self.library_roots());
179 for (root_id, is_local) in change.new_roots { 120 for (root_id, is_local) in change.new_roots {
180 let root = 121 let root =
181 if is_local { SourceRoot::new_local() } else { SourceRoot::new_library() }; 122 if is_local { SourceRoot::new_local() } else { SourceRoot::new_library() };
@@ -183,9 +124,12 @@ impl RootDatabase {
183 self.set_source_root_with_durability(root_id, Arc::new(root), durability); 124 self.set_source_root_with_durability(root_id, Arc::new(root), durability);
184 if is_local { 125 if is_local {
185 local_roots.push(root_id); 126 local_roots.push(root_id);
127 } else {
128 libraries.push(root_id)
186 } 129 }
187 } 130 }
188 self.set_local_roots_with_durability(Arc::new(local_roots), Durability::HIGH); 131 self.set_local_roots_with_durability(Arc::new(local_roots), Durability::HIGH);
132 self.set_library_roots_with_durability(Arc::new(libraries), Durability::HIGH);
189 } 133 }
190 134
191 for (root_id, root_change) in change.roots_changed { 135 for (root_id, root_change) in change.roots_changed {
@@ -197,29 +141,9 @@ impl RootDatabase {
197 let durability = durability(&source_root); 141 let durability = durability(&source_root);
198 self.set_file_text_with_durability(file_id, text, durability) 142 self.set_file_text_with_durability(file_id, text, durability)
199 } 143 }
200 if !change.libraries_added.is_empty() {
201 let mut libraries = Vec::clone(&self.library_roots());
202 for library in change.libraries_added {
203 libraries.push(library.root_id);
204 self.set_source_root_with_durability(
205 library.root_id,
206 Arc::new(SourceRoot::new_library()),
207 Durability::HIGH,
208 );
209 self.set_library_symbols_with_durability(
210 library.root_id,
211 Arc::new(library.symbol_index),
212 Durability::HIGH,
213 );
214 self.apply_root_change(library.root_id, library.root_change);
215 }
216 self.set_library_roots_with_durability(Arc::new(libraries), Durability::HIGH);
217 }
218 if let Some(crate_graph) = change.crate_graph { 144 if let Some(crate_graph) = change.crate_graph {
219 self.set_crate_graph_with_durability(Arc::new(crate_graph), Durability::HIGH) 145 self.set_crate_graph_with_durability(Arc::new(crate_graph), Durability::HIGH)
220 } 146 }
221
222 Arc::make_mut(&mut self.debug_data).merge(change.debug_data)
223 } 147 }
224 148
225 fn apply_root_change(&mut self, root_id: SourceRootId, root_change: RootChange) { 149 fn apply_root_change(&mut self, root_id: SourceRootId, root_change: RootChange) {
diff --git a/crates/ra_ide_db/src/defs.rs b/crates/ra_ide_db/src/defs.rs
index 1826f3ac6..3ef5e74b6 100644
--- a/crates/ra_ide_db/src/defs.rs
+++ b/crates/ra_ide_db/src/defs.rs
@@ -78,6 +78,7 @@ impl Definition {
78 } 78 }
79} 79}
80 80
81#[derive(Debug)]
81pub enum NameClass { 82pub enum NameClass {
82 Definition(Definition), 83 Definition(Definition),
83 /// `None` in `if let None = Some(82) {}` 84 /// `None` in `if let None = Some(82) {}`
@@ -131,9 +132,11 @@ pub fn classify_name(sema: &Semantics<RootDatabase>, name: &ast::Name) -> Option
131 let local = sema.to_def(&it)?; 132 let local = sema.to_def(&it)?;
132 133
133 if let Some(record_field_pat) = it.syntax().parent().and_then(ast::RecordFieldPat::cast) { 134 if let Some(record_field_pat) = it.syntax().parent().and_then(ast::RecordFieldPat::cast) {
134 if let Some(field) = sema.resolve_record_field_pat(&record_field_pat) { 135 if record_field_pat.name_ref().is_none() {
135 let field = Definition::Field(field); 136 if let Some(field) = sema.resolve_record_field_pat(&record_field_pat) {
136 return Some(NameClass::FieldShorthand { local, field }); 137 let field = Definition::Field(field);
138 return Some(NameClass::FieldShorthand { local, field });
139 }
137 } 140 }
138 } 141 }
139 142
diff --git a/crates/ra_ide_db/src/imports_locator.rs b/crates/ra_ide_db/src/imports_locator.rs
index bf0d8db60..fff112e66 100644
--- a/crates/ra_ide_db/src/imports_locator.rs
+++ b/crates/ra_ide_db/src/imports_locator.rs
@@ -1,7 +1,7 @@
1//! This module contains an import search funcionality that is provided to the ra_assists module. 1//! This module contains an import search funcionality that is provided to the ra_assists module.
2//! Later, this should be moved away to a separate crate that is accessible from the ra_assists module. 2//! Later, this should be moved away to a separate crate that is accessible from the ra_assists module.
3 3
4use hir::{MacroDef, ModuleDef, Semantics}; 4use hir::{Crate, MacroDef, ModuleDef, Semantics};
5use ra_prof::profile; 5use ra_prof::profile;
6use ra_syntax::{ast, AstNode, SyntaxKind::NAME}; 6use ra_syntax::{ast, AstNode, SyntaxKind::NAME};
7 7
@@ -11,44 +11,46 @@ use crate::{
11 RootDatabase, 11 RootDatabase,
12}; 12};
13use either::Either; 13use either::Either;
14use rustc_hash::FxHashSet;
14 15
15pub struct ImportsLocator<'a> { 16pub struct ImportsLocator<'a> {
16 sema: Semantics<'a, RootDatabase>, 17 sema: Semantics<'a, RootDatabase>,
18 krate: Crate,
17} 19}
18 20
19impl<'a> ImportsLocator<'a> { 21impl<'a> ImportsLocator<'a> {
20 pub fn new(db: &'a RootDatabase) -> Self { 22 pub fn new(db: &'a RootDatabase, krate: Crate) -> Self {
21 Self { sema: Semantics::new(db) } 23 Self { sema: Semantics::new(db), krate }
22 } 24 }
23 25
24 pub fn find_imports(&mut self, name_to_import: &str) -> Vec<Either<ModuleDef, MacroDef>> { 26 pub fn find_imports(&mut self, name_to_import: &str) -> Vec<Either<ModuleDef, MacroDef>> {
25 let _p = profile("search_for_imports"); 27 let _p = profile("search_for_imports");
26 let db = self.sema.db; 28 let db = self.sema.db;
27 29
28 let project_results = { 30 // Query dependencies first.
29 let mut query = Query::new(name_to_import.to_string()); 31 let mut candidates: FxHashSet<_> =
30 query.exact(); 32 self.krate.query_external_importables(db, name_to_import).collect();
31 query.limit(40); 33
32 symbol_index::world_symbols(db, query) 34 // Query the local crate using the symbol index.
33 }; 35 let local_results = {
34 let lib_results = {
35 let mut query = Query::new(name_to_import.to_string()); 36 let mut query = Query::new(name_to_import.to_string());
36 query.libs();
37 query.exact(); 37 query.exact();
38 query.limit(40); 38 query.limit(40);
39 symbol_index::world_symbols(db, query) 39 symbol_index::crate_symbols(db, self.krate.into(), query)
40 }; 40 };
41 41
42 project_results 42 candidates.extend(
43 .into_iter() 43 local_results
44 .chain(lib_results.into_iter()) 44 .into_iter()
45 .filter_map(|import_candidate| self.get_name_definition(&import_candidate)) 45 .filter_map(|import_candidate| self.get_name_definition(&import_candidate))
46 .filter_map(|name_definition_to_import| match name_definition_to_import { 46 .filter_map(|name_definition_to_import| match name_definition_to_import {
47 Definition::ModuleDef(module_def) => Some(Either::Left(module_def)), 47 Definition::ModuleDef(module_def) => Some(Either::Left(module_def)),
48 Definition::Macro(macro_def) => Some(Either::Right(macro_def)), 48 Definition::Macro(macro_def) => Some(Either::Right(macro_def)),
49 _ => None, 49 _ => None,
50 }) 50 }),
51 .collect() 51 );
52
53 candidates.into_iter().collect()
52 } 54 }
53 55
54 fn get_name_definition(&mut self, import_candidate: &FileSymbol) -> Option<Definition> { 56 fn get_name_definition(&mut self, import_candidate: &FileSymbol) -> Option<Definition> {
diff --git a/crates/ra_ide_db/src/lib.rs b/crates/ra_ide_db/src/lib.rs
index 727d743b5..a808de4f1 100644
--- a/crates/ra_ide_db/src/lib.rs
+++ b/crates/ra_ide_db/src/lib.rs
@@ -17,9 +17,9 @@ use hir::db::{AstDatabase, DefDatabase};
17use ra_db::{ 17use ra_db::{
18 salsa::{self, Database, Durability}, 18 salsa::{self, Database, Durability},
19 Canceled, CheckCanceled, CrateId, FileId, FileLoader, FileLoaderDelegate, SourceDatabase, 19 Canceled, CheckCanceled, CrateId, FileId, FileLoader, FileLoaderDelegate, SourceDatabase,
20 SourceRootId, Upcast, 20 Upcast,
21}; 21};
22use rustc_hash::FxHashMap; 22use rustc_hash::FxHashSet;
23 23
24use crate::{line_index::LineIndex, symbol_index::SymbolsDatabase}; 24use crate::{line_index::LineIndex, symbol_index::SymbolsDatabase};
25 25
@@ -36,7 +36,6 @@ use crate::{line_index::LineIndex, symbol_index::SymbolsDatabase};
36#[derive(Debug)] 36#[derive(Debug)]
37pub struct RootDatabase { 37pub struct RootDatabase {
38 runtime: salsa::Runtime<RootDatabase>, 38 runtime: salsa::Runtime<RootDatabase>,
39 pub(crate) debug_data: Arc<DebugData>,
40 pub last_gc: crate::wasm_shims::Instant, 39 pub last_gc: crate::wasm_shims::Instant,
41 pub last_gc_check: crate::wasm_shims::Instant, 40 pub last_gc_check: crate::wasm_shims::Instant,
42} 41}
@@ -60,7 +59,7 @@ impl FileLoader for RootDatabase {
60 fn resolve_path(&self, anchor: FileId, path: &str) -> Option<FileId> { 59 fn resolve_path(&self, anchor: FileId, path: &str) -> Option<FileId> {
61 FileLoaderDelegate(self).resolve_path(anchor, path) 60 FileLoaderDelegate(self).resolve_path(anchor, path)
62 } 61 }
63 fn relevant_crates(&self, file_id: FileId) -> Arc<Vec<CrateId>> { 62 fn relevant_crates(&self, file_id: FileId) -> Arc<FxHashSet<CrateId>> {
64 FileLoaderDelegate(self).relevant_crates(file_id) 63 FileLoaderDelegate(self).relevant_crates(file_id)
65 } 64 }
66} 65}
@@ -98,7 +97,6 @@ impl RootDatabase {
98 runtime: salsa::Runtime::default(), 97 runtime: salsa::Runtime::default(),
99 last_gc: crate::wasm_shims::Instant::now(), 98 last_gc: crate::wasm_shims::Instant::now(),
100 last_gc_check: crate::wasm_shims::Instant::now(), 99 last_gc_check: crate::wasm_shims::Instant::now(),
101 debug_data: Default::default(),
102 }; 100 };
103 db.set_crate_graph_with_durability(Default::default(), Durability::HIGH); 101 db.set_crate_graph_with_durability(Default::default(), Durability::HIGH);
104 db.set_local_roots_with_durability(Default::default(), Durability::HIGH); 102 db.set_local_roots_with_durability(Default::default(), Durability::HIGH);
@@ -121,7 +119,6 @@ impl salsa::ParallelDatabase for RootDatabase {
121 runtime: self.runtime.snapshot(self), 119 runtime: self.runtime.snapshot(self),
122 last_gc: self.last_gc, 120 last_gc: self.last_gc,
123 last_gc_check: self.last_gc_check, 121 last_gc_check: self.last_gc_check,
124 debug_data: Arc::clone(&self.debug_data),
125 }) 122 })
126 } 123 }
127} 124}
@@ -135,14 +132,3 @@ fn line_index(db: &impl LineIndexDatabase, file_id: FileId) -> Arc<LineIndex> {
135 let text = db.file_text(file_id); 132 let text = db.file_text(file_id);
136 Arc::new(LineIndex::new(&*text)) 133 Arc::new(LineIndex::new(&*text))
137} 134}
138
139#[derive(Debug, Default, Clone)]
140pub(crate) struct DebugData {
141 pub(crate) root_paths: FxHashMap<SourceRootId, String>,
142}
143
144impl DebugData {
145 pub(crate) fn merge(&mut self, other: DebugData) {
146 self.root_paths.extend(other.root_paths.into_iter());
147 }
148}
diff --git a/crates/ra_ide_db/src/source_change.rs b/crates/ra_ide_db/src/source_change.rs
index f40ae8304..0bbd3c3e5 100644
--- a/crates/ra_ide_db/src/source_change.rs
+++ b/crates/ra_ide_db/src/source_change.rs
@@ -3,7 +3,7 @@
3//! 3//!
4//! It can be viewed as a dual for `AnalysisChange`. 4//! It can be viewed as a dual for `AnalysisChange`.
5 5
6use ra_db::{FileId, RelativePathBuf, SourceRootId}; 6use ra_db::FileId;
7use ra_text_edit::TextEdit; 7use ra_text_edit::TextEdit;
8 8
9#[derive(Debug, Clone)] 9#[derive(Debug, Clone)]
@@ -44,8 +44,8 @@ impl From<Vec<SourceFileEdit>> for SourceChange {
44 44
45#[derive(Debug, Clone)] 45#[derive(Debug, Clone)]
46pub enum FileSystemEdit { 46pub enum FileSystemEdit {
47 CreateFile { source_root: SourceRootId, path: RelativePathBuf }, 47 CreateFile { anchor: FileId, dst: String },
48 MoveFile { src: FileId, dst_source_root: SourceRootId, dst_path: RelativePathBuf }, 48 MoveFile { src: FileId, anchor: FileId, dst: String },
49} 49}
50 50
51impl From<FileSystemEdit> for SourceChange { 51impl From<FileSystemEdit> for SourceChange {
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 }