diff options
author | Aleksey Kladov <[email protected]> | 2018-08-31 17:14:08 +0100 |
---|---|---|
committer | Aleksey Kladov <[email protected]> | 2018-08-31 17:14:08 +0100 |
commit | f2772e29aeda5e35c282f3b023ce9d470f3fb441 (patch) | |
tree | f517fd3d40f569de0d4dbb2529f38c9d470b2db9 | |
parent | 7a5bc94774a50837f8c9bf8b96c8272882aca640 (diff) |
add crate graph
-rw-r--r-- | crates/libanalysis/src/imp.rs | 53 | ||||
-rw-r--r-- | crates/libanalysis/src/lib.rs | 19 | ||||
-rw-r--r-- | crates/libanalysis/src/module_map.rs | 36 | ||||
-rw-r--r-- | crates/libanalysis/tests/tests.rs | 38 |
4 files changed, 131 insertions, 15 deletions
diff --git a/crates/libanalysis/src/imp.rs b/crates/libanalysis/src/imp.rs index 6a6e1e933..f1d72da15 100644 --- a/crates/libanalysis/src/imp.rs +++ b/crates/libanalysis/src/imp.rs | |||
@@ -5,7 +5,7 @@ use std::{ | |||
5 | }, | 5 | }, |
6 | fmt, | 6 | fmt, |
7 | time::Instant, | 7 | time::Instant, |
8 | collections::HashMap, | 8 | collections::{HashMap, HashSet, VecDeque}, |
9 | panic, | 9 | panic, |
10 | }; | 10 | }; |
11 | 11 | ||
@@ -23,7 +23,7 @@ use { | |||
23 | module_map::Problem, | 23 | module_map::Problem, |
24 | symbol_index::FileSymbols, | 24 | symbol_index::FileSymbols, |
25 | module_map::{ModuleMap, ChangeKind}, | 25 | module_map::{ModuleMap, ChangeKind}, |
26 | JobToken, | 26 | JobToken, CrateGraph, CrateId, |
27 | }; | 27 | }; |
28 | 28 | ||
29 | #[derive(Debug)] | 29 | #[derive(Debug)] |
@@ -37,7 +37,6 @@ impl AnalysisHostImpl { | |||
37 | data: Arc::new(WorldData::default()), | 37 | data: Arc::new(WorldData::default()), |
38 | } | 38 | } |
39 | } | 39 | } |
40 | |||
41 | pub fn analysis( | 40 | pub fn analysis( |
42 | &self, | 41 | &self, |
43 | file_resolver: Arc<dyn FileResolver>, | 42 | file_resolver: Arc<dyn FileResolver>, |
@@ -48,7 +47,6 @@ impl AnalysisHostImpl { | |||
48 | data: self.data.clone(), | 47 | data: self.data.clone(), |
49 | } | 48 | } |
50 | } | 49 | } |
51 | |||
52 | pub fn change_files(&mut self, changes: &mut dyn Iterator<Item=(FileId, Option<String>)>) { | 50 | pub fn change_files(&mut self, changes: &mut dyn Iterator<Item=(FileId, Option<String>)>) { |
53 | let data = self.data_mut(); | 51 | let data = self.data_mut(); |
54 | for (file_id, text) in changes { | 52 | for (file_id, text) in changes { |
@@ -71,7 +69,15 @@ impl AnalysisHostImpl { | |||
71 | } | 69 | } |
72 | } | 70 | } |
73 | } | 71 | } |
74 | 72 | pub fn set_crate_graph(&mut self, graph: CrateGraph) { | |
73 | let mut visited = HashSet::new(); | ||
74 | for &file_id in graph.crate_roots.values() { | ||
75 | if !visited.insert(file_id) { | ||
76 | panic!("duplicate crate root: {:?}", file_id); | ||
77 | } | ||
78 | } | ||
79 | self.data_mut().crate_graph = graph; | ||
80 | } | ||
75 | fn data_mut(&mut self) -> &mut WorldData { | 81 | fn data_mut(&mut self) -> &mut WorldData { |
76 | Arc::make_mut(&mut self.data) | 82 | Arc::make_mut(&mut self.data) |
77 | } | 83 | } |
@@ -145,6 +151,33 @@ impl AnalysisImpl { | |||
145 | .collect() | 151 | .collect() |
146 | } | 152 | } |
147 | 153 | ||
154 | pub fn crate_root(&self, id: FileId) -> Vec<CrateId> { | ||
155 | let module_map = &self.data.module_map; | ||
156 | let crate_graph = &self.data.crate_graph; | ||
157 | let mut res = Vec::new(); | ||
158 | let mut work = VecDeque::new(); | ||
159 | work.push_back(id); | ||
160 | let mut visited = HashSet::new(); | ||
161 | while let Some(id) = work.pop_front() { | ||
162 | if let Some(crate_id) = crate_graph.crate_id_for_crate_root(id) { | ||
163 | res.push(crate_id); | ||
164 | continue; | ||
165 | } | ||
166 | let mid = module_map.file2module(id); | ||
167 | let parents = module_map | ||
168 | .parent_module_ids( | ||
169 | mid, | ||
170 | &*self.file_resolver, | ||
171 | &|file_id| self.file_syntax(file_id), | ||
172 | ) | ||
173 | .into_iter() | ||
174 | .map(|id| module_map.module2file(id)) | ||
175 | .filter(|&id| visited.insert(id)); | ||
176 | work.extend(parents); | ||
177 | } | ||
178 | res | ||
179 | } | ||
180 | |||
148 | pub fn approximately_resolve_symbol( | 181 | pub fn approximately_resolve_symbol( |
149 | &self, | 182 | &self, |
150 | id: FileId, | 183 | id: FileId, |
@@ -295,6 +328,7 @@ impl AnalysisImpl { | |||
295 | 328 | ||
296 | #[derive(Clone, Default, Debug)] | 329 | #[derive(Clone, Default, Debug)] |
297 | struct WorldData { | 330 | struct WorldData { |
331 | crate_graph: CrateGraph, | ||
298 | file_map: HashMap<FileId, Arc<FileData>>, | 332 | file_map: HashMap<FileId, Arc<FileData>>, |
299 | module_map: ModuleMap, | 333 | module_map: ModuleMap, |
300 | } | 334 | } |
@@ -356,3 +390,12 @@ impl SourceChange { | |||
356 | } | 390 | } |
357 | } | 391 | } |
358 | } | 392 | } |
393 | |||
394 | impl CrateGraph { | ||
395 | fn crate_id_for_crate_root(&self, file_id: FileId) -> Option<CrateId> { | ||
396 | let (&crate_id, _) = self.crate_roots | ||
397 | .iter() | ||
398 | .find(|(_crate_id, &root_id)| root_id == file_id)?; | ||
399 | Some(crate_id) | ||
400 | } | ||
401 | } | ||
diff --git a/crates/libanalysis/src/lib.rs b/crates/libanalysis/src/lib.rs index a59fd1c09..041abbb89 100644 --- a/crates/libanalysis/src/lib.rs +++ b/crates/libanalysis/src/lib.rs | |||
@@ -15,7 +15,10 @@ mod module_map; | |||
15 | mod imp; | 15 | mod imp; |
16 | mod job; | 16 | mod job; |
17 | 17 | ||
18 | use std::sync::Arc; | 18 | use std::{ |
19 | sync::Arc, | ||
20 | collections::HashMap, | ||
21 | }; | ||
19 | 22 | ||
20 | use relative_path::{RelativePath, RelativePathBuf}; | 23 | use relative_path::{RelativePath, RelativePathBuf}; |
21 | use libsyntax2::{File, TextRange, TextUnit, AtomEdit}; | 24 | use libsyntax2::{File, TextRange, TextUnit, AtomEdit}; |
@@ -30,6 +33,14 @@ pub use job::{JobToken, JobHandle}; | |||
30 | #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] | 33 | #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] |
31 | pub struct FileId(pub u32); | 34 | pub struct FileId(pub u32); |
32 | 35 | ||
36 | #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] | ||
37 | pub struct CrateId(pub u32); | ||
38 | |||
39 | #[derive(Debug, Clone, Default)] | ||
40 | pub struct CrateGraph { | ||
41 | pub crate_roots: HashMap<CrateId, FileId>, | ||
42 | } | ||
43 | |||
33 | pub trait FileResolver: Send + Sync + 'static { | 44 | pub trait FileResolver: Send + Sync + 'static { |
34 | fn file_stem(&self, id: FileId) -> String; | 45 | fn file_stem(&self, id: FileId) -> String; |
35 | fn resolve(&self, id: FileId, path: &RelativePath) -> Option<FileId>; | 46 | fn resolve(&self, id: FileId, path: &RelativePath) -> Option<FileId>; |
@@ -53,6 +64,9 @@ impl AnalysisHost { | |||
53 | pub fn change_files(&mut self, mut changes: impl Iterator<Item=(FileId, Option<String>)>) { | 64 | pub fn change_files(&mut self, mut changes: impl Iterator<Item=(FileId, Option<String>)>) { |
54 | self.imp.change_files(&mut changes) | 65 | self.imp.change_files(&mut changes) |
55 | } | 66 | } |
67 | pub fn set_crate_graph(&mut self, graph: CrateGraph) { | ||
68 | self.imp.set_crate_graph(graph) | ||
69 | } | ||
56 | } | 70 | } |
57 | 71 | ||
58 | #[derive(Debug)] | 72 | #[derive(Debug)] |
@@ -168,6 +182,9 @@ impl Analysis { | |||
168 | pub fn parent_module(&self, file_id: FileId) -> Vec<(FileId, FileSymbol)> { | 182 | pub fn parent_module(&self, file_id: FileId) -> Vec<(FileId, FileSymbol)> { |
169 | self.imp.parent_module(file_id) | 183 | self.imp.parent_module(file_id) |
170 | } | 184 | } |
185 | pub fn crate_root(&self, file_id: FileId) -> Vec<CrateId> { | ||
186 | self.imp.crate_root(file_id) | ||
187 | } | ||
171 | pub fn runnables(&self, file_id: FileId) -> Vec<Runnable> { | 188 | pub fn runnables(&self, file_id: FileId) -> Vec<Runnable> { |
172 | let file = self.file_syntax(file_id); | 189 | let file = self.file_syntax(file_id); |
173 | libeditor::runnables(&file) | 190 | libeditor::runnables(&file) |
diff --git a/crates/libanalysis/src/module_map.rs b/crates/libanalysis/src/module_map.rs index 47c0018e1..38935807d 100644 --- a/crates/libanalysis/src/module_map.rs +++ b/crates/libanalysis/src/module_map.rs | |||
@@ -91,16 +91,38 @@ impl ModuleMap { | |||
91 | file_resolver: &FileResolver, | 91 | file_resolver: &FileResolver, |
92 | syntax_provider: &SyntaxProvider, | 92 | syntax_provider: &SyntaxProvider, |
93 | ) -> Vec<(ModuleId, SmolStr, SyntaxNode)> { | 93 | ) -> Vec<(ModuleId, SmolStr, SyntaxNode)> { |
94 | let links = self.links(file_resolver, syntax_provider); | 94 | let mut res = Vec::new(); |
95 | let res = links | 95 | self.for_each_parent_link(m, file_resolver, syntax_provider, |link| { |
96 | res.push( | ||
97 | (link.owner, link.name().clone(), link.syntax.clone()) | ||
98 | ) | ||
99 | }); | ||
100 | res | ||
101 | } | ||
102 | |||
103 | pub fn parent_module_ids( | ||
104 | &self, | ||
105 | m: ModuleId, | ||
106 | file_resolver: &FileResolver, | ||
107 | syntax_provider: &SyntaxProvider, | ||
108 | ) -> Vec<ModuleId> { | ||
109 | let mut res = Vec::new(); | ||
110 | self.for_each_parent_link(m, file_resolver, syntax_provider, |link| res.push(link.owner)); | ||
111 | res | ||
112 | } | ||
113 | |||
114 | fn for_each_parent_link( | ||
115 | &self, | ||
116 | m: ModuleId, | ||
117 | file_resolver: &FileResolver, | ||
118 | syntax_provider: &SyntaxProvider, | ||
119 | f: impl FnMut(&Link) | ||
120 | ) { | ||
121 | self.links(file_resolver, syntax_provider) | ||
96 | .links | 122 | .links |
97 | .iter() | 123 | .iter() |
98 | .filter(move |link| link.points_to.iter().any(|&it| it == m)) | 124 | .filter(move |link| link.points_to.iter().any(|&it| it == m)) |
99 | .map(|link| { | 125 | .for_each(f) |
100 | (link.owner, link.name().clone(), link.syntax.clone()) | ||
101 | }) | ||
102 | .collect(); | ||
103 | res | ||
104 | } | 126 | } |
105 | 127 | ||
106 | pub fn problems( | 128 | pub fn problems( |
diff --git a/crates/libanalysis/tests/tests.rs b/crates/libanalysis/tests/tests.rs index 887e13fa3..c098c8e8c 100644 --- a/crates/libanalysis/tests/tests.rs +++ b/crates/libanalysis/tests/tests.rs | |||
@@ -2,10 +2,13 @@ extern crate libanalysis; | |||
2 | extern crate relative_path; | 2 | extern crate relative_path; |
3 | extern crate test_utils; | 3 | extern crate test_utils; |
4 | 4 | ||
5 | use std::path::{Path}; | 5 | use std::{ |
6 | collections::HashMap, | ||
7 | path::{Path}, | ||
8 | }; | ||
6 | 9 | ||
7 | use relative_path::RelativePath; | 10 | use relative_path::RelativePath; |
8 | use libanalysis::{AnalysisHost, FileId, FileResolver, JobHandle}; | 11 | use libanalysis::{AnalysisHost, FileId, FileResolver, JobHandle, CrateGraph, CrateId}; |
9 | use test_utils::assert_eq_dbg; | 12 | use test_utils::assert_eq_dbg; |
10 | 13 | ||
11 | struct FileMap(&'static [(u32, &'static str)]); | 14 | struct FileMap(&'static [(u32, &'static str)]); |
@@ -112,3 +115,34 @@ fn test_resolve_parent_module() { | |||
112 | &symbols, | 115 | &symbols, |
113 | ); | 116 | ); |
114 | } | 117 | } |
118 | |||
119 | #[test] | ||
120 | fn test_resolve_crate_root() { | ||
121 | let mut world = AnalysisHost::new(); | ||
122 | world.change_file(FileId(1), Some("mod foo;".to_string())); | ||
123 | world.change_file(FileId(2), Some("".to_string())); | ||
124 | |||
125 | let snap = world.analysis(FileMap(&[ | ||
126 | (1, "/lib.rs"), | ||
127 | (2, "/foo.rs"), | ||
128 | ])); | ||
129 | assert!(snap.crate_root(FileId(2)).is_empty()); | ||
130 | |||
131 | let crate_graph = CrateGraph { | ||
132 | crate_roots: { | ||
133 | let mut m = HashMap::new(); | ||
134 | m.insert(CrateId(1), FileId(1)); | ||
135 | m | ||
136 | }, | ||
137 | }; | ||
138 | world.set_crate_graph(crate_graph); | ||
139 | |||
140 | let snap = world.analysis(FileMap(&[ | ||
141 | (1, "/lib.rs"), | ||
142 | (2, "/foo.rs"), | ||
143 | ])); | ||
144 | assert_eq!( | ||
145 | snap.crate_root(FileId(2)), | ||
146 | vec![CrateId(1)], | ||
147 | ); | ||
148 | } | ||