diff options
Diffstat (limited to 'crates/ra_hir_ty/src/test_db.rs')
-rw-r--r-- | crates/ra_hir_ty/src/test_db.rs | 146 |
1 files changed, 146 insertions, 0 deletions
diff --git a/crates/ra_hir_ty/src/test_db.rs b/crates/ra_hir_ty/src/test_db.rs new file mode 100644 index 000000000..874357008 --- /dev/null +++ b/crates/ra_hir_ty/src/test_db.rs | |||
@@ -0,0 +1,146 @@ | |||
1 | //! Database used for testing `hir`. | ||
2 | |||
3 | use std::{ | ||
4 | panic, | ||
5 | sync::{Arc, Mutex}, | ||
6 | }; | ||
7 | |||
8 | use hir_def::{db::DefDatabase, AssocItemId, ModuleDefId, ModuleId}; | ||
9 | use hir_expand::diagnostics::DiagnosticSink; | ||
10 | use ra_db::{salsa, CrateId, FileId, FileLoader, FileLoaderDelegate, RelativePath, SourceDatabase}; | ||
11 | |||
12 | use crate::{db::HirDatabase, expr::ExprValidator}; | ||
13 | |||
14 | #[salsa::database( | ||
15 | ra_db::SourceDatabaseExtStorage, | ||
16 | ra_db::SourceDatabaseStorage, | ||
17 | hir_expand::db::AstDatabaseStorage, | ||
18 | hir_def::db::InternDatabaseStorage, | ||
19 | hir_def::db::DefDatabaseStorage, | ||
20 | crate::db::HirDatabaseStorage | ||
21 | )] | ||
22 | #[derive(Debug, Default)] | ||
23 | pub struct TestDB { | ||
24 | events: Mutex<Option<Vec<salsa::Event<TestDB>>>>, | ||
25 | runtime: salsa::Runtime<TestDB>, | ||
26 | } | ||
27 | |||
28 | impl salsa::Database for TestDB { | ||
29 | fn salsa_runtime(&self) -> &salsa::Runtime<TestDB> { | ||
30 | &self.runtime | ||
31 | } | ||
32 | |||
33 | fn salsa_runtime_mut(&mut self) -> &mut salsa::Runtime<Self> { | ||
34 | &mut self.runtime | ||
35 | } | ||
36 | |||
37 | fn salsa_event(&self, event: impl Fn() -> salsa::Event<TestDB>) { | ||
38 | let mut events = self.events.lock().unwrap(); | ||
39 | if let Some(events) = &mut *events { | ||
40 | events.push(event()); | ||
41 | } | ||
42 | } | ||
43 | } | ||
44 | |||
45 | impl salsa::ParallelDatabase for TestDB { | ||
46 | fn snapshot(&self) -> salsa::Snapshot<TestDB> { | ||
47 | salsa::Snapshot::new(TestDB { | ||
48 | events: Default::default(), | ||
49 | runtime: self.runtime.snapshot(self), | ||
50 | }) | ||
51 | } | ||
52 | } | ||
53 | |||
54 | impl panic::RefUnwindSafe for TestDB {} | ||
55 | |||
56 | impl FileLoader for TestDB { | ||
57 | fn file_text(&self, file_id: FileId) -> Arc<String> { | ||
58 | FileLoaderDelegate(self).file_text(file_id) | ||
59 | } | ||
60 | fn resolve_relative_path( | ||
61 | &self, | ||
62 | anchor: FileId, | ||
63 | relative_path: &RelativePath, | ||
64 | ) -> Option<FileId> { | ||
65 | FileLoaderDelegate(self).resolve_relative_path(anchor, relative_path) | ||
66 | } | ||
67 | fn relevant_crates(&self, file_id: FileId) -> Arc<Vec<CrateId>> { | ||
68 | FileLoaderDelegate(self).relevant_crates(file_id) | ||
69 | } | ||
70 | } | ||
71 | |||
72 | impl TestDB { | ||
73 | pub fn module_for_file(&self, file_id: FileId) -> ModuleId { | ||
74 | for &krate in self.relevant_crates(file_id).iter() { | ||
75 | let crate_def_map = self.crate_def_map(krate); | ||
76 | for (module_id, data) in crate_def_map.modules.iter() { | ||
77 | if data.definition == Some(file_id) { | ||
78 | return ModuleId { krate, module_id }; | ||
79 | } | ||
80 | } | ||
81 | } | ||
82 | panic!("Can't find module for file") | ||
83 | } | ||
84 | |||
85 | // FIXME: don't duplicate this | ||
86 | pub fn diagnostics(&self) -> String { | ||
87 | let mut buf = String::new(); | ||
88 | let crate_graph = self.crate_graph(); | ||
89 | for krate in crate_graph.iter().next() { | ||
90 | let crate_def_map = self.crate_def_map(krate); | ||
91 | |||
92 | let mut fns = Vec::new(); | ||
93 | for (module_id, _) in crate_def_map.modules.iter() { | ||
94 | for decl in crate_def_map[module_id].scope.declarations() { | ||
95 | match decl { | ||
96 | ModuleDefId::FunctionId(f) => fns.push(f), | ||
97 | _ => (), | ||
98 | } | ||
99 | } | ||
100 | |||
101 | for &impl_id in crate_def_map[module_id].impls.iter() { | ||
102 | let impl_data = self.impl_data(impl_id); | ||
103 | for item in impl_data.items.iter() { | ||
104 | if let AssocItemId::FunctionId(f) = item { | ||
105 | fns.push(*f) | ||
106 | } | ||
107 | } | ||
108 | } | ||
109 | } | ||
110 | |||
111 | for f in fns { | ||
112 | let infer = self.infer(f.into()); | ||
113 | let mut sink = DiagnosticSink::new(|d| { | ||
114 | buf += &format!("{:?}: {}\n", d.syntax_node(self).text(), d.message()); | ||
115 | }); | ||
116 | infer.add_diagnostics(self, f, &mut sink); | ||
117 | let mut validator = ExprValidator::new(f, infer, &mut sink); | ||
118 | validator.validate_body(self); | ||
119 | } | ||
120 | } | ||
121 | buf | ||
122 | } | ||
123 | } | ||
124 | |||
125 | impl TestDB { | ||
126 | pub fn log(&self, f: impl FnOnce()) -> Vec<salsa::Event<TestDB>> { | ||
127 | *self.events.lock().unwrap() = Some(Vec::new()); | ||
128 | f(); | ||
129 | self.events.lock().unwrap().take().unwrap() | ||
130 | } | ||
131 | |||
132 | pub fn log_executed(&self, f: impl FnOnce()) -> Vec<String> { | ||
133 | let events = self.log(f); | ||
134 | events | ||
135 | .into_iter() | ||
136 | .filter_map(|e| match e.kind { | ||
137 | // This pretty horrible, but `Debug` is the only way to inspect | ||
138 | // QueryDescriptor at the moment. | ||
139 | salsa::EventKind::WillExecute { database_key } => { | ||
140 | Some(format!("{:?}", database_key)) | ||
141 | } | ||
142 | _ => None, | ||
143 | }) | ||
144 | .collect() | ||
145 | } | ||
146 | } | ||