]> git.lizzy.rs Git - rust.git/blob - crates/ra_ide_db/src/change.rs
Split `CrateImplDefs` in inherent and trait impls
[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, RelativePathBuf, SourceDatabase, SourceDatabaseExt, SourceRoot,
9     SourceRootId,
10 };
11 use ra_prof::{memory_usage, profile, Bytes};
12 use rustc_hash::FxHashSet;
13
14 use crate::{symbol_index::SymbolsDatabase, RootDatabase};
15
16 #[derive(Default)]
17 pub struct AnalysisChange {
18     roots: Option<Vec<SourceRoot>>,
19     files_changed: Vec<(FileId, Option<Arc<String>>)>,
20     crate_graph: Option<CrateGraph>,
21 }
22
23 impl fmt::Debug for AnalysisChange {
24     fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
25         let mut d = fmt.debug_struct("AnalysisChange");
26         if let Some(roots) = &self.roots {
27             d.field("roots", roots);
28         }
29         if !self.files_changed.is_empty() {
30             d.field("files_changed", &self.files_changed.len());
31         }
32         if self.crate_graph.is_some() {
33             d.field("crate_graph", &self.crate_graph);
34         }
35         d.finish()
36     }
37 }
38
39 impl AnalysisChange {
40     pub fn new() -> AnalysisChange {
41         AnalysisChange::default()
42     }
43
44     pub fn set_roots(&mut self, roots: Vec<SourceRoot>) {
45         self.roots = Some(roots);
46     }
47
48     pub fn change_file(&mut self, file_id: FileId, new_text: Option<Arc<String>>) {
49         self.files_changed.push((file_id, new_text))
50     }
51
52     pub fn set_crate_graph(&mut self, graph: CrateGraph) {
53         self.crate_graph = Some(graph);
54     }
55 }
56
57 #[derive(Debug)]
58 struct AddFile {
59     file_id: FileId,
60     path: RelativePathBuf,
61     text: Arc<String>,
62 }
63
64 #[derive(Debug)]
65 struct RemoveFile {
66     file_id: FileId,
67     path: RelativePathBuf,
68 }
69
70 #[derive(Default)]
71 struct RootChange {
72     added: Vec<AddFile>,
73     removed: Vec<RemoveFile>,
74 }
75
76 impl fmt::Debug for RootChange {
77     fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
78         fmt.debug_struct("AnalysisChange")
79             .field("added", &self.added.len())
80             .field("removed", &self.removed.len())
81             .finish()
82     }
83 }
84
85 const GC_COOLDOWN: time::Duration = time::Duration::from_millis(100);
86
87 impl RootDatabase {
88     pub fn request_cancellation(&mut self) {
89         let _p = profile("RootDatabase::request_cancellation");
90         self.salsa_runtime_mut().synthetic_write(Durability::LOW);
91     }
92
93     pub fn apply_change(&mut self, change: AnalysisChange) {
94         let _p = profile("RootDatabase::apply_change");
95         self.request_cancellation();
96         log::info!("apply_change {:?}", change);
97         if let Some(roots) = change.roots {
98             let mut local_roots = FxHashSet::default();
99             let mut library_roots = FxHashSet::default();
100             for (idx, root) in roots.into_iter().enumerate() {
101                 let root_id = SourceRootId(idx as u32);
102                 let durability = durability(&root);
103                 if root.is_library {
104                     library_roots.insert(root_id);
105                 } else {
106                     local_roots.insert(root_id);
107                 }
108                 for file_id in root.iter() {
109                     self.set_file_source_root_with_durability(file_id, root_id, durability);
110                 }
111                 self.set_source_root_with_durability(root_id, Arc::new(root), durability);
112             }
113             self.set_local_roots_with_durability(Arc::new(local_roots), Durability::HIGH);
114             self.set_library_roots_with_durability(Arc::new(library_roots), Durability::HIGH);
115         }
116
117         for (file_id, text) in change.files_changed {
118             let source_root_id = self.file_source_root(file_id);
119             let source_root = self.source_root(source_root_id);
120             let durability = durability(&source_root);
121             // XXX: can't actually remove the file, just reset the text
122             let text = text.unwrap_or_default();
123             self.set_file_text_with_durability(file_id, text, durability)
124         }
125         if let Some(crate_graph) = change.crate_graph {
126             self.set_crate_graph_with_durability(Arc::new(crate_graph), Durability::HIGH)
127         }
128     }
129
130     pub fn maybe_collect_garbage(&mut self) {
131         if cfg!(feature = "wasm") {
132             return;
133         }
134
135         if self.last_gc_check.elapsed() > GC_COOLDOWN {
136             self.last_gc_check = crate::wasm_shims::Instant::now();
137         }
138     }
139
140     pub fn collect_garbage(&mut self) {
141         if cfg!(feature = "wasm") {
142             return;
143         }
144
145         let _p = profile("RootDatabase::collect_garbage");
146         self.last_gc = crate::wasm_shims::Instant::now();
147
148         let sweep = SweepStrategy::default().discard_values().sweep_all_revisions();
149
150         self.query(ra_db::ParseQuery).sweep(sweep);
151         self.query(hir::db::ParseMacroQuery).sweep(sweep);
152
153         // Macros do take significant space, but less then the syntax trees
154         // self.query(hir::db::MacroDefQuery).sweep(sweep);
155         // self.query(hir::db::MacroArgQuery).sweep(sweep);
156         // self.query(hir::db::MacroExpandQuery).sweep(sweep);
157
158         self.query(hir::db::AstIdMapQuery).sweep(sweep);
159
160         self.query(hir::db::BodyWithSourceMapQuery).sweep(sweep);
161
162         self.query(hir::db::ExprScopesQuery).sweep(sweep);
163         self.query(hir::db::InferQueryQuery).sweep(sweep);
164         self.query(hir::db::BodyQuery).sweep(sweep);
165     }
166
167     pub fn per_query_memory_usage(&mut self) -> Vec<(String, Bytes)> {
168         let mut acc: Vec<(String, Bytes)> = vec![];
169         let sweep = SweepStrategy::default().discard_values().sweep_all_revisions();
170         macro_rules! sweep_each_query {
171             ($($q:path)*) => {$(
172                 let before = memory_usage().allocated;
173                 self.query($q).sweep(sweep);
174                 let after = memory_usage().allocated;
175                 let q: $q = Default::default();
176                 let name = format!("{:?}", q);
177                 acc.push((name, before - after));
178
179                 let before = memory_usage().allocated;
180                 self.query($q).sweep(sweep.discard_everything());
181                 let after = memory_usage().allocated;
182                 let q: $q = Default::default();
183                 let name = format!("{:?} (deps)", q);
184                 acc.push((name, before - after));
185             )*}
186         }
187         sweep_each_query![
188             // SourceDatabase
189             ra_db::ParseQuery
190             ra_db::SourceRootCratesQuery
191
192             // AstDatabase
193             hir::db::AstIdMapQuery
194             hir::db::InternMacroQuery
195             hir::db::MacroArgQuery
196             hir::db::MacroDefQuery
197             hir::db::ParseMacroQuery
198             hir::db::MacroExpandQuery
199             hir::db::InternEagerExpansionQuery
200
201             // DefDatabase
202             hir::db::ItemTreeQuery
203             hir::db::CrateDefMapQueryQuery
204             hir::db::StructDataQuery
205             hir::db::UnionDataQuery
206             hir::db::EnumDataQuery
207             hir::db::ImplDataQuery
208             hir::db::TraitDataQuery
209             hir::db::TypeAliasDataQuery
210             hir::db::FunctionDataQuery
211             hir::db::ConstDataQuery
212             hir::db::StaticDataQuery
213             hir::db::BodyWithSourceMapQuery
214             hir::db::BodyQuery
215             hir::db::ExprScopesQuery
216             hir::db::GenericParamsQuery
217             hir::db::AttrsQuery
218             hir::db::ModuleLangItemsQuery
219             hir::db::CrateLangItemsQuery
220             hir::db::LangItemQuery
221             hir::db::DocumentationQuery
222             hir::db::ImportMapQuery
223
224             // InternDatabase
225             hir::db::InternFunctionQuery
226             hir::db::InternStructQuery
227             hir::db::InternUnionQuery
228             hir::db::InternEnumQuery
229             hir::db::InternConstQuery
230             hir::db::InternStaticQuery
231             hir::db::InternTraitQuery
232             hir::db::InternTypeAliasQuery
233             hir::db::InternImplQuery
234
235             // HirDatabase
236             hir::db::InferQueryQuery
237             hir::db::TyQuery
238             hir::db::ValueTyQuery
239             hir::db::ImplSelfTyQuery
240             hir::db::ImplTraitQuery
241             hir::db::FieldTypesQuery
242             hir::db::CallableItemSignatureQuery
243             hir::db::GenericPredicatesForParamQuery
244             hir::db::GenericPredicatesQuery
245             hir::db::GenericDefaultsQuery
246             hir::db::InherentImplsInCrateQuery
247             hir::db::TraitImplsInCrateQuery
248             hir::db::TraitImplsInDepsQuery
249             hir::db::InternTypeCtorQuery
250             hir::db::InternTypeParamIdQuery
251             hir::db::InternChalkImplQuery
252             hir::db::InternAssocTyValueQuery
253             hir::db::AssociatedTyDataQuery
254             hir::db::TraitDatumQuery
255             hir::db::StructDatumQuery
256             hir::db::ImplDatumQuery
257             hir::db::AssociatedTyValueQuery
258             hir::db::TraitSolveQuery
259             hir::db::ReturnTypeImplTraitsQuery
260
261             // SymbolsDatabase
262             crate::symbol_index::FileSymbolsQuery
263
264             // LineIndexDatabase
265             crate::LineIndexQuery
266         ];
267         acc.sort_by_key(|it| std::cmp::Reverse(it.1));
268         acc
269     }
270 }
271
272 fn durability(source_root: &SourceRoot) -> Durability {
273     if source_root.is_library {
274         Durability::HIGH
275     } else {
276         Durability::LOW
277     }
278 }