diff options
Diffstat (limited to 'crates/hir_ty/src/test_db.rs')
-rw-r--r-- | crates/hir_ty/src/test_db.rs | 136 |
1 files changed, 136 insertions, 0 deletions
diff --git a/crates/hir_ty/src/test_db.rs b/crates/hir_ty/src/test_db.rs new file mode 100644 index 000000000..15b8435e9 --- /dev/null +++ b/crates/hir_ty/src/test_db.rs | |||
@@ -0,0 +1,136 @@ | |||
1 | //! Database used for testing `hir`. | ||
2 | |||
3 | use std::{ | ||
4 | fmt, panic, | ||
5 | sync::{Arc, Mutex}, | ||
6 | }; | ||
7 | |||
8 | use base_db::{salsa, CrateId, FileId, FileLoader, FileLoaderDelegate, SourceDatabase, Upcast}; | ||
9 | use hir_def::{db::DefDatabase, ModuleId}; | ||
10 | use hir_expand::db::AstDatabase; | ||
11 | use rustc_hash::{FxHashMap, FxHashSet}; | ||
12 | use syntax::TextRange; | ||
13 | use test_utils::extract_annotations; | ||
14 | |||
15 | #[salsa::database( | ||
16 | base_db::SourceDatabaseExtStorage, | ||
17 | base_db::SourceDatabaseStorage, | ||
18 | hir_expand::db::AstDatabaseStorage, | ||
19 | hir_def::db::InternDatabaseStorage, | ||
20 | hir_def::db::DefDatabaseStorage, | ||
21 | crate::db::HirDatabaseStorage | ||
22 | )] | ||
23 | #[derive(Default)] | ||
24 | pub struct TestDB { | ||
25 | storage: salsa::Storage<TestDB>, | ||
26 | events: Mutex<Option<Vec<salsa::Event>>>, | ||
27 | } | ||
28 | impl fmt::Debug for TestDB { | ||
29 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { | ||
30 | f.debug_struct("TestDB").finish() | ||
31 | } | ||
32 | } | ||
33 | |||
34 | impl Upcast<dyn AstDatabase> for TestDB { | ||
35 | fn upcast(&self) -> &(dyn AstDatabase + 'static) { | ||
36 | &*self | ||
37 | } | ||
38 | } | ||
39 | |||
40 | impl Upcast<dyn DefDatabase> for TestDB { | ||
41 | fn upcast(&self) -> &(dyn DefDatabase + 'static) { | ||
42 | &*self | ||
43 | } | ||
44 | } | ||
45 | |||
46 | impl salsa::Database for TestDB { | ||
47 | fn salsa_event(&self, event: salsa::Event) { | ||
48 | let mut events = self.events.lock().unwrap(); | ||
49 | if let Some(events) = &mut *events { | ||
50 | events.push(event); | ||
51 | } | ||
52 | } | ||
53 | } | ||
54 | |||
55 | impl salsa::ParallelDatabase for TestDB { | ||
56 | fn snapshot(&self) -> salsa::Snapshot<TestDB> { | ||
57 | salsa::Snapshot::new(TestDB { | ||
58 | storage: self.storage.snapshot(), | ||
59 | events: Default::default(), | ||
60 | }) | ||
61 | } | ||
62 | } | ||
63 | |||
64 | impl panic::RefUnwindSafe for TestDB {} | ||
65 | |||
66 | impl FileLoader for TestDB { | ||
67 | fn file_text(&self, file_id: FileId) -> Arc<String> { | ||
68 | FileLoaderDelegate(self).file_text(file_id) | ||
69 | } | ||
70 | fn resolve_path(&self, anchor: FileId, path: &str) -> Option<FileId> { | ||
71 | FileLoaderDelegate(self).resolve_path(anchor, path) | ||
72 | } | ||
73 | fn relevant_crates(&self, file_id: FileId) -> Arc<FxHashSet<CrateId>> { | ||
74 | FileLoaderDelegate(self).relevant_crates(file_id) | ||
75 | } | ||
76 | } | ||
77 | |||
78 | impl TestDB { | ||
79 | pub(crate) fn module_for_file(&self, file_id: FileId) -> ModuleId { | ||
80 | for &krate in self.relevant_crates(file_id).iter() { | ||
81 | let crate_def_map = self.crate_def_map(krate); | ||
82 | for (local_id, data) in crate_def_map.modules.iter() { | ||
83 | if data.origin.file_id() == Some(file_id) { | ||
84 | return ModuleId { krate, local_id }; | ||
85 | } | ||
86 | } | ||
87 | } | ||
88 | panic!("Can't find module for file") | ||
89 | } | ||
90 | |||
91 | pub(crate) fn extract_annotations(&self) -> FxHashMap<FileId, Vec<(TextRange, String)>> { | ||
92 | let mut files = Vec::new(); | ||
93 | let crate_graph = self.crate_graph(); | ||
94 | for krate in crate_graph.iter() { | ||
95 | let crate_def_map = self.crate_def_map(krate); | ||
96 | for (module_id, _) in crate_def_map.modules.iter() { | ||
97 | let file_id = crate_def_map[module_id].origin.file_id(); | ||
98 | files.extend(file_id) | ||
99 | } | ||
100 | } | ||
101 | files | ||
102 | .into_iter() | ||
103 | .filter_map(|file_id| { | ||
104 | let text = self.file_text(file_id); | ||
105 | let annotations = extract_annotations(&text); | ||
106 | if annotations.is_empty() { | ||
107 | return None; | ||
108 | } | ||
109 | Some((file_id, annotations)) | ||
110 | }) | ||
111 | .collect() | ||
112 | } | ||
113 | } | ||
114 | |||
115 | impl TestDB { | ||
116 | pub fn log(&self, f: impl FnOnce()) -> Vec<salsa::Event> { | ||
117 | *self.events.lock().unwrap() = Some(Vec::new()); | ||
118 | f(); | ||
119 | self.events.lock().unwrap().take().unwrap() | ||
120 | } | ||
121 | |||
122 | pub fn log_executed(&self, f: impl FnOnce()) -> Vec<String> { | ||
123 | let events = self.log(f); | ||
124 | events | ||
125 | .into_iter() | ||
126 | .filter_map(|e| match e.kind { | ||
127 | // This pretty horrible, but `Debug` is the only way to inspect | ||
128 | // QueryDescriptor at the moment. | ||
129 | salsa::EventKind::WillExecute { database_key } => { | ||
130 | Some(format!("{:?}", database_key.debug(self))) | ||
131 | } | ||
132 | _ => None, | ||
133 | }) | ||
134 | .collect() | ||
135 | } | ||
136 | } | ||