diff options
-rw-r--r-- | crates/libanalysis/src/imp.rs | 65 | ||||
-rw-r--r-- | crates/libanalysis/src/lib.rs | 21 | ||||
-rw-r--r-- | crates/libanalysis/src/module_map.rs | 41 | ||||
-rw-r--r-- | crates/libanalysis/src/roots.rs | 7 | ||||
-rw-r--r-- | crates/libanalysis/tests/tests.rs | 93 | ||||
-rw-r--r-- | crates/server/src/main_loop/mod.rs | 4 | ||||
-rw-r--r-- | crates/server/src/server_world.rs | 31 |
7 files changed, 146 insertions, 116 deletions
diff --git a/crates/libanalysis/src/imp.rs b/crates/libanalysis/src/imp.rs index 47b0d79ff..3e65ee14a 100644 --- a/crates/libanalysis/src/imp.rs +++ b/crates/libanalysis/src/imp.rs | |||
@@ -7,6 +7,7 @@ use std::{ | |||
7 | collections::{HashSet, VecDeque}, | 7 | collections::{HashSet, VecDeque}, |
8 | }; | 8 | }; |
9 | 9 | ||
10 | use relative_path::RelativePath; | ||
10 | use libeditor::{self, FileSymbol, LineIndex, find_node_at_offset, LocalEdit}; | 11 | use libeditor::{self, FileSymbol, LineIndex, find_node_at_offset, LocalEdit}; |
11 | use libsyntax2::{ | 12 | use libsyntax2::{ |
12 | TextUnit, TextRange, SmolStr, File, AstNode, | 13 | TextUnit, TextRange, SmolStr, File, AstNode, |
@@ -21,6 +22,40 @@ use { | |||
21 | roots::{SourceRoot, ReadonlySourceRoot, WritableSourceRoot}, | 22 | roots::{SourceRoot, ReadonlySourceRoot, WritableSourceRoot}, |
22 | }; | 23 | }; |
23 | 24 | ||
25 | |||
26 | #[derive(Clone, Debug)] | ||
27 | pub(crate) struct FileResolverImp { | ||
28 | inner: Arc<FileResolver> | ||
29 | } | ||
30 | |||
31 | impl FileResolverImp { | ||
32 | pub(crate) fn new(inner: Arc<FileResolver>) -> FileResolverImp { | ||
33 | FileResolverImp { inner } | ||
34 | } | ||
35 | pub(crate) fn file_stem(&self, file_id: FileId) -> String { | ||
36 | self.inner.file_stem(file_id) | ||
37 | } | ||
38 | pub(crate) fn resolve(&self, file_id: FileId, path: &RelativePath) -> Option<FileId> { | ||
39 | self.inner.resolve(file_id, path) | ||
40 | } | ||
41 | } | ||
42 | |||
43 | impl Default for FileResolverImp { | ||
44 | fn default() -> FileResolverImp { | ||
45 | #[derive(Debug)] | ||
46 | struct DummyResolver; | ||
47 | impl FileResolver for DummyResolver { | ||
48 | fn file_stem(&self, _file_: FileId) -> String { | ||
49 | panic!("file resolver not set") | ||
50 | } | ||
51 | fn resolve(&self, _file_id: FileId, _path: &::relative_path::RelativePath) -> Option<FileId> { | ||
52 | panic!("file resolver not set") | ||
53 | } | ||
54 | } | ||
55 | FileResolverImp { inner: Arc::new(DummyResolver) } | ||
56 | } | ||
57 | } | ||
58 | |||
24 | #[derive(Debug)] | 59 | #[derive(Debug)] |
25 | pub(crate) struct AnalysisHostImpl { | 60 | pub(crate) struct AnalysisHostImpl { |
26 | data: Arc<WorldData> | 61 | data: Arc<WorldData> |
@@ -32,13 +67,9 @@ impl AnalysisHostImpl { | |||
32 | data: Arc::new(WorldData::default()), | 67 | data: Arc::new(WorldData::default()), |
33 | } | 68 | } |
34 | } | 69 | } |
35 | pub fn analysis( | 70 | pub fn analysis(&self) -> AnalysisImpl { |
36 | &self, | ||
37 | file_resolver: Arc<dyn FileResolver>, | ||
38 | ) -> AnalysisImpl { | ||
39 | AnalysisImpl { | 71 | AnalysisImpl { |
40 | needs_reindex: AtomicBool::new(false), | 72 | needs_reindex: AtomicBool::new(false), |
41 | file_resolver, | ||
42 | data: self.data.clone(), | 73 | data: self.data.clone(), |
43 | } | 74 | } |
44 | } | 75 | } |
@@ -48,6 +79,11 @@ impl AnalysisHostImpl { | |||
48 | data.root.update(file_id, text); | 79 | data.root.update(file_id, text); |
49 | } | 80 | } |
50 | } | 81 | } |
82 | pub fn set_file_resolver(&mut self, resolver: FileResolverImp) { | ||
83 | let data = self.data_mut(); | ||
84 | data.file_resolver = resolver.clone(); | ||
85 | data.root.set_file_resolver(resolver); | ||
86 | } | ||
51 | pub fn set_crate_graph(&mut self, graph: CrateGraph) { | 87 | pub fn set_crate_graph(&mut self, graph: CrateGraph) { |
52 | let mut visited = HashSet::new(); | 88 | let mut visited = HashSet::new(); |
53 | for &file_id in graph.crate_roots.values() { | 89 | for &file_id in graph.crate_roots.values() { |
@@ -67,7 +103,6 @@ impl AnalysisHostImpl { | |||
67 | 103 | ||
68 | pub(crate) struct AnalysisImpl { | 104 | pub(crate) struct AnalysisImpl { |
69 | needs_reindex: AtomicBool, | 105 | needs_reindex: AtomicBool, |
70 | file_resolver: Arc<dyn FileResolver>, | ||
71 | data: Arc<WorldData>, | 106 | data: Arc<WorldData>, |
72 | } | 107 | } |
73 | 108 | ||
@@ -81,7 +116,6 @@ impl Clone for AnalysisImpl { | |||
81 | fn clone(&self) -> AnalysisImpl { | 116 | fn clone(&self) -> AnalysisImpl { |
82 | AnalysisImpl { | 117 | AnalysisImpl { |
83 | needs_reindex: AtomicBool::new(self.needs_reindex.load(SeqCst)), | 118 | needs_reindex: AtomicBool::new(self.needs_reindex.load(SeqCst)), |
84 | file_resolver: Arc::clone(&self.file_resolver), | ||
85 | data: Arc::clone(&self.data), | 119 | data: Arc::clone(&self.data), |
86 | } | 120 | } |
87 | } | 121 | } |
@@ -117,11 +151,7 @@ impl AnalysisImpl { | |||
117 | let module_map = root.module_map(); | 151 | let module_map = root.module_map(); |
118 | let id = module_map.file2module(file_id); | 152 | let id = module_map.file2module(file_id); |
119 | module_map | 153 | module_map |
120 | .parent_modules( | 154 | .parent_modules(id, &|file_id| root.syntax(file_id)) |
121 | id, | ||
122 | &*self.file_resolver, | ||
123 | &|file_id| root.syntax(file_id), | ||
124 | ) | ||
125 | .into_iter() | 155 | .into_iter() |
126 | .map(|(id, name, node)| { | 156 | .map(|(id, name, node)| { |
127 | let id = module_map.module2file(id); | 157 | let id = module_map.module2file(id); |
@@ -149,11 +179,7 @@ impl AnalysisImpl { | |||
149 | } | 179 | } |
150 | let mid = module_map.file2module(id); | 180 | let mid = module_map.file2module(id); |
151 | let parents = module_map | 181 | let parents = module_map |
152 | .parent_module_ids( | 182 | .parent_module_ids(mid, &|file_id| self.file_syntax(file_id)) |
153 | mid, | ||
154 | &*self.file_resolver, | ||
155 | &|file_id| self.file_syntax(file_id), | ||
156 | ) | ||
157 | .into_iter() | 183 | .into_iter() |
158 | .map(|id| module_map.module2file(id)) | 184 | .map(|id| module_map.module2file(id)) |
159 | .filter(|&id| visited.insert(id)); | 185 | .filter(|&id| visited.insert(id)); |
@@ -213,7 +239,6 @@ impl AnalysisImpl { | |||
213 | 239 | ||
214 | module_map.problems( | 240 | module_map.problems( |
215 | file_id, | 241 | file_id, |
216 | &*self.file_resolver, | ||
217 | &|file_id| self.file_syntax(file_id), | 242 | &|file_id| self.file_syntax(file_id), |
218 | |name_node, problem| { | 243 | |name_node, problem| { |
219 | let diag = match problem { | 244 | let diag = match problem { |
@@ -291,7 +316,6 @@ impl AnalysisImpl { | |||
291 | module_map | 316 | module_map |
292 | .child_module_by_name( | 317 | .child_module_by_name( |
293 | id, name.as_str(), | 318 | id, name.as_str(), |
294 | &*self.file_resolver, | ||
295 | &|file_id| self.file_syntax(file_id), | 319 | &|file_id| self.file_syntax(file_id), |
296 | ) | 320 | ) |
297 | .into_iter() | 321 | .into_iter() |
@@ -306,8 +330,9 @@ impl AnalysisImpl { | |||
306 | } | 330 | } |
307 | } | 331 | } |
308 | 332 | ||
309 | #[derive(Clone, Default, Debug)] | 333 | #[derive(Default, Clone, Debug)] |
310 | struct WorldData { | 334 | struct WorldData { |
335 | file_resolver: FileResolverImp, | ||
311 | crate_graph: CrateGraph, | 336 | crate_graph: CrateGraph, |
312 | root: WritableSourceRoot, | 337 | root: WritableSourceRoot, |
313 | libs: Vec<Arc<ReadonlySourceRoot>>, | 338 | libs: Vec<Arc<ReadonlySourceRoot>>, |
diff --git a/crates/libanalysis/src/lib.rs b/crates/libanalysis/src/lib.rs index ff4fc709b..80cde079f 100644 --- a/crates/libanalysis/src/lib.rs +++ b/crates/libanalysis/src/lib.rs | |||
@@ -19,11 +19,12 @@ mod roots; | |||
19 | use std::{ | 19 | use std::{ |
20 | sync::Arc, | 20 | sync::Arc, |
21 | collections::HashMap, | 21 | collections::HashMap, |
22 | fmt::Debug, | ||
22 | }; | 23 | }; |
23 | 24 | ||
24 | use relative_path::{RelativePath, RelativePathBuf}; | 25 | use relative_path::{RelativePath, RelativePathBuf}; |
25 | use libsyntax2::{File, TextRange, TextUnit, AtomEdit}; | 26 | use libsyntax2::{File, TextRange, TextUnit, AtomEdit}; |
26 | use imp::{AnalysisImpl, AnalysisHostImpl}; | 27 | use imp::{AnalysisImpl, AnalysisHostImpl, FileResolverImp}; |
27 | 28 | ||
28 | pub use libeditor::{ | 29 | pub use libeditor::{ |
29 | StructureNode, LineIndex, FileSymbol, | 30 | StructureNode, LineIndex, FileSymbol, |
@@ -42,9 +43,9 @@ pub struct CrateGraph { | |||
42 | pub crate_roots: HashMap<CrateId, FileId>, | 43 | pub crate_roots: HashMap<CrateId, FileId>, |
43 | } | 44 | } |
44 | 45 | ||
45 | pub trait FileResolver: Send + Sync + 'static { | 46 | pub trait FileResolver: Debug + Send + Sync + 'static { |
46 | fn file_stem(&self, id: FileId) -> String; | 47 | fn file_stem(&self, file_id: FileId) -> String; |
47 | fn resolve(&self, id: FileId, path: &RelativePath) -> Option<FileId>; | 48 | fn resolve(&self, file_id: FileId, path: &RelativePath) -> Option<FileId>; |
48 | } | 49 | } |
49 | 50 | ||
50 | #[derive(Debug)] | 51 | #[derive(Debug)] |
@@ -56,8 +57,8 @@ impl AnalysisHost { | |||
56 | pub fn new() -> AnalysisHost { | 57 | pub fn new() -> AnalysisHost { |
57 | AnalysisHost { imp: AnalysisHostImpl::new() } | 58 | AnalysisHost { imp: AnalysisHostImpl::new() } |
58 | } | 59 | } |
59 | pub fn analysis(&self, file_resolver: impl FileResolver) -> Analysis { | 60 | pub fn analysis(&self) -> Analysis { |
60 | Analysis { imp: self.imp.analysis(Arc::new(file_resolver)) } | 61 | Analysis { imp: self.imp.analysis() } |
61 | } | 62 | } |
62 | pub fn change_file(&mut self, file_id: FileId, text: Option<String>) { | 63 | pub fn change_file(&mut self, file_id: FileId, text: Option<String>) { |
63 | self.change_files(::std::iter::once((file_id, text))); | 64 | self.change_files(::std::iter::once((file_id, text))); |
@@ -65,6 +66,9 @@ impl AnalysisHost { | |||
65 | pub fn change_files(&mut self, mut changes: impl Iterator<Item=(FileId, Option<String>)>) { | 66 | pub fn change_files(&mut self, mut changes: impl Iterator<Item=(FileId, Option<String>)>) { |
66 | self.imp.change_files(&mut changes) | 67 | self.imp.change_files(&mut changes) |
67 | } | 68 | } |
69 | pub fn set_file_resolver(&mut self, resolver: Arc<FileResolver>) { | ||
70 | self.imp.set_file_resolver(FileResolverImp::new(resolver)); | ||
71 | } | ||
68 | pub fn set_crate_graph(&mut self, graph: CrateGraph) { | 72 | pub fn set_crate_graph(&mut self, graph: CrateGraph) { |
69 | self.imp.set_crate_graph(graph) | 73 | self.imp.set_crate_graph(graph) |
70 | } | 74 | } |
@@ -223,8 +227,9 @@ pub struct LibraryData { | |||
223 | } | 227 | } |
224 | 228 | ||
225 | impl LibraryData { | 229 | impl LibraryData { |
226 | pub fn prepare(files: Vec<(FileId, String)>) -> LibraryData { | 230 | pub fn prepare(files: Vec<(FileId, String)>, file_resolver: Arc<FileResolver>) -> LibraryData { |
227 | let root = roots::ReadonlySourceRoot::new(files); | 231 | let file_resolver = FileResolverImp::new(file_resolver); |
232 | let root = roots::ReadonlySourceRoot::new(files, file_resolver); | ||
228 | LibraryData { root } | 233 | LibraryData { root } |
229 | } | 234 | } |
230 | } | 235 | } |
diff --git a/crates/libanalysis/src/module_map.rs b/crates/libanalysis/src/module_map.rs index 1b225ecee..9acebd6e2 100644 --- a/crates/libanalysis/src/module_map.rs +++ b/crates/libanalysis/src/module_map.rs | |||
@@ -1,12 +1,11 @@ | |||
1 | use relative_path::RelativePathBuf; | 1 | use relative_path::RelativePathBuf; |
2 | |||
3 | use parking_lot::{RwLock, RwLockReadGuard, RwLockWriteGuard}; | 2 | use parking_lot::{RwLock, RwLockReadGuard, RwLockWriteGuard}; |
4 | use libsyntax2::{ | 3 | use libsyntax2::{ |
5 | File, | 4 | File, |
6 | ast::{self, AstNode, NameOwner}, | 5 | ast::{self, AstNode, NameOwner}, |
7 | SyntaxNode, SmolStr, | 6 | SyntaxNode, SmolStr, |
8 | }; | 7 | }; |
9 | use {FileId, FileResolver}; | 8 | use {FileId, imp::FileResolverImp}; |
10 | 9 | ||
11 | type SyntaxProvider<'a> = dyn Fn(FileId) -> &'a File + 'a; | 10 | type SyntaxProvider<'a> = dyn Fn(FileId) -> &'a File + 'a; |
12 | 11 | ||
@@ -32,6 +31,7 @@ impl Clone for ModuleMap { | |||
32 | 31 | ||
33 | #[derive(Clone, Debug, Default)] | 32 | #[derive(Clone, Debug, Default)] |
34 | struct State { | 33 | struct State { |
34 | file_resolver: FileResolverImp, | ||
35 | changes: Vec<(FileId, ChangeKind)>, | 35 | changes: Vec<(FileId, ChangeKind)>, |
36 | links: Vec<Link>, | 36 | links: Vec<Link>, |
37 | } | 37 | } |
@@ -59,27 +59,25 @@ impl ModuleMap { | |||
59 | pub fn new() -> ModuleMap { | 59 | pub fn new() -> ModuleMap { |
60 | Default::default() | 60 | Default::default() |
61 | } | 61 | } |
62 | 62 | pub fn update_file(&mut self, file_id: FileId, change_kind: ChangeKind) { | |
63 | pub fn update_file(&mut self, file: FileId, change_kind: ChangeKind) { | 63 | self.state.get_mut().changes.push((file_id, change_kind)); |
64 | self.state.get_mut().changes.push((file, change_kind)); | 64 | } |
65 | pub(crate) fn set_file_resolver(&mut self, file_resolver: FileResolverImp) { | ||
66 | self.state.get_mut().file_resolver = file_resolver; | ||
65 | } | 67 | } |
66 | |||
67 | pub fn module2file(&self, m: ModuleId) -> FileId { | 68 | pub fn module2file(&self, m: ModuleId) -> FileId { |
68 | m.0 | 69 | m.0 |
69 | } | 70 | } |
70 | |||
71 | pub fn file2module(&self, file_id: FileId) -> ModuleId { | 71 | pub fn file2module(&self, file_id: FileId) -> ModuleId { |
72 | ModuleId(file_id) | 72 | ModuleId(file_id) |
73 | } | 73 | } |
74 | |||
75 | pub fn child_module_by_name<'a>( | 74 | pub fn child_module_by_name<'a>( |
76 | &self, | 75 | &self, |
77 | parent_mod: ModuleId, | 76 | parent_mod: ModuleId, |
78 | child_mod: &str, | 77 | child_mod: &str, |
79 | file_resolver: &FileResolver, | ||
80 | syntax_provider: &SyntaxProvider, | 78 | syntax_provider: &SyntaxProvider, |
81 | ) -> Vec<ModuleId> { | 79 | ) -> Vec<ModuleId> { |
82 | self.links(file_resolver, syntax_provider) | 80 | self.links(syntax_provider) |
83 | .links | 81 | .links |
84 | .iter() | 82 | .iter() |
85 | .filter(|link| link.owner == parent_mod) | 83 | .filter(|link| link.owner == parent_mod) |
@@ -92,11 +90,10 @@ impl ModuleMap { | |||
92 | pub fn parent_modules( | 90 | pub fn parent_modules( |
93 | &self, | 91 | &self, |
94 | m: ModuleId, | 92 | m: ModuleId, |
95 | file_resolver: &FileResolver, | ||
96 | syntax_provider: &SyntaxProvider, | 93 | syntax_provider: &SyntaxProvider, |
97 | ) -> Vec<(ModuleId, SmolStr, SyntaxNode)> { | 94 | ) -> Vec<(ModuleId, SmolStr, SyntaxNode)> { |
98 | let mut res = Vec::new(); | 95 | let mut res = Vec::new(); |
99 | self.for_each_parent_link(m, file_resolver, syntax_provider, |link| { | 96 | self.for_each_parent_link(m, syntax_provider, |link| { |
100 | res.push( | 97 | res.push( |
101 | (link.owner, link.name().clone(), link.syntax.clone()) | 98 | (link.owner, link.name().clone(), link.syntax.clone()) |
102 | ) | 99 | ) |
@@ -107,22 +104,20 @@ impl ModuleMap { | |||
107 | pub fn parent_module_ids( | 104 | pub fn parent_module_ids( |
108 | &self, | 105 | &self, |
109 | m: ModuleId, | 106 | m: ModuleId, |
110 | file_resolver: &FileResolver, | ||
111 | syntax_provider: &SyntaxProvider, | 107 | syntax_provider: &SyntaxProvider, |
112 | ) -> Vec<ModuleId> { | 108 | ) -> Vec<ModuleId> { |
113 | let mut res = Vec::new(); | 109 | let mut res = Vec::new(); |
114 | self.for_each_parent_link(m, file_resolver, syntax_provider, |link| res.push(link.owner)); | 110 | self.for_each_parent_link(m, syntax_provider, |link| res.push(link.owner)); |
115 | res | 111 | res |
116 | } | 112 | } |
117 | 113 | ||
118 | fn for_each_parent_link( | 114 | fn for_each_parent_link( |
119 | &self, | 115 | &self, |
120 | m: ModuleId, | 116 | m: ModuleId, |
121 | file_resolver: &FileResolver, | ||
122 | syntax_provider: &SyntaxProvider, | 117 | syntax_provider: &SyntaxProvider, |
123 | f: impl FnMut(&Link) | 118 | f: impl FnMut(&Link) |
124 | ) { | 119 | ) { |
125 | self.links(file_resolver, syntax_provider) | 120 | self.links(syntax_provider) |
126 | .links | 121 | .links |
127 | .iter() | 122 | .iter() |
128 | .filter(move |link| link.points_to.iter().any(|&it| it == m)) | 123 | .filter(move |link| link.points_to.iter().any(|&it| it == m)) |
@@ -132,12 +127,11 @@ impl ModuleMap { | |||
132 | pub fn problems( | 127 | pub fn problems( |
133 | &self, | 128 | &self, |
134 | file: FileId, | 129 | file: FileId, |
135 | file_resolver: &FileResolver, | ||
136 | syntax_provider: &SyntaxProvider, | 130 | syntax_provider: &SyntaxProvider, |
137 | mut cb: impl FnMut(ast::Name, &Problem), | 131 | mut cb: impl FnMut(ast::Name, &Problem), |
138 | ) { | 132 | ) { |
139 | let module = self.file2module(file); | 133 | let module = self.file2module(file); |
140 | let links = self.links(file_resolver, syntax_provider); | 134 | let links = self.links(syntax_provider); |
141 | links | 135 | links |
142 | .links | 136 | .links |
143 | .iter() | 137 | .iter() |
@@ -151,7 +145,6 @@ impl ModuleMap { | |||
151 | 145 | ||
152 | fn links( | 146 | fn links( |
153 | &self, | 147 | &self, |
154 | file_resolver: &FileResolver, | ||
155 | syntax_provider: &SyntaxProvider, | 148 | syntax_provider: &SyntaxProvider, |
156 | ) -> RwLockReadGuard<State> { | 149 | ) -> RwLockReadGuard<State> { |
157 | { | 150 | { |
@@ -162,7 +155,7 @@ impl ModuleMap { | |||
162 | } | 155 | } |
163 | let mut guard = self.state.write(); | 156 | let mut guard = self.state.write(); |
164 | if !guard.changes.is_empty() { | 157 | if !guard.changes.is_empty() { |
165 | guard.apply_changes(file_resolver, syntax_provider); | 158 | guard.apply_changes(syntax_provider); |
166 | } | 159 | } |
167 | assert!(guard.changes.is_empty()); | 160 | assert!(guard.changes.is_empty()); |
168 | RwLockWriteGuard::downgrade(guard) | 161 | RwLockWriteGuard::downgrade(guard) |
@@ -172,7 +165,6 @@ impl ModuleMap { | |||
172 | impl State { | 165 | impl State { |
173 | pub fn apply_changes( | 166 | pub fn apply_changes( |
174 | &mut self, | 167 | &mut self, |
175 | file_resolver: &FileResolver, | ||
176 | syntax_provider: &SyntaxProvider, | 168 | syntax_provider: &SyntaxProvider, |
177 | ) { | 169 | ) { |
178 | let mut reresolve = false; | 170 | let mut reresolve = false; |
@@ -197,13 +189,14 @@ impl State { | |||
197 | } | 189 | } |
198 | ChangeKind::Update => { | 190 | ChangeKind::Update => { |
199 | let file = syntax_provider(file_id); | 191 | let file = syntax_provider(file_id); |
192 | let resolver = &self.file_resolver; | ||
200 | self.links.extend( | 193 | self.links.extend( |
201 | file | 194 | file |
202 | .ast() | 195 | .ast() |
203 | .modules() | 196 | .modules() |
204 | .filter_map(|it| Link::new(mod_id, it)) | 197 | .filter_map(|it| Link::new(mod_id, it)) |
205 | .map(|mut link| { | 198 | .map(|mut link| { |
206 | link.resolve(file_resolver); | 199 | link.resolve(resolver); |
207 | link | 200 | link |
208 | }) | 201 | }) |
209 | ); | 202 | ); |
@@ -212,7 +205,7 @@ impl State { | |||
212 | } | 205 | } |
213 | if reresolve { | 206 | if reresolve { |
214 | for link in self.links.iter_mut() { | 207 | for link in self.links.iter_mut() { |
215 | link.resolve(file_resolver) | 208 | link.resolve(&self.file_resolver) |
216 | } | 209 | } |
217 | } | 210 | } |
218 | } | 211 | } |
@@ -245,7 +238,7 @@ impl Link { | |||
245 | .unwrap() | 238 | .unwrap() |
246 | } | 239 | } |
247 | 240 | ||
248 | fn resolve(&mut self, file_resolver: &FileResolver) { | 241 | fn resolve(&mut self, file_resolver: &FileResolverImp) { |
249 | if !self.ast().has_semi() { | 242 | if !self.ast().has_semi() { |
250 | self.problem = None; | 243 | self.problem = None; |
251 | self.points_to = Vec::new(); | 244 | self.points_to = Vec::new(); |
diff --git a/crates/libanalysis/src/roots.rs b/crates/libanalysis/src/roots.rs index 6d1375f88..629a697c5 100644 --- a/crates/libanalysis/src/roots.rs +++ b/crates/libanalysis/src/roots.rs | |||
@@ -12,6 +12,7 @@ use libsyntax2::File; | |||
12 | 12 | ||
13 | use { | 13 | use { |
14 | FileId, | 14 | FileId, |
15 | imp::FileResolverImp, | ||
15 | module_map::{ModuleMap, ChangeKind}, | 16 | module_map::{ModuleMap, ChangeKind}, |
16 | symbol_index::SymbolIndex, | 17 | symbol_index::SymbolIndex, |
17 | }; | 18 | }; |
@@ -48,6 +49,9 @@ impl WritableSourceRoot { | |||
48 | self.file_map.insert(file_id, Arc::new((file_data, Default::default()))); | 49 | self.file_map.insert(file_id, Arc::new((file_data, Default::default()))); |
49 | } | 50 | } |
50 | } | 51 | } |
52 | pub fn set_file_resolver(&mut self, file_resolver: FileResolverImp) { | ||
53 | self.module_map.set_file_resolver(file_resolver) | ||
54 | } | ||
51 | pub fn reindex(&self) { | 55 | pub fn reindex(&self) { |
52 | let now = Instant::now(); | 56 | let now = Instant::now(); |
53 | self.file_map | 57 | self.file_map |
@@ -136,8 +140,9 @@ pub(crate) struct ReadonlySourceRoot { | |||
136 | } | 140 | } |
137 | 141 | ||
138 | impl ReadonlySourceRoot { | 142 | impl ReadonlySourceRoot { |
139 | pub fn new(files: Vec<(FileId, String)>) -> ReadonlySourceRoot { | 143 | pub(crate) fn new(files: Vec<(FileId, String)>, file_resolver: FileResolverImp) -> ReadonlySourceRoot { |
140 | let mut module_map = ModuleMap::new(); | 144 | let mut module_map = ModuleMap::new(); |
145 | module_map.set_file_resolver(file_resolver); | ||
141 | let symbol_index = SymbolIndex::for_files( | 146 | let symbol_index = SymbolIndex::for_files( |
142 | files.par_iter().map(|(file_id, text)| { | 147 | files.par_iter().map(|(file_id, text)| { |
143 | (*file_id, File::parse(text)) | 148 | (*file_id, File::parse(text)) |
diff --git a/crates/libanalysis/tests/tests.rs b/crates/libanalysis/tests/tests.rs index ebc8037b3..00efe059c 100644 --- a/crates/libanalysis/tests/tests.rs +++ b/crates/libanalysis/tests/tests.rs | |||
@@ -3,21 +3,38 @@ extern crate relative_path; | |||
3 | extern crate test_utils; | 3 | extern crate test_utils; |
4 | 4 | ||
5 | use std::{ | 5 | use std::{ |
6 | sync::Arc, | ||
6 | collections::HashMap, | 7 | collections::HashMap, |
7 | }; | 8 | }; |
8 | 9 | ||
9 | use relative_path::{RelativePath}; | 10 | use relative_path::{RelativePath, RelativePathBuf}; |
10 | use libanalysis::{AnalysisHost, FileId, FileResolver, JobHandle, CrateGraph, CrateId}; | 11 | use libanalysis::{Analysis, AnalysisHost, FileId, FileResolver, JobHandle, CrateGraph, CrateId}; |
11 | use test_utils::assert_eq_dbg; | 12 | use test_utils::assert_eq_dbg; |
12 | 13 | ||
13 | struct FileMap(&'static [(u32, &'static str)]); | 14 | #[derive(Debug)] |
15 | struct FileMap(Vec<(FileId, RelativePathBuf)>); | ||
16 | |||
17 | fn analysis_host(files: &'static [(&'static str, &'static str)]) -> AnalysisHost { | ||
18 | let mut host = AnalysisHost::new(); | ||
19 | let mut file_map = Vec::new(); | ||
20 | for (id, &(path, contents)) in files.iter().enumerate() { | ||
21 | let file_id = FileId((id + 1) as u32); | ||
22 | assert!(path.starts_with('/')); | ||
23 | let path = RelativePathBuf::from_path(&path[1..]).unwrap(); | ||
24 | host.change_file(file_id, Some(contents.to_string())); | ||
25 | file_map.push((file_id, path)); | ||
26 | } | ||
27 | host.set_file_resolver(Arc::new(FileMap(file_map))); | ||
28 | host | ||
29 | } | ||
30 | |||
31 | fn analysis(files: &'static [(&'static str, &'static str)]) -> Analysis { | ||
32 | analysis_host(files).analysis() | ||
33 | } | ||
14 | 34 | ||
15 | impl FileMap { | 35 | impl FileMap { |
16 | fn iter<'a>(&'a self) -> impl Iterator<Item=(FileId, &'a RelativePath)> + 'a { | 36 | fn iter<'a>(&'a self) -> impl Iterator<Item=(FileId, &'a RelativePath)> + 'a { |
17 | self.0.iter().map(|&(id, path)| { | 37 | self.0.iter().map(|(id, path)| (*id, path.as_relative_path())) |
18 | assert!(path.starts_with('/')); | ||
19 | (FileId(id), RelativePath::new(&path[1..])) | ||
20 | }) | ||
21 | } | 38 | } |
22 | 39 | ||
23 | fn path(&self, id: FileId) -> &RelativePath { | 40 | fn path(&self, id: FileId) -> &RelativePath { |
@@ -42,14 +59,10 @@ impl FileResolver for FileMap { | |||
42 | 59 | ||
43 | #[test] | 60 | #[test] |
44 | fn test_resolve_module() { | 61 | fn test_resolve_module() { |
45 | let mut world = AnalysisHost::new(); | 62 | let snap = analysis(&[ |
46 | world.change_file(FileId(1), Some("mod foo;".to_string())); | 63 | ("/lib.rs", "mod foo;"), |
47 | world.change_file(FileId(2), Some("".to_string())); | 64 | ("/foo.rs", "") |
48 | 65 | ]); | |
49 | let snap = world.analysis(FileMap(&[ | ||
50 | (1, "/lib.rs"), | ||
51 | (2, "/foo.rs"), | ||
52 | ])); | ||
53 | let (_handle, token) = JobHandle::new(); | 66 | let (_handle, token) = JobHandle::new(); |
54 | let symbols = snap.approximately_resolve_symbol(FileId(1), 4.into(), &token); | 67 | let symbols = snap.approximately_resolve_symbol(FileId(1), 4.into(), &token); |
55 | assert_eq_dbg( | 68 | assert_eq_dbg( |
@@ -57,10 +70,10 @@ fn test_resolve_module() { | |||
57 | &symbols, | 70 | &symbols, |
58 | ); | 71 | ); |
59 | 72 | ||
60 | let snap = world.analysis(FileMap(&[ | 73 | let snap = analysis(&[ |
61 | (1, "/lib.rs"), | 74 | ("/lib.rs", "mod foo;"), |
62 | (2, "/foo/mod.rs") | 75 | ("/foo/mod.rs", "") |
63 | ])); | 76 | ]); |
64 | let symbols = snap.approximately_resolve_symbol(FileId(1), 4.into(), &token); | 77 | let symbols = snap.approximately_resolve_symbol(FileId(1), 4.into(), &token); |
65 | assert_eq_dbg( | 78 | assert_eq_dbg( |
66 | r#"[(FileId(2), FileSymbol { name: "foo", node_range: [0; 0), kind: MODULE })]"#, | 79 | r#"[(FileId(2), FileSymbol { name: "foo", node_range: [0; 0), kind: MODULE })]"#, |
@@ -70,10 +83,7 @@ fn test_resolve_module() { | |||
70 | 83 | ||
71 | #[test] | 84 | #[test] |
72 | fn test_unresolved_module_diagnostic() { | 85 | fn test_unresolved_module_diagnostic() { |
73 | let mut world = AnalysisHost::new(); | 86 | let snap = analysis(&[("/lib.rs", "mod foo;")]); |
74 | world.change_file(FileId(1), Some("mod foo;".to_string())); | ||
75 | |||
76 | let snap = world.analysis(FileMap(&[(1, "/lib.rs")])); | ||
77 | let diagnostics = snap.diagnostics(FileId(1)); | 87 | let diagnostics = snap.diagnostics(FileId(1)); |
78 | assert_eq_dbg( | 88 | assert_eq_dbg( |
79 | r#"[Diagnostic { | 89 | r#"[Diagnostic { |
@@ -90,10 +100,7 @@ fn test_unresolved_module_diagnostic() { | |||
90 | 100 | ||
91 | #[test] | 101 | #[test] |
92 | fn test_unresolved_module_diagnostic_no_diag_for_inline_mode() { | 102 | fn test_unresolved_module_diagnostic_no_diag_for_inline_mode() { |
93 | let mut world = AnalysisHost::new(); | 103 | let snap = analysis(&[("/lib.rs", "mod foo {}")]); |
94 | world.change_file(FileId(1), Some("mod foo {}".to_string())); | ||
95 | |||
96 | let snap = world.analysis(FileMap(&[(1, "/lib.rs")])); | ||
97 | let diagnostics = snap.diagnostics(FileId(1)); | 104 | let diagnostics = snap.diagnostics(FileId(1)); |
98 | assert_eq_dbg( | 105 | assert_eq_dbg( |
99 | r#"[]"#, | 106 | r#"[]"#, |
@@ -103,14 +110,10 @@ fn test_unresolved_module_diagnostic_no_diag_for_inline_mode() { | |||
103 | 110 | ||
104 | #[test] | 111 | #[test] |
105 | fn test_resolve_parent_module() { | 112 | fn test_resolve_parent_module() { |
106 | let mut world = AnalysisHost::new(); | 113 | let snap = analysis(&[ |
107 | world.change_file(FileId(1), Some("mod foo;".to_string())); | 114 | ("/lib.rs", "mod foo;"), |
108 | world.change_file(FileId(2), Some("".to_string())); | 115 | ("/foo.rs", ""), |
109 | 116 | ]); | |
110 | let snap = world.analysis(FileMap(&[ | ||
111 | (1, "/lib.rs"), | ||
112 | (2, "/foo.rs"), | ||
113 | ])); | ||
114 | let symbols = snap.parent_module(FileId(2)); | 117 | let symbols = snap.parent_module(FileId(2)); |
115 | assert_eq_dbg( | 118 | assert_eq_dbg( |
116 | r#"[(FileId(1), FileSymbol { name: "foo", node_range: [0; 8), kind: MODULE })]"#, | 119 | r#"[(FileId(1), FileSymbol { name: "foo", node_range: [0; 8), kind: MODULE })]"#, |
@@ -120,14 +123,11 @@ fn test_resolve_parent_module() { | |||
120 | 123 | ||
121 | #[test] | 124 | #[test] |
122 | fn test_resolve_crate_root() { | 125 | fn test_resolve_crate_root() { |
123 | let mut world = AnalysisHost::new(); | 126 | let mut host = analysis_host(&[ |
124 | world.change_file(FileId(1), Some("mod foo;".to_string())); | 127 | ("/lib.rs", "mod foo;"), |
125 | world.change_file(FileId(2), Some("".to_string())); | 128 | ("/foo.rs", ""), |
126 | 129 | ]); | |
127 | let snap = world.analysis(FileMap(&[ | 130 | let snap = host.analysis(); |
128 | (1, "/lib.rs"), | ||
129 | (2, "/foo.rs"), | ||
130 | ])); | ||
131 | assert!(snap.crate_for(FileId(2)).is_empty()); | 131 | assert!(snap.crate_for(FileId(2)).is_empty()); |
132 | 132 | ||
133 | let crate_graph = CrateGraph { | 133 | let crate_graph = CrateGraph { |
@@ -137,12 +137,9 @@ fn test_resolve_crate_root() { | |||
137 | m | 137 | m |
138 | }, | 138 | }, |
139 | }; | 139 | }; |
140 | world.set_crate_graph(crate_graph); | 140 | host.set_crate_graph(crate_graph); |
141 | let snap = host.analysis(); | ||
141 | 142 | ||
142 | let snap = world.analysis(FileMap(&[ | ||
143 | (1, "/lib.rs"), | ||
144 | (2, "/foo.rs"), | ||
145 | ])); | ||
146 | assert_eq!( | 143 | assert_eq!( |
147 | snap.crate_for(FileId(2)), | 144 | snap.crate_for(FileId(2)), |
148 | vec![CrateId(1)], | 145 | vec![CrateId(1)], |
diff --git a/crates/server/src/main_loop/mod.rs b/crates/server/src/main_loop/mod.rs index f1297ee48..f3b2744bf 100644 --- a/crates/server/src/main_loop/mod.rs +++ b/crates/server/src/main_loop/mod.rs | |||
@@ -135,12 +135,12 @@ fn main_loop_inner( | |||
135 | if root == ws_root { | 135 | if root == ws_root { |
136 | state.apply_fs_changes(events); | 136 | state.apply_fs_changes(events); |
137 | } else { | 137 | } else { |
138 | let files = state.events_to_files(events); | 138 | let (files, resolver) = state.events_to_files(events); |
139 | let sender = libdata_sender.clone(); | 139 | let sender = libdata_sender.clone(); |
140 | pool.spawn(move || { | 140 | pool.spawn(move || { |
141 | let start = ::std::time::Instant::now(); | 141 | let start = ::std::time::Instant::now(); |
142 | info!("indexing {} ... ", root.display()); | 142 | info!("indexing {} ... ", root.display()); |
143 | let data = LibraryData::prepare(files); | 143 | let data = LibraryData::prepare(files, resolver); |
144 | info!("indexed {:?} {}", start.elapsed(), root.display()); | 144 | info!("indexed {:?} {}", start.elapsed(), root.display()); |
145 | sender.send(data); | 145 | sender.send(data); |
146 | }); | 146 | }); |
diff --git a/crates/server/src/server_world.rs b/crates/server/src/server_world.rs index 8ceec594f..ffa0e74b8 100644 --- a/crates/server/src/server_world.rs +++ b/crates/server/src/server_world.rs | |||
@@ -6,7 +6,7 @@ use std::{ | |||
6 | }; | 6 | }; |
7 | 7 | ||
8 | use languageserver_types::Url; | 8 | use languageserver_types::Url; |
9 | use libanalysis::{FileId, AnalysisHost, Analysis, CrateGraph, CrateId, LibraryData}; | 9 | use libanalysis::{FileId, AnalysisHost, Analysis, CrateGraph, CrateId, LibraryData, FileResolver}; |
10 | 10 | ||
11 | use { | 11 | use { |
12 | Result, | 12 | Result, |
@@ -64,17 +64,21 @@ impl ServerWorldState { | |||
64 | 64 | ||
65 | self.analysis_host.change_files(changes); | 65 | self.analysis_host.change_files(changes); |
66 | } | 66 | } |
67 | pub fn events_to_files(&mut self, events: Vec<FileEvent>) -> Vec<(FileId, String)> { | 67 | pub fn events_to_files(&mut self, events: Vec<FileEvent>) -> (Vec<(FileId, String)>, Arc<FileResolver>) { |
68 | let pm = &mut self.path_map; | 68 | let files = { |
69 | events.into_iter() | 69 | let pm = &mut self.path_map; |
70 | .map(|event| { | 70 | events.into_iter() |
71 | let text = match event.kind { | 71 | .map(|event| { |
72 | FileEventKind::Add(text) => text, | 72 | let text = match event.kind { |
73 | }; | 73 | FileEventKind::Add(text) => text, |
74 | (event.path, text) | 74 | }; |
75 | }) | 75 | (event.path, text) |
76 | .map(|(path, text)| (pm.get_or_insert(path, Root::Lib), text)) | 76 | }) |
77 | .collect() | 77 | .map(|(path, text)| (pm.get_or_insert(path, Root::Lib), text)) |
78 | .collect() | ||
79 | }; | ||
80 | let resolver = Arc::new(self.path_map.clone()); | ||
81 | (files, resolver) | ||
78 | } | 82 | } |
79 | pub fn add_lib(&mut self, data: LibraryData) { | 83 | pub fn add_lib(&mut self, data: LibraryData) { |
80 | self.analysis_host.add_library(data); | 84 | self.analysis_host.add_library(data); |
@@ -82,6 +86,7 @@ impl ServerWorldState { | |||
82 | 86 | ||
83 | pub fn add_mem_file(&mut self, path: PathBuf, text: String) -> FileId { | 87 | pub fn add_mem_file(&mut self, path: PathBuf, text: String) -> FileId { |
84 | let file_id = self.path_map.get_or_insert(path, Root::Workspace); | 88 | let file_id = self.path_map.get_or_insert(path, Root::Workspace); |
89 | self.analysis_host.set_file_resolver(Arc::new(self.path_map.clone())); | ||
85 | self.mem_map.insert(file_id, None); | 90 | self.mem_map.insert(file_id, None); |
86 | if self.path_map.get_root(file_id) != Root::Lib { | 91 | if self.path_map.get_root(file_id) != Root::Lib { |
87 | self.analysis_host.change_file(file_id, Some(text)); | 92 | self.analysis_host.change_file(file_id, Some(text)); |
@@ -135,7 +140,7 @@ impl ServerWorldState { | |||
135 | pub fn snapshot(&self) -> ServerWorld { | 140 | pub fn snapshot(&self) -> ServerWorld { |
136 | ServerWorld { | 141 | ServerWorld { |
137 | workspaces: Arc::clone(&self.workspaces), | 142 | workspaces: Arc::clone(&self.workspaces), |
138 | analysis: self.analysis_host.analysis(self.path_map.clone()), | 143 | analysis: self.analysis_host.analysis(), |
139 | path_map: self.path_map.clone() | 144 | path_map: self.path_map.clone() |
140 | } | 145 | } |
141 | } | 146 | } |