diff options
author | bors[bot] <bors[bot]@users.noreply.github.com> | 2018-12-09 11:00:56 +0000 |
---|---|---|
committer | bors[bot] <bors[bot]@users.noreply.github.com> | 2018-12-09 11:00:56 +0000 |
commit | 19f6cdcc034a2a91e6112a4ceb32e26413b0aa0d (patch) | |
tree | 548400065966f715ae203e6f6e0fcfd9f12e4470 /crates/ra_hir | |
parent | 34956b7823d72467fbf4fa62bd4413dfb680f78d (diff) | |
parent | 7784c7a701ba944decf671f80dea581d68667663 (diff) |
Merge #268
268: WIP: resolve imports across crates r=matklad a=matklad
Co-authored-by: Aleksey Kladov <[email protected]>
Diffstat (limited to 'crates/ra_hir')
-rw-r--r-- | crates/ra_hir/src/krate.rs | 48 | ||||
-rw-r--r-- | crates/ra_hir/src/lib.rs | 7 | ||||
-rw-r--r-- | crates/ra_hir/src/mock.rs | 24 | ||||
-rw-r--r-- | crates/ra_hir/src/module.rs | 11 | ||||
-rw-r--r-- | crates/ra_hir/src/module/nameres.rs | 199 | ||||
-rw-r--r-- | crates/ra_hir/src/module/nameres/tests.rs | 127 | ||||
-rw-r--r-- | crates/ra_hir/src/query_definitions.rs | 9 |
7 files changed, 281 insertions, 144 deletions
diff --git a/crates/ra_hir/src/krate.rs b/crates/ra_hir/src/krate.rs new file mode 100644 index 000000000..1196dcef1 --- /dev/null +++ b/crates/ra_hir/src/krate.rs | |||
@@ -0,0 +1,48 @@ | |||
1 | use ra_syntax::SmolStr; | ||
2 | pub use ra_db::CrateId; | ||
3 | |||
4 | use crate::{HirDatabase, Module, Cancelable}; | ||
5 | |||
6 | /// hir::Crate describes a single crate. It's the main inteface with which | ||
7 | /// crate's dependencies interact. Mostly, it should be just a proxy for the | ||
8 | /// root module. | ||
9 | #[derive(Debug)] | ||
10 | pub struct Crate { | ||
11 | crate_id: CrateId, | ||
12 | } | ||
13 | |||
14 | #[derive(Debug)] | ||
15 | pub struct CrateDependency { | ||
16 | pub krate: Crate, | ||
17 | pub name: SmolStr, | ||
18 | } | ||
19 | |||
20 | impl Crate { | ||
21 | pub(crate) fn new(crate_id: CrateId) -> Crate { | ||
22 | Crate { crate_id } | ||
23 | } | ||
24 | pub fn dependencies(&self, db: &impl HirDatabase) -> Vec<CrateDependency> { | ||
25 | let crate_graph = db.crate_graph(); | ||
26 | crate_graph | ||
27 | .dependencies(self.crate_id) | ||
28 | .map(|dep| { | ||
29 | let krate = Crate::new(dep.crate_id()); | ||
30 | let name = dep.name.clone(); | ||
31 | CrateDependency { krate, name } | ||
32 | }) | ||
33 | .collect() | ||
34 | } | ||
35 | pub fn root_module(&self, db: &impl HirDatabase) -> Cancelable<Option<Module>> { | ||
36 | let crate_graph = db.crate_graph(); | ||
37 | let file_id = crate_graph.crate_root(self.crate_id); | ||
38 | let source_root_id = db.file_source_root(file_id); | ||
39 | let module_tree = db.module_tree(source_root_id)?; | ||
40 | // FIXME: teach module tree about crate roots instead of guessing | ||
41 | let (module_id, _) = ctry!(module_tree | ||
42 | .modules_with_sources() | ||
43 | .find(|(_, src)| src.file_id() == file_id)); | ||
44 | |||
45 | let module = Module::new(db, source_root_id, module_id)?; | ||
46 | Ok(Some(module)) | ||
47 | } | ||
48 | } | ||
diff --git a/crates/ra_hir/src/lib.rs b/crates/ra_hir/src/lib.rs index f50b922af..578fde259 100644 --- a/crates/ra_hir/src/lib.rs +++ b/crates/ra_hir/src/lib.rs | |||
@@ -18,12 +18,14 @@ pub mod db; | |||
18 | #[cfg(test)] | 18 | #[cfg(test)] |
19 | mod mock; | 19 | mod mock; |
20 | mod query_definitions; | 20 | mod query_definitions; |
21 | mod function; | ||
22 | mod module; | ||
23 | mod path; | 21 | mod path; |
24 | mod arena; | 22 | mod arena; |
25 | pub mod source_binder; | 23 | pub mod source_binder; |
26 | 24 | ||
25 | mod krate; | ||
26 | mod module; | ||
27 | mod function; | ||
28 | |||
27 | use std::ops::Index; | 29 | use std::ops::Index; |
28 | 30 | ||
29 | use ra_syntax::{SyntaxNodeRef, SyntaxNode}; | 31 | use ra_syntax::{SyntaxNodeRef, SyntaxNode}; |
@@ -36,6 +38,7 @@ use crate::{ | |||
36 | 38 | ||
37 | pub use self::{ | 39 | pub use self::{ |
38 | path::{Path, PathKind}, | 40 | path::{Path, PathKind}, |
41 | krate::Crate, | ||
39 | module::{Module, ModuleId, Problem, nameres::ItemMap}, | 42 | module::{Module, ModuleId, Problem, nameres::ItemMap}, |
40 | function::{Function, FnScopes}, | 43 | function::{Function, FnScopes}, |
41 | }; | 44 | }; |
diff --git a/crates/ra_hir/src/mock.rs b/crates/ra_hir/src/mock.rs index e855df11d..b7193c4f3 100644 --- a/crates/ra_hir/src/mock.rs +++ b/crates/ra_hir/src/mock.rs | |||
@@ -2,7 +2,7 @@ use std::sync::Arc; | |||
2 | 2 | ||
3 | use parking_lot::Mutex; | 3 | use parking_lot::Mutex; |
4 | use salsa::{self, Database}; | 4 | use salsa::{self, Database}; |
5 | use ra_db::{LocationIntener, BaseDatabase, FilePosition, mock::FileMap, FileId, WORKSPACE}; | 5 | use ra_db::{LocationIntener, BaseDatabase, FilePosition, mock::FileMap, FileId, WORKSPACE, CrateGraph}; |
6 | use relative_path::RelativePathBuf; | 6 | use relative_path::RelativePathBuf; |
7 | use test_utils::{parse_fixture, CURSOR_MARKER, extract_offset}; | 7 | use test_utils::{parse_fixture, CURSOR_MARKER, extract_offset}; |
8 | 8 | ||
@@ -16,7 +16,24 @@ pub(crate) struct MockDatabase { | |||
16 | } | 16 | } |
17 | 17 | ||
18 | impl MockDatabase { | 18 | impl MockDatabase { |
19 | pub(crate) fn with_files(fixture: &str) -> (MockDatabase, FileMap) { | ||
20 | let (db, file_map, position) = MockDatabase::from_fixture(fixture); | ||
21 | assert!(position.is_none()); | ||
22 | (db, file_map) | ||
23 | } | ||
24 | |||
19 | pub(crate) fn with_position(fixture: &str) -> (MockDatabase, FilePosition) { | 25 | pub(crate) fn with_position(fixture: &str) -> (MockDatabase, FilePosition) { |
26 | let (db, _, position) = MockDatabase::from_fixture(fixture); | ||
27 | let position = position.expect("expected a marker ( <|> )"); | ||
28 | (db, position) | ||
29 | } | ||
30 | |||
31 | pub(crate) fn set_crate_graph(&mut self, crate_graph: CrateGraph) { | ||
32 | self.query_mut(ra_db::CrateGraphQuery) | ||
33 | .set((), Arc::new(crate_graph)); | ||
34 | } | ||
35 | |||
36 | fn from_fixture(fixture: &str) -> (MockDatabase, FileMap, Option<FilePosition>) { | ||
20 | let mut db = MockDatabase::default(); | 37 | let mut db = MockDatabase::default(); |
21 | 38 | ||
22 | let mut position = None; | 39 | let mut position = None; |
@@ -32,11 +49,10 @@ impl MockDatabase { | |||
32 | db.add_file(&mut file_map, &entry.meta, &entry.text); | 49 | db.add_file(&mut file_map, &entry.meta, &entry.text); |
33 | } | 50 | } |
34 | } | 51 | } |
35 | let position = position.expect("expected a marker (<|>)"); | 52 | let source_root = file_map.clone().into_source_root(); |
36 | let source_root = file_map.into_source_root(); | ||
37 | db.query_mut(ra_db::SourceRootQuery) | 53 | db.query_mut(ra_db::SourceRootQuery) |
38 | .set(WORKSPACE, Arc::new(source_root)); | 54 | .set(WORKSPACE, Arc::new(source_root)); |
39 | (db, position) | 55 | (db, file_map, position) |
40 | } | 56 | } |
41 | 57 | ||
42 | fn add_file(&mut self, file_map: &mut FileMap, path: &str, text: &str) -> FileId { | 58 | fn add_file(&mut self, file_map: &mut FileMap, path: &str, text: &str) -> FileId { |
diff --git a/crates/ra_hir/src/module.rs b/crates/ra_hir/src/module.rs index e7a49f83a..c6bb76d56 100644 --- a/crates/ra_hir/src/module.rs +++ b/crates/ra_hir/src/module.rs | |||
@@ -12,7 +12,7 @@ use ra_db::{SourceRootId, FileId, Cancelable}; | |||
12 | use relative_path::RelativePathBuf; | 12 | use relative_path::RelativePathBuf; |
13 | 13 | ||
14 | use crate::{ | 14 | use crate::{ |
15 | DefKind, DefLoc, DefId, Path, PathKind, HirDatabase, SourceItemId, SourceFileItemId, | 15 | DefKind, DefLoc, DefId, Path, PathKind, HirDatabase, SourceItemId, SourceFileItemId, Crate, |
16 | arena::{Arena, Id}, | 16 | arena::{Arena, Id}, |
17 | }; | 17 | }; |
18 | 18 | ||
@@ -64,6 +64,15 @@ impl Module { | |||
64 | }) | 64 | }) |
65 | } | 65 | } |
66 | 66 | ||
67 | /// Returns the crate this module is part of. | ||
68 | pub fn krate(&self, db: &impl HirDatabase) -> Option<Crate> { | ||
69 | let root_id = self.module_id.crate_root(&self.tree); | ||
70 | let file_id = root_id.source(&self.tree).file_id(); | ||
71 | let crate_graph = db.crate_graph(); | ||
72 | let crate_id = crate_graph.crate_id_for_crate_root(file_id)?; | ||
73 | Some(Crate::new(crate_id)) | ||
74 | } | ||
75 | |||
67 | /// The root of the tree this module is part of | 76 | /// The root of the tree this module is part of |
68 | pub fn crate_root(&self) -> Module { | 77 | pub fn crate_root(&self) -> Module { |
69 | let root_id = self.module_id.crate_root(&self.tree); | 78 | let root_id = self.module_id.crate_root(&self.tree); |
diff --git a/crates/ra_hir/src/module/nameres.rs b/crates/ra_hir/src/module/nameres.rs index 6511359d0..9afeade9e 100644 --- a/crates/ra_hir/src/module/nameres.rs +++ b/crates/ra_hir/src/module/nameres.rs | |||
@@ -31,7 +31,7 @@ use crate::{ | |||
31 | DefId, DefLoc, DefKind, | 31 | DefId, DefLoc, DefKind, |
32 | SourceItemId, SourceFileItemId, SourceFileItems, | 32 | SourceItemId, SourceFileItemId, SourceFileItems, |
33 | Path, PathKind, | 33 | Path, PathKind, |
34 | HirDatabase, | 34 | HirDatabase, Crate, |
35 | module::{ModuleId, ModuleTree}, | 35 | module::{ModuleId, ModuleTree}, |
36 | }; | 36 | }; |
37 | 37 | ||
@@ -200,34 +200,63 @@ impl ModuleItem { | |||
200 | } | 200 | } |
201 | 201 | ||
202 | pub(crate) struct Resolver<'a, DB> { | 202 | pub(crate) struct Resolver<'a, DB> { |
203 | pub(crate) db: &'a DB, | 203 | db: &'a DB, |
204 | pub(crate) input: &'a FxHashMap<ModuleId, Arc<InputModuleItems>>, | 204 | input: &'a FxHashMap<ModuleId, Arc<InputModuleItems>>, |
205 | pub(crate) source_root: SourceRootId, | 205 | source_root: SourceRootId, |
206 | pub(crate) module_tree: Arc<ModuleTree>, | 206 | module_tree: Arc<ModuleTree>, |
207 | pub(crate) result: ItemMap, | 207 | result: ItemMap, |
208 | } | 208 | } |
209 | 209 | ||
210 | impl<'a, DB> Resolver<'a, DB> | 210 | impl<'a, DB> Resolver<'a, DB> |
211 | where | 211 | where |
212 | DB: HirDatabase, | 212 | DB: HirDatabase, |
213 | { | 213 | { |
214 | pub(crate) fn new( | ||
215 | db: &'a DB, | ||
216 | input: &'a FxHashMap<ModuleId, Arc<InputModuleItems>>, | ||
217 | source_root: SourceRootId, | ||
218 | module_tree: Arc<ModuleTree>, | ||
219 | ) -> Resolver<'a, DB> { | ||
220 | Resolver { | ||
221 | db, | ||
222 | input, | ||
223 | source_root, | ||
224 | module_tree, | ||
225 | result: ItemMap::default(), | ||
226 | } | ||
227 | } | ||
228 | |||
214 | pub(crate) fn resolve(mut self) -> Cancelable<ItemMap> { | 229 | pub(crate) fn resolve(mut self) -> Cancelable<ItemMap> { |
215 | for (&module_id, items) in self.input.iter() { | 230 | for (&module_id, items) in self.input.iter() { |
216 | self.populate_module(module_id, items) | 231 | self.populate_module(module_id, items)?; |
217 | } | 232 | } |
218 | 233 | ||
219 | for &module_id in self.input.keys() { | 234 | for &module_id in self.input.keys() { |
220 | self.db.check_canceled()?; | 235 | self.db.check_canceled()?; |
221 | self.resolve_imports(module_id); | 236 | self.resolve_imports(module_id)?; |
222 | } | 237 | } |
223 | Ok(self.result) | 238 | Ok(self.result) |
224 | } | 239 | } |
225 | 240 | ||
226 | fn populate_module(&mut self, module_id: ModuleId, input: &InputModuleItems) { | 241 | fn populate_module(&mut self, module_id: ModuleId, input: &InputModuleItems) -> Cancelable<()> { |
227 | let file_id = module_id.source(&self.module_tree).file_id(); | 242 | let file_id = module_id.source(&self.module_tree).file_id(); |
228 | 243 | ||
229 | let mut module_items = ModuleScope::default(); | 244 | let mut module_items = ModuleScope::default(); |
230 | 245 | ||
246 | // Populate extern crates prelude | ||
247 | { | ||
248 | let root_id = module_id.crate_root(&self.module_tree); | ||
249 | let file_id = root_id.source(&self.module_tree).file_id(); | ||
250 | let crate_graph = self.db.crate_graph(); | ||
251 | if let Some(crate_id) = crate_graph.crate_id_for_crate_root(file_id) { | ||
252 | let krate = Crate::new(crate_id); | ||
253 | for dep in krate.dependencies(self.db) { | ||
254 | if let Some(module) = dep.krate.root_module(self.db)? { | ||
255 | self.add_module_item(&mut module_items, dep.name, module.module_id); | ||
256 | } | ||
257 | } | ||
258 | }; | ||
259 | } | ||
231 | for import in input.imports.iter() { | 260 | for import in input.imports.iter() { |
232 | if let Some(name) = import.path.segments.iter().last() { | 261 | if let Some(name) = import.path.segments.iter().last() { |
233 | if let ImportKind::Named(import) = import.kind { | 262 | if let ImportKind::Named(import) = import.kind { |
@@ -241,10 +270,9 @@ where | |||
241 | } | 270 | } |
242 | } | 271 | } |
243 | } | 272 | } |
244 | 273 | // Populate explicitelly declared items, except modules | |
245 | for item in input.items.iter() { | 274 | for item in input.items.iter() { |
246 | if item.kind == MODULE { | 275 | if item.kind == MODULE { |
247 | // handle submodules separatelly | ||
248 | continue; | 276 | continue; |
249 | } | 277 | } |
250 | let def_loc = DefLoc { | 278 | let def_loc = DefLoc { |
@@ -264,45 +292,50 @@ where | |||
264 | module_items.items.insert(item.name.clone(), resolution); | 292 | module_items.items.insert(item.name.clone(), resolution); |
265 | } | 293 | } |
266 | 294 | ||
295 | // Populate modules | ||
267 | for (name, module_id) in module_id.children(&self.module_tree) { | 296 | for (name, module_id) in module_id.children(&self.module_tree) { |
268 | let def_loc = DefLoc { | 297 | self.add_module_item(&mut module_items, name, module_id); |
269 | kind: DefKind::Module, | ||
270 | source_root_id: self.source_root, | ||
271 | module_id, | ||
272 | source_item_id: module_id.source(&self.module_tree).0, | ||
273 | }; | ||
274 | let def_id = def_loc.id(self.db); | ||
275 | let resolution = Resolution { | ||
276 | def_id: Some(def_id), | ||
277 | import: None, | ||
278 | }; | ||
279 | module_items.items.insert(name, resolution); | ||
280 | } | 298 | } |
281 | 299 | ||
282 | self.result.per_module.insert(module_id, module_items); | 300 | self.result.per_module.insert(module_id, module_items); |
301 | Ok(()) | ||
283 | } | 302 | } |
284 | 303 | ||
285 | fn resolve_imports(&mut self, module_id: ModuleId) { | 304 | fn add_module_item(&self, module_items: &mut ModuleScope, name: SmolStr, module_id: ModuleId) { |
305 | let def_loc = DefLoc { | ||
306 | kind: DefKind::Module, | ||
307 | source_root_id: self.source_root, | ||
308 | module_id, | ||
309 | source_item_id: module_id.source(&self.module_tree).0, | ||
310 | }; | ||
311 | let def_id = def_loc.id(self.db); | ||
312 | let resolution = Resolution { | ||
313 | def_id: Some(def_id), | ||
314 | import: None, | ||
315 | }; | ||
316 | module_items.items.insert(name, resolution); | ||
317 | } | ||
318 | |||
319 | fn resolve_imports(&mut self, module_id: ModuleId) -> Cancelable<()> { | ||
286 | for import in self.input[&module_id].imports.iter() { | 320 | for import in self.input[&module_id].imports.iter() { |
287 | self.resolve_import(module_id, import); | 321 | self.resolve_import(module_id, import)?; |
288 | } | 322 | } |
323 | Ok(()) | ||
289 | } | 324 | } |
290 | 325 | ||
291 | fn resolve_import(&mut self, module_id: ModuleId, import: &Import) { | 326 | fn resolve_import(&mut self, module_id: ModuleId, import: &Import) -> Cancelable<()> { |
292 | let ptr = match import.kind { | 327 | let ptr = match import.kind { |
293 | ImportKind::Glob => return, | 328 | ImportKind::Glob => return Ok(()), |
294 | ImportKind::Named(ptr) => ptr, | 329 | ImportKind::Named(ptr) => ptr, |
295 | }; | 330 | }; |
296 | 331 | ||
297 | let mut curr = match import.path.kind { | 332 | let mut curr = match import.path.kind { |
298 | // TODO: handle extern crates | 333 | PathKind::Plain | PathKind::Self_ => module_id, |
299 | PathKind::Plain => return, | ||
300 | PathKind::Self_ => module_id, | ||
301 | PathKind::Super => { | 334 | PathKind::Super => { |
302 | match module_id.parent(&self.module_tree) { | 335 | match module_id.parent(&self.module_tree) { |
303 | Some(it) => it, | 336 | Some(it) => it, |
304 | // TODO: error | 337 | // TODO: error |
305 | None => return, | 338 | None => return Ok(()), |
306 | } | 339 | } |
307 | } | 340 | } |
308 | PathKind::Crate => module_id.crate_root(&self.module_tree), | 341 | PathKind::Crate => module_id.crate_root(&self.module_tree), |
@@ -312,10 +345,10 @@ where | |||
312 | let is_last = i == import.path.segments.len() - 1; | 345 | let is_last = i == import.path.segments.len() - 1; |
313 | 346 | ||
314 | let def_id = match self.result.per_module[&curr].items.get(name) { | 347 | let def_id = match self.result.per_module[&curr].items.get(name) { |
315 | None => return, | 348 | None => return Ok(()), |
316 | Some(res) => match res.def_id { | 349 | Some(res) => match res.def_id { |
317 | Some(it) => it, | 350 | Some(it) => it, |
318 | None => return, | 351 | None => return Ok(()), |
319 | }, | 352 | }, |
320 | }; | 353 | }; |
321 | 354 | ||
@@ -326,7 +359,7 @@ where | |||
326 | module_id, | 359 | module_id, |
327 | .. | 360 | .. |
328 | } => module_id, | 361 | } => module_id, |
329 | _ => return, | 362 | _ => return Ok(()), |
330 | } | 363 | } |
331 | } else { | 364 | } else { |
332 | self.update(module_id, |items| { | 365 | self.update(module_id, |items| { |
@@ -338,6 +371,7 @@ where | |||
338 | }) | 371 | }) |
339 | } | 372 | } |
340 | } | 373 | } |
374 | Ok(()) | ||
341 | } | 375 | } |
342 | 376 | ||
343 | fn update(&mut self, module_id: ModuleId, f: impl FnOnce(&mut ModuleScope)) { | 377 | fn update(&mut self, module_id: ModuleId, f: impl FnOnce(&mut ModuleScope)) { |
@@ -347,99 +381,4 @@ where | |||
347 | } | 381 | } |
348 | 382 | ||
349 | #[cfg(test)] | 383 | #[cfg(test)] |
350 | mod tests { | 384 | mod tests; |
351 | use std::sync::Arc; | ||
352 | |||
353 | use salsa::Database; | ||
354 | use ra_db::FilesDatabase; | ||
355 | use ra_syntax::SmolStr; | ||
356 | |||
357 | use crate::{ | ||
358 | self as hir, | ||
359 | db::HirDatabase, | ||
360 | mock::MockDatabase, | ||
361 | }; | ||
362 | |||
363 | fn item_map(fixture: &str) -> (Arc<hir::ItemMap>, hir::ModuleId) { | ||
364 | let (db, pos) = MockDatabase::with_position(fixture); | ||
365 | let source_root = db.file_source_root(pos.file_id); | ||
366 | let module = hir::source_binder::module_from_position(&db, pos) | ||
367 | .unwrap() | ||
368 | .unwrap(); | ||
369 | let module_id = module.module_id; | ||
370 | (db.item_map(source_root).unwrap(), module_id) | ||
371 | } | ||
372 | |||
373 | #[test] | ||
374 | fn test_item_map() { | ||
375 | let (item_map, module_id) = item_map( | ||
376 | " | ||
377 | //- /lib.rs | ||
378 | mod foo; | ||
379 | |||
380 | use crate::foo::bar::Baz; | ||
381 | <|> | ||
382 | |||
383 | //- /foo/mod.rs | ||
384 | pub mod bar; | ||
385 | |||
386 | //- /foo/bar.rs | ||
387 | pub struct Baz; | ||
388 | ", | ||
389 | ); | ||
390 | let name = SmolStr::from("Baz"); | ||
391 | let resolution = &item_map.per_module[&module_id].items[&name]; | ||
392 | assert!(resolution.def_id.is_some()); | ||
393 | } | ||
394 | |||
395 | #[test] | ||
396 | fn typing_inside_a_function_should_not_invalidate_item_map() { | ||
397 | let (mut db, pos) = MockDatabase::with_position( | ||
398 | " | ||
399 | //- /lib.rs | ||
400 | mod foo;<|> | ||
401 | |||
402 | use crate::foo::bar::Baz; | ||
403 | |||
404 | fn foo() -> i32 { | ||
405 | 1 + 1 | ||
406 | } | ||
407 | //- /foo/mod.rs | ||
408 | pub mod bar; | ||
409 | |||
410 | //- /foo/bar.rs | ||
411 | pub struct Baz; | ||
412 | ", | ||
413 | ); | ||
414 | let source_root = db.file_source_root(pos.file_id); | ||
415 | { | ||
416 | let events = db.log_executed(|| { | ||
417 | db.item_map(source_root).unwrap(); | ||
418 | }); | ||
419 | assert!(format!("{:?}", events).contains("item_map")) | ||
420 | } | ||
421 | |||
422 | let new_text = " | ||
423 | mod foo; | ||
424 | |||
425 | use crate::foo::bar::Baz; | ||
426 | |||
427 | fn foo() -> i32 { 92 } | ||
428 | " | ||
429 | .to_string(); | ||
430 | |||
431 | db.query_mut(ra_db::FileTextQuery) | ||
432 | .set(pos.file_id, Arc::new(new_text)); | ||
433 | |||
434 | { | ||
435 | let events = db.log_executed(|| { | ||
436 | db.item_map(source_root).unwrap(); | ||
437 | }); | ||
438 | assert!( | ||
439 | !format!("{:?}", events).contains("_item_map"), | ||
440 | "{:#?}", | ||
441 | events | ||
442 | ) | ||
443 | } | ||
444 | } | ||
445 | } | ||
diff --git a/crates/ra_hir/src/module/nameres/tests.rs b/crates/ra_hir/src/module/nameres/tests.rs new file mode 100644 index 000000000..9ddc32dcd --- /dev/null +++ b/crates/ra_hir/src/module/nameres/tests.rs | |||
@@ -0,0 +1,127 @@ | |||
1 | use std::sync::Arc; | ||
2 | |||
3 | use salsa::Database; | ||
4 | use ra_db::{FilesDatabase, CrateGraph}; | ||
5 | use ra_syntax::SmolStr; | ||
6 | |||
7 | use crate::{ | ||
8 | self as hir, | ||
9 | db::HirDatabase, | ||
10 | mock::MockDatabase, | ||
11 | }; | ||
12 | |||
13 | fn item_map(fixture: &str) -> (Arc<hir::ItemMap>, hir::ModuleId) { | ||
14 | let (db, pos) = MockDatabase::with_position(fixture); | ||
15 | let source_root = db.file_source_root(pos.file_id); | ||
16 | let module = hir::source_binder::module_from_position(&db, pos) | ||
17 | .unwrap() | ||
18 | .unwrap(); | ||
19 | let module_id = module.module_id; | ||
20 | (db.item_map(source_root).unwrap(), module_id) | ||
21 | } | ||
22 | |||
23 | #[test] | ||
24 | fn item_map_smoke_test() { | ||
25 | let (item_map, module_id) = item_map( | ||
26 | " | ||
27 | //- /lib.rs | ||
28 | mod foo; | ||
29 | |||
30 | use crate::foo::bar::Baz; | ||
31 | <|> | ||
32 | |||
33 | //- /foo/mod.rs | ||
34 | pub mod bar; | ||
35 | |||
36 | //- /foo/bar.rs | ||
37 | pub struct Baz; | ||
38 | ", | ||
39 | ); | ||
40 | let name = SmolStr::from("Baz"); | ||
41 | let resolution = &item_map.per_module[&module_id].items[&name]; | ||
42 | assert!(resolution.def_id.is_some()); | ||
43 | } | ||
44 | |||
45 | #[test] | ||
46 | fn item_map_across_crates() { | ||
47 | let (mut db, files) = MockDatabase::with_files( | ||
48 | " | ||
49 | //- /main.rs | ||
50 | use test_crate::Baz; | ||
51 | |||
52 | //- /lib.rs | ||
53 | pub struct Baz; | ||
54 | ", | ||
55 | ); | ||
56 | let main_id = files.file_id("/main.rs"); | ||
57 | let lib_id = files.file_id("/lib.rs"); | ||
58 | |||
59 | let mut crate_graph = CrateGraph::default(); | ||
60 | let main_crate = crate_graph.add_crate_root(main_id); | ||
61 | let lib_crate = crate_graph.add_crate_root(lib_id); | ||
62 | crate_graph.add_dep(main_crate, "test_crate".into(), lib_crate); | ||
63 | |||
64 | db.set_crate_graph(crate_graph); | ||
65 | |||
66 | let source_root = db.file_source_root(main_id); | ||
67 | let module = hir::source_binder::module_from_file_id(&db, main_id) | ||
68 | .unwrap() | ||
69 | .unwrap(); | ||
70 | let module_id = module.module_id; | ||
71 | let item_map = db.item_map(source_root).unwrap(); | ||
72 | |||
73 | let name = SmolStr::from("Baz"); | ||
74 | let resolution = &item_map.per_module[&module_id].items[&name]; | ||
75 | assert!(resolution.def_id.is_some()); | ||
76 | } | ||
77 | |||
78 | #[test] | ||
79 | fn typing_inside_a_function_should_not_invalidate_item_map() { | ||
80 | let (mut db, pos) = MockDatabase::with_position( | ||
81 | " | ||
82 | //- /lib.rs | ||
83 | mod foo;<|> | ||
84 | |||
85 | use crate::foo::bar::Baz; | ||
86 | |||
87 | fn foo() -> i32 { | ||
88 | 1 + 1 | ||
89 | } | ||
90 | //- /foo/mod.rs | ||
91 | pub mod bar; | ||
92 | |||
93 | //- /foo/bar.rs | ||
94 | pub struct Baz; | ||
95 | ", | ||
96 | ); | ||
97 | let source_root = db.file_source_root(pos.file_id); | ||
98 | { | ||
99 | let events = db.log_executed(|| { | ||
100 | db.item_map(source_root).unwrap(); | ||
101 | }); | ||
102 | assert!(format!("{:?}", events).contains("item_map")) | ||
103 | } | ||
104 | |||
105 | let new_text = " | ||
106 | mod foo; | ||
107 | |||
108 | use crate::foo::bar::Baz; | ||
109 | |||
110 | fn foo() -> i32 { 92 } | ||
111 | " | ||
112 | .to_string(); | ||
113 | |||
114 | db.query_mut(ra_db::FileTextQuery) | ||
115 | .set(pos.file_id, Arc::new(new_text)); | ||
116 | |||
117 | { | ||
118 | let events = db.log_executed(|| { | ||
119 | db.item_map(source_root).unwrap(); | ||
120 | }); | ||
121 | assert!( | ||
122 | !format!("{:?}", events).contains("_item_map"), | ||
123 | "{:#?}", | ||
124 | events | ||
125 | ) | ||
126 | } | ||
127 | } | ||
diff --git a/crates/ra_hir/src/query_definitions.rs b/crates/ra_hir/src/query_definitions.rs index bb4457d07..37c4f9e4f 100644 --- a/crates/ra_hir/src/query_definitions.rs +++ b/crates/ra_hir/src/query_definitions.rs | |||
@@ -141,13 +141,8 @@ pub(super) fn item_map( | |||
141 | Ok((id, items)) | 141 | Ok((id, items)) |
142 | }) | 142 | }) |
143 | .collect::<Cancelable<FxHashMap<_, _>>>()?; | 143 | .collect::<Cancelable<FxHashMap<_, _>>>()?; |
144 | let resolver = Resolver { | 144 | |
145 | db: db, | 145 | let resolver = Resolver::new(db, &input, source_root, module_tree); |
146 | input: &input, | ||
147 | source_root, | ||
148 | module_tree, | ||
149 | result: ItemMap::default(), | ||
150 | }; | ||
151 | let res = resolver.resolve()?; | 146 | let res = resolver.resolve()?; |
152 | let elapsed = start.elapsed(); | 147 | let elapsed = start.elapsed(); |
153 | log::info!("item_map: {:?}", elapsed); | 148 | log::info!("item_map: {:?}", elapsed); |