diff options
Diffstat (limited to 'crates/ra_hir_ty/src/test_db.rs')
-rw-r--r-- | crates/ra_hir_ty/src/test_db.rs | 129 |
1 files changed, 39 insertions, 90 deletions
diff --git a/crates/ra_hir_ty/src/test_db.rs b/crates/ra_hir_ty/src/test_db.rs index 8498d3d96..a1714ff0f 100644 --- a/crates/ra_hir_ty/src/test_db.rs +++ b/crates/ra_hir_ty/src/test_db.rs | |||
@@ -1,18 +1,16 @@ | |||
1 | //! Database used for testing `hir`. | 1 | //! Database used for testing `hir`. |
2 | 2 | ||
3 | use std::{ | 3 | use std::{ |
4 | panic, | 4 | fmt, panic, |
5 | sync::{Arc, Mutex}, | 5 | sync::{Arc, Mutex}, |
6 | }; | 6 | }; |
7 | 7 | ||
8 | use hir_def::{db::DefDatabase, AssocItemId, ModuleDefId, ModuleId}; | 8 | use hir_def::{db::DefDatabase, ModuleId}; |
9 | use hir_expand::{db::AstDatabase, diagnostics::DiagnosticSink}; | 9 | use hir_expand::db::AstDatabase; |
10 | use ra_db::{ | 10 | use ra_db::{salsa, CrateId, FileId, FileLoader, FileLoaderDelegate, SourceDatabase, Upcast}; |
11 | salsa, CrateId, FileId, FileLoader, FileLoaderDelegate, RelativePath, SourceDatabase, Upcast, | 11 | use ra_syntax::TextRange; |
12 | }; | 12 | use rustc_hash::{FxHashMap, FxHashSet}; |
13 | use stdx::format_to; | 13 | use test_utils::extract_annotations; |
14 | |||
15 | use crate::{db::HirDatabase, diagnostics::Diagnostic, expr::ExprValidator}; | ||
16 | 14 | ||
17 | #[salsa::database( | 15 | #[salsa::database( |
18 | ra_db::SourceDatabaseExtStorage, | 16 | ra_db::SourceDatabaseExtStorage, |
@@ -22,10 +20,15 @@ use crate::{db::HirDatabase, diagnostics::Diagnostic, expr::ExprValidator}; | |||
22 | hir_def::db::DefDatabaseStorage, | 20 | hir_def::db::DefDatabaseStorage, |
23 | crate::db::HirDatabaseStorage | 21 | crate::db::HirDatabaseStorage |
24 | )] | 22 | )] |
25 | #[derive(Debug, Default)] | 23 | #[derive(Default)] |
26 | pub struct TestDB { | 24 | pub struct TestDB { |
27 | events: Mutex<Option<Vec<salsa::Event<TestDB>>>>, | 25 | storage: salsa::Storage<TestDB>, |
28 | runtime: salsa::Runtime<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 | } | ||
29 | } | 32 | } |
30 | 33 | ||
31 | impl Upcast<dyn AstDatabase> for TestDB { | 34 | impl Upcast<dyn AstDatabase> for TestDB { |
@@ -41,18 +44,10 @@ impl Upcast<dyn DefDatabase> for TestDB { | |||
41 | } | 44 | } |
42 | 45 | ||
43 | impl salsa::Database for TestDB { | 46 | impl salsa::Database for TestDB { |
44 | fn salsa_runtime(&self) -> &salsa::Runtime<TestDB> { | 47 | fn salsa_event(&self, event: salsa::Event) { |
45 | &self.runtime | ||
46 | } | ||
47 | |||
48 | fn salsa_runtime_mut(&mut self) -> &mut salsa::Runtime<Self> { | ||
49 | &mut self.runtime | ||
50 | } | ||
51 | |||
52 | fn salsa_event(&self, event: impl Fn() -> salsa::Event<TestDB>) { | ||
53 | let mut events = self.events.lock().unwrap(); | 48 | let mut events = self.events.lock().unwrap(); |
54 | if let Some(events) = &mut *events { | 49 | if let Some(events) = &mut *events { |
55 | events.push(event()); | 50 | events.push(event); |
56 | } | 51 | } |
57 | } | 52 | } |
58 | } | 53 | } |
@@ -60,8 +55,8 @@ impl salsa::Database for TestDB { | |||
60 | impl salsa::ParallelDatabase for TestDB { | 55 | impl salsa::ParallelDatabase for TestDB { |
61 | fn snapshot(&self) -> salsa::Snapshot<TestDB> { | 56 | fn snapshot(&self) -> salsa::Snapshot<TestDB> { |
62 | salsa::Snapshot::new(TestDB { | 57 | salsa::Snapshot::new(TestDB { |
58 | storage: self.storage.snapshot(), | ||
63 | events: Default::default(), | 59 | events: Default::default(), |
64 | runtime: self.runtime.snapshot(self), | ||
65 | }) | 60 | }) |
66 | } | 61 | } |
67 | } | 62 | } |
@@ -72,27 +67,16 @@ impl FileLoader for TestDB { | |||
72 | fn file_text(&self, file_id: FileId) -> Arc<String> { | 67 | fn file_text(&self, file_id: FileId) -> Arc<String> { |
73 | FileLoaderDelegate(self).file_text(file_id) | 68 | FileLoaderDelegate(self).file_text(file_id) |
74 | } | 69 | } |
75 | fn resolve_relative_path( | 70 | fn resolve_path(&self, anchor: FileId, path: &str) -> Option<FileId> { |
76 | &self, | 71 | FileLoaderDelegate(self).resolve_path(anchor, path) |
77 | anchor: FileId, | ||
78 | relative_path: &RelativePath, | ||
79 | ) -> Option<FileId> { | ||
80 | FileLoaderDelegate(self).resolve_relative_path(anchor, relative_path) | ||
81 | } | 72 | } |
82 | fn relevant_crates(&self, file_id: FileId) -> Arc<Vec<CrateId>> { | 73 | fn relevant_crates(&self, file_id: FileId) -> Arc<FxHashSet<CrateId>> { |
83 | FileLoaderDelegate(self).relevant_crates(file_id) | 74 | FileLoaderDelegate(self).relevant_crates(file_id) |
84 | } | 75 | } |
85 | fn resolve_extern_path( | ||
86 | &self, | ||
87 | extern_id: ra_db::ExternSourceId, | ||
88 | relative_path: &RelativePath, | ||
89 | ) -> Option<FileId> { | ||
90 | FileLoaderDelegate(self).resolve_extern_path(extern_id, relative_path) | ||
91 | } | ||
92 | } | 76 | } |
93 | 77 | ||
94 | impl TestDB { | 78 | impl TestDB { |
95 | pub fn module_for_file(&self, file_id: FileId) -> ModuleId { | 79 | pub(crate) fn module_for_file(&self, file_id: FileId) -> ModuleId { |
96 | for &krate in self.relevant_crates(file_id).iter() { | 80 | for &krate in self.relevant_crates(file_id).iter() { |
97 | let crate_def_map = self.crate_def_map(krate); | 81 | let crate_def_map = self.crate_def_map(krate); |
98 | for (local_id, data) in crate_def_map.modules.iter() { | 82 | for (local_id, data) in crate_def_map.modules.iter() { |
@@ -104,67 +88,32 @@ impl TestDB { | |||
104 | panic!("Can't find module for file") | 88 | panic!("Can't find module for file") |
105 | } | 89 | } |
106 | 90 | ||
107 | fn diag<F: FnMut(&dyn Diagnostic)>(&self, mut cb: F) { | 91 | pub(crate) fn extract_annotations(&self) -> FxHashMap<FileId, Vec<(TextRange, String)>> { |
92 | let mut files = Vec::new(); | ||
108 | let crate_graph = self.crate_graph(); | 93 | let crate_graph = self.crate_graph(); |
109 | for krate in crate_graph.iter() { | 94 | for krate in crate_graph.iter() { |
110 | let crate_def_map = self.crate_def_map(krate); | 95 | let crate_def_map = self.crate_def_map(krate); |
111 | |||
112 | let mut fns = Vec::new(); | ||
113 | for (module_id, _) in crate_def_map.modules.iter() { | 96 | for (module_id, _) in crate_def_map.modules.iter() { |
114 | for decl in crate_def_map[module_id].scope.declarations() { | 97 | let file_id = crate_def_map[module_id].origin.file_id(); |
115 | if let ModuleDefId::FunctionId(f) = decl { | 98 | files.extend(file_id) |
116 | fns.push(f) | ||
117 | } | ||
118 | } | ||
119 | |||
120 | for impl_id in crate_def_map[module_id].scope.impls() { | ||
121 | let impl_data = self.impl_data(impl_id); | ||
122 | for item in impl_data.items.iter() { | ||
123 | if let AssocItemId::FunctionId(f) = item { | ||
124 | fns.push(*f) | ||
125 | } | ||
126 | } | ||
127 | } | ||
128 | } | ||
129 | |||
130 | for f in fns { | ||
131 | let infer = self.infer(f.into()); | ||
132 | let mut sink = DiagnosticSink::new(&mut cb); | ||
133 | infer.add_diagnostics(self, f, &mut sink); | ||
134 | let mut validator = ExprValidator::new(f, infer, &mut sink); | ||
135 | validator.validate_body(self); | ||
136 | } | 99 | } |
137 | } | 100 | } |
138 | } | 101 | files |
139 | 102 | .into_iter() | |
140 | pub fn diagnostics(&self) -> (String, u32) { | 103 | .filter_map(|file_id| { |
141 | let mut buf = String::new(); | 104 | let text = self.file_text(file_id); |
142 | let mut count = 0; | 105 | let annotations = extract_annotations(&text); |
143 | self.diag(|d| { | 106 | if annotations.is_empty() { |
144 | format_to!(buf, "{:?}: {}\n", d.syntax_node(self).text(), d.message()); | 107 | return None; |
145 | count += 1; | 108 | } |
146 | }); | 109 | Some((file_id, annotations)) |
147 | (buf, count) | 110 | }) |
148 | } | 111 | .collect() |
149 | |||
150 | /// Like `diagnostics`, but filtered for a single diagnostic. | ||
151 | pub fn diagnostic<D: Diagnostic>(&self) -> (String, u32) { | ||
152 | let mut buf = String::new(); | ||
153 | let mut count = 0; | ||
154 | self.diag(|d| { | ||
155 | // We want to filter diagnostics by the particular one we are testing for, to | ||
156 | // avoid surprising results in tests. | ||
157 | if d.downcast_ref::<D>().is_some() { | ||
158 | format_to!(buf, "{:?}: {}\n", d.syntax_node(self).text(), d.message()); | ||
159 | count += 1; | ||
160 | }; | ||
161 | }); | ||
162 | (buf, count) | ||
163 | } | 112 | } |
164 | } | 113 | } |
165 | 114 | ||
166 | impl TestDB { | 115 | impl TestDB { |
167 | pub fn log(&self, f: impl FnOnce()) -> Vec<salsa::Event<TestDB>> { | 116 | pub fn log(&self, f: impl FnOnce()) -> Vec<salsa::Event> { |
168 | *self.events.lock().unwrap() = Some(Vec::new()); | 117 | *self.events.lock().unwrap() = Some(Vec::new()); |
169 | f(); | 118 | f(); |
170 | self.events.lock().unwrap().take().unwrap() | 119 | self.events.lock().unwrap().take().unwrap() |
@@ -178,7 +127,7 @@ impl TestDB { | |||
178 | // This pretty horrible, but `Debug` is the only way to inspect | 127 | // This pretty horrible, but `Debug` is the only way to inspect |
179 | // QueryDescriptor at the moment. | 128 | // QueryDescriptor at the moment. |
180 | salsa::EventKind::WillExecute { database_key } => { | 129 | salsa::EventKind::WillExecute { database_key } => { |
181 | Some(format!("{:?}", database_key)) | 130 | Some(format!("{:?}", database_key.debug(self))) |
182 | } | 131 | } |
183 | _ => None, | 132 | _ => None, |
184 | }) | 133 | }) |