diff options
Diffstat (limited to 'crates/ra_hir/src')
-rw-r--r-- | crates/ra_hir/src/nameres.rs | 47 | ||||
-rw-r--r-- | crates/ra_hir/src/nameres/tests.rs | 31 |
2 files changed, 62 insertions, 16 deletions
diff --git a/crates/ra_hir/src/nameres.rs b/crates/ra_hir/src/nameres.rs index 749fd604e..4181bf4b8 100644 --- a/crates/ra_hir/src/nameres.rs +++ b/crates/ra_hir/src/nameres.rs | |||
@@ -16,7 +16,7 @@ | |||
16 | //! structure itself is modified. | 16 | //! structure itself is modified. |
17 | use std::sync::Arc; | 17 | use std::sync::Arc; |
18 | 18 | ||
19 | use rustc_hash::FxHashMap; | 19 | use rustc_hash::{FxHashMap, FxHashSet}; |
20 | use ra_syntax::{ | 20 | use ra_syntax::{ |
21 | TextRange, | 21 | TextRange, |
22 | SyntaxKind::{self, *}, | 22 | SyntaxKind::{self, *}, |
@@ -295,6 +295,7 @@ pub(crate) struct Resolver<'a, DB> { | |||
295 | input: &'a FxHashMap<ModuleId, Arc<InputModuleItems>>, | 295 | input: &'a FxHashMap<ModuleId, Arc<InputModuleItems>>, |
296 | source_root: SourceRootId, | 296 | source_root: SourceRootId, |
297 | module_tree: Arc<ModuleTree>, | 297 | module_tree: Arc<ModuleTree>, |
298 | processed_imports: FxHashSet<(ModuleId, usize)>, | ||
298 | result: ItemMap, | 299 | result: ItemMap, |
299 | } | 300 | } |
300 | 301 | ||
@@ -313,6 +314,7 @@ where | |||
313 | input, | 314 | input, |
314 | source_root, | 315 | source_root, |
315 | module_tree, | 316 | module_tree, |
317 | processed_imports: FxHashSet::default(), | ||
316 | result: ItemMap::default(), | 318 | result: ItemMap::default(), |
317 | } | 319 | } |
318 | } | 320 | } |
@@ -322,9 +324,16 @@ where | |||
322 | self.populate_module(module_id, Arc::clone(items))?; | 324 | self.populate_module(module_id, Arc::clone(items))?; |
323 | } | 325 | } |
324 | 326 | ||
325 | for &module_id in self.input.keys() { | 327 | loop { |
326 | self.db.check_canceled()?; | 328 | let processed_imports_count = self.processed_imports.len(); |
327 | self.resolve_imports(module_id)?; | 329 | for &module_id in self.input.keys() { |
330 | self.db.check_canceled()?; | ||
331 | self.resolve_imports(module_id)?; | ||
332 | } | ||
333 | if processed_imports_count == self.processed_imports.len() { | ||
334 | // no new imports resolved | ||
335 | break; | ||
336 | } | ||
328 | } | 337 | } |
329 | Ok(self.result) | 338 | Ok(self.result) |
330 | } | 339 | } |
@@ -418,15 +427,21 @@ where | |||
418 | } | 427 | } |
419 | 428 | ||
420 | fn resolve_imports(&mut self, module_id: ModuleId) -> Cancelable<()> { | 429 | fn resolve_imports(&mut self, module_id: ModuleId) -> Cancelable<()> { |
421 | for import in self.input[&module_id].imports.iter() { | 430 | for (i, import) in self.input[&module_id].imports.iter().enumerate() { |
422 | self.resolve_import(module_id, import)?; | 431 | if self.processed_imports.contains(&(module_id, i)) { |
432 | // already done | ||
433 | continue; | ||
434 | } | ||
435 | if self.resolve_import(module_id, import)? { | ||
436 | self.processed_imports.insert((module_id, i)); | ||
437 | } | ||
423 | } | 438 | } |
424 | Ok(()) | 439 | Ok(()) |
425 | } | 440 | } |
426 | 441 | ||
427 | fn resolve_import(&mut self, module_id: ModuleId, import: &Import) -> Cancelable<()> { | 442 | fn resolve_import(&mut self, module_id: ModuleId, import: &Import) -> Cancelable<bool> { |
428 | let ptr = match import.kind { | 443 | let ptr = match import.kind { |
429 | ImportKind::Glob => return Ok(()), | 444 | ImportKind::Glob => return Ok(false), |
430 | ImportKind::Named(ptr) => ptr, | 445 | ImportKind::Named(ptr) => ptr, |
431 | }; | 446 | }; |
432 | 447 | ||
@@ -436,7 +451,7 @@ where | |||
436 | match module_id.parent(&self.module_tree) { | 451 | match module_id.parent(&self.module_tree) { |
437 | Some(it) => it, | 452 | Some(it) => it, |
438 | // TODO: error | 453 | // TODO: error |
439 | None => return Ok(()), | 454 | None => return Ok(true), // this can't suddenly resolve if we just resolve some other imports |
440 | } | 455 | } |
441 | } | 456 | } |
442 | PathKind::Crate => module_id.crate_root(&self.module_tree), | 457 | PathKind::Crate => module_id.crate_root(&self.module_tree), |
@@ -447,14 +462,14 @@ where | |||
447 | 462 | ||
448 | let def_id = match self.result.per_module[&curr].items.get(name) { | 463 | let def_id = match self.result.per_module[&curr].items.get(name) { |
449 | Some(res) if !res.def_id.is_none() => res.def_id, | 464 | Some(res) if !res.def_id.is_none() => res.def_id, |
450 | _ => return Ok(()), | 465 | _ => return Ok(false), |
451 | }; | 466 | }; |
452 | 467 | ||
453 | if !is_last { | 468 | if !is_last { |
454 | let type_def_id = if let Some(d) = def_id.take(Namespace::Types) { | 469 | let type_def_id = if let Some(d) = def_id.take(Namespace::Types) { |
455 | d | 470 | d |
456 | } else { | 471 | } else { |
457 | return Ok(()); | 472 | return Ok(false); |
458 | }; | 473 | }; |
459 | curr = match type_def_id.loc(self.db) { | 474 | curr = match type_def_id.loc(self.db) { |
460 | DefLoc { | 475 | DefLoc { |
@@ -479,12 +494,14 @@ where | |||
479 | import: Some(ptr), | 494 | import: Some(ptr), |
480 | }; | 495 | }; |
481 | items.items.insert(name.clone(), res); | 496 | items.items.insert(name.clone(), res); |
482 | }) | 497 | }); |
498 | return Ok(true); | ||
499 | } else { | ||
500 | return Ok(false); | ||
483 | } | 501 | } |
484 | return Ok(()); | ||
485 | } | 502 | } |
486 | } | 503 | } |
487 | _ => return Ok(()), | 504 | _ => return Ok(true), // this resolved to a non-module, so the path won't ever resolve |
488 | } | 505 | } |
489 | } else { | 506 | } else { |
490 | self.update(module_id, |items| { | 507 | self.update(module_id, |items| { |
@@ -496,7 +513,7 @@ where | |||
496 | }) | 513 | }) |
497 | } | 514 | } |
498 | } | 515 | } |
499 | Ok(()) | 516 | Ok(true) |
500 | } | 517 | } |
501 | 518 | ||
502 | fn update(&mut self, module_id: ModuleId, f: impl FnOnce(&mut ModuleScope)) { | 519 | fn update(&mut self, module_id: ModuleId, f: impl FnOnce(&mut ModuleScope)) { |
diff --git a/crates/ra_hir/src/nameres/tests.rs b/crates/ra_hir/src/nameres/tests.rs index dcbe65aec..04faec4fb 100644 --- a/crates/ra_hir/src/nameres/tests.rs +++ b/crates/ra_hir/src/nameres/tests.rs | |||
@@ -35,7 +35,7 @@ fn check_module_item_map(map: &hir::ItemMap, module_id: hir::ModuleId, expected: | |||
35 | .map(|it| it.trim()) | 35 | .map(|it| it.trim()) |
36 | .collect::<Vec<_>>() | 36 | .collect::<Vec<_>>() |
37 | .join("\n"); | 37 | .join("\n"); |
38 | assert_eq_text!(&actual, &expected); | 38 | assert_eq_text!(&expected, &actual); |
39 | 39 | ||
40 | fn dump_resolution(resolution: &hir::Resolution) -> &'static str { | 40 | fn dump_resolution(resolution: &hir::Resolution) -> &'static str { |
41 | match ( | 41 | match ( |
@@ -78,6 +78,35 @@ fn item_map_smoke_test() { | |||
78 | } | 78 | } |
79 | 79 | ||
80 | #[test] | 80 | #[test] |
81 | fn re_exports() { | ||
82 | let (item_map, module_id) = item_map( | ||
83 | " | ||
84 | //- /lib.rs | ||
85 | mod foo; | ||
86 | |||
87 | use self::foo::Baz; | ||
88 | <|> | ||
89 | |||
90 | //- /foo/mod.rs | ||
91 | pub mod bar; | ||
92 | |||
93 | pub use self::bar::Baz; | ||
94 | |||
95 | //- /foo/bar.rs | ||
96 | pub struct Baz; | ||
97 | ", | ||
98 | ); | ||
99 | check_module_item_map( | ||
100 | &item_map, | ||
101 | module_id, | ||
102 | " | ||
103 | Baz: t v | ||
104 | foo: t | ||
105 | ", | ||
106 | ); | ||
107 | } | ||
108 | |||
109 | #[test] | ||
81 | fn item_map_contains_items_from_expansions() { | 110 | fn item_map_contains_items_from_expansions() { |
82 | let (item_map, module_id) = item_map( | 111 | let (item_map, module_id) = item_map( |
83 | " | 112 | " |