aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_analysis
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_analysis')
-rw-r--r--crates/ra_analysis/src/db.rs43
-rw-r--r--crates/ra_analysis/src/lib.rs109
-rw-r--r--crates/ra_analysis/src/mock_analysis.rs40
3 files changed, 7 insertions, 185 deletions
diff --git a/crates/ra_analysis/src/db.rs b/crates/ra_analysis/src/db.rs
index 7fc3fe31b..df2ef293d 100644
--- a/crates/ra_analysis/src/db.rs
+++ b/crates/ra_analysis/src/db.rs
@@ -1,6 +1,4 @@
1use std::sync::Arc; 1use std::sync::Arc;
2#[cfg(test)]
3use parking_lot::Mutex;
4use salsa::{self, Database}; 2use salsa::{self, Database};
5use ra_db::{LocationIntener, BaseDatabase}; 3use ra_db::{LocationIntener, BaseDatabase};
6use hir::{self, DefId, DefLoc, FnId, SourceItemId}; 4use hir::{self, DefId, DefLoc, FnId, SourceItemId};
@@ -11,11 +9,6 @@ use crate::{
11 9
12#[derive(Debug)] 10#[derive(Debug)]
13pub(crate) struct RootDatabase { 11pub(crate) struct RootDatabase {
14 #[cfg(test)]
15 events: Mutex<Option<Vec<salsa::Event<RootDatabase>>>>,
16 #[cfg(not(test))]
17 events: (),
18
19 runtime: salsa::Runtime<RootDatabase>, 12 runtime: salsa::Runtime<RootDatabase>,
20 id_maps: Arc<IdMaps>, 13 id_maps: Arc<IdMaps>,
21} 14}
@@ -30,23 +23,11 @@ impl salsa::Database for RootDatabase {
30 fn salsa_runtime(&self) -> &salsa::Runtime<RootDatabase> { 23 fn salsa_runtime(&self) -> &salsa::Runtime<RootDatabase> {
31 &self.runtime 24 &self.runtime
32 } 25 }
33
34 #[allow(unused)]
35 fn salsa_event(&self, event: impl Fn() -> salsa::Event<RootDatabase>) {
36 #[cfg(test)]
37 {
38 let mut events = self.events.lock();
39 if let Some(events) = &mut *events {
40 events.push(event());
41 }
42 }
43 }
44} 26}
45 27
46impl Default for RootDatabase { 28impl Default for RootDatabase {
47 fn default() -> RootDatabase { 29 fn default() -> RootDatabase {
48 let mut db = RootDatabase { 30 let mut db = RootDatabase {
49 events: Default::default(),
50 runtime: salsa::Runtime::default(), 31 runtime: salsa::Runtime::default(),
51 id_maps: Default::default(), 32 id_maps: Default::default(),
52 }; 33 };
@@ -63,7 +44,6 @@ impl Default for RootDatabase {
63impl salsa::ParallelDatabase for RootDatabase { 44impl salsa::ParallelDatabase for RootDatabase {
64 fn snapshot(&self) -> salsa::Snapshot<RootDatabase> { 45 fn snapshot(&self) -> salsa::Snapshot<RootDatabase> {
65 salsa::Snapshot::new(RootDatabase { 46 salsa::Snapshot::new(RootDatabase {
66 events: Default::default(),
67 runtime: self.runtime.snapshot(self), 47 runtime: self.runtime.snapshot(self),
68 id_maps: self.id_maps.clone(), 48 id_maps: self.id_maps.clone(),
69 }) 49 })
@@ -84,29 +64,6 @@ impl AsRef<LocationIntener<hir::SourceItemId, FnId>> for RootDatabase {
84 } 64 }
85} 65}
86 66
87#[cfg(test)]
88impl RootDatabase {
89 pub(crate) fn log(&self, f: impl FnOnce()) -> Vec<salsa::Event<RootDatabase>> {
90 *self.events.lock() = Some(Vec::new());
91 f();
92 let events = self.events.lock().take().unwrap();
93 events
94 }
95
96 pub(crate) fn log_executed(&self, f: impl FnOnce()) -> Vec<String> {
97 let events = self.log(f);
98 events
99 .into_iter()
100 .filter_map(|e| match e.kind {
101 // This pretty horrible, but `Debug` is the only way to inspect
102 // QueryDescriptor at the moment.
103 salsa::EventKind::WillExecute { descriptor } => Some(format!("{:?}", descriptor)),
104 _ => None,
105 })
106 .collect()
107 }
108}
109
110salsa::database_storage! { 67salsa::database_storage! {
111 pub(crate) struct RootDatabaseStorage for RootDatabase { 68 pub(crate) struct RootDatabaseStorage for RootDatabase {
112 impl ra_db::FilesDatabase { 69 impl ra_db::FilesDatabase {
diff --git a/crates/ra_analysis/src/lib.rs b/crates/ra_analysis/src/lib.rs
index 350a6d627..12df580ba 100644
--- a/crates/ra_analysis/src/lib.rs
+++ b/crates/ra_analysis/src/lib.rs
@@ -317,112 +317,3 @@ fn analysis_is_send() {
317 fn is_send<T: Send>() {} 317 fn is_send<T: Send>() {}
318 is_send::<Analysis>(); 318 is_send::<Analysis>();
319} 319}
320
321//TODO: move to hir
322#[cfg(test)]
323mod hir_namres_tests {
324 use std::sync::Arc;
325 use ra_db::FilesDatabase;
326 use ra_syntax::SmolStr;
327 use hir::{self, db::HirDatabase};
328
329 use crate::{
330 AnalysisChange,
331 mock_analysis::{MockAnalysis, analysis_and_position},
332};
333
334 fn item_map(fixture: &str) -> (Arc<hir::ItemMap>, hir::ModuleId) {
335 let (analysis, pos) = analysis_and_position(fixture);
336 let db = analysis.imp.db;
337 let source_root = db.file_source_root(pos.file_id);
338 let descr = hir::Module::guess_from_position(&*db, pos)
339 .unwrap()
340 .unwrap();
341 let module_id = descr.module_id;
342 (db.item_map(source_root).unwrap(), module_id)
343 }
344
345 #[test]
346 fn test_item_map() {
347 let (item_map, module_id) = item_map(
348 "
349 //- /lib.rs
350 mod foo;
351
352 use crate::foo::bar::Baz;
353 <|>
354
355 //- /foo/mod.rs
356 pub mod bar;
357
358 //- /foo/bar.rs
359 pub struct Baz;
360 ",
361 );
362 let name = SmolStr::from("Baz");
363 let resolution = &item_map.per_module[&module_id].items[&name];
364 assert!(resolution.def_id.is_some());
365 }
366
367 #[test]
368 fn typing_inside_a_function_should_not_invalidate_item_map() {
369 let mock_analysis = MockAnalysis::with_files(
370 "
371 //- /lib.rs
372 mod foo;
373
374 use crate::foo::bar::Baz;
375
376 fn foo() -> i32 {
377 1 + 1
378 }
379 //- /foo/mod.rs
380 pub mod bar;
381
382 //- /foo/bar.rs
383 pub struct Baz;
384 ",
385 );
386
387 let file_id = mock_analysis.id_of("/lib.rs");
388 let mut host = mock_analysis.analysis_host();
389
390 let source_root = host.analysis().imp.db.file_source_root(file_id);
391
392 {
393 let db = host.analysis().imp.db;
394 let events = db.log_executed(|| {
395 db.item_map(source_root).unwrap();
396 });
397 assert!(format!("{:?}", events).contains("item_map"))
398 }
399
400 let mut change = AnalysisChange::new();
401
402 change.change_file(
403 file_id,
404 "
405 mod foo;
406
407 use crate::foo::bar::Baz;
408
409 fn foo() -> i32 { 92 }
410 "
411 .to_string(),
412 );
413
414 host.apply_change(change);
415
416 {
417 let db = host.analysis().imp.db;
418 let events = db.log_executed(|| {
419 db.item_map(source_root).unwrap();
420 });
421 assert!(
422 !format!("{:?}", events).contains("_item_map"),
423 "{:#?}",
424 events
425 )
426 }
427 }
428}
diff --git a/crates/ra_analysis/src/mock_analysis.rs b/crates/ra_analysis/src/mock_analysis.rs
index 8e8f969f4..0d9a7a147 100644
--- a/crates/ra_analysis/src/mock_analysis.rs
+++ b/crates/ra_analysis/src/mock_analysis.rs
@@ -1,9 +1,10 @@
1use std::sync::Arc; 1use std::sync::Arc;
2 2
3use relative_path::{RelativePath, RelativePathBuf}; 3use relative_path::{RelativePathBuf};
4use test_utils::{extract_offset, parse_fixture, CURSOR_MARKER}; 4use test_utils::{extract_offset, parse_fixture, CURSOR_MARKER};
5use ra_db::mock::FileMap;
5 6
6use crate::{Analysis, AnalysisChange, AnalysisHost, FileId, FileResolver, FilePosition}; 7use crate::{Analysis, AnalysisChange, AnalysisHost, FileId, FilePosition};
7 8
8/// Mock analysis is used in test to bootstrap an AnalysisHost/Analysis 9/// Mock analysis is used in test to bootstrap an AnalysisHost/Analysis
9/// from a set of in-memory files. 10/// from a set of in-memory files.
@@ -76,16 +77,15 @@ impl MockAnalysis {
76 } 77 }
77 pub fn analysis_host(self) -> AnalysisHost { 78 pub fn analysis_host(self) -> AnalysisHost {
78 let mut host = AnalysisHost::default(); 79 let mut host = AnalysisHost::default();
79 let mut file_map = Vec::new(); 80 let mut file_map = FileMap::default();
80 let mut change = AnalysisChange::new(); 81 let mut change = AnalysisChange::new();
81 for (id, (path, contents)) in self.files.into_iter().enumerate() { 82 for (path, contents) in self.files.into_iter() {
82 let file_id = FileId((id + 1) as u32);
83 assert!(path.starts_with('/')); 83 assert!(path.starts_with('/'));
84 let path = RelativePathBuf::from_path(&path[1..]).unwrap(); 84 let path = RelativePathBuf::from_path(&path[1..]).unwrap();
85 let file_id = file_map.add(path);
85 change.add_file(file_id, contents); 86 change.add_file(file_id, contents);
86 file_map.push((file_id, path));
87 } 87 }
88 change.set_file_resolver(Arc::new(FileMap(file_map))); 88 change.set_file_resolver(Arc::new(file_map));
89 host.apply_change(change); 89 host.apply_change(change);
90 host 90 host
91 } 91 }
@@ -113,29 +113,3 @@ pub fn single_file_with_position(code: &str) -> (Analysis, FilePosition) {
113 let pos = mock.add_file_with_position("/main.rs", code); 113 let pos = mock.add_file_with_position("/main.rs", code);
114 (mock.analysis(), pos) 114 (mock.analysis(), pos)
115} 115}
116
117#[derive(Debug)]
118struct FileMap(Vec<(FileId, RelativePathBuf)>);
119
120impl FileMap {
121 fn iter<'a>(&'a self) -> impl Iterator<Item = (FileId, &'a RelativePath)> + 'a {
122 self.0
123 .iter()
124 .map(|(id, path)| (*id, path.as_relative_path()))
125 }
126
127 fn path(&self, id: FileId) -> &RelativePath {
128 self.iter().find(|&(it, _)| it == id).unwrap().1
129 }
130}
131
132impl FileResolver for FileMap {
133 fn file_stem(&self, id: FileId) -> String {
134 self.path(id).file_stem().unwrap().to_string()
135 }
136 fn resolve(&self, id: FileId, rel: &RelativePath) -> Option<FileId> {
137 let path = self.path(id).join(rel).normalize();
138 let id = self.iter().find(|&(_, p)| path == p)?.0;
139 Some(id)
140 }
141}