aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_ide_db/src
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_ide_db/src')
-rw-r--r--crates/ra_ide_db/src/change.rs254
-rw-r--r--crates/ra_ide_db/src/defs.rs69
-rw-r--r--crates/ra_ide_db/src/imports_locator.rs84
-rw-r--r--crates/ra_ide_db/src/lib.rs80
-rw-r--r--crates/ra_ide_db/src/search.rs16
-rw-r--r--crates/ra_ide_db/src/source_change.rs31
-rw-r--r--crates/ra_ide_db/src/symbol_index.rs138
7 files changed, 291 insertions, 381 deletions
diff --git a/crates/ra_ide_db/src/change.rs b/crates/ra_ide_db/src/change.rs
index 8446ef88e..a1bb3043b 100644
--- a/crates/ra_ide_db/src/change.rs
+++ b/crates/ra_ide_db/src/change.rs
@@ -5,45 +5,29 @@ use std::{fmt, sync::Arc, time};
5 5
6use ra_db::{ 6use ra_db::{
7 salsa::{Database, Durability, SweepStrategy}, 7 salsa::{Database, Durability, SweepStrategy},
8 CrateGraph, FileId, RelativePathBuf, SourceDatabase, SourceDatabaseExt, SourceRoot, 8 CrateGraph, FileId, SourceDatabase, SourceDatabaseExt, SourceRoot, SourceRootId,
9 SourceRootId,
10}; 9};
11use ra_prof::{memory_usage, profile, Bytes}; 10use ra_prof::{memory_usage, profile, Bytes};
12use ra_syntax::SourceFile; 11use rustc_hash::FxHashSet;
13#[cfg(not(feature = "wasm"))] 12
14use rayon::prelude::*; 13use crate::{symbol_index::SymbolsDatabase, RootDatabase};
15use rustc_hash::FxHashMap;
16
17use crate::{
18 symbol_index::{SymbolIndex, SymbolsDatabase},
19 DebugData, RootDatabase,
20};
21 14
22#[derive(Default)] 15#[derive(Default)]
23pub struct AnalysisChange { 16pub struct AnalysisChange {
24 new_roots: Vec<(SourceRootId, bool)>, 17 roots: Option<Vec<SourceRoot>>,
25 roots_changed: FxHashMap<SourceRootId, RootChange>, 18 files_changed: Vec<(FileId, Option<Arc<String>>)>,
26 files_changed: Vec<(FileId, Arc<String>)>,
27 libraries_added: Vec<LibraryData>,
28 crate_graph: Option<CrateGraph>, 19 crate_graph: Option<CrateGraph>,
29 debug_data: DebugData,
30} 20}
31 21
32impl fmt::Debug for AnalysisChange { 22impl fmt::Debug for AnalysisChange {
33 fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { 23 fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
34 let mut d = fmt.debug_struct("AnalysisChange"); 24 let mut d = fmt.debug_struct("AnalysisChange");
35 if !self.new_roots.is_empty() { 25 if let Some(roots) = &self.roots {
36 d.field("new_roots", &self.new_roots); 26 d.field("roots", roots);
37 }
38 if !self.roots_changed.is_empty() {
39 d.field("roots_changed", &self.roots_changed);
40 } 27 }
41 if !self.files_changed.is_empty() { 28 if !self.files_changed.is_empty() {
42 d.field("files_changed", &self.files_changed.len()); 29 d.field("files_changed", &self.files_changed.len());
43 } 30 }
44 if !self.libraries_added.is_empty() {
45 d.field("libraries_added", &self.libraries_added.len());
46 }
47 if self.crate_graph.is_some() { 31 if self.crate_graph.is_some() {
48 d.field("crate_graph", &self.crate_graph); 32 d.field("crate_graph", &self.crate_graph);
49 } 33 }
@@ -56,54 +40,30 @@ impl AnalysisChange {
56 AnalysisChange::default() 40 AnalysisChange::default()
57 } 41 }
58 42
59 pub fn add_root(&mut self, root_id: SourceRootId, is_local: bool) { 43 pub fn set_roots(&mut self, roots: Vec<SourceRoot>) {
60 self.new_roots.push((root_id, is_local)); 44 self.roots = Some(roots);
61 } 45 }
62 46
63 pub fn add_file( 47 pub fn change_file(&mut self, file_id: FileId, new_text: Option<Arc<String>>) {
64 &mut self,
65 root_id: SourceRootId,
66 file_id: FileId,
67 path: RelativePathBuf,
68 text: Arc<String>,
69 ) {
70 let file = AddFile { file_id, path, text };
71 self.roots_changed.entry(root_id).or_default().added.push(file);
72 }
73
74 pub fn change_file(&mut self, file_id: FileId, new_text: Arc<String>) {
75 self.files_changed.push((file_id, new_text)) 48 self.files_changed.push((file_id, new_text))
76 } 49 }
77 50
78 pub fn remove_file(&mut self, root_id: SourceRootId, file_id: FileId, path: RelativePathBuf) {
79 let file = RemoveFile { file_id, path };
80 self.roots_changed.entry(root_id).or_default().removed.push(file);
81 }
82
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) { 51 pub fn set_crate_graph(&mut self, graph: CrateGraph) {
88 self.crate_graph = Some(graph); 52 self.crate_graph = Some(graph);
89 } 53 }
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} 54}
95 55
96#[derive(Debug)] 56#[derive(Debug)]
97struct AddFile { 57struct AddFile {
98 file_id: FileId, 58 file_id: FileId,
99 path: RelativePathBuf, 59 path: String,
100 text: Arc<String>, 60 text: Arc<String>,
101} 61}
102 62
103#[derive(Debug)] 63#[derive(Debug)]
104struct RemoveFile { 64struct RemoveFile {
105 file_id: FileId, 65 file_id: FileId,
106 path: RelativePathBuf, 66 path: String,
107} 67}
108 68
109#[derive(Default)] 69#[derive(Default)]
@@ -121,47 +81,6 @@ impl fmt::Debug for RootChange {
121 } 81 }
122} 82}
123 83
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); 84const GC_COOLDOWN: time::Duration = time::Duration::from_millis(100);
166 85
167impl RootDatabase { 86impl RootDatabase {
@@ -174,72 +93,37 @@ impl RootDatabase {
174 let _p = profile("RootDatabase::apply_change"); 93 let _p = profile("RootDatabase::apply_change");
175 self.request_cancellation(); 94 self.request_cancellation();
176 log::info!("apply_change {:?}", change); 95 log::info!("apply_change {:?}", change);
177 if !change.new_roots.is_empty() { 96 if let Some(roots) = change.roots {
178 let mut local_roots = Vec::clone(&self.local_roots()); 97 let mut local_roots = FxHashSet::default();
179 for (root_id, is_local) in change.new_roots { 98 let mut library_roots = FxHashSet::default();
180 let root = 99 for (idx, root) in roots.into_iter().enumerate() {
181 if is_local { SourceRoot::new_local() } else { SourceRoot::new_library() }; 100 let root_id = SourceRootId(idx as u32);
182 let durability = durability(&root); 101 let durability = durability(&root);
183 self.set_source_root_with_durability(root_id, Arc::new(root), durability); 102 if root.is_library {
184 if is_local { 103 library_roots.insert(root_id);
185 local_roots.push(root_id); 104 } else {
105 local_roots.insert(root_id);
186 } 106 }
107 for file_id in root.iter() {
108 self.set_file_source_root_with_durability(file_id, root_id, durability);
109 }
110 self.set_source_root_with_durability(root_id, Arc::new(root), durability);
187 } 111 }
188 self.set_local_roots_with_durability(Arc::new(local_roots), Durability::HIGH); 112 self.set_local_roots_with_durability(Arc::new(local_roots), Durability::HIGH);
113 self.set_library_roots_with_durability(Arc::new(library_roots), Durability::HIGH);
189 } 114 }
190 115
191 for (root_id, root_change) in change.roots_changed {
192 self.apply_root_change(root_id, root_change);
193 }
194 for (file_id, text) in change.files_changed { 116 for (file_id, text) in change.files_changed {
195 let source_root_id = self.file_source_root(file_id); 117 let source_root_id = self.file_source_root(file_id);
196 let source_root = self.source_root(source_root_id); 118 let source_root = self.source_root(source_root_id);
197 let durability = durability(&source_root); 119 let durability = durability(&source_root);
120 // XXX: can't actually remove the file, just reset the text
121 let text = text.unwrap_or_default();
198 self.set_file_text_with_durability(file_id, text, durability) 122 self.set_file_text_with_durability(file_id, text, durability)
199 } 123 }
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 { 124 if let Some(crate_graph) = change.crate_graph {
219 self.set_crate_graph_with_durability(Arc::new(crate_graph), Durability::HIGH) 125 self.set_crate_graph_with_durability(Arc::new(crate_graph), Durability::HIGH)
220 } 126 }
221
222 Arc::make_mut(&mut self.debug_data).merge(change.debug_data)
223 }
224
225 fn apply_root_change(&mut self, root_id: SourceRootId, root_change: RootChange) {
226 let mut source_root = SourceRoot::clone(&self.source_root(root_id));
227 let durability = durability(&source_root);
228 for add_file in root_change.added {
229 self.set_file_text_with_durability(add_file.file_id, add_file.text, durability);
230 self.set_file_relative_path_with_durability(
231 add_file.file_id,
232 add_file.path.clone(),
233 durability,
234 );
235 self.set_file_source_root_with_durability(add_file.file_id, root_id, durability);
236 source_root.insert_file(add_file.path, add_file.file_id);
237 }
238 for remove_file in root_change.removed {
239 self.set_file_text_with_durability(remove_file.file_id, Default::default(), durability);
240 source_root.remove_file(&remove_file.path);
241 }
242 self.set_source_root_with_durability(root_id, Arc::new(source_root), durability);
243 } 127 }
244 128
245 pub fn maybe_collect_garbage(&mut self) { 129 pub fn maybe_collect_garbage(&mut self) {
@@ -262,37 +146,46 @@ impl RootDatabase {
262 146
263 let sweep = SweepStrategy::default().discard_values().sweep_all_revisions(); 147 let sweep = SweepStrategy::default().discard_values().sweep_all_revisions();
264 148
265 self.query(ra_db::ParseQuery).sweep(sweep); 149 ra_db::ParseQuery.in_db(self).sweep(sweep);
266 self.query(hir::db::ParseMacroQuery).sweep(sweep); 150 hir::db::ParseMacroQuery.in_db(self).sweep(sweep);
267 151
268 // Macros do take significant space, but less then the syntax trees 152 // Macros do take significant space, but less then the syntax trees
269 // self.query(hir::db::MacroDefQuery).sweep(sweep); 153 // self.query(hir::db::MacroDefQuery).sweep(sweep);
270 // self.query(hir::db::MacroArgQuery).sweep(sweep); 154 // self.query(hir::db::MacroArgQuery).sweep(sweep);
271 // self.query(hir::db::MacroExpandQuery).sweep(sweep); 155 // self.query(hir::db::MacroExpandQuery).sweep(sweep);
272 156
273 self.query(hir::db::AstIdMapQuery).sweep(sweep); 157 hir::db::AstIdMapQuery.in_db(self).sweep(sweep);
274 158
275 self.query(hir::db::BodyWithSourceMapQuery).sweep(sweep); 159 hir::db::BodyWithSourceMapQuery.in_db(self).sweep(sweep);
276 160
277 self.query(hir::db::ExprScopesQuery).sweep(sweep); 161 hir::db::ExprScopesQuery.in_db(self).sweep(sweep);
278 self.query(hir::db::InferQueryQuery).sweep(sweep); 162 hir::db::InferQueryQuery.in_db(self).sweep(sweep);
279 self.query(hir::db::BodyQuery).sweep(sweep); 163 hir::db::BodyQuery.in_db(self).sweep(sweep);
280 } 164 }
281 165
166 // Feature: Memory Usage
167 //
168 // Clears rust-analyzer's internal database and prints memory usage statistics.
169 //
170 // |===
171 // | Editor | Action Name
172 //
173 // | VS Code | **Rust Analyzer: Memory Usage (Clears Database)**
174 // |===
282 pub fn per_query_memory_usage(&mut self) -> Vec<(String, Bytes)> { 175 pub fn per_query_memory_usage(&mut self) -> Vec<(String, Bytes)> {
283 let mut acc: Vec<(String, Bytes)> = vec![]; 176 let mut acc: Vec<(String, Bytes)> = vec![];
284 let sweep = SweepStrategy::default().discard_values().sweep_all_revisions(); 177 let sweep = SweepStrategy::default().discard_values().sweep_all_revisions();
285 macro_rules! sweep_each_query { 178 macro_rules! sweep_each_query {
286 ($($q:path)*) => {$( 179 ($($q:path)*) => {$(
287 let before = memory_usage().allocated; 180 let before = memory_usage().allocated;
288 self.query($q).sweep(sweep); 181 $q.in_db(self).sweep(sweep);
289 let after = memory_usage().allocated; 182 let after = memory_usage().allocated;
290 let q: $q = Default::default(); 183 let q: $q = Default::default();
291 let name = format!("{:?}", q); 184 let name = format!("{:?}", q);
292 acc.push((name, before - after)); 185 acc.push((name, before - after));
293 186
294 let before = memory_usage().allocated; 187 let before = memory_usage().allocated;
295 self.query($q).sweep(sweep.discard_everything()); 188 $q.in_db(self).sweep(sweep.discard_everything());
296 let after = memory_usage().allocated; 189 let after = memory_usage().allocated;
297 let q: $q = Default::default(); 190 let q: $q = Default::default();
298 let name = format!("{:?} (deps)", q); 191 let name = format!("{:?} (deps)", q);
@@ -306,15 +199,13 @@ impl RootDatabase {
306 199
307 // AstDatabase 200 // AstDatabase
308 hir::db::AstIdMapQuery 201 hir::db::AstIdMapQuery
309 hir::db::InternMacroQuery
310 hir::db::MacroArgQuery 202 hir::db::MacroArgQuery
311 hir::db::MacroDefQuery 203 hir::db::MacroDefQuery
312 hir::db::ParseMacroQuery 204 hir::db::ParseMacroQuery
313 hir::db::MacroExpandQuery 205 hir::db::MacroExpandQuery
314 hir::db::InternEagerExpansionQuery
315 206
316 // DefDatabase 207 // DefDatabase
317 hir::db::RawItemsQuery 208 hir::db::ItemTreeQuery
318 hir::db::CrateDefMapQueryQuery 209 hir::db::CrateDefMapQueryQuery
319 hir::db::StructDataQuery 210 hir::db::StructDataQuery
320 hir::db::UnionDataQuery 211 hir::db::UnionDataQuery
@@ -334,17 +225,7 @@ impl RootDatabase {
334 hir::db::CrateLangItemsQuery 225 hir::db::CrateLangItemsQuery
335 hir::db::LangItemQuery 226 hir::db::LangItemQuery
336 hir::db::DocumentationQuery 227 hir::db::DocumentationQuery
337 228 hir::db::ImportMapQuery
338 // InternDatabase
339 hir::db::InternFunctionQuery
340 hir::db::InternStructQuery
341 hir::db::InternUnionQuery
342 hir::db::InternEnumQuery
343 hir::db::InternConstQuery
344 hir::db::InternStaticQuery
345 hir::db::InternTraitQuery
346 hir::db::InternTypeAliasQuery
347 hir::db::InternImplQuery
348 229
349 // HirDatabase 230 // HirDatabase
350 hir::db::InferQueryQuery 231 hir::db::InferQueryQuery
@@ -357,18 +238,16 @@ impl RootDatabase {
357 hir::db::GenericPredicatesForParamQuery 238 hir::db::GenericPredicatesForParamQuery
358 hir::db::GenericPredicatesQuery 239 hir::db::GenericPredicatesQuery
359 hir::db::GenericDefaultsQuery 240 hir::db::GenericDefaultsQuery
360 hir::db::ImplsInCrateQuery 241 hir::db::InherentImplsInCrateQuery
361 hir::db::ImplsForTraitQuery 242 hir::db::TraitImplsInCrateQuery
362 hir::db::InternTypeCtorQuery 243 hir::db::TraitImplsInDepsQuery
363 hir::db::InternTypeParamIdQuery
364 hir::db::InternChalkImplQuery
365 hir::db::InternAssocTyValueQuery
366 hir::db::AssociatedTyDataQuery 244 hir::db::AssociatedTyDataQuery
367 hir::db::TraitDatumQuery 245 hir::db::TraitDatumQuery
368 hir::db::StructDatumQuery 246 hir::db::StructDatumQuery
369 hir::db::ImplDatumQuery 247 hir::db::ImplDatumQuery
370 hir::db::AssociatedTyValueQuery 248 hir::db::AssociatedTyValueQuery
371 hir::db::TraitSolveQuery 249 hir::db::TraitSolveQuery
250 hir::db::ReturnTypeImplTraitsQuery
372 251
373 // SymbolsDatabase 252 // SymbolsDatabase
374 crate::symbol_index::FileSymbolsQuery 253 crate::symbol_index::FileSymbolsQuery
@@ -376,6 +255,33 @@ impl RootDatabase {
376 // LineIndexDatabase 255 // LineIndexDatabase
377 crate::LineIndexQuery 256 crate::LineIndexQuery
378 ]; 257 ];
258
259 // To collect interned data, we need to bump the revision counter by performing a synthetic
260 // write.
261 // We do this after collecting the non-interned queries to correctly attribute memory used
262 // by interned data.
263 self.salsa_runtime_mut().synthetic_write(Durability::HIGH);
264
265 sweep_each_query![
266 // AstDatabase
267 hir::db::InternMacroQuery
268 hir::db::InternEagerExpansionQuery
269
270 // InternDatabase
271 hir::db::InternFunctionQuery
272 hir::db::InternStructQuery
273 hir::db::InternUnionQuery
274 hir::db::InternEnumQuery
275 hir::db::InternConstQuery
276 hir::db::InternStaticQuery
277 hir::db::InternTraitQuery
278 hir::db::InternTypeAliasQuery
279 hir::db::InternImplQuery
280
281 // HirDatabase
282 hir::db::InternTypeParamIdQuery
283 ];
284
379 acc.sort_by_key(|it| std::cmp::Reverse(it.1)); 285 acc.sort_by_key(|it| std::cmp::Reverse(it.1));
380 acc 286 acc
381 } 287 }
diff --git a/crates/ra_ide_db/src/defs.rs b/crates/ra_ide_db/src/defs.rs
index 8b06cbfc5..bcaabca92 100644
--- a/crates/ra_ide_db/src/defs.rs
+++ b/crates/ra_ide_db/src/defs.rs
@@ -18,7 +18,7 @@ use ra_syntax::{
18use crate::RootDatabase; 18use crate::RootDatabase;
19 19
20// FIXME: a more precise name would probably be `Symbol`? 20// FIXME: a more precise name would probably be `Symbol`?
21#[derive(Debug, PartialEq, Eq)] 21#[derive(Debug, PartialEq, Eq, Copy, Clone)]
22pub enum Definition { 22pub enum Definition {
23 Macro(MacroDef), 23 Macro(MacroDef),
24 Field(Field), 24 Field(Field),
@@ -78,10 +78,15 @@ 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) {}`
84 ConstReference(Definition), 85 ConstReference(Definition),
86 FieldShorthand {
87 local: Local,
88 field: Definition,
89 },
85} 90}
86 91
87impl NameClass { 92impl NameClass {
@@ -89,12 +94,14 @@ impl NameClass {
89 match self { 94 match self {
90 NameClass::Definition(it) => Some(it), 95 NameClass::Definition(it) => Some(it),
91 NameClass::ConstReference(_) => None, 96 NameClass::ConstReference(_) => None,
97 NameClass::FieldShorthand { local, field: _ } => Some(Definition::Local(local)),
92 } 98 }
93 } 99 }
94 100
95 pub fn definition(self) -> Definition { 101 pub fn definition(self) -> Definition {
96 match self { 102 match self {
97 NameClass::Definition(it) | NameClass::ConstReference(it) => it, 103 NameClass::Definition(it) | NameClass::ConstReference(it) => it,
104 NameClass::FieldShorthand { local: _, field } => field,
98 } 105 }
99 } 106 }
100} 107}
@@ -102,18 +109,14 @@ impl NameClass {
102pub fn classify_name(sema: &Semantics<RootDatabase>, name: &ast::Name) -> Option<NameClass> { 109pub fn classify_name(sema: &Semantics<RootDatabase>, name: &ast::Name) -> Option<NameClass> {
103 let _p = profile("classify_name"); 110 let _p = profile("classify_name");
104 111
105 if let Some(bind_pat) = name.syntax().parent().and_then(ast::BindPat::cast) { 112 let parent = name.syntax().parent()?;
113
114 if let Some(bind_pat) = ast::BindPat::cast(parent.clone()) {
106 if let Some(def) = sema.resolve_bind_pat_to_const(&bind_pat) { 115 if let Some(def) = sema.resolve_bind_pat_to_const(&bind_pat) {
107 return Some(NameClass::ConstReference(Definition::ModuleDef(def))); 116 return Some(NameClass::ConstReference(Definition::ModuleDef(def)));
108 } 117 }
109 } 118 }
110 119
111 classify_name_inner(sema, name).map(NameClass::Definition)
112}
113
114fn classify_name_inner(sema: &Semantics<RootDatabase>, name: &ast::Name) -> Option<Definition> {
115 let parent = name.syntax().parent()?;
116
117 match_ast! { 120 match_ast! {
118 match parent { 121 match parent {
119 ast::Alias(it) => { 122 ast::Alias(it) => {
@@ -123,63 +126,73 @@ fn classify_name_inner(sema: &Semantics<RootDatabase>, name: &ast::Name) -> Opti
123 let name_ref = path_segment.name_ref()?; 126 let name_ref = path_segment.name_ref()?;
124 let name_ref_class = classify_name_ref(sema, &name_ref)?; 127 let name_ref_class = classify_name_ref(sema, &name_ref)?;
125 128
126 Some(name_ref_class.definition()) 129 Some(NameClass::Definition(name_ref_class.definition()))
127 }, 130 },
128 ast::BindPat(it) => { 131 ast::BindPat(it) => {
129 let local = sema.to_def(&it)?; 132 let local = sema.to_def(&it)?;
130 Some(Definition::Local(local)) 133
134 if let Some(record_field_pat) = it.syntax().parent().and_then(ast::RecordFieldPat::cast) {
135 if record_field_pat.name_ref().is_none() {
136 if let Some(field) = sema.resolve_record_field_pat(&record_field_pat) {
137 let field = Definition::Field(field);
138 return Some(NameClass::FieldShorthand { local, field });
139 }
140 }
141 }
142
143 Some(NameClass::Definition(Definition::Local(local)))
131 }, 144 },
132 ast::RecordFieldDef(it) => { 145 ast::RecordFieldDef(it) => {
133 let field: hir::Field = sema.to_def(&it)?; 146 let field: hir::Field = sema.to_def(&it)?;
134 Some(Definition::Field(field)) 147 Some(NameClass::Definition(Definition::Field(field)))
135 }, 148 },
136 ast::Module(it) => { 149 ast::Module(it) => {
137 let def = sema.to_def(&it)?; 150 let def = sema.to_def(&it)?;
138 Some(Definition::ModuleDef(def.into())) 151 Some(NameClass::Definition(Definition::ModuleDef(def.into())))
139 }, 152 },
140 ast::StructDef(it) => { 153 ast::StructDef(it) => {
141 let def: hir::Struct = sema.to_def(&it)?; 154 let def: hir::Struct = sema.to_def(&it)?;
142 Some(Definition::ModuleDef(def.into())) 155 Some(NameClass::Definition(Definition::ModuleDef(def.into())))
143 }, 156 },
144 ast::UnionDef(it) => { 157 ast::UnionDef(it) => {
145 let def: hir::Union = sema.to_def(&it)?; 158 let def: hir::Union = sema.to_def(&it)?;
146 Some(Definition::ModuleDef(def.into())) 159 Some(NameClass::Definition(Definition::ModuleDef(def.into())))
147 }, 160 },
148 ast::EnumDef(it) => { 161 ast::EnumDef(it) => {
149 let def: hir::Enum = sema.to_def(&it)?; 162 let def: hir::Enum = sema.to_def(&it)?;
150 Some(Definition::ModuleDef(def.into())) 163 Some(NameClass::Definition(Definition::ModuleDef(def.into())))
151 }, 164 },
152 ast::TraitDef(it) => { 165 ast::TraitDef(it) => {
153 let def: hir::Trait = sema.to_def(&it)?; 166 let def: hir::Trait = sema.to_def(&it)?;
154 Some(Definition::ModuleDef(def.into())) 167 Some(NameClass::Definition(Definition::ModuleDef(def.into())))
155 }, 168 },
156 ast::StaticDef(it) => { 169 ast::StaticDef(it) => {
157 let def: hir::Static = sema.to_def(&it)?; 170 let def: hir::Static = sema.to_def(&it)?;
158 Some(Definition::ModuleDef(def.into())) 171 Some(NameClass::Definition(Definition::ModuleDef(def.into())))
159 }, 172 },
160 ast::EnumVariant(it) => { 173 ast::EnumVariant(it) => {
161 let def: hir::EnumVariant = sema.to_def(&it)?; 174 let def: hir::EnumVariant = sema.to_def(&it)?;
162 Some(Definition::ModuleDef(def.into())) 175 Some(NameClass::Definition(Definition::ModuleDef(def.into())))
163 }, 176 },
164 ast::FnDef(it) => { 177 ast::FnDef(it) => {
165 let def: hir::Function = sema.to_def(&it)?; 178 let def: hir::Function = sema.to_def(&it)?;
166 Some(Definition::ModuleDef(def.into())) 179 Some(NameClass::Definition(Definition::ModuleDef(def.into())))
167 }, 180 },
168 ast::ConstDef(it) => { 181 ast::ConstDef(it) => {
169 let def: hir::Const = sema.to_def(&it)?; 182 let def: hir::Const = sema.to_def(&it)?;
170 Some(Definition::ModuleDef(def.into())) 183 Some(NameClass::Definition(Definition::ModuleDef(def.into())))
171 }, 184 },
172 ast::TypeAliasDef(it) => { 185 ast::TypeAliasDef(it) => {
173 let def: hir::TypeAlias = sema.to_def(&it)?; 186 let def: hir::TypeAlias = sema.to_def(&it)?;
174 Some(Definition::ModuleDef(def.into())) 187 Some(NameClass::Definition(Definition::ModuleDef(def.into())))
175 }, 188 },
176 ast::MacroCall(it) => { 189 ast::MacroCall(it) => {
177 let def = sema.to_def(&it)?; 190 let def = sema.to_def(&it)?;
178 Some(Definition::Macro(def)) 191 Some(NameClass::Definition(Definition::Macro(def)))
179 }, 192 },
180 ast::TypeParam(it) => { 193 ast::TypeParam(it) => {
181 let def = sema.to_def(&it)?; 194 let def = sema.to_def(&it)?;
182 Some(Definition::TypeParam(def)) 195 Some(NameClass::Definition(Definition::TypeParam(def)))
183 }, 196 },
184 _ => None, 197 _ => None,
185 } 198 }
@@ -242,8 +255,14 @@ pub fn classify_name_ref(
242 } 255 }
243 256
244 if let Some(macro_call) = parent.ancestors().find_map(ast::MacroCall::cast) { 257 if let Some(macro_call) = parent.ancestors().find_map(ast::MacroCall::cast) {
245 if let Some(macro_def) = sema.resolve_macro_call(&macro_call) { 258 if let Some(path) = macro_call.path() {
246 return Some(NameRefClass::Definition(Definition::Macro(macro_def))); 259 if path.qualifier().is_none() {
260 // Only use this to resolve single-segment macro calls like `foo!()`. Multi-segment
261 // paths are handled below (allowing `log<|>::info!` to resolve to the log crate).
262 if let Some(macro_def) = sema.resolve_macro_call(&macro_call) {
263 return Some(NameRefClass::Definition(Definition::Macro(macro_def)));
264 }
265 }
247 } 266 }
248 } 267 }
249 268
diff --git a/crates/ra_ide_db/src/imports_locator.rs b/crates/ra_ide_db/src/imports_locator.rs
index bf0d8db60..1fba71ff8 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,57 +11,55 @@ 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 fn find_imports<'a>(
16 sema: Semantics<'a, RootDatabase>, 17 sema: &Semantics<'a, RootDatabase>,
17} 18 krate: Crate,
18 19 name_to_import: &str,
19impl<'a> ImportsLocator<'a> { 20) -> Vec<Either<ModuleDef, MacroDef>> {
20 pub fn new(db: &'a RootDatabase) -> Self { 21 let _p = profile("search_for_imports");
21 Self { sema: Semantics::new(db) } 22 let db = sema.db;
22 }
23 23
24 pub fn find_imports(&mut self, name_to_import: &str) -> Vec<Either<ModuleDef, MacroDef>> { 24 // Query dependencies first.
25 let _p = profile("search_for_imports"); 25 let mut candidates: FxHashSet<_> =
26 let db = self.sema.db; 26 krate.query_external_importables(db, name_to_import).collect();
27 27
28 let project_results = { 28 // Query the local crate using the symbol index.
29 let mut query = Query::new(name_to_import.to_string()); 29 let local_results = {
30 query.exact(); 30 let mut query = Query::new(name_to_import.to_string());
31 query.limit(40); 31 query.exact();
32 symbol_index::world_symbols(db, query) 32 query.limit(40);
33 }; 33 symbol_index::crate_symbols(db, krate.into(), query)
34 let lib_results = { 34 };
35 let mut query = Query::new(name_to_import.to_string());
36 query.libs();
37 query.exact();
38 query.limit(40);
39 symbol_index::world_symbols(db, query)
40 };
41 35
42 project_results 36 candidates.extend(
37 local_results
43 .into_iter() 38 .into_iter()
44 .chain(lib_results.into_iter()) 39 .filter_map(|import_candidate| get_name_definition(sema, &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 { 40 .filter_map(|name_definition_to_import| match name_definition_to_import {
47 Definition::ModuleDef(module_def) => Some(Either::Left(module_def)), 41 Definition::ModuleDef(module_def) => Some(Either::Left(module_def)),
48 Definition::Macro(macro_def) => Some(Either::Right(macro_def)), 42 Definition::Macro(macro_def) => Some(Either::Right(macro_def)),
49 _ => None, 43 _ => None,
50 }) 44 }),
51 .collect() 45 );
52 } 46
47 candidates.into_iter().collect()
48}
53 49
54 fn get_name_definition(&mut self, import_candidate: &FileSymbol) -> Option<Definition> { 50fn get_name_definition<'a>(
55 let _p = profile("get_name_definition"); 51 sema: &Semantics<'a, RootDatabase>,
56 let file_id = import_candidate.file_id; 52 import_candidate: &FileSymbol,
53) -> Option<Definition> {
54 let _p = profile("get_name_definition");
55 let file_id = import_candidate.file_id;
57 56
58 let candidate_node = import_candidate.ptr.to_node(self.sema.parse(file_id).syntax()); 57 let candidate_node = import_candidate.ptr.to_node(sema.parse(file_id).syntax());
59 let candidate_name_node = if candidate_node.kind() != NAME { 58 let candidate_name_node = if candidate_node.kind() != NAME {
60 candidate_node.children().find(|it| it.kind() == NAME)? 59 candidate_node.children().find(|it| it.kind() == NAME)?
61 } else { 60 } else {
62 candidate_node 61 candidate_node
63 }; 62 };
64 let name = ast::Name::cast(candidate_name_node)?; 63 let name = ast::Name::cast(candidate_name_node)?;
65 classify_name(&self.sema, &name)?.into_definition() 64 classify_name(sema, &name)?.into_definition()
66 }
67} 65}
diff --git a/crates/ra_ide_db/src/lib.rs b/crates/ra_ide_db/src/lib.rs
index 1b74e6558..6900cac73 100644
--- a/crates/ra_ide_db/src/lib.rs
+++ b/crates/ra_ide_db/src/lib.rs
@@ -11,15 +11,15 @@ pub mod imports_locator;
11pub mod source_change; 11pub mod source_change;
12mod wasm_shims; 12mod wasm_shims;
13 13
14use std::sync::Arc; 14use std::{fmt, sync::Arc};
15 15
16use hir::db::{AstDatabase, DefDatabase}; 16use hir::db::{AstDatabase, DefDatabase, HirDatabase};
17use ra_db::{ 17use ra_db::{
18 salsa::{self, Database, Durability}, 18 salsa::{self, Durability},
19 Canceled, CheckCanceled, CrateId, FileId, FileLoader, FileLoaderDelegate, RelativePath, 19 Canceled, CheckCanceled, CrateId, FileId, FileLoader, FileLoaderDelegate, SourceDatabase,
20 SourceDatabase, 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
@@ -33,14 +33,18 @@ use crate::{line_index::LineIndex, symbol_index::SymbolsDatabase};
33 hir::db::DefDatabaseStorage, 33 hir::db::DefDatabaseStorage,
34 hir::db::HirDatabaseStorage 34 hir::db::HirDatabaseStorage
35)] 35)]
36#[derive(Debug)]
37pub struct RootDatabase { 36pub struct RootDatabase {
38 runtime: salsa::Runtime<RootDatabase>, 37 storage: salsa::Storage<RootDatabase>,
39 pub(crate) debug_data: Arc<DebugData>,
40 pub last_gc: crate::wasm_shims::Instant, 38 pub last_gc: crate::wasm_shims::Instant,
41 pub last_gc_check: crate::wasm_shims::Instant, 39 pub last_gc_check: crate::wasm_shims::Instant,
42} 40}
43 41
42impl fmt::Debug for RootDatabase {
43 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
44 f.debug_struct("RootDatabase").finish()
45 }
46}
47
44impl Upcast<dyn AstDatabase> for RootDatabase { 48impl Upcast<dyn AstDatabase> for RootDatabase {
45 fn upcast(&self) -> &(dyn AstDatabase + 'static) { 49 fn upcast(&self) -> &(dyn AstDatabase + 'static) {
46 &*self 50 &*self
@@ -53,41 +57,30 @@ impl Upcast<dyn DefDatabase> for RootDatabase {
53 } 57 }
54} 58}
55 59
60impl Upcast<dyn HirDatabase> for RootDatabase {
61 fn upcast(&self) -> &(dyn HirDatabase + 'static) {
62 &*self
63 }
64}
65
56impl FileLoader for RootDatabase { 66impl FileLoader for RootDatabase {
57 fn file_text(&self, file_id: FileId) -> Arc<String> { 67 fn file_text(&self, file_id: FileId) -> Arc<String> {
58 FileLoaderDelegate(self).file_text(file_id) 68 FileLoaderDelegate(self).file_text(file_id)
59 } 69 }
60 fn resolve_relative_path( 70 fn resolve_path(&self, anchor: FileId, path: &str) -> Option<FileId> {
61 &self, 71 FileLoaderDelegate(self).resolve_path(anchor, path)
62 anchor: FileId,
63 relative_path: &RelativePath,
64 ) -> Option<FileId> {
65 FileLoaderDelegate(self).resolve_relative_path(anchor, relative_path)
66 } 72 }
67 fn relevant_crates(&self, file_id: FileId) -> Arc<Vec<CrateId>> { 73 fn relevant_crates(&self, file_id: FileId) -> Arc<FxHashSet<CrateId>> {
68 FileLoaderDelegate(self).relevant_crates(file_id) 74 FileLoaderDelegate(self).relevant_crates(file_id)
69 } 75 }
70 fn resolve_extern_path(
71 &self,
72 extern_id: ra_db::ExternSourceId,
73 relative_path: &RelativePath,
74 ) -> Option<FileId> {
75 FileLoaderDelegate(self).resolve_extern_path(extern_id, relative_path)
76 }
77} 76}
78 77
79impl salsa::Database for RootDatabase { 78impl salsa::Database for RootDatabase {
80 fn salsa_runtime(&self) -> &salsa::Runtime<RootDatabase> {
81 &self.runtime
82 }
83 fn salsa_runtime_mut(&mut self) -> &mut salsa::Runtime<Self> {
84 &mut self.runtime
85 }
86 fn on_propagated_panic(&self) -> ! { 79 fn on_propagated_panic(&self) -> ! {
87 Canceled::throw() 80 Canceled::throw()
88 } 81 }
89 fn salsa_event(&self, event: impl Fn() -> salsa::Event<RootDatabase>) { 82 fn salsa_event(&self, event: salsa::Event) {
90 match event().kind { 83 match event.kind {
91 salsa::EventKind::DidValidateMemoizedValue { .. } 84 salsa::EventKind::DidValidateMemoizedValue { .. }
92 | salsa::EventKind::WillExecute { .. } => { 85 | salsa::EventKind::WillExecute { .. } => {
93 self.check_canceled(); 86 self.check_canceled();
@@ -106,10 +99,9 @@ impl Default for RootDatabase {
106impl RootDatabase { 99impl RootDatabase {
107 pub fn new(lru_capacity: Option<usize>) -> RootDatabase { 100 pub fn new(lru_capacity: Option<usize>) -> RootDatabase {
108 let mut db = RootDatabase { 101 let mut db = RootDatabase {
109 runtime: salsa::Runtime::default(), 102 storage: salsa::Storage::default(),
110 last_gc: crate::wasm_shims::Instant::now(), 103 last_gc: crate::wasm_shims::Instant::now(),
111 last_gc_check: crate::wasm_shims::Instant::now(), 104 last_gc_check: crate::wasm_shims::Instant::now(),
112 debug_data: Default::default(),
113 }; 105 };
114 db.set_crate_graph_with_durability(Default::default(), Durability::HIGH); 106 db.set_crate_graph_with_durability(Default::default(), Durability::HIGH);
115 db.set_local_roots_with_durability(Default::default(), Durability::HIGH); 107 db.set_local_roots_with_durability(Default::default(), Durability::HIGH);
@@ -120,19 +112,18 @@ impl RootDatabase {
120 112
121 pub fn update_lru_capacity(&mut self, lru_capacity: Option<usize>) { 113 pub fn update_lru_capacity(&mut self, lru_capacity: Option<usize>) {
122 let lru_capacity = lru_capacity.unwrap_or(ra_db::DEFAULT_LRU_CAP); 114 let lru_capacity = lru_capacity.unwrap_or(ra_db::DEFAULT_LRU_CAP);
123 self.query_mut(ra_db::ParseQuery).set_lru_capacity(lru_capacity); 115 ra_db::ParseQuery.in_db_mut(self).set_lru_capacity(lru_capacity);
124 self.query_mut(hir::db::ParseMacroQuery).set_lru_capacity(lru_capacity); 116 hir::db::ParseMacroQuery.in_db_mut(self).set_lru_capacity(lru_capacity);
125 self.query_mut(hir::db::MacroExpandQuery).set_lru_capacity(lru_capacity); 117 hir::db::MacroExpandQuery.in_db_mut(self).set_lru_capacity(lru_capacity);
126 } 118 }
127} 119}
128 120
129impl salsa::ParallelDatabase for RootDatabase { 121impl salsa::ParallelDatabase for RootDatabase {
130 fn snapshot(&self) -> salsa::Snapshot<RootDatabase> { 122 fn snapshot(&self) -> salsa::Snapshot<RootDatabase> {
131 salsa::Snapshot::new(RootDatabase { 123 salsa::Snapshot::new(RootDatabase {
132 runtime: self.runtime.snapshot(self), 124 storage: self.storage.snapshot(),
133 last_gc: self.last_gc, 125 last_gc: self.last_gc,
134 last_gc_check: self.last_gc_check, 126 last_gc_check: self.last_gc_check,
135 debug_data: Arc::clone(&self.debug_data),
136 }) 127 })
137 } 128 }
138} 129}
@@ -142,18 +133,7 @@ pub trait LineIndexDatabase: ra_db::SourceDatabase + CheckCanceled {
142 fn line_index(&self, file_id: FileId) -> Arc<LineIndex>; 133 fn line_index(&self, file_id: FileId) -> Arc<LineIndex>;
143} 134}
144 135
145fn line_index(db: &impl LineIndexDatabase, file_id: FileId) -> Arc<LineIndex> { 136fn line_index(db: &dyn LineIndexDatabase, file_id: FileId) -> Arc<LineIndex> {
146 let text = db.file_text(file_id); 137 let text = db.file_text(file_id);
147 Arc::new(LineIndex::new(&*text)) 138 Arc::new(LineIndex::new(&*text))
148} 139}
149
150#[derive(Debug, Default, Clone)]
151pub(crate) struct DebugData {
152 pub(crate) root_paths: FxHashMap<SourceRootId, String>,
153}
154
155impl DebugData {
156 pub(crate) fn merge(&mut self, other: DebugData) {
157 self.root_paths.extend(other.root_paths.into_iter());
158 }
159}
diff --git a/crates/ra_ide_db/src/search.rs b/crates/ra_ide_db/src/search.rs
index 335a1ad03..81553150b 100644
--- a/crates/ra_ide_db/src/search.rs
+++ b/crates/ra_ide_db/src/search.rs
@@ -157,14 +157,14 @@ impl Definition {
157 if let Some(Visibility::Public) = vis { 157 if let Some(Visibility::Public) = vis {
158 let source_root_id = db.file_source_root(file_id); 158 let source_root_id = db.file_source_root(file_id);
159 let source_root = db.source_root(source_root_id); 159 let source_root = db.source_root(source_root_id);
160 let mut res = source_root.walk().map(|id| (id, None)).collect::<FxHashMap<_, _>>(); 160 let mut res = source_root.iter().map(|id| (id, None)).collect::<FxHashMap<_, _>>();
161 161
162 let krate = module.krate(); 162 let krate = module.krate();
163 for rev_dep in krate.reverse_dependencies(db) { 163 for rev_dep in krate.reverse_dependencies(db) {
164 let root_file = rev_dep.root_file(db); 164 let root_file = rev_dep.root_file(db);
165 let source_root_id = db.file_source_root(root_file); 165 let source_root_id = db.file_source_root(root_file);
166 let source_root = db.source_root(source_root_id); 166 let source_root = db.source_root(source_root_id);
167 res.extend(source_root.walk().map(|id| (id, None))); 167 res.extend(source_root.iter().map(|id| (id, None)));
168 } 168 }
169 return SearchScope::new(res); 169 return SearchScope::new(res);
170 } 170 }
@@ -180,20 +180,20 @@ impl Definition {
180 180
181 pub fn find_usages( 181 pub fn find_usages(
182 &self, 182 &self,
183 db: &RootDatabase, 183 sema: &Semantics<RootDatabase>,
184 search_scope: Option<SearchScope>, 184 search_scope: Option<SearchScope>,
185 ) -> Vec<Reference> { 185 ) -> Vec<Reference> {
186 let _p = profile("Definition::find_usages"); 186 let _p = profile("Definition::find_usages");
187 187
188 let search_scope = { 188 let search_scope = {
189 let base = self.search_scope(db); 189 let base = self.search_scope(sema.db);
190 match search_scope { 190 match search_scope {
191 None => base, 191 None => base,
192 Some(scope) => base.intersection(&scope), 192 Some(scope) => base.intersection(&scope),
193 } 193 }
194 }; 194 };
195 195
196 let name = match self.name(db) { 196 let name = match self.name(sema.db) {
197 None => return Vec::new(), 197 None => return Vec::new(),
198 Some(it) => it.to_string(), 198 Some(it) => it.to_string(),
199 }; 199 };
@@ -202,11 +202,10 @@ impl Definition {
202 let mut refs = vec![]; 202 let mut refs = vec![];
203 203
204 for (file_id, search_range) in search_scope { 204 for (file_id, search_range) in search_scope {
205 let text = db.file_text(file_id); 205 let text = sema.db.file_text(file_id);
206 let search_range = 206 let search_range =
207 search_range.unwrap_or(TextRange::up_to(TextSize::of(text.as_str()))); 207 search_range.unwrap_or(TextRange::up_to(TextSize::of(text.as_str())));
208 208
209 let sema = Semantics::new(db);
210 let tree = Lazy::new(|| sema.parse(file_id).syntax().clone()); 209 let tree = Lazy::new(|| sema.parse(file_id).syntax().clone());
211 210
212 for (idx, _) in text.match_indices(pat) { 211 for (idx, _) in text.match_indices(pat) {
@@ -222,9 +221,6 @@ impl Definition {
222 continue; 221 continue;
223 }; 222 };
224 223
225 // FIXME: reuse sb
226 // See https://github.com/rust-lang/rust/pull/68198#issuecomment-574269098
227
228 match classify_name_ref(&sema, &name_ref) { 224 match classify_name_ref(&sema, &name_ref) {
229 Some(NameRefClass::Definition(def)) if &def == self => { 225 Some(NameRefClass::Definition(def)) if &def == self => {
230 let kind = if is_record_lit_name_ref(&name_ref) 226 let kind = if is_record_lit_name_ref(&name_ref)
diff --git a/crates/ra_ide_db/src/source_change.rs b/crates/ra_ide_db/src/source_change.rs
index e713f4b7e..abb83f421 100644
--- a/crates/ra_ide_db/src/source_change.rs
+++ b/crates/ra_ide_db/src/source_change.rs
@@ -3,10 +3,10 @@
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(Default, Debug, Clone)]
10pub struct SourceChange { 10pub struct SourceChange {
11 pub source_file_edits: Vec<SourceFileEdit>, 11 pub source_file_edits: Vec<SourceFileEdit>,
12 pub file_system_edits: Vec<FileSystemEdit>, 12 pub file_system_edits: Vec<FileSystemEdit>,
@@ -22,17 +22,6 @@ impl SourceChange {
22 ) -> Self { 22 ) -> Self {
23 SourceChange { source_file_edits, file_system_edits, is_snippet: false } 23 SourceChange { source_file_edits, file_system_edits, is_snippet: false }
24 } 24 }
25
26 /// Creates a new SourceChange with the given label,
27 /// containing only the given `SourceFileEdits`.
28 pub fn source_file_edits(edits: Vec<SourceFileEdit>) -> Self {
29 SourceChange { source_file_edits: edits, file_system_edits: vec![], is_snippet: false }
30 }
31 /// Creates a new SourceChange with the given label
32 /// from the given `FileId` and `TextEdit`
33 pub fn source_file_edit_from(file_id: FileId, edit: TextEdit) -> Self {
34 SourceFileEdit { file_id, edit }.into()
35 }
36} 25}
37 26
38#[derive(Debug, Clone)] 27#[derive(Debug, Clone)]
@@ -43,18 +32,20 @@ pub struct SourceFileEdit {
43 32
44impl From<SourceFileEdit> for SourceChange { 33impl From<SourceFileEdit> for SourceChange {
45 fn from(edit: SourceFileEdit) -> SourceChange { 34 fn from(edit: SourceFileEdit) -> SourceChange {
46 SourceChange { 35 vec![edit].into()
47 source_file_edits: vec![edit], 36 }
48 file_system_edits: Vec::new(), 37}
49 is_snippet: false, 38
50 } 39impl From<Vec<SourceFileEdit>> for SourceChange {
40 fn from(source_file_edits: Vec<SourceFileEdit>) -> SourceChange {
41 SourceChange { source_file_edits, file_system_edits: Vec::new(), is_snippet: false }
51 } 42 }
52} 43}
53 44
54#[derive(Debug, Clone)] 45#[derive(Debug, Clone)]
55pub enum FileSystemEdit { 46pub enum FileSystemEdit {
56 CreateFile { source_root: SourceRootId, path: RelativePathBuf }, 47 CreateFile { anchor: FileId, dst: String },
57 MoveFile { src: FileId, dst_source_root: SourceRootId, dst_path: RelativePathBuf }, 48 MoveFile { src: FileId, anchor: FileId, dst: String },
58} 49}
59 50
60impl 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..131e2a128 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, FxHashSet};
44 46
45use crate::RootDatabase; 47use crate::RootDatabase;
46 48
@@ -85,21 +87,41 @@ 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 {
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]
95 fn local_roots(&self) -> Arc<Vec<SourceRootId>>; 96 fn local_roots(&self) -> Arc<FxHashSet<SourceRootId>>;
96 /// The set of roots for crates.io libraries. 97 /// The set of roots for crates.io libraries.
97 /// Files in libraries are assumed to never change. 98 /// Files in libraries are assumed to never change.
98 #[salsa::input] 99 #[salsa::input]
99 fn library_roots(&self) -> Arc<Vec<SourceRootId>>; 100 fn library_roots(&self) -> Arc<FxHashSet<SourceRootId>>;
101}
102
103fn library_symbols(db: &dyn SymbolsDatabase) -> Arc<FxHashMap<SourceRootId, SymbolIndex>> {
104 let _p = profile("library_symbols");
105
106 let roots = db.library_roots();
107 let res = roots
108 .iter()
109 .map(|&root_id| {
110 let root = db.source_root(root_id);
111 let files = root
112 .iter()
113 .map(|it| (it, SourceDatabaseExt::file_text(db, it)))
114 .collect::<Vec<_>>();
115 let symbol_index = SymbolIndex::for_files(
116 files.into_par_iter().map(|(file, text)| (file, SourceFile::parse(&text))),
117 );
118 (root_id, symbol_index)
119 })
120 .collect();
121 Arc::new(res)
100} 122}
101 123
102fn file_symbols(db: &impl SymbolsDatabase, file_id: FileId) -> Arc<SymbolIndex> { 124fn file_symbols(db: &dyn SymbolsDatabase, file_id: FileId) -> Arc<SymbolIndex> {
103 db.check_canceled(); 125 db.check_canceled();
104 let parse = db.parse(file_id); 126 let parse = db.parse(file_id);
105 127
@@ -110,6 +132,14 @@ fn file_symbols(db: &impl SymbolsDatabase, file_id: FileId) -> Arc<SymbolIndex>
110 Arc::new(SymbolIndex::new(symbols)) 132 Arc::new(SymbolIndex::new(symbols))
111} 133}
112 134
135/// Need to wrap Snapshot to provide `Clone` impl for `map_with`
136struct Snap<DB>(DB);
137impl<DB: ParallelDatabase> Clone for Snap<salsa::Snapshot<DB>> {
138 fn clone(&self) -> Snap<salsa::Snapshot<DB>> {
139 Snap(self.0.snapshot())
140 }
141}
142
113// Feature: Workspace Symbol 143// Feature: Workspace Symbol
114// 144//
115// Uses fuzzy-search to find types, modules and functions by name across your 145// Uses fuzzy-search to find types, modules and functions by name across your
@@ -132,44 +162,51 @@ fn file_symbols(db: &impl SymbolsDatabase, file_id: FileId) -> Arc<SymbolIndex>
132// | VS Code | kbd:[Ctrl+T] 162// | VS Code | kbd:[Ctrl+T]
133// |=== 163// |===
134pub fn world_symbols(db: &RootDatabase, query: Query) -> Vec<FileSymbol> { 164pub fn world_symbols(db: &RootDatabase, query: Query) -> Vec<FileSymbol> {
135 /// Need to wrap Snapshot to provide `Clone` impl for `map_with` 165 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 166
143 let buf: Vec<Arc<SymbolIndex>> = if query.libs { 167 let tmp1;
144 let snap = Snap(db.snapshot()); 168 let tmp2;
145 #[cfg(not(feature = "wasm"))] 169 let buf: Vec<&SymbolIndex> = if query.libs {
146 let buf = db 170 tmp1 = db.library_symbols();
147 .library_roots() 171 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 { 172 } else {
157 let mut files = Vec::new(); 173 let mut files = Vec::new();
158 for &root in db.local_roots().iter() { 174 for &root in db.local_roots().iter() {
159 let sr = db.source_root(root); 175 let sr = db.source_root(root);
160 files.extend(sr.walk()) 176 files.extend(sr.iter())
161 } 177 }
162 178
163 let snap = Snap(db.snapshot()); 179 let snap = Snap(db.snapshot());
164 #[cfg(not(feature = "wasm"))] 180 tmp2 = files
165 let buf = 181 .par_iter()
166 files.par_iter().map_with(snap, |db, &file_id| db.0.file_symbols(file_id)).collect(); 182 .map_with(snap, |db, &file_id| db.0.file_symbols(file_id))
183 .collect::<Vec<_>>();
184 tmp2.iter().map(|it| &**it).collect()
185 };
186 query.search(&buf)
187}
167 188
168 #[cfg(feature = "wasm")] 189pub 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(); 190 // FIXME(#4842): This now depends on CrateDefMap, why not build the entire symbol index from
191 // that instead?
192
193 let def_map = db.crate_def_map(krate);
194 let mut files = Vec::new();
195 let mut modules = vec![def_map.root];
196 while let Some(module) = modules.pop() {
197 let data = &def_map[module];
198 files.extend(data.origin.file_id());
199 modules.extend(data.children.values());
200 }
201
202 let snap = Snap(db.snapshot());
203
204 let buf = files
205 .par_iter()
206 .map_with(snap, |db, &file_id| db.0.file_symbols(file_id))
207 .collect::<Vec<_>>();
208 let buf = buf.iter().map(|it| &**it).collect::<Vec<_>>();
170 209
171 buf
172 };
173 query.search(&buf) 210 query.search(&buf)
174} 211}
175 212
@@ -215,12 +252,8 @@ impl SymbolIndex {
215 lhs_chars.cmp(rhs_chars) 252 lhs_chars.cmp(rhs_chars)
216 } 253 }
217 254
218 #[cfg(not(feature = "wasm"))]
219 symbols.par_sort_by(cmp); 255 symbols.par_sort_by(cmp);
220 256
221 #[cfg(feature = "wasm")]
222 symbols.sort_by(cmp);
223
224 let mut builder = fst::MapBuilder::memory(); 257 let mut builder = fst::MapBuilder::memory();
225 258
226 let mut last_batch_start = 0; 259 let mut last_batch_start = 0;
@@ -254,7 +287,6 @@ impl SymbolIndex {
254 self.map.as_fst().size() + self.symbols.len() * mem::size_of::<FileSymbol>() 287 self.map.as_fst().size() + self.symbols.len() * mem::size_of::<FileSymbol>()
255 } 288 }
256 289
257 #[cfg(not(feature = "wasm"))]
258 pub(crate) fn for_files( 290 pub(crate) fn for_files(
259 files: impl ParallelIterator<Item = (FileId, Parse<ast::SourceFile>)>, 291 files: impl ParallelIterator<Item = (FileId, Parse<ast::SourceFile>)>,
260 ) -> SymbolIndex { 292 ) -> SymbolIndex {
@@ -264,16 +296,6 @@ impl SymbolIndex {
264 SymbolIndex::new(symbols) 296 SymbolIndex::new(symbols)
265 } 297 }
266 298
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 { 299 fn range_to_map_value(start: usize, end: usize) -> u64 {
278 debug_assert![start <= (std::u32::MAX as usize)]; 300 debug_assert![start <= (std::u32::MAX as usize)];
279 debug_assert![end <= (std::u32::MAX as usize)]; 301 debug_assert![end <= (std::u32::MAX as usize)];
@@ -289,7 +311,7 @@ impl SymbolIndex {
289} 311}
290 312
291impl Query { 313impl Query {
292 pub(crate) fn search(self, indices: &[Arc<SymbolIndex>]) -> Vec<FileSymbol> { 314 pub(crate) fn search(self, indices: &[&SymbolIndex]) -> Vec<FileSymbol> {
293 let mut op = fst::map::OpBuilder::new(); 315 let mut op = fst::map::OpBuilder::new();
294 for file_symbols in indices.iter() { 316 for file_symbols in indices.iter() {
295 let automaton = fst::automaton::Subsequence::new(&self.lowercased); 317 let automaton = fst::automaton::Subsequence::new(&self.lowercased);
@@ -298,9 +320,6 @@ impl Query {
298 let mut stream = op.union(); 320 let mut stream = op.union();
299 let mut res = Vec::new(); 321 let mut res = Vec::new();
300 while let Some((_, indexed_values)) = stream.next() { 322 while let Some((_, indexed_values)) = stream.next() {
301 if res.len() >= self.limit {
302 break;
303 }
304 for indexed_value in indexed_values { 323 for indexed_value in indexed_values {
305 let symbol_index = &indices[indexed_value.index]; 324 let symbol_index = &indices[indexed_value.index];
306 let (start, end) = SymbolIndex::map_value_to_range(indexed_value.value); 325 let (start, end) = SymbolIndex::map_value_to_range(indexed_value.value);
@@ -312,7 +331,11 @@ impl Query {
312 if self.exact && symbol.name != self.query { 331 if self.exact && symbol.name != self.query {
313 continue; 332 continue;
314 } 333 }
334
315 res.push(symbol.clone()); 335 res.push(symbol.clone());
336 if res.len() >= self.limit {
337 return res;
338 }
316 } 339 }
317 } 340 }
318 } 341 }
@@ -321,10 +344,7 @@ impl Query {
321} 344}
322 345
323fn is_type(kind: SyntaxKind) -> bool { 346fn is_type(kind: SyntaxKind) -> bool {
324 match kind { 347 matches!(kind, STRUCT_DEF | ENUM_DEF | TRAIT_DEF | TYPE_ALIAS_DEF)
325 STRUCT_DEF | ENUM_DEF | TRAIT_DEF | TYPE_ALIAS_DEF => true,
326 _ => false,
327 }
328} 348}
329 349
330/// The actual data that is stored in the index. It should be as compact as 350/// The actual data that is stored in the index. It should be as compact as