diff options
Diffstat (limited to 'crates/ra_ide/src/mock_analysis.rs')
-rw-r--r-- | crates/ra_ide/src/mock_analysis.rs | 123 |
1 files changed, 102 insertions, 21 deletions
diff --git a/crates/ra_ide/src/mock_analysis.rs b/crates/ra_ide/src/mock_analysis.rs index 2c13f206a..ad78d2d93 100644 --- a/crates/ra_ide/src/mock_analysis.rs +++ b/crates/ra_ide/src/mock_analysis.rs | |||
@@ -1,21 +1,81 @@ | |||
1 | //! FIXME: write short doc here | 1 | //! FIXME: write short doc here |
2 | 2 | ||
3 | use std::str::FromStr; | ||
3 | use std::sync::Arc; | 4 | use std::sync::Arc; |
4 | 5 | ||
5 | use ra_cfg::CfgOptions; | 6 | use ra_cfg::CfgOptions; |
6 | use ra_db::{CrateName, Env, RelativePathBuf}; | 7 | use ra_db::{CrateName, Env, RelativePathBuf}; |
7 | use test_utils::{extract_offset, extract_range, parse_fixture, CURSOR_MARKER}; | 8 | use test_utils::{extract_offset, extract_range, parse_fixture, FixtureEntry, CURSOR_MARKER}; |
8 | 9 | ||
9 | use crate::{ | 10 | use crate::{ |
10 | Analysis, AnalysisChange, AnalysisHost, CrateGraph, Edition::Edition2018, FileId, FilePosition, | 11 | Analysis, AnalysisChange, AnalysisHost, CrateGraph, Edition, FileId, FilePosition, FileRange, |
11 | FileRange, SourceRootId, | 12 | SourceRootId, |
12 | }; | 13 | }; |
13 | 14 | ||
15 | #[derive(Debug)] | ||
16 | enum MockFileData { | ||
17 | Plain { path: String, content: String }, | ||
18 | Fixture(FixtureEntry), | ||
19 | } | ||
20 | |||
21 | impl MockFileData { | ||
22 | fn new(path: String, content: String) -> Self { | ||
23 | // `Self::Plain` causes a false warning: 'variant is never constructed: `Plain` ' | ||
24 | // see https://github.com/rust-lang/rust/issues/69018 | ||
25 | MockFileData::Plain { path, content } | ||
26 | } | ||
27 | |||
28 | fn path(&self) -> &str { | ||
29 | match self { | ||
30 | MockFileData::Plain { path, .. } => path.as_str(), | ||
31 | MockFileData::Fixture(f) => f.meta.path().as_str(), | ||
32 | } | ||
33 | } | ||
34 | |||
35 | fn content(&self) -> &str { | ||
36 | match self { | ||
37 | MockFileData::Plain { content, .. } => content, | ||
38 | MockFileData::Fixture(f) => f.text.as_str(), | ||
39 | } | ||
40 | } | ||
41 | |||
42 | fn cfg_options(&self) -> CfgOptions { | ||
43 | match self { | ||
44 | MockFileData::Fixture(f) => { | ||
45 | f.meta.cfg_options().map_or_else(Default::default, |o| o.clone()) | ||
46 | } | ||
47 | _ => CfgOptions::default(), | ||
48 | } | ||
49 | } | ||
50 | |||
51 | fn edition(&self) -> Edition { | ||
52 | match self { | ||
53 | MockFileData::Fixture(f) => { | ||
54 | f.meta.edition().map_or(Edition::Edition2018, |v| Edition::from_str(v).unwrap()) | ||
55 | } | ||
56 | _ => Edition::Edition2018, | ||
57 | } | ||
58 | } | ||
59 | |||
60 | fn env(&self) -> Env { | ||
61 | match self { | ||
62 | MockFileData::Fixture(f) => Env::from(f.meta.env()), | ||
63 | _ => Env::default(), | ||
64 | } | ||
65 | } | ||
66 | } | ||
67 | |||
68 | impl From<FixtureEntry> for MockFileData { | ||
69 | fn from(fixture: FixtureEntry) -> Self { | ||
70 | Self::Fixture(fixture) | ||
71 | } | ||
72 | } | ||
73 | |||
14 | /// Mock analysis is used in test to bootstrap an AnalysisHost/Analysis | 74 | /// Mock analysis is used in test to bootstrap an AnalysisHost/Analysis |
15 | /// from a set of in-memory files. | 75 | /// from a set of in-memory files. |
16 | #[derive(Debug, Default)] | 76 | #[derive(Debug, Default)] |
17 | pub struct MockAnalysis { | 77 | pub struct MockAnalysis { |
18 | files: Vec<(String, String)>, | 78 | files: Vec<MockFileData>, |
19 | } | 79 | } |
20 | 80 | ||
21 | impl MockAnalysis { | 81 | impl MockAnalysis { |
@@ -35,7 +95,7 @@ impl MockAnalysis { | |||
35 | pub fn with_files(fixture: &str) -> MockAnalysis { | 95 | pub fn with_files(fixture: &str) -> MockAnalysis { |
36 | let mut res = MockAnalysis::new(); | 96 | let mut res = MockAnalysis::new(); |
37 | for entry in parse_fixture(fixture) { | 97 | for entry in parse_fixture(fixture) { |
38 | res.add_file(&entry.meta, &entry.text); | 98 | res.add_file_fixture(entry); |
39 | } | 99 | } |
40 | res | 100 | res |
41 | } | 101 | } |
@@ -48,30 +108,44 @@ impl MockAnalysis { | |||
48 | for entry in parse_fixture(fixture) { | 108 | for entry in parse_fixture(fixture) { |
49 | if entry.text.contains(CURSOR_MARKER) { | 109 | if entry.text.contains(CURSOR_MARKER) { |
50 | assert!(position.is_none(), "only one marker (<|>) per fixture is allowed"); | 110 | assert!(position.is_none(), "only one marker (<|>) per fixture is allowed"); |
51 | position = Some(res.add_file_with_position(&entry.meta, &entry.text)); | 111 | position = Some(res.add_file_fixture_with_position(entry)); |
52 | } else { | 112 | } else { |
53 | res.add_file(&entry.meta, &entry.text); | 113 | res.add_file_fixture(entry); |
54 | } | 114 | } |
55 | } | 115 | } |
56 | let position = position.expect("expected a marker (<|>)"); | 116 | let position = position.expect("expected a marker (<|>)"); |
57 | (res, position) | 117 | (res, position) |
58 | } | 118 | } |
59 | 119 | ||
120 | pub fn add_file_fixture(&mut self, fixture: FixtureEntry) -> FileId { | ||
121 | let file_id = self.next_id(); | ||
122 | self.files.push(MockFileData::from(fixture)); | ||
123 | file_id | ||
124 | } | ||
125 | |||
126 | pub fn add_file_fixture_with_position(&mut self, mut fixture: FixtureEntry) -> FilePosition { | ||
127 | let (offset, text) = extract_offset(&fixture.text); | ||
128 | fixture.text = text; | ||
129 | let file_id = self.next_id(); | ||
130 | self.files.push(MockFileData::from(fixture)); | ||
131 | FilePosition { file_id, offset } | ||
132 | } | ||
133 | |||
60 | pub fn add_file(&mut self, path: &str, text: &str) -> FileId { | 134 | pub fn add_file(&mut self, path: &str, text: &str) -> FileId { |
61 | let file_id = FileId((self.files.len() + 1) as u32); | 135 | let file_id = self.next_id(); |
62 | self.files.push((path.to_string(), text.to_string())); | 136 | self.files.push(MockFileData::new(path.to_string(), text.to_string())); |
63 | file_id | 137 | file_id |
64 | } | 138 | } |
65 | pub fn add_file_with_position(&mut self, path: &str, text: &str) -> FilePosition { | 139 | pub fn add_file_with_position(&mut self, path: &str, text: &str) -> FilePosition { |
66 | let (offset, text) = extract_offset(text); | 140 | let (offset, text) = extract_offset(text); |
67 | let file_id = FileId((self.files.len() + 1) as u32); | 141 | let file_id = self.next_id(); |
68 | self.files.push((path.to_string(), text)); | 142 | self.files.push(MockFileData::new(path.to_string(), text)); |
69 | FilePosition { file_id, offset } | 143 | FilePosition { file_id, offset } |
70 | } | 144 | } |
71 | pub fn add_file_with_range(&mut self, path: &str, text: &str) -> FileRange { | 145 | pub fn add_file_with_range(&mut self, path: &str, text: &str) -> FileRange { |
72 | let (range, text) = extract_range(text); | 146 | let (range, text) = extract_range(text); |
73 | let file_id = FileId((self.files.len() + 1) as u32); | 147 | let file_id = self.next_id(); |
74 | self.files.push((path.to_string(), text)); | 148 | self.files.push(MockFileData::new(path.to_string(), text)); |
75 | FileRange { file_id, range } | 149 | FileRange { file_id, range } |
76 | } | 150 | } |
77 | pub fn id_of(&self, path: &str) -> FileId { | 151 | pub fn id_of(&self, path: &str) -> FileId { |
@@ -79,7 +153,7 @@ impl MockAnalysis { | |||
79 | .files | 153 | .files |
80 | .iter() | 154 | .iter() |
81 | .enumerate() | 155 | .enumerate() |
82 | .find(|(_, (p, _text))| path == p) | 156 | .find(|(_, data)| path == data.path()) |
83 | .expect("no file in this mock"); | 157 | .expect("no file in this mock"); |
84 | FileId(idx as u32 + 1) | 158 | FileId(idx as u32 + 1) |
85 | } | 159 | } |
@@ -90,18 +164,21 @@ impl MockAnalysis { | |||
90 | change.add_root(source_root, true); | 164 | change.add_root(source_root, true); |
91 | let mut crate_graph = CrateGraph::default(); | 165 | let mut crate_graph = CrateGraph::default(); |
92 | let mut root_crate = None; | 166 | let mut root_crate = None; |
93 | for (i, (path, contents)) in self.files.into_iter().enumerate() { | 167 | for (i, data) in self.files.into_iter().enumerate() { |
168 | let path = data.path(); | ||
94 | assert!(path.starts_with('/')); | 169 | assert!(path.starts_with('/')); |
95 | let path = RelativePathBuf::from_path(&path[1..]).unwrap(); | 170 | let path = RelativePathBuf::from_path(&path[1..]).unwrap(); |
171 | let cfg_options = data.cfg_options(); | ||
96 | let file_id = FileId(i as u32 + 1); | 172 | let file_id = FileId(i as u32 + 1); |
97 | let cfg_options = CfgOptions::default(); | 173 | let edition = data.edition(); |
174 | let env = data.env(); | ||
98 | if path == "/lib.rs" || path == "/main.rs" { | 175 | if path == "/lib.rs" || path == "/main.rs" { |
99 | root_crate = Some(crate_graph.add_crate_root( | 176 | root_crate = Some(crate_graph.add_crate_root( |
100 | file_id, | 177 | file_id, |
101 | Edition2018, | 178 | edition, |
102 | None, | 179 | None, |
103 | cfg_options, | 180 | cfg_options, |
104 | Env::default(), | 181 | env, |
105 | Default::default(), | 182 | Default::default(), |
106 | Default::default(), | 183 | Default::default(), |
107 | )); | 184 | )); |
@@ -109,10 +186,10 @@ impl MockAnalysis { | |||
109 | let crate_name = path.parent().unwrap().file_name().unwrap(); | 186 | let crate_name = path.parent().unwrap().file_name().unwrap(); |
110 | let other_crate = crate_graph.add_crate_root( | 187 | let other_crate = crate_graph.add_crate_root( |
111 | file_id, | 188 | file_id, |
112 | Edition2018, | 189 | edition, |
113 | Some(CrateName::new(crate_name).unwrap()), | 190 | Some(CrateName::new(crate_name).unwrap()), |
114 | cfg_options, | 191 | cfg_options, |
115 | Env::default(), | 192 | env, |
116 | Default::default(), | 193 | Default::default(), |
117 | Default::default(), | 194 | Default::default(), |
118 | ); | 195 | ); |
@@ -122,7 +199,7 @@ impl MockAnalysis { | |||
122 | .unwrap(); | 199 | .unwrap(); |
123 | } | 200 | } |
124 | } | 201 | } |
125 | change.add_file(source_root, file_id, path, Arc::new(contents)); | 202 | change.add_file(source_root, file_id, path, Arc::new(data.content().to_owned())); |
126 | } | 203 | } |
127 | change.set_crate_graph(crate_graph); | 204 | change.set_crate_graph(crate_graph); |
128 | host.apply_change(change); | 205 | host.apply_change(change); |
@@ -131,6 +208,10 @@ impl MockAnalysis { | |||
131 | pub fn analysis(self) -> Analysis { | 208 | pub fn analysis(self) -> Analysis { |
132 | self.analysis_host().analysis() | 209 | self.analysis_host().analysis() |
133 | } | 210 | } |
211 | |||
212 | fn next_id(&self) -> FileId { | ||
213 | FileId((self.files.len() + 1) as u32) | ||
214 | } | ||
134 | } | 215 | } |
135 | 216 | ||
136 | /// Creates analysis from a multi-file fixture, returns positions marked with <|>. | 217 | /// Creates analysis from a multi-file fixture, returns positions marked with <|>. |