aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_ide_db/src/change.rs
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_ide_db/src/change.rs')
-rw-r--r--crates/ra_ide_db/src/change.rs254
1 files changed, 80 insertions, 174 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 }