diff options
Diffstat (limited to 'crates/ra_ide')
-rw-r--r-- | crates/ra_ide/src/diagnostics.rs | 6 | ||||
-rw-r--r-- | crates/ra_ide/src/mock_analysis.rs | 138 | ||||
-rw-r--r-- | crates/ra_ide/src/parent_module.rs | 12 | ||||
-rw-r--r-- | crates/ra_ide/src/syntax_tree.rs | 12 |
4 files changed, 55 insertions, 113 deletions
diff --git a/crates/ra_ide/src/diagnostics.rs b/crates/ra_ide/src/diagnostics.rs index 8a18bc18c..05fb799d6 100644 --- a/crates/ra_ide/src/diagnostics.rs +++ b/crates/ra_ide/src/diagnostics.rs | |||
@@ -573,10 +573,9 @@ mod tests { | |||
573 | 573 | ||
574 | impl Expr { | 574 | impl Expr { |
575 | fn new_bin(lhs: Box<Expr>, rhs: Box<Expr>) -> Expr { | 575 | fn new_bin(lhs: Box<Expr>, rhs: Box<Expr>) -> Expr { |
576 | Expr::Bin { <|> } | 576 | Expr::Bin { } |
577 | } | 577 | } |
578 | } | 578 | } |
579 | |||
580 | "; | 579 | "; |
581 | let after = r" | 580 | let after = r" |
582 | enum Expr { | 581 | enum Expr { |
@@ -585,10 +584,9 @@ mod tests { | |||
585 | 584 | ||
586 | impl Expr { | 585 | impl Expr { |
587 | fn new_bin(lhs: Box<Expr>, rhs: Box<Expr>) -> Expr { | 586 | fn new_bin(lhs: Box<Expr>, rhs: Box<Expr>) -> Expr { |
588 | Expr::Bin { lhs: (), rhs: () <|> } | 587 | Expr::Bin { lhs: (), rhs: () } |
589 | } | 588 | } |
590 | } | 589 | } |
591 | |||
592 | "; | 590 | "; |
593 | check_apply_diagnostic_fix(before, after); | 591 | check_apply_diagnostic_fix(before, after); |
594 | } | 592 | } |
diff --git a/crates/ra_ide/src/mock_analysis.rs b/crates/ra_ide/src/mock_analysis.rs index b7325bfc3..889b84c59 100644 --- a/crates/ra_ide/src/mock_analysis.rs +++ b/crates/ra_ide/src/mock_analysis.rs | |||
@@ -1,81 +1,19 @@ | |||
1 | //! FIXME: write short doc here | 1 | //! FIXME: write short doc here |
2 | use std::{str::FromStr, sync::Arc}; | 2 | use std::sync::Arc; |
3 | 3 | ||
4 | use ra_cfg::CfgOptions; | 4 | use ra_cfg::CfgOptions; |
5 | use ra_db::{CrateName, Env, FileSet, SourceRoot, VfsPath}; | 5 | use ra_db::{CrateName, Env, FileSet, SourceRoot, VfsPath}; |
6 | use test_utils::{extract_offset, extract_range, Fixture, CURSOR_MARKER}; | 6 | use test_utils::{extract_range_or_offset, Fixture, RangeOrOffset, CURSOR_MARKER}; |
7 | 7 | ||
8 | use crate::{ | 8 | use crate::{ |
9 | Analysis, AnalysisChange, AnalysisHost, CrateGraph, Edition, FileId, FilePosition, FileRange, | 9 | Analysis, AnalysisChange, AnalysisHost, CrateGraph, Edition, FileId, FilePosition, FileRange, |
10 | }; | 10 | }; |
11 | 11 | ||
12 | #[derive(Debug)] | ||
13 | enum MockFileData { | ||
14 | Plain { path: String, content: String }, | ||
15 | Fixture(Fixture), | ||
16 | } | ||
17 | |||
18 | impl MockFileData { | ||
19 | fn new(path: String, content: String) -> Self { | ||
20 | // `Self::Plain` causes a false warning: 'variant is never constructed: `Plain` ' | ||
21 | // see https://github.com/rust-lang/rust/issues/69018 | ||
22 | MockFileData::Plain { path, content } | ||
23 | } | ||
24 | |||
25 | fn path(&self) -> &str { | ||
26 | match self { | ||
27 | MockFileData::Plain { path, .. } => path.as_str(), | ||
28 | MockFileData::Fixture(f) => f.path.as_str(), | ||
29 | } | ||
30 | } | ||
31 | |||
32 | fn content(&self) -> &str { | ||
33 | match self { | ||
34 | MockFileData::Plain { content, .. } => content, | ||
35 | MockFileData::Fixture(f) => f.text.as_str(), | ||
36 | } | ||
37 | } | ||
38 | |||
39 | fn cfg_options(&self) -> CfgOptions { | ||
40 | match self { | ||
41 | MockFileData::Fixture(f) => { | ||
42 | let mut cfg = CfgOptions::default(); | ||
43 | f.cfg_atoms.iter().for_each(|it| cfg.insert_atom(it.into())); | ||
44 | f.cfg_key_values.iter().for_each(|(k, v)| cfg.insert_key_value(k.into(), v.into())); | ||
45 | cfg | ||
46 | } | ||
47 | _ => CfgOptions::default(), | ||
48 | } | ||
49 | } | ||
50 | |||
51 | fn edition(&self) -> Edition { | ||
52 | match self { | ||
53 | MockFileData::Fixture(f) => { | ||
54 | f.edition.as_ref().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.env.iter()), | ||
63 | _ => Env::default(), | ||
64 | } | ||
65 | } | ||
66 | } | ||
67 | |||
68 | impl From<Fixture> for MockFileData { | ||
69 | fn from(fixture: Fixture) -> Self { | ||
70 | Self::Fixture(fixture) | ||
71 | } | ||
72 | } | ||
73 | |||
74 | /// Mock analysis is used in test to bootstrap an AnalysisHost/Analysis | 12 | /// Mock analysis is used in test to bootstrap an AnalysisHost/Analysis |
75 | /// from a set of in-memory files. | 13 | /// from a set of in-memory files. |
76 | #[derive(Debug, Default)] | 14 | #[derive(Debug, Default)] |
77 | pub struct MockAnalysis { | 15 | pub struct MockAnalysis { |
78 | files: Vec<MockFileData>, | 16 | files: Vec<Fixture>, |
79 | } | 17 | } |
80 | 18 | ||
81 | impl MockAnalysis { | 19 | impl MockAnalysis { |
@@ -89,52 +27,53 @@ impl MockAnalysis { | |||
89 | /// //- /foo.rs | 27 | /// //- /foo.rs |
90 | /// struct Baz; | 28 | /// struct Baz; |
91 | /// ``` | 29 | /// ``` |
92 | pub fn with_files(fixture: &str) -> MockAnalysis { | 30 | pub fn with_files(ra_fixture: &str) -> MockAnalysis { |
93 | let mut res = MockAnalysis::default(); | 31 | let (res, pos) = MockAnalysis::with_fixture(ra_fixture); |
94 | for entry in Fixture::parse(fixture) { | 32 | assert!(pos.is_none()); |
95 | res.add_file_fixture(entry); | ||
96 | } | ||
97 | res | 33 | res |
98 | } | 34 | } |
99 | 35 | ||
100 | /// Same as `with_files`, but requires that a single file contains a `<|>` marker, | 36 | /// Same as `with_files`, but requires that a single file contains a `<|>` marker, |
101 | /// whose position is also returned. | 37 | /// whose position is also returned. |
102 | pub fn with_files_and_position(fixture: &str) -> (MockAnalysis, FilePosition) { | 38 | pub 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)>) { | ||
103 | let mut position = None; | 49 | let mut position = None; |
104 | let mut res = MockAnalysis::default(); | 50 | let mut res = MockAnalysis::default(); |
105 | for mut entry in Fixture::parse(fixture) { | 51 | for mut entry in Fixture::parse(fixture) { |
106 | if entry.text.contains(CURSOR_MARKER) { | 52 | if entry.text.contains(CURSOR_MARKER) { |
107 | assert!(position.is_none(), "only one marker (<|>) per fixture is allowed"); | 53 | assert!(position.is_none(), "only one marker (<|>) per fixture is allowed"); |
108 | let (offset, text) = extract_offset(&entry.text); | 54 | let (range_or_offset, text) = extract_range_or_offset(&entry.text); |
109 | entry.text = text; | 55 | entry.text = text; |
110 | let file_id = res.add_file_fixture(entry); | 56 | let file_id = res.add_file_fixture(entry); |
111 | position = Some(FilePosition { file_id, offset }); | 57 | position = Some((file_id, range_or_offset)); |
112 | } else { | 58 | } else { |
113 | res.add_file_fixture(entry); | 59 | res.add_file_fixture(entry); |
114 | } | 60 | } |
115 | } | 61 | } |
116 | let position = position.expect("expected a marker (<|>)"); | ||
117 | (res, position) | 62 | (res, position) |
118 | } | 63 | } |
119 | 64 | ||
120 | fn add_file_fixture(&mut self, fixture: Fixture) -> FileId { | 65 | fn add_file_fixture(&mut self, fixture: Fixture) -> FileId { |
121 | let file_id = self.next_id(); | 66 | let file_id = FileId((self.files.len() + 1) as u32); |
122 | self.files.push(MockFileData::from(fixture)); | 67 | self.files.push(fixture); |
123 | file_id | 68 | file_id |
124 | } | 69 | } |
125 | 70 | ||
126 | fn add_file_with_range(&mut self, path: &str, text: &str) -> FileRange { | ||
127 | let (range, text) = extract_range(text); | ||
128 | let file_id = self.next_id(); | ||
129 | self.files.push(MockFileData::new(path.to_string(), text)); | ||
130 | FileRange { file_id, range } | ||
131 | } | ||
132 | pub fn id_of(&self, path: &str) -> FileId { | 71 | pub fn id_of(&self, path: &str) -> FileId { |
133 | let (idx, _) = self | 72 | let (idx, _) = self |
134 | .files | 73 | .files |
135 | .iter() | 74 | .iter() |
136 | .enumerate() | 75 | .enumerate() |
137 | .find(|(_, data)| path == data.path()) | 76 | .find(|(_, data)| path == data.path) |
138 | .expect("no file in this mock"); | 77 | .expect("no file in this mock"); |
139 | FileId(idx as u32 + 1) | 78 | FileId(idx as u32 + 1) |
140 | } | 79 | } |
@@ -145,18 +84,23 @@ impl MockAnalysis { | |||
145 | let mut crate_graph = CrateGraph::default(); | 84 | let mut crate_graph = CrateGraph::default(); |
146 | let mut root_crate = None; | 85 | let mut root_crate = None; |
147 | for (i, data) in self.files.into_iter().enumerate() { | 86 | for (i, data) in self.files.into_iter().enumerate() { |
148 | let path = data.path(); | 87 | let path = data.path; |
149 | assert!(path.starts_with('/')); | 88 | assert!(path.starts_with('/')); |
150 | let cfg_options = data.cfg_options(); | 89 | |
90 | let mut cfg = CfgOptions::default(); | ||
91 | data.cfg_atoms.iter().for_each(|it| cfg.insert_atom(it.into())); | ||
92 | data.cfg_key_values.iter().for_each(|(k, v)| cfg.insert_key_value(k.into(), v.into())); | ||
93 | let edition: Edition = | ||
94 | data.edition.and_then(|it| it.parse().ok()).unwrap_or(Edition::Edition2018); | ||
95 | |||
151 | let file_id = FileId(i as u32 + 1); | 96 | let file_id = FileId(i as u32 + 1); |
152 | let edition = data.edition(); | 97 | let env = Env::from(data.env.iter()); |
153 | let env = data.env(); | ||
154 | if path == "/lib.rs" || path == "/main.rs" { | 98 | if path == "/lib.rs" || path == "/main.rs" { |
155 | root_crate = Some(crate_graph.add_crate_root( | 99 | root_crate = Some(crate_graph.add_crate_root( |
156 | file_id, | 100 | file_id, |
157 | edition, | 101 | edition, |
158 | None, | 102 | None, |
159 | cfg_options, | 103 | cfg, |
160 | env, | 104 | env, |
161 | Default::default(), | 105 | Default::default(), |
162 | )); | 106 | )); |
@@ -167,7 +111,7 @@ impl MockAnalysis { | |||
167 | file_id, | 111 | file_id, |
168 | edition, | 112 | edition, |
169 | Some(CrateName::new(crate_name).unwrap()), | 113 | Some(CrateName::new(crate_name).unwrap()), |
170 | cfg_options, | 114 | cfg, |
171 | env, | 115 | env, |
172 | Default::default(), | 116 | Default::default(), |
173 | ); | 117 | ); |
@@ -179,7 +123,7 @@ impl MockAnalysis { | |||
179 | } | 123 | } |
180 | let path = VfsPath::new_virtual_path(path.to_string()); | 124 | let path = VfsPath::new_virtual_path(path.to_string()); |
181 | file_set.insert(file_id, path); | 125 | file_set.insert(file_id, path); |
182 | change.change_file(file_id, Some(Arc::new(data.content().to_owned()))); | 126 | change.change_file(file_id, Some(Arc::new(data.text).to_owned())); |
183 | } | 127 | } |
184 | change.set_crate_graph(crate_graph); | 128 | change.set_crate_graph(crate_graph); |
185 | change.set_roots(vec![SourceRoot::new_local(file_set)]); | 129 | change.set_roots(vec![SourceRoot::new_local(file_set)]); |
@@ -189,10 +133,6 @@ impl MockAnalysis { | |||
189 | pub fn analysis(self) -> Analysis { | 133 | pub fn analysis(self) -> Analysis { |
190 | self.analysis_host().analysis() | 134 | self.analysis_host().analysis() |
191 | } | 135 | } |
192 | |||
193 | fn next_id(&self) -> FileId { | ||
194 | FileId((self.files.len() + 1) as u32) | ||
195 | } | ||
196 | } | 136 | } |
197 | 137 | ||
198 | /// Creates analysis from a multi-file fixture, returns positions marked with <|>. | 138 | /// Creates analysis from a multi-file fixture, returns positions marked with <|>. |
@@ -209,8 +149,12 @@ pub fn single_file(ra_fixture: &str) -> (Analysis, FileId) { | |||
209 | } | 149 | } |
210 | 150 | ||
211 | /// Creates analysis for a single file, returns range marked with a pair of <|>. | 151 | /// Creates analysis for a single file, returns range marked with a pair of <|>. |
212 | pub fn single_file_with_range(ra_fixture: &str) -> (Analysis, FileRange) { | 152 | pub fn analysis_and_range(ra_fixture: &str) -> (Analysis, FileRange) { |
213 | let mut mock = MockAnalysis::default(); | 153 | let (res, position) = MockAnalysis::with_fixture(ra_fixture); |
214 | let pos = mock.add_file_with_range("/main.rs", ra_fixture); | 154 | let (file_id, range_or_offset) = position.expect("expected a marker (<|>)"); |
215 | (mock.analysis(), pos) | 155 | let range = match range_or_offset { |
156 | RangeOrOffset::Range(it) => it, | ||
157 | RangeOrOffset::Offset(_) => panic!(), | ||
158 | }; | ||
159 | (res.analysis(), FileRange { file_id, range }) | ||
216 | } | 160 | } |
diff --git a/crates/ra_ide/src/parent_module.rs b/crates/ra_ide/src/parent_module.rs index bc7f65470..e3e0c7639 100644 --- a/crates/ra_ide/src/parent_module.rs +++ b/crates/ra_ide/src/parent_module.rs | |||
@@ -125,12 +125,12 @@ mod tests { | |||
125 | #[test] | 125 | #[test] |
126 | fn test_resolve_crate_root() { | 126 | fn test_resolve_crate_root() { |
127 | let mock = MockAnalysis::with_files( | 127 | let mock = MockAnalysis::with_files( |
128 | " | 128 | r#" |
129 | //- /bar.rs | 129 | //- /bar.rs |
130 | mod foo; | 130 | mod foo; |
131 | //- /foo.rs | 131 | //- /foo.rs |
132 | // empty <|> | 132 | // empty |
133 | ", | 133 | "#, |
134 | ); | 134 | ); |
135 | let root_file = mock.id_of("/bar.rs"); | 135 | let root_file = mock.id_of("/bar.rs"); |
136 | let mod_file = mock.id_of("/foo.rs"); | 136 | let mod_file = mock.id_of("/foo.rs"); |
diff --git a/crates/ra_ide/src/syntax_tree.rs b/crates/ra_ide/src/syntax_tree.rs index a341684fd..f716a3861 100644 --- a/crates/ra_ide/src/syntax_tree.rs +++ b/crates/ra_ide/src/syntax_tree.rs | |||
@@ -104,7 +104,7 @@ fn syntax_tree_for_token(node: &SyntaxToken, text_range: TextRange) -> Option<St | |||
104 | mod tests { | 104 | mod tests { |
105 | use test_utils::assert_eq_text; | 105 | use test_utils::assert_eq_text; |
106 | 106 | ||
107 | use crate::mock_analysis::{single_file, single_file_with_range}; | 107 | use crate::mock_analysis::{analysis_and_range, single_file}; |
108 | 108 | ||
109 | #[test] | 109 | #[test] |
110 | fn test_syntax_tree_without_range() { | 110 | fn test_syntax_tree_without_range() { |
@@ -184,7 +184,7 @@ [email protected] | |||
184 | 184 | ||
185 | #[test] | 185 | #[test] |
186 | fn test_syntax_tree_with_range() { | 186 | fn test_syntax_tree_with_range() { |
187 | let (analysis, range) = single_file_with_range(r#"<|>fn foo() {}<|>"#.trim()); | 187 | let (analysis, range) = analysis_and_range(r#"<|>fn foo() {}<|>"#.trim()); |
188 | let syn = analysis.syntax_tree(range.file_id, Some(range.range)).unwrap(); | 188 | let syn = analysis.syntax_tree(range.file_id, Some(range.range)).unwrap(); |
189 | 189 | ||
190 | assert_eq_text!( | 190 | assert_eq_text!( |
@@ -206,7 +206,7 @@ [email protected] | |||
206 | .trim() | 206 | .trim() |
207 | ); | 207 | ); |
208 | 208 | ||
209 | let (analysis, range) = single_file_with_range( | 209 | let (analysis, range) = analysis_and_range( |
210 | r#"fn test() { | 210 | r#"fn test() { |
211 | <|>assert!(" | 211 | <|>assert!(" |
212 | fn foo() { | 212 | fn foo() { |
@@ -242,7 +242,7 @@ [email protected] | |||
242 | 242 | ||
243 | #[test] | 243 | #[test] |
244 | fn test_syntax_tree_inside_string() { | 244 | fn test_syntax_tree_inside_string() { |
245 | let (analysis, range) = single_file_with_range( | 245 | let (analysis, range) = analysis_and_range( |
246 | r#"fn test() { | 246 | r#"fn test() { |
247 | assert!(" | 247 | assert!(" |
248 | <|>fn foo() { | 248 | <|>fn foo() { |
@@ -276,7 +276,7 @@ [email protected] | |||
276 | ); | 276 | ); |
277 | 277 | ||
278 | // With a raw string | 278 | // With a raw string |
279 | let (analysis, range) = single_file_with_range( | 279 | let (analysis, range) = analysis_and_range( |
280 | r###"fn test() { | 280 | r###"fn test() { |
281 | assert!(r#" | 281 | assert!(r#" |
282 | <|>fn foo() { | 282 | <|>fn foo() { |
@@ -310,7 +310,7 @@ [email protected] | |||
310 | ); | 310 | ); |
311 | 311 | ||
312 | // With a raw string | 312 | // With a raw string |
313 | let (analysis, range) = single_file_with_range( | 313 | let (analysis, range) = analysis_and_range( |
314 | r###"fn test() { | 314 | r###"fn test() { |
315 | assert!(r<|>#" | 315 | assert!(r<|>#" |
316 | fn foo() { | 316 | fn foo() { |