aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_ide_api/src/mock_analysis.rs
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_ide_api/src/mock_analysis.rs')
-rw-r--r--crates/ra_ide_api/src/mock_analysis.rs135
1 files changed, 135 insertions, 0 deletions
diff --git a/crates/ra_ide_api/src/mock_analysis.rs b/crates/ra_ide_api/src/mock_analysis.rs
new file mode 100644
index 000000000..846c76cfe
--- /dev/null
+++ b/crates/ra_ide_api/src/mock_analysis.rs
@@ -0,0 +1,135 @@
1use std::sync::Arc;
2
3use relative_path::RelativePathBuf;
4use test_utils::{extract_offset, extract_range, parse_fixture, CURSOR_MARKER};
5use ra_db::mock::FileMap;
6
7use crate::{Analysis, AnalysisChange, AnalysisHost, CrateGraph, FileId, FilePosition, FileRange, SourceRootId};
8
9/// Mock analysis is used in test to bootstrap an AnalysisHost/Analysis
10/// from a set of in-memory files.
11#[derive(Debug, Default)]
12pub struct MockAnalysis {
13 files: Vec<(String, String)>,
14}
15
16impl MockAnalysis {
17 pub fn new() -> MockAnalysis {
18 MockAnalysis::default()
19 }
20 /// Creates `MockAnalysis` using a fixture data in the following format:
21 ///
22 /// ```notrust
23 /// //- /main.rs
24 /// mod foo;
25 /// fn main() {}
26 ///
27 /// //- /foo.rs
28 /// struct Baz;
29 /// ```
30 pub fn with_files(fixture: &str) -> MockAnalysis {
31 let mut res = MockAnalysis::new();
32 for entry in parse_fixture(fixture) {
33 res.add_file(&entry.meta, &entry.text);
34 }
35 res
36 }
37
38 /// Same as `with_files`, but requires that a single file contains a `<|>` marker,
39 /// whose position is also returned.
40 pub fn with_files_and_position(fixture: &str) -> (MockAnalysis, FilePosition) {
41 let mut position = None;
42 let mut res = MockAnalysis::new();
43 for entry in parse_fixture(fixture) {
44 if entry.text.contains(CURSOR_MARKER) {
45 assert!(
46 position.is_none(),
47 "only one marker (<|>) per fixture is allowed"
48 );
49 position = Some(res.add_file_with_position(&entry.meta, &entry.text));
50 } else {
51 res.add_file(&entry.meta, &entry.text);
52 }
53 }
54 let position = position.expect("expected a marker (<|>)");
55 (res, position)
56 }
57
58 pub fn add_file(&mut self, path: &str, text: &str) -> FileId {
59 let file_id = FileId((self.files.len() + 1) as u32);
60 self.files.push((path.to_string(), text.to_string()));
61 file_id
62 }
63 pub fn add_file_with_position(&mut self, path: &str, text: &str) -> FilePosition {
64 let (offset, text) = extract_offset(text);
65 let file_id = FileId((self.files.len() + 1) as u32);
66 self.files.push((path.to_string(), text.to_string()));
67 FilePosition { file_id, offset }
68 }
69 pub fn add_file_with_range(&mut self, path: &str, text: &str) -> FileRange {
70 let (range, text) = extract_range(text);
71 let file_id = FileId((self.files.len() + 1) as u32);
72 self.files.push((path.to_string(), text.to_string()));
73 FileRange { file_id, range }
74 }
75 pub fn id_of(&self, path: &str) -> FileId {
76 let (idx, _) = self
77 .files
78 .iter()
79 .enumerate()
80 .find(|(_, (p, _text))| path == p)
81 .expect("no file in this mock");
82 FileId(idx as u32 + 1)
83 }
84 pub fn analysis_host(self) -> AnalysisHost {
85 let mut host = AnalysisHost::default();
86 let mut file_map = FileMap::default();
87 let source_root = SourceRootId(0);
88 let mut change = AnalysisChange::new();
89 change.add_root(source_root, true);
90 let mut crate_graph = CrateGraph::default();
91 for (path, contents) in self.files.into_iter() {
92 assert!(path.starts_with('/'));
93 let path = RelativePathBuf::from_path(&path[1..]).unwrap();
94 let file_id = file_map.add(path.clone());
95 if path == "/lib.rs" || path == "/main.rs" {
96 crate_graph.add_crate_root(file_id);
97 }
98 change.add_file(source_root, file_id, path, Arc::new(contents));
99 }
100 change.set_crate_graph(crate_graph);
101 // change.set_file_resolver(Arc::new(file_map));
102 host.apply_change(change);
103 host
104 }
105 pub fn analysis(self) -> Analysis {
106 self.analysis_host().analysis()
107 }
108}
109
110/// Creates analysis from a multi-file fixture, returns positions marked with <|>.
111pub fn analysis_and_position(fixture: &str) -> (Analysis, FilePosition) {
112 let (mock, position) = MockAnalysis::with_files_and_position(fixture);
113 (mock.analysis(), position)
114}
115
116/// Creates analysis for a single file.
117pub fn single_file(code: &str) -> (Analysis, FileId) {
118 let mut mock = MockAnalysis::new();
119 let file_id = mock.add_file("/main.rs", code);
120 (mock.analysis(), file_id)
121}
122
123/// Creates analysis for a single file, returns position marked with <|>.
124pub fn single_file_with_position(code: &str) -> (Analysis, FilePosition) {
125 let mut mock = MockAnalysis::new();
126 let pos = mock.add_file_with_position("/main.rs", code);
127 (mock.analysis(), pos)
128}
129
130/// Creates analysis for a single file, returns range marked with a pair of <|>.
131pub fn single_file_with_range(code: &str) -> (Analysis, FileRange) {
132 let mut mock = MockAnalysis::new();
133 let pos = mock.add_file_with_range("/main.rs", code);
134 (mock.analysis(), pos)
135}