]> git.lizzy.rs Git - rust.git/blob - crates/ra_ide_db/src/change.rs
Remove relative_path dependency
[rust.git] / crates / ra_ide_db / src / change.rs
1 //! Defines a unit of change that can applied to a state of IDE to get the next
2 //! state. Changes are transactional.
3
4 use std::{fmt, sync::Arc, time};
5
6 use ra_db::{
7     salsa::{Database, Durability, SweepStrategy},
8     CrateGraph, FileId, SourceDatabase, SourceDatabaseExt, SourceRoot, SourceRootId,
9 };
10 use ra_prof::{memory_usage, profile, Bytes};
11 use rustc_hash::FxHashSet;
12
13 use crate::{symbol_index::SymbolsDatabase, RootDatabase};
14
15 #[derive(Default)]
16 pub struct AnalysisChange {
17     roots: Option<Vec<SourceRoot>>,
18     files_changed: Vec<(FileId, Option<Arc<String>>)>,
19     crate_graph: Option<CrateGraph>,
20 }
21
22 impl fmt::Debug for AnalysisChange {
23     fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
24         let mut d = fmt.debug_struct("AnalysisChange");
25         if let Some(roots) = &self.roots {
26             d.field("roots", roots);
27         }
28         if !self.files_changed.is_empty() {
29             d.field("files_changed", &self.files_changed.len());
30         }
31         if self.crate_graph.is_some() {
32             d.field("crate_graph", &self.crate_graph);
33         }
34         d.finish()
35     }
36 }
37
38 impl AnalysisChange {
39     pub fn new() -> AnalysisChange {
40         AnalysisChange::default()
41     }
42
43     pub fn set_roots(&mut self, roots: Vec<SourceRoot>) {
44         self.roots = Some(roots);
45     }
46
47     pub fn change_file(&mut self, file_id: FileId, new_text: Option<Arc<String>>) {
48         self.files_changed.push((file_id, new_text))
49     }
50
51     pub fn set_crate_graph(&mut self, graph: CrateGraph) {
52         self.crate_graph = Some(graph);
53     }
54 }
55
56 #[derive(Debug)]
57 struct AddFile {
58     file_id: FileId,
59     path: String,
60     text: Arc<String>,
61 }
62
63 #[derive(Debug)]
64 struct RemoveFile {
65     file_id: FileId,
66     path: String,
67 }
68
69 #[derive(Default)]
70 struct RootChange {
71     added: Vec<AddFile>,
72     removed: Vec<RemoveFile>,
73 }
74
75 impl fmt::Debug for RootChange {
76     fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
77         fmt.debug_struct("AnalysisChange")
78             .field("added", &self.added.len())
79             .field("removed", &self.removed.len())
80             .finish()
81     }
82 }
83
84 const GC_COOLDOWN: time::Duration = time::Duration::from_millis(100);
85
86 impl RootDatabase {
87     pub fn request_cancellation(&mut self) {
88         let _p = profile("RootDatabase::request_cancellation");
89         self.salsa_runtime_mut().synthetic_write(Durability::LOW);
90     }
91
92     pub fn apply_change(&mut self, change: AnalysisChange) {
93         let _p = profile("RootDatabase::apply_change");
94         self.request_cancellation();
95         log::info!("apply_change {:?}", change);
96         if let Some(roots) = change.roots {
97             let mut local_roots = FxHashSet::default();
98             let mut library_roots = FxHashSet::default();
99             for (idx, root) in roots.into_iter().enumerate() {
100                 let root_id = SourceRootId(idx as u32);
101                 let durability = durability(&root);
102                 if root.is_library {
103                     library_roots.insert(root_id);
104                 } else {
105                     local_roots.insert(root_id);
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);
111             }
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);
114         }
115
116         for (file_id, text) in change.files_changed {
117             let source_root_id = self.file_source_root(file_id);
118             let source_root = self.source_root(source_root_id);
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();
122             self.set_file_text_with_durability(file_id, text, durability)
123         }
124         if let Some(crate_graph) = change.crate_graph {
125             self.set_crate_graph_with_durability(Arc::new(crate_graph), Durability::HIGH)
126         }
127     }
128
129     pub fn maybe_collect_garbage(&mut self) {
130         if cfg!(feature = "wasm") {
131             return;
132         }
133
134         if self.last_gc_check.elapsed() > GC_COOLDOWN {
135             self.last_gc_check = crate::wasm_shims::Instant::now();
136         }
137     }
138
139     pub fn collect_garbage(&mut self) {
140         if cfg!(feature = "wasm") {
141             return;
142         }
143
144         let _p = profile("RootDatabase::collect_garbage");
145         self.last_gc = crate::wasm_shims::Instant::now();
146
147         let sweep = SweepStrategy::default().discard_values().sweep_all_revisions();
148
149         ra_db::ParseQuery.in_db(self).sweep(sweep);
150         hir::db::ParseMacroQuery.in_db(self).sweep(sweep);
151
152         // Macros do take significant space, but less then the syntax trees
153         // self.query(hir::db::MacroDefQuery).sweep(sweep);
154         // self.query(hir::db::MacroArgQuery).sweep(sweep);
155         // self.query(hir::db::MacroExpandQuery).sweep(sweep);
156
157         hir::db::AstIdMapQuery.in_db(self).sweep(sweep);
158
159         hir::db::BodyWithSourceMapQuery.in_db(self).sweep(sweep);
160
161         hir::db::ExprScopesQuery.in_db(self).sweep(sweep);
162         hir::db::InferQueryQuery.in_db(self).sweep(sweep);
163         hir::db::BodyQuery.in_db(self).sweep(sweep);
164     }
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     // |===
175     pub fn per_query_memory_usage(&mut self) -> Vec<(String, Bytes)> {
176         let mut acc: Vec<(String, Bytes)> = vec![];
177         let sweep = SweepStrategy::default().discard_values().sweep_all_revisions();
178         macro_rules! sweep_each_query {
179             ($($q:path)*) => {$(
180                 let before = memory_usage().allocated;
181                 $q.in_db(self).sweep(sweep);
182                 let after = memory_usage().allocated;
183                 let q: $q = Default::default();
184                 let name = format!("{:?}", q);
185                 acc.push((name, before - after));
186
187                 let before = memory_usage().allocated;
188                 $q.in_db(self).sweep(sweep.discard_everything());
189                 let after = memory_usage().allocated;
190                 let q: $q = Default::default();
191                 let name = format!("{:?} (deps)", q);
192                 acc.push((name, before - after));
193             )*}
194         }
195         sweep_each_query![
196             // SourceDatabase
197             ra_db::ParseQuery
198             ra_db::SourceRootCratesQuery
199
200             // AstDatabase
201             hir::db::AstIdMapQuery
202             hir::db::MacroArgQuery
203             hir::db::MacroDefQuery
204             hir::db::ParseMacroQuery
205             hir::db::MacroExpandQuery
206
207             // DefDatabase
208             hir::db::ItemTreeQuery
209             hir::db::CrateDefMapQueryQuery
210             hir::db::StructDataQuery
211             hir::db::UnionDataQuery
212             hir::db::EnumDataQuery
213             hir::db::ImplDataQuery
214             hir::db::TraitDataQuery
215             hir::db::TypeAliasDataQuery
216             hir::db::FunctionDataQuery
217             hir::db::ConstDataQuery
218             hir::db::StaticDataQuery
219             hir::db::BodyWithSourceMapQuery
220             hir::db::BodyQuery
221             hir::db::ExprScopesQuery
222             hir::db::GenericParamsQuery
223             hir::db::AttrsQuery
224             hir::db::ModuleLangItemsQuery
225             hir::db::CrateLangItemsQuery
226             hir::db::LangItemQuery
227             hir::db::DocumentationQuery
228             hir::db::ImportMapQuery
229
230             // HirDatabase
231             hir::db::InferQueryQuery
232             hir::db::TyQuery
233             hir::db::ValueTyQuery
234             hir::db::ImplSelfTyQuery
235             hir::db::ImplTraitQuery
236             hir::db::FieldTypesQuery
237             hir::db::CallableItemSignatureQuery
238             hir::db::GenericPredicatesForParamQuery
239             hir::db::GenericPredicatesQuery
240             hir::db::GenericDefaultsQuery
241             hir::db::InherentImplsInCrateQuery
242             hir::db::TraitImplsInCrateQuery
243             hir::db::TraitImplsInDepsQuery
244             hir::db::AssociatedTyDataQuery
245             hir::db::TraitDatumQuery
246             hir::db::StructDatumQuery
247             hir::db::ImplDatumQuery
248             hir::db::AssociatedTyValueQuery
249             hir::db::TraitSolveQuery
250             hir::db::ReturnTypeImplTraitsQuery
251
252             // SymbolsDatabase
253             crate::symbol_index::FileSymbolsQuery
254
255             // LineIndexDatabase
256             crate::LineIndexQuery
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::InternTypeCtorQuery
283             hir::db::InternTypeParamIdQuery
284             hir::db::InternChalkImplQuery
285             hir::db::InternAssocTyValueQuery
286         ];
287
288         acc.sort_by_key(|it| std::cmp::Reverse(it.1));
289         acc
290     }
291 }
292
293 fn durability(source_root: &SourceRoot) -> Durability {
294     if source_root.is_library {
295         Durability::HIGH
296     } else {
297         Durability::LOW
298     }
299 }