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