diff options
author | Jonas Schievink <[email protected]> | 2021-03-01 18:36:34 +0000 |
---|---|---|
committer | Jonas Schievink <[email protected]> | 2021-03-01 18:39:17 +0000 |
commit | 0dcec31553f0fe42d7c18e6471655e8fa2258bfc (patch) | |
tree | 60c4eafe81bb517ed90ba027b60582b14d73d48a | |
parent | 5efb7f85eb24c7ad76136a7d81e8f8cffe213aa8 (diff) |
Fix `find_path` when inner items are present
-rw-r--r-- | crates/hir_def/src/find_path.rs | 59 | ||||
-rw-r--r-- | crates/hir_def/src/item_scope.rs | 22 | ||||
-rw-r--r-- | crates/hir_def/src/lib.rs | 23 | ||||
-rw-r--r-- | crates/hir_def/src/nameres.rs | 12 |
4 files changed, 88 insertions, 28 deletions
diff --git a/crates/hir_def/src/find_path.rs b/crates/hir_def/src/find_path.rs index 5e2a711b8..3e19a7702 100644 --- a/crates/hir_def/src/find_path.rs +++ b/crates/hir_def/src/find_path.rs | |||
@@ -1,5 +1,7 @@ | |||
1 | //! An algorithm to find a path to refer to a certain item. | 1 | //! An algorithm to find a path to refer to a certain item. |
2 | 2 | ||
3 | use std::iter; | ||
4 | |||
3 | use hir_expand::name::{known, AsName, Name}; | 5 | use hir_expand::name::{known, AsName, Name}; |
4 | use rustc_hash::FxHashSet; | 6 | use rustc_hash::FxHashSet; |
5 | use test_utils::mark; | 7 | use test_utils::mark; |
@@ -95,7 +97,7 @@ fn find_path_inner( | |||
95 | item: ItemInNs, | 97 | item: ItemInNs, |
96 | from: ModuleId, | 98 | from: ModuleId, |
97 | max_len: usize, | 99 | max_len: usize, |
98 | prefixed: Option<PrefixKind>, | 100 | mut prefixed: Option<PrefixKind>, |
99 | ) -> Option<ModPath> { | 101 | ) -> Option<ModPath> { |
100 | if max_len == 0 { | 102 | if max_len == 0 { |
101 | return None; | 103 | return None; |
@@ -114,8 +116,9 @@ fn find_path_inner( | |||
114 | } | 116 | } |
115 | 117 | ||
116 | // - if the item is the crate root, return `crate` | 118 | // - if the item is the crate root, return `crate` |
117 | let root = def_map.module_id(def_map.root()); | 119 | let root = def_map.crate_root(db); |
118 | if item == ItemInNs::Types(ModuleDefId::ModuleId(root)) && def_map.block_id().is_none() { | 120 | if item == ItemInNs::Types(ModuleDefId::ModuleId(root)) && def_map.block_id().is_none() { |
121 | // FIXME: the `block_id()` check should be unnecessary, but affects the result | ||
119 | return Some(ModPath::from_segments(PathKind::Crate, Vec::new())); | 122 | return Some(ModPath::from_segments(PathKind::Crate, Vec::new())); |
120 | } | 123 | } |
121 | 124 | ||
@@ -165,7 +168,7 @@ fn find_path_inner( | |||
165 | 168 | ||
166 | // - otherwise, look for modules containing (reexporting) it and import it from one of those | 169 | // - otherwise, look for modules containing (reexporting) it and import it from one of those |
167 | 170 | ||
168 | let crate_root = def_map.module_id(def_map.root()); | 171 | let crate_root = def_map.crate_root(db); |
169 | let crate_attrs = db.attrs(crate_root.into()); | 172 | let crate_attrs = db.attrs(crate_root.into()); |
170 | let prefer_no_std = crate_attrs.by_key("no_std").exists(); | 173 | let prefer_no_std = crate_attrs.by_key("no_std").exists(); |
171 | let mut best_path = None; | 174 | let mut best_path = None; |
@@ -228,12 +231,16 @@ fn find_path_inner( | |||
228 | } | 231 | } |
229 | } | 232 | } |
230 | 233 | ||
231 | if let Some(mut prefix) = prefixed.map(PrefixKind::prefix) { | 234 | // If the item is declared inside a block expression, don't use a prefix, as we don't handle |
232 | if matches!(prefix, PathKind::Crate | PathKind::Super(0)) && def_map.block_id().is_some() { | 235 | // that correctly (FIXME). |
233 | // Inner items cannot be referred to via `crate::` or `self::` paths. | 236 | if let Some(item_module) = item.as_module_def_id().and_then(|did| did.module(db)) { |
234 | prefix = PathKind::Plain; | 237 | if item_module.def_map(db).block_id().is_some() && prefixed.is_some() { |
238 | mark::hit!(prefixed_in_block_expression); | ||
239 | prefixed = Some(PrefixKind::Plain); | ||
235 | } | 240 | } |
241 | } | ||
236 | 242 | ||
243 | if let Some(prefix) = prefixed.map(PrefixKind::prefix) { | ||
237 | best_path.or_else(|| { | 244 | best_path.or_else(|| { |
238 | scope_name.map(|scope_name| ModPath::from_segments(prefix, vec![scope_name])) | 245 | scope_name.map(|scope_name| ModPath::from_segments(prefix, vec![scope_name])) |
239 | }) | 246 | }) |
@@ -285,12 +292,12 @@ fn find_local_import_locations( | |||
285 | let data = &def_map[from.local_id]; | 292 | let data = &def_map[from.local_id]; |
286 | let mut worklist = | 293 | let mut worklist = |
287 | data.children.values().map(|child| def_map.module_id(*child)).collect::<Vec<_>>(); | 294 | data.children.values().map(|child| def_map.module_id(*child)).collect::<Vec<_>>(); |
288 | let mut parent = data.parent; | 295 | for ancestor in iter::successors(from.containing_module(db), |m| m.containing_module(db)) { |
289 | while let Some(p) = parent { | 296 | worklist.push(ancestor); |
290 | worklist.push(def_map.module_id(p)); | ||
291 | parent = def_map[p].parent; | ||
292 | } | 297 | } |
293 | 298 | ||
299 | let def_map = def_map.crate_root(db).def_map(db); | ||
300 | |||
294 | let mut seen: FxHashSet<_> = FxHashSet::default(); | 301 | let mut seen: FxHashSet<_> = FxHashSet::default(); |
295 | 302 | ||
296 | let mut locations = Vec::new(); | 303 | let mut locations = Vec::new(); |
@@ -301,7 +308,14 @@ fn find_local_import_locations( | |||
301 | 308 | ||
302 | let ext_def_map; | 309 | let ext_def_map; |
303 | let data = if module.krate == from.krate { | 310 | let data = if module.krate == from.krate { |
304 | &def_map[module.local_id] | 311 | if module.block.is_some() { |
312 | // Re-query the block's DefMap | ||
313 | ext_def_map = module.def_map(db); | ||
314 | &ext_def_map[module.local_id] | ||
315 | } else { | ||
316 | // Reuse the root DefMap | ||
317 | &def_map[module.local_id] | ||
318 | } | ||
305 | } else { | 319 | } else { |
306 | // The crate might reexport a module defined in another crate. | 320 | // The crate might reexport a module defined in another crate. |
307 | ext_def_map = module.def_map(db); | 321 | ext_def_map = module.def_map(db); |
@@ -828,6 +842,7 @@ mod tests { | |||
828 | 842 | ||
829 | #[test] | 843 | #[test] |
830 | fn inner_items_from_inner_module() { | 844 | fn inner_items_from_inner_module() { |
845 | mark::check!(prefixed_in_block_expression); | ||
831 | check_found_path( | 846 | check_found_path( |
832 | r#" | 847 | r#" |
833 | fn main() { | 848 | fn main() { |
@@ -869,4 +884,24 @@ mod tests { | |||
869 | "super::Struct", | 884 | "super::Struct", |
870 | ); | 885 | ); |
871 | } | 886 | } |
887 | |||
888 | #[test] | ||
889 | fn outer_items_with_inner_items_present() { | ||
890 | check_found_path( | ||
891 | r#" | ||
892 | mod module { | ||
893 | pub struct CompleteMe; | ||
894 | } | ||
895 | |||
896 | fn main() { | ||
897 | fn inner() {} | ||
898 | $0 | ||
899 | } | ||
900 | "#, | ||
901 | "module::CompleteMe", | ||
902 | "module::CompleteMe", | ||
903 | "crate::module::CompleteMe", | ||
904 | "self::module::CompleteMe", | ||
905 | ) | ||
906 | } | ||
872 | } | 907 | } |
diff --git a/crates/hir_def/src/item_scope.rs b/crates/hir_def/src/item_scope.rs index ee46c3330..4e5daa2ff 100644 --- a/crates/hir_def/src/item_scope.rs +++ b/crates/hir_def/src/item_scope.rs | |||
@@ -12,8 +12,8 @@ use stdx::format_to; | |||
12 | use test_utils::mark; | 12 | use test_utils::mark; |
13 | 13 | ||
14 | use crate::{ | 14 | use crate::{ |
15 | db::DefDatabase, per_ns::PerNs, visibility::Visibility, AdtId, BuiltinType, HasModule, ImplId, | 15 | db::DefDatabase, per_ns::PerNs, visibility::Visibility, AdtId, BuiltinType, ImplId, |
16 | LocalModuleId, Lookup, MacroDefId, ModuleDefId, ModuleId, TraitId, | 16 | LocalModuleId, MacroDefId, ModuleDefId, ModuleId, TraitId, |
17 | }; | 17 | }; |
18 | 18 | ||
19 | #[derive(Copy, Clone)] | 19 | #[derive(Copy, Clone)] |
@@ -375,19 +375,9 @@ impl ItemInNs { | |||
375 | 375 | ||
376 | /// Returns the crate defining this item (or `None` if `self` is built-in). | 376 | /// Returns the crate defining this item (or `None` if `self` is built-in). |
377 | pub fn krate(&self, db: &dyn DefDatabase) -> Option<CrateId> { | 377 | pub fn krate(&self, db: &dyn DefDatabase) -> Option<CrateId> { |
378 | Some(match self { | 378 | match self { |
379 | ItemInNs::Types(did) | ItemInNs::Values(did) => match did { | 379 | ItemInNs::Types(did) | ItemInNs::Values(did) => did.module(db).map(|m| m.krate), |
380 | ModuleDefId::ModuleId(id) => id.krate, | 380 | ItemInNs::Macros(id) => Some(id.krate), |
381 | ModuleDefId::FunctionId(id) => id.lookup(db).module(db).krate, | 381 | } |
382 | ModuleDefId::AdtId(id) => id.module(db).krate, | ||
383 | ModuleDefId::EnumVariantId(id) => id.parent.lookup(db).container.module(db).krate, | ||
384 | ModuleDefId::ConstId(id) => id.lookup(db).container.module(db).krate, | ||
385 | ModuleDefId::StaticId(id) => id.lookup(db).container.module(db).krate, | ||
386 | ModuleDefId::TraitId(id) => id.lookup(db).container.module(db).krate, | ||
387 | ModuleDefId::TypeAliasId(id) => id.lookup(db).module(db).krate, | ||
388 | ModuleDefId::BuiltinType(_) => return None, | ||
389 | }, | ||
390 | ItemInNs::Macros(id) => return Some(id.krate), | ||
391 | }) | ||
392 | } | 382 | } |
393 | } | 383 | } |
diff --git a/crates/hir_def/src/lib.rs b/crates/hir_def/src/lib.rs index 6802bc250..4498d94bb 100644 --- a/crates/hir_def/src/lib.rs +++ b/crates/hir_def/src/lib.rs | |||
@@ -97,6 +97,10 @@ impl ModuleId { | |||
97 | pub fn krate(&self) -> CrateId { | 97 | pub fn krate(&self) -> CrateId { |
98 | self.krate | 98 | self.krate |
99 | } | 99 | } |
100 | |||
101 | pub fn containing_module(&self, db: &dyn db::DefDatabase) -> Option<ModuleId> { | ||
102 | self.def_map(db).containing_module(self.local_id) | ||
103 | } | ||
100 | } | 104 | } |
101 | 105 | ||
102 | /// An ID of a module, **local** to a specific crate | 106 | /// An ID of a module, **local** to a specific crate |
@@ -529,6 +533,25 @@ impl HasModule for StaticLoc { | |||
529 | } | 533 | } |
530 | } | 534 | } |
531 | 535 | ||
536 | impl ModuleDefId { | ||
537 | /// Returns the module containing `self` (or `self`, if `self` is itself a module). | ||
538 | /// | ||
539 | /// Returns `None` if `self` refers to a primitive type. | ||
540 | pub fn module(&self, db: &dyn db::DefDatabase) -> Option<ModuleId> { | ||
541 | Some(match self { | ||
542 | ModuleDefId::ModuleId(id) => *id, | ||
543 | ModuleDefId::FunctionId(id) => id.lookup(db).module(db), | ||
544 | ModuleDefId::AdtId(id) => id.module(db), | ||
545 | ModuleDefId::EnumVariantId(id) => id.parent.lookup(db).container.module(db), | ||
546 | ModuleDefId::ConstId(id) => id.lookup(db).container.module(db), | ||
547 | ModuleDefId::StaticId(id) => id.lookup(db).container.module(db), | ||
548 | ModuleDefId::TraitId(id) => id.lookup(db).container.module(db), | ||
549 | ModuleDefId::TypeAliasId(id) => id.lookup(db).module(db), | ||
550 | ModuleDefId::BuiltinType(_) => return None, | ||
551 | }) | ||
552 | } | ||
553 | } | ||
554 | |||
532 | impl AttrDefId { | 555 | impl AttrDefId { |
533 | pub fn krate(&self, db: &dyn db::DefDatabase) -> CrateId { | 556 | pub fn krate(&self, db: &dyn db::DefDatabase) -> CrateId { |
534 | match self { | 557 | match self { |
diff --git a/crates/hir_def/src/nameres.rs b/crates/hir_def/src/nameres.rs index 6a3456f2e..003d668ca 100644 --- a/crates/hir_def/src/nameres.rs +++ b/crates/hir_def/src/nameres.rs | |||
@@ -343,6 +343,18 @@ impl DefMap { | |||
343 | Some(self.block?.parent) | 343 | Some(self.block?.parent) |
344 | } | 344 | } |
345 | 345 | ||
346 | /// Returns the module containing `local_mod`, either the parent `mod`, or the module containing | ||
347 | /// the block, if `self` corresponds to a block expression. | ||
348 | pub fn containing_module(&self, local_mod: LocalModuleId) -> Option<ModuleId> { | ||
349 | match &self[local_mod].parent { | ||
350 | Some(parent) => Some(self.module_id(*parent)), | ||
351 | None => match &self.block { | ||
352 | Some(block) => Some(block.parent), | ||
353 | None => None, | ||
354 | }, | ||
355 | } | ||
356 | } | ||
357 | |||
346 | // FIXME: this can use some more human-readable format (ideally, an IR | 358 | // FIXME: this can use some more human-readable format (ideally, an IR |
347 | // even), as this should be a great debugging aid. | 359 | // even), as this should be a great debugging aid. |
348 | pub fn dump(&self, db: &dyn DefDatabase) -> String { | 360 | pub fn dump(&self, db: &dyn DefDatabase) -> String { |