diff options
Diffstat (limited to 'crates/ra_hir/src/mock.rs')
-rw-r--r-- | crates/ra_hir/src/mock.rs | 262 |
1 files changed, 0 insertions, 262 deletions
diff --git a/crates/ra_hir/src/mock.rs b/crates/ra_hir/src/mock.rs deleted file mode 100644 index ab97a09b9..000000000 --- a/crates/ra_hir/src/mock.rs +++ /dev/null | |||
@@ -1,262 +0,0 @@ | |||
1 | //! FIXME: write short doc here | ||
2 | |||
3 | use std::{panic, sync::Arc}; | ||
4 | |||
5 | use hir_expand::diagnostics::DiagnosticSink; | ||
6 | use parking_lot::Mutex; | ||
7 | use ra_cfg::CfgOptions; | ||
8 | use ra_db::{ | ||
9 | salsa, CrateGraph, CrateId, Edition, FileId, FileLoader, FileLoaderDelegate, FilePosition, | ||
10 | RelativePath, RelativePathBuf, SourceDatabase, SourceDatabaseExt, SourceRoot, SourceRootId, | ||
11 | }; | ||
12 | use rustc_hash::FxHashMap; | ||
13 | use test_utils::{extract_offset, parse_fixture, CURSOR_MARKER}; | ||
14 | |||
15 | use crate::{db, debug::HirDebugHelper}; | ||
16 | |||
17 | pub const WORKSPACE: SourceRootId = SourceRootId(0); | ||
18 | |||
19 | #[salsa::database( | ||
20 | ra_db::SourceDatabaseExtStorage, | ||
21 | ra_db::SourceDatabaseStorage, | ||
22 | db::InternDatabaseStorage, | ||
23 | db::AstDatabaseStorage, | ||
24 | db::DefDatabaseStorage, | ||
25 | db::DefDatabase2Storage, | ||
26 | db::HirDatabaseStorage | ||
27 | )] | ||
28 | #[derive(Debug)] | ||
29 | pub struct MockDatabase { | ||
30 | events: Mutex<Option<Vec<salsa::Event<MockDatabase>>>>, | ||
31 | runtime: salsa::Runtime<MockDatabase>, | ||
32 | files: FxHashMap<String, FileId>, | ||
33 | crate_names: Arc<FxHashMap<CrateId, String>>, | ||
34 | file_paths: Arc<FxHashMap<FileId, String>>, | ||
35 | } | ||
36 | |||
37 | impl panic::RefUnwindSafe for MockDatabase {} | ||
38 | |||
39 | impl FileLoader for MockDatabase { | ||
40 | fn file_text(&self, file_id: FileId) -> Arc<String> { | ||
41 | FileLoaderDelegate(self).file_text(file_id) | ||
42 | } | ||
43 | fn resolve_relative_path( | ||
44 | &self, | ||
45 | anchor: FileId, | ||
46 | relative_path: &RelativePath, | ||
47 | ) -> Option<FileId> { | ||
48 | FileLoaderDelegate(self).resolve_relative_path(anchor, relative_path) | ||
49 | } | ||
50 | fn relevant_crates(&self, file_id: FileId) -> Arc<Vec<CrateId>> { | ||
51 | FileLoaderDelegate(self).relevant_crates(file_id) | ||
52 | } | ||
53 | } | ||
54 | |||
55 | impl HirDebugHelper for MockDatabase { | ||
56 | fn crate_name(&self, krate: CrateId) -> Option<String> { | ||
57 | self.crate_names.get(&krate).cloned() | ||
58 | } | ||
59 | |||
60 | fn file_path(&self, file_id: FileId) -> Option<String> { | ||
61 | self.file_paths.get(&file_id).cloned() | ||
62 | } | ||
63 | } | ||
64 | |||
65 | impl MockDatabase { | ||
66 | pub fn with_files(fixture: &str) -> MockDatabase { | ||
67 | let (db, position) = MockDatabase::from_fixture(fixture); | ||
68 | assert!(position.is_none()); | ||
69 | db | ||
70 | } | ||
71 | |||
72 | pub fn with_single_file(text: &str) -> (MockDatabase, SourceRoot, FileId) { | ||
73 | let mut db = MockDatabase::default(); | ||
74 | let mut source_root = SourceRoot::default(); | ||
75 | let file_id = db.add_file(WORKSPACE, "/", &mut source_root, "/main.rs", text); | ||
76 | db.set_source_root(WORKSPACE, Arc::new(source_root.clone())); | ||
77 | (db, source_root, file_id) | ||
78 | } | ||
79 | |||
80 | pub fn file_id_of(&self, path: &str) -> FileId { | ||
81 | match self.files.get(path) { | ||
82 | Some(it) => *it, | ||
83 | None => panic!("unknown file: {:?}\nexisting files:\n{:#?}", path, self.files), | ||
84 | } | ||
85 | } | ||
86 | |||
87 | pub fn diagnostics(&self) -> String { | ||
88 | let mut buf = String::new(); | ||
89 | let mut files: Vec<FileId> = self.files.values().copied().collect(); | ||
90 | files.sort(); | ||
91 | for file in files { | ||
92 | let src = crate::Source { | ||
93 | file_id: file.into(), | ||
94 | ast: crate::ModuleSource::new(self, Some(file), None), | ||
95 | }; | ||
96 | let module = crate::Module::from_definition(self, src).unwrap(); | ||
97 | module.diagnostics( | ||
98 | self, | ||
99 | &mut DiagnosticSink::new(|d| { | ||
100 | buf += &format!("{:?}: {}\n", d.syntax_node(self).text(), d.message()); | ||
101 | }), | ||
102 | ) | ||
103 | } | ||
104 | buf | ||
105 | } | ||
106 | |||
107 | fn from_fixture(fixture: &str) -> (MockDatabase, Option<FilePosition>) { | ||
108 | let mut db = MockDatabase::default(); | ||
109 | |||
110 | let pos = db.add_fixture(fixture); | ||
111 | |||
112 | (db, pos) | ||
113 | } | ||
114 | |||
115 | fn add_fixture(&mut self, fixture: &str) -> Option<FilePosition> { | ||
116 | let mut position = None; | ||
117 | let mut source_root = SourceRoot::default(); | ||
118 | let mut source_root_id = WORKSPACE; | ||
119 | let mut source_root_prefix = "/".to_string(); | ||
120 | for entry in parse_fixture(fixture) { | ||
121 | if entry.meta.starts_with("root") { | ||
122 | self.set_source_root(source_root_id, Arc::new(source_root)); | ||
123 | source_root = SourceRoot::default(); | ||
124 | |||
125 | source_root_id = SourceRootId(source_root_id.0 + 1); | ||
126 | source_root_prefix = entry.meta["root".len()..].trim().to_string(); | ||
127 | continue; | ||
128 | } | ||
129 | if entry.text.contains(CURSOR_MARKER) { | ||
130 | assert!(position.is_none(), "only one marker (<|>) per fixture is allowed"); | ||
131 | position = Some(self.add_file_with_position( | ||
132 | source_root_id, | ||
133 | &source_root_prefix, | ||
134 | &mut source_root, | ||
135 | &entry.meta, | ||
136 | &entry.text, | ||
137 | )); | ||
138 | } else { | ||
139 | self.add_file( | ||
140 | source_root_id, | ||
141 | &source_root_prefix, | ||
142 | &mut source_root, | ||
143 | &entry.meta, | ||
144 | &entry.text, | ||
145 | ); | ||
146 | } | ||
147 | } | ||
148 | self.set_source_root(source_root_id, Arc::new(source_root)); | ||
149 | position | ||
150 | } | ||
151 | |||
152 | fn add_file( | ||
153 | &mut self, | ||
154 | source_root_id: SourceRootId, | ||
155 | source_root_prefix: &str, | ||
156 | source_root: &mut SourceRoot, | ||
157 | path: &str, | ||
158 | text: &str, | ||
159 | ) -> FileId { | ||
160 | assert!(source_root_prefix.starts_with('/')); | ||
161 | assert!(source_root_prefix.ends_with('/')); | ||
162 | assert!(path.starts_with(source_root_prefix)); | ||
163 | let rel_path = RelativePathBuf::from_path(&path[source_root_prefix.len()..]).unwrap(); | ||
164 | |||
165 | let is_crate_root = rel_path == "lib.rs" || rel_path == "/main.rs"; | ||
166 | |||
167 | let file_id = FileId(self.files.len() as u32); | ||
168 | |||
169 | let prev = self.files.insert(path.to_string(), file_id); | ||
170 | assert!(prev.is_none(), "duplicate files in the text fixture"); | ||
171 | Arc::make_mut(&mut self.file_paths).insert(file_id, path.to_string()); | ||
172 | |||
173 | let text = Arc::new(text.to_string()); | ||
174 | self.set_file_text(file_id, text); | ||
175 | self.set_file_relative_path(file_id, rel_path.clone()); | ||
176 | self.set_file_source_root(file_id, source_root_id); | ||
177 | source_root.insert_file(rel_path, file_id); | ||
178 | |||
179 | if is_crate_root { | ||
180 | let mut crate_graph = CrateGraph::default(); | ||
181 | crate_graph.add_crate_root(file_id, Edition::Edition2018, CfgOptions::default()); | ||
182 | self.set_crate_graph(Arc::new(crate_graph)); | ||
183 | } | ||
184 | file_id | ||
185 | } | ||
186 | |||
187 | fn add_file_with_position( | ||
188 | &mut self, | ||
189 | source_root_id: SourceRootId, | ||
190 | source_root_prefix: &str, | ||
191 | source_root: &mut SourceRoot, | ||
192 | path: &str, | ||
193 | text: &str, | ||
194 | ) -> FilePosition { | ||
195 | let (offset, text) = extract_offset(text); | ||
196 | let file_id = self.add_file(source_root_id, source_root_prefix, source_root, path, &text); | ||
197 | FilePosition { file_id, offset } | ||
198 | } | ||
199 | } | ||
200 | |||
201 | impl salsa::Database for MockDatabase { | ||
202 | fn salsa_runtime(&self) -> &salsa::Runtime<MockDatabase> { | ||
203 | &self.runtime | ||
204 | } | ||
205 | |||
206 | fn salsa_event(&self, event: impl Fn() -> salsa::Event<MockDatabase>) { | ||
207 | let mut events = self.events.lock(); | ||
208 | if let Some(events) = &mut *events { | ||
209 | events.push(event()); | ||
210 | } | ||
211 | } | ||
212 | } | ||
213 | |||
214 | impl Default for MockDatabase { | ||
215 | fn default() -> MockDatabase { | ||
216 | let mut db = MockDatabase { | ||
217 | events: Default::default(), | ||
218 | runtime: salsa::Runtime::default(), | ||
219 | files: FxHashMap::default(), | ||
220 | crate_names: Default::default(), | ||
221 | file_paths: Default::default(), | ||
222 | }; | ||
223 | db.set_crate_graph(Default::default()); | ||
224 | db | ||
225 | } | ||
226 | } | ||
227 | |||
228 | impl salsa::ParallelDatabase for MockDatabase { | ||
229 | fn snapshot(&self) -> salsa::Snapshot<MockDatabase> { | ||
230 | salsa::Snapshot::new(MockDatabase { | ||
231 | events: Default::default(), | ||
232 | runtime: self.runtime.snapshot(self), | ||
233 | // only the root database can be used to get file_id by path. | ||
234 | files: FxHashMap::default(), | ||
235 | file_paths: Arc::clone(&self.file_paths), | ||
236 | crate_names: Arc::clone(&self.crate_names), | ||
237 | }) | ||
238 | } | ||
239 | } | ||
240 | |||
241 | impl MockDatabase { | ||
242 | pub fn log(&self, f: impl FnOnce()) -> Vec<salsa::Event<MockDatabase>> { | ||
243 | *self.events.lock() = Some(Vec::new()); | ||
244 | f(); | ||
245 | self.events.lock().take().unwrap() | ||
246 | } | ||
247 | |||
248 | pub fn log_executed(&self, f: impl FnOnce()) -> Vec<String> { | ||
249 | let events = self.log(f); | ||
250 | events | ||
251 | .into_iter() | ||
252 | .filter_map(|e| match e.kind { | ||
253 | // This pretty horrible, but `Debug` is the only way to inspect | ||
254 | // QueryDescriptor at the moment. | ||
255 | salsa::EventKind::WillExecute { database_key } => { | ||
256 | Some(format!("{:?}", database_key)) | ||
257 | } | ||
258 | _ => None, | ||
259 | }) | ||
260 | .collect() | ||
261 | } | ||
262 | } | ||