aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--crates/libanalysis/src/imp.rs65
-rw-r--r--crates/libanalysis/src/lib.rs21
-rw-r--r--crates/libanalysis/src/module_map.rs41
-rw-r--r--crates/libanalysis/src/roots.rs7
-rw-r--r--crates/libanalysis/tests/tests.rs93
-rw-r--r--crates/server/src/main_loop/mod.rs4
-rw-r--r--crates/server/src/server_world.rs31
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
10use relative_path::RelativePath;
10use libeditor::{self, FileSymbol, LineIndex, find_node_at_offset, LocalEdit}; 11use libeditor::{self, FileSymbol, LineIndex, find_node_at_offset, LocalEdit};
11use libsyntax2::{ 12use 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)]
27pub(crate) struct FileResolverImp {
28 inner: Arc<FileResolver>
29}
30
31impl 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
43impl 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)]
25pub(crate) struct AnalysisHostImpl { 60pub(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
68pub(crate) struct AnalysisImpl { 104pub(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)]
310struct WorldData { 334struct 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;
19use std::{ 19use std::{
20 sync::Arc, 20 sync::Arc,
21 collections::HashMap, 21 collections::HashMap,
22 fmt::Debug,
22}; 23};
23 24
24use relative_path::{RelativePath, RelativePathBuf}; 25use relative_path::{RelativePath, RelativePathBuf};
25use libsyntax2::{File, TextRange, TextUnit, AtomEdit}; 26use libsyntax2::{File, TextRange, TextUnit, AtomEdit};
26use imp::{AnalysisImpl, AnalysisHostImpl}; 27use imp::{AnalysisImpl, AnalysisHostImpl, FileResolverImp};
27 28
28pub use libeditor::{ 29pub 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
45pub trait FileResolver: Send + Sync + 'static { 46pub 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
225impl LibraryData { 229impl 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 @@
1use relative_path::RelativePathBuf; 1use relative_path::RelativePathBuf;
2
3use parking_lot::{RwLock, RwLockReadGuard, RwLockWriteGuard}; 2use parking_lot::{RwLock, RwLockReadGuard, RwLockWriteGuard};
4use libsyntax2::{ 3use libsyntax2::{
5 File, 4 File,
6 ast::{self, AstNode, NameOwner}, 5 ast::{self, AstNode, NameOwner},
7 SyntaxNode, SmolStr, 6 SyntaxNode, SmolStr,
8}; 7};
9use {FileId, FileResolver}; 8use {FileId, imp::FileResolverImp};
10 9
11type SyntaxProvider<'a> = dyn Fn(FileId) -> &'a File + 'a; 10type 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)]
34struct State { 33struct 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 {
172impl State { 165impl 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
13use { 13use {
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
138impl ReadonlySourceRoot { 142impl 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;
3extern crate test_utils; 3extern crate test_utils;
4 4
5use std::{ 5use std::{
6 sync::Arc,
6 collections::HashMap, 7 collections::HashMap,
7}; 8};
8 9
9use relative_path::{RelativePath}; 10use relative_path::{RelativePath, RelativePathBuf};
10use libanalysis::{AnalysisHost, FileId, FileResolver, JobHandle, CrateGraph, CrateId}; 11use libanalysis::{Analysis, AnalysisHost, FileId, FileResolver, JobHandle, CrateGraph, CrateId};
11use test_utils::assert_eq_dbg; 12use test_utils::assert_eq_dbg;
12 13
13struct FileMap(&'static [(u32, &'static str)]); 14#[derive(Debug)]
15struct FileMap(Vec<(FileId, RelativePathBuf)>);
16
17fn 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
31fn analysis(files: &'static [(&'static str, &'static str)]) -> Analysis {
32 analysis_host(files).analysis()
33}
14 34
15impl FileMap { 35impl 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]
44fn test_resolve_module() { 61fn 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]
72fn test_unresolved_module_diagnostic() { 85fn 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]
92fn test_unresolved_module_diagnostic_no_diag_for_inline_mode() { 102fn 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]
105fn test_resolve_parent_module() { 112fn 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]
122fn test_resolve_crate_root() { 125fn 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
8use languageserver_types::Url; 8use languageserver_types::Url;
9use libanalysis::{FileId, AnalysisHost, Analysis, CrateGraph, CrateId, LibraryData}; 9use libanalysis::{FileId, AnalysisHost, Analysis, CrateGraph, CrateId, LibraryData, FileResolver};
10 10
11use { 11use {
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 }