aboutsummaryrefslogtreecommitdiff
path: root/crates/ide/src/mock_analysis.rs
diff options
context:
space:
mode:
authorAleksey Kladov <[email protected]>2020-10-02 15:13:48 +0100
committerAleksey Kladov <[email protected]>2020-10-02 16:31:20 +0100
commit09348b247465864c6462a39055803bcbb0156cfe (patch)
treed57122ddcaa21d6f4ea50204afc3e3bc341583fc /crates/ide/src/mock_analysis.rs
parenteeb27f95f1025128f8a1d24a515eb009498a1d44 (diff)
Get rid of MockAnalysis
Diffstat (limited to 'crates/ide/src/mock_analysis.rs')
-rw-r--r--crates/ide/src/mock_analysis.rs209
1 files changed, 54 insertions, 155 deletions
diff --git a/crates/ide/src/mock_analysis.rs b/crates/ide/src/mock_analysis.rs
index 6812db9b9..838547599 100644
--- a/crates/ide/src/mock_analysis.rs
+++ b/crates/ide/src/mock_analysis.rs
@@ -1,174 +1,73 @@
1//! FIXME: write short doc here 1//! FIXME: write short doc here
2use std::sync::Arc;
3 2
4use base_db::{CrateName, FileSet, SourceRoot, VfsPath}; 3use base_db::fixture::ChangeFixture;
5use cfg::CfgOptions; 4use test_utils::{extract_annotations, RangeOrOffset};
6use test_utils::{
7 extract_annotations, extract_range_or_offset, Fixture, RangeOrOffset, CURSOR_MARKER,
8};
9 5
10use crate::{Analysis, AnalysisHost, Change, CrateGraph, Edition, FileId, FilePosition, FileRange}; 6use crate::{Analysis, AnalysisHost, FileId, FilePosition, FileRange};
11
12/// Mock analysis is used in test to bootstrap an AnalysisHost/Analysis
13/// from a set of in-memory files.
14#[derive(Debug, Default)]
15pub(crate) struct MockAnalysis {
16 files: Vec<Fixture>,
17}
18
19impl MockAnalysis {
20 /// Creates `MockAnalysis` using a fixture data in the following format:
21 ///
22 /// ```not_rust
23 /// //- /main.rs
24 /// mod foo;
25 /// fn main() {}
26 ///
27 /// //- /foo.rs
28 /// struct Baz;
29 /// ```
30 pub(crate) fn with_files(ra_fixture: &str) -> MockAnalysis {
31 let (res, pos) = MockAnalysis::with_fixture(ra_fixture);
32 assert!(pos.is_none());
33 res
34 }
35
36 /// Same as `with_files`, but requires that a single file contains a `<|>` marker,
37 /// whose position is also returned.
38 pub(crate) fn with_files_and_position(fixture: &str) -> (MockAnalysis, FilePosition) {
39 let (res, position) = MockAnalysis::with_fixture(fixture);
40 let (file_id, range_or_offset) = position.expect("expected a marker (<|>)");
41 let offset = match range_or_offset {
42 RangeOrOffset::Range(_) => panic!(),
43 RangeOrOffset::Offset(it) => it,
44 };
45 (res, FilePosition { file_id, offset })
46 }
47
48 fn with_fixture(fixture: &str) -> (MockAnalysis, Option<(FileId, RangeOrOffset)>) {
49 let mut position = None;
50 let mut res = MockAnalysis::default();
51 for mut entry in Fixture::parse(fixture) {
52 if entry.text.contains(CURSOR_MARKER) {
53 assert!(position.is_none(), "only one marker (<|>) per fixture is allowed");
54 let (range_or_offset, text) = extract_range_or_offset(&entry.text);
55 entry.text = text;
56 let file_id = res.add_file_fixture(entry);
57 position = Some((file_id, range_or_offset));
58 } else {
59 res.add_file_fixture(entry);
60 }
61 }
62 (res, position)
63 }
64
65 fn add_file_fixture(&mut self, fixture: Fixture) -> FileId {
66 let file_id = FileId((self.files.len() + 1) as u32);
67 self.files.push(fixture);
68 file_id
69 }
70
71 pub(crate) fn id_of(&self, path: &str) -> FileId {
72 let (file_id, _) =
73 self.files().find(|(_, data)| path == data.path).expect("no file in this mock");
74 file_id
75 }
76 pub(crate) fn annotations(&self) -> Vec<(FileRange, String)> {
77 self.files()
78 .flat_map(|(file_id, fixture)| {
79 let annotations = extract_annotations(&fixture.text);
80 annotations
81 .into_iter()
82 .map(move |(range, data)| (FileRange { file_id, range }, data))
83 })
84 .collect()
85 }
86 pub(crate) fn files(&self) -> impl Iterator<Item = (FileId, &Fixture)> + '_ {
87 self.files.iter().enumerate().map(|(idx, fixture)| (FileId(idx as u32 + 1), fixture))
88 }
89 pub(crate) fn annotation(&self) -> (FileRange, String) {
90 let mut all = self.annotations();
91 assert_eq!(all.len(), 1);
92 all.pop().unwrap()
93 }
94 pub(crate) fn analysis_host(self) -> AnalysisHost {
95 let mut host = AnalysisHost::default();
96 let mut change = Change::new();
97 let mut file_set = FileSet::default();
98 let mut crate_graph = CrateGraph::default();
99 let mut root_crate = None;
100 for (i, data) in self.files.into_iter().enumerate() {
101 let path = data.path;
102 assert!(path.starts_with('/'));
103
104 let mut cfg = CfgOptions::default();
105 data.cfg_atoms.iter().for_each(|it| cfg.insert_atom(it.into()));
106 data.cfg_key_values.iter().for_each(|(k, v)| cfg.insert_key_value(k.into(), v.into()));
107 let edition: Edition =
108 data.edition.and_then(|it| it.parse().ok()).unwrap_or(Edition::Edition2018);
109
110 let file_id = FileId(i as u32 + 1);
111 let env = data.env.into_iter().collect();
112 if path == "/lib.rs" || path == "/main.rs" {
113 root_crate = Some(crate_graph.add_crate_root(
114 file_id,
115 edition,
116 Some("test".to_string()),
117 cfg,
118 env,
119 Default::default(),
120 ));
121 } else if path.ends_with("/lib.rs") {
122 let base = &path[..path.len() - "/lib.rs".len()];
123 let crate_name = &base[base.rfind('/').unwrap() + '/'.len_utf8()..];
124 let other_crate = crate_graph.add_crate_root(
125 file_id,
126 edition,
127 Some(crate_name.to_string()),
128 cfg,
129 env,
130 Default::default(),
131 );
132 if let Some(root_crate) = root_crate {
133 crate_graph
134 .add_dep(root_crate, CrateName::new(crate_name).unwrap(), other_crate)
135 .unwrap();
136 }
137 }
138 let path = VfsPath::new_virtual_path(path.to_string());
139 file_set.insert(file_id, path);
140 change.change_file(file_id, Some(Arc::new(data.text).to_owned()));
141 }
142 change.set_crate_graph(crate_graph);
143 change.set_roots(vec![SourceRoot::new_local(file_set)]);
144 host.apply_change(change);
145 host
146 }
147 pub(crate) fn analysis(self) -> Analysis {
148 self.analysis_host().analysis()
149 }
150}
151 7
152/// Creates analysis from a multi-file fixture, returns positions marked with <|>. 8/// Creates analysis from a multi-file fixture, returns positions marked with <|>.
153pub(crate) fn analysis_and_position(ra_fixture: &str) -> (Analysis, FilePosition) { 9pub(crate) fn analysis_and_position(ra_fixture: &str) -> (Analysis, FilePosition) {
154 let (mock, position) = MockAnalysis::with_files_and_position(ra_fixture); 10 let mut host = AnalysisHost::default();
155 (mock.analysis(), position) 11 let change_fixture = ChangeFixture::parse(ra_fixture);
12 host.db.apply_change(change_fixture.change);
13 let (file_id, range_or_offset) = change_fixture.file_position.expect("expected a marker (<|>)");
14 let offset = match range_or_offset {
15 RangeOrOffset::Range(_) => panic!(),
16 RangeOrOffset::Offset(it) => it,
17 };
18 (host.analysis(), FilePosition { file_id, offset })
156} 19}
157 20
158/// Creates analysis for a single file. 21/// Creates analysis for a single file.
159pub(crate) fn single_file(ra_fixture: &str) -> (Analysis, FileId) { 22pub(crate) fn single_file(ra_fixture: &str) -> (Analysis, FileId) {
160 let mock = MockAnalysis::with_files(ra_fixture); 23 let mut host = AnalysisHost::default();
161 let file_id = mock.id_of("/main.rs"); 24 let change_fixture = ChangeFixture::parse(ra_fixture);
162 (mock.analysis(), file_id) 25 host.db.apply_change(change_fixture.change);
26 (host.analysis(), change_fixture.files[0])
27}
28
29/// Creates analysis for a single file.
30pub(crate) fn many_files(ra_fixture: &str) -> (Analysis, Vec<FileId>) {
31 let mut host = AnalysisHost::default();
32 let change_fixture = ChangeFixture::parse(ra_fixture);
33 host.db.apply_change(change_fixture.change);
34 (host.analysis(), change_fixture.files)
163} 35}
164 36
165/// Creates analysis for a single file, returns range marked with a pair of <|>. 37/// Creates analysis for a single file, returns range marked with a pair of <|>.
166pub(crate) fn analysis_and_range(ra_fixture: &str) -> (Analysis, FileRange) { 38pub(crate) fn analysis_and_range(ra_fixture: &str) -> (Analysis, FileRange) {
167 let (res, position) = MockAnalysis::with_fixture(ra_fixture); 39 let mut host = AnalysisHost::default();
168 let (file_id, range_or_offset) = position.expect("expected a marker (<|>)"); 40 let change_fixture = ChangeFixture::parse(ra_fixture);
41 host.db.apply_change(change_fixture.change);
42 let (file_id, range_or_offset) = change_fixture.file_position.expect("expected a marker (<|>)");
169 let range = match range_or_offset { 43 let range = match range_or_offset {
170 RangeOrOffset::Range(it) => it, 44 RangeOrOffset::Range(it) => it,
171 RangeOrOffset::Offset(_) => panic!(), 45 RangeOrOffset::Offset(_) => panic!(),
172 }; 46 };
173 (res.analysis(), FileRange { file_id, range }) 47 (host.analysis(), FileRange { file_id, range })
48}
49
50/// Creates analysis from a multi-file fixture, returns positions marked with <|>.
51pub(crate) fn analysis_and_annotations(
52 ra_fixture: &str,
53) -> (Analysis, FilePosition, Vec<(FileRange, String)>) {
54 let mut host = AnalysisHost::default();
55 let change_fixture = ChangeFixture::parse(ra_fixture);
56 host.db.apply_change(change_fixture.change);
57 let (file_id, range_or_offset) = change_fixture.file_position.expect("expected a marker (<|>)");
58 let offset = match range_or_offset {
59 RangeOrOffset::Range(_) => panic!(),
60 RangeOrOffset::Offset(it) => it,
61 };
62
63 let annotations = change_fixture
64 .files
65 .iter()
66 .flat_map(|&file_id| {
67 let file_text = host.analysis().file_text(file_id).unwrap();
68 let annotations = extract_annotations(&file_text);
69 annotations.into_iter().map(move |(range, data)| (FileRange { file_id, range }, data))
70 })
71 .collect();
72 (host.analysis(), FilePosition { file_id, offset }, annotations)
174} 73}