diff options
author | Aleksey Kladov <[email protected]> | 2018-10-31 17:59:17 +0000 |
---|---|---|
committer | Aleksey Kladov <[email protected]> | 2018-10-31 18:01:51 +0000 |
commit | f3fb59d7077801a3a68d2d03eef17d59c2925ae8 (patch) | |
tree | 7665461636576d121063d7cc391351b284a399b9 /crates/ra_analysis/src/mock_analysis.rs | |
parent | c02be1502c76cc504ccf7f73dce929585c94377c (diff) |
Move completion to ra_analysis
While we should handle completion for isolated file, it's better
achieved by using empty Analysis, rather than working only with &File:
we need memoization for type inference even inside a single file.
Diffstat (limited to 'crates/ra_analysis/src/mock_analysis.rs')
-rw-r--r-- | crates/ra_analysis/src/mock_analysis.rs | 71 |
1 files changed, 71 insertions, 0 deletions
diff --git a/crates/ra_analysis/src/mock_analysis.rs b/crates/ra_analysis/src/mock_analysis.rs new file mode 100644 index 000000000..1c1dbee7c --- /dev/null +++ b/crates/ra_analysis/src/mock_analysis.rs | |||
@@ -0,0 +1,71 @@ | |||
1 | |||
2 | use std::sync::Arc; | ||
3 | |||
4 | use relative_path::{RelativePath, RelativePathBuf}; | ||
5 | |||
6 | use crate::{ | ||
7 | AnalysisChange, Analysis, AnalysisHost, FileId, FileResolver, | ||
8 | }; | ||
9 | |||
10 | /// Mock analysis is used in test to bootstrap an AnalysisHost/Analysis | ||
11 | /// from a set of in-memory files. | ||
12 | #[derive(Debug, Default)] | ||
13 | pub struct MockAnalysis { | ||
14 | files: Vec<(String, String)>, | ||
15 | } | ||
16 | |||
17 | impl MockAnalysis { | ||
18 | pub fn new() -> MockAnalysis { | ||
19 | MockAnalysis::default() | ||
20 | } | ||
21 | pub fn with_files(files: &[(&str, &str)]) -> MockAnalysis { | ||
22 | let files = files.iter() | ||
23 | .map(|it| (it.0.to_string(), it.1.to_string())) | ||
24 | .collect(); | ||
25 | MockAnalysis { files } | ||
26 | } | ||
27 | pub fn analysis_host(self) -> AnalysisHost { | ||
28 | let mut host = AnalysisHost::new(); | ||
29 | let mut file_map = Vec::new(); | ||
30 | let mut change = AnalysisChange::new(); | ||
31 | for (id, (path, contents)) in self.files.into_iter().enumerate() { | ||
32 | let file_id = FileId((id + 1) as u32); | ||
33 | assert!(path.starts_with('/')); | ||
34 | let path = RelativePathBuf::from_path(&path[1..]).unwrap(); | ||
35 | change.add_file(file_id, contents); | ||
36 | file_map.push((file_id, path)); | ||
37 | } | ||
38 | change.set_file_resolver(Arc::new(FileMap(file_map))); | ||
39 | host.apply_change(change); | ||
40 | host | ||
41 | } | ||
42 | pub fn analysis(self) -> Analysis { | ||
43 | self.analysis_host().analysis() | ||
44 | } | ||
45 | } | ||
46 | |||
47 | #[derive(Debug)] | ||
48 | struct FileMap(Vec<(FileId, RelativePathBuf)>); | ||
49 | |||
50 | impl FileMap { | ||
51 | fn iter<'a>(&'a self) -> impl Iterator<Item = (FileId, &'a RelativePath)> + 'a { | ||
52 | self.0 | ||
53 | .iter() | ||
54 | .map(|(id, path)| (*id, path.as_relative_path())) | ||
55 | } | ||
56 | |||
57 | fn path(&self, id: FileId) -> &RelativePath { | ||
58 | self.iter().find(|&(it, _)| it == id).unwrap().1 | ||
59 | } | ||
60 | } | ||
61 | |||
62 | impl FileResolver for FileMap { | ||
63 | fn file_stem(&self, id: FileId) -> String { | ||
64 | self.path(id).file_stem().unwrap().to_string() | ||
65 | } | ||
66 | fn resolve(&self, id: FileId, rel: &RelativePath) -> Option<FileId> { | ||
67 | let path = self.path(id).join(rel).normalize(); | ||
68 | let id = self.iter().find(|&(_, p)| path == p)?.0; | ||
69 | Some(id) | ||
70 | } | ||
71 | } | ||