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