diff options
-rw-r--r-- | crates/hir_def/src/find_path.rs | 101 |
1 files changed, 91 insertions, 10 deletions
diff --git a/crates/hir_def/src/find_path.rs b/crates/hir_def/src/find_path.rs index aa2c6e04e..5e2a711b8 100644 --- a/crates/hir_def/src/find_path.rs +++ b/crates/hir_def/src/find_path.rs | |||
@@ -13,8 +13,6 @@ use crate::{ | |||
13 | ModuleDefId, ModuleId, | 13 | ModuleDefId, ModuleId, |
14 | }; | 14 | }; |
15 | 15 | ||
16 | // FIXME: handle local items | ||
17 | |||
18 | /// Find a path that can be used to refer to a certain item. This can depend on | 16 | /// Find a path that can be used to refer to a certain item. This can depend on |
19 | /// *from where* you're referring to the item, hence the `from` parameter. | 17 | /// *from where* you're referring to the item, hence the `from` parameter. |
20 | pub fn find_path(db: &dyn DefDatabase, item: ItemInNs, from: ModuleId) -> Option<ModPath> { | 18 | pub fn find_path(db: &dyn DefDatabase, item: ItemInNs, from: ModuleId) -> Option<ModPath> { |
@@ -107,9 +105,9 @@ fn find_path_inner( | |||
107 | 105 | ||
108 | // - if the item is already in scope, return the name under which it is | 106 | // - if the item is already in scope, return the name under which it is |
109 | let def_map = from.def_map(db); | 107 | let def_map = from.def_map(db); |
110 | let from_scope: &crate::item_scope::ItemScope = &def_map[from.local_id].scope; | 108 | let scope_name = def_map.with_ancestor_maps(db, from.local_id, &mut |def_map, local_id| { |
111 | let scope_name = | 109 | def_map[local_id].scope.name_of(item).map(|(name, _)| name.clone()) |
112 | if let Some((name, _)) = from_scope.name_of(item) { Some(name.clone()) } else { None }; | 110 | }); |
113 | if prefixed.is_none() && scope_name.is_some() { | 111 | if prefixed.is_none() && scope_name.is_some() { |
114 | return scope_name | 112 | return scope_name |
115 | .map(|scope_name| ModPath::from_segments(PathKind::Plain, vec![scope_name])); | 113 | .map(|scope_name| ModPath::from_segments(PathKind::Plain, vec![scope_name])); |
@@ -117,7 +115,7 @@ fn find_path_inner( | |||
117 | 115 | ||
118 | // - if the item is the crate root, return `crate` | 116 | // - if the item is the crate root, return `crate` |
119 | let root = def_map.module_id(def_map.root()); | 117 | let root = def_map.module_id(def_map.root()); |
120 | if item == ItemInNs::Types(ModuleDefId::ModuleId(root)) { | 118 | if item == ItemInNs::Types(ModuleDefId::ModuleId(root)) && def_map.block_id().is_none() { |
121 | return Some(ModPath::from_segments(PathKind::Crate, Vec::new())); | 119 | return Some(ModPath::from_segments(PathKind::Crate, Vec::new())); |
122 | } | 120 | } |
123 | 121 | ||
@@ -230,7 +228,12 @@ fn find_path_inner( | |||
230 | } | 228 | } |
231 | } | 229 | } |
232 | 230 | ||
233 | if let Some(prefix) = prefixed.map(PrefixKind::prefix) { | 231 | if let Some(mut prefix) = prefixed.map(PrefixKind::prefix) { |
232 | if matches!(prefix, PathKind::Crate | PathKind::Super(0)) && def_map.block_id().is_some() { | ||
233 | // Inner items cannot be referred to via `crate::` or `self::` paths. | ||
234 | prefix = PathKind::Plain; | ||
235 | } | ||
236 | |||
234 | best_path.or_else(|| { | 237 | best_path.or_else(|| { |
235 | scope_name.map(|scope_name| ModPath::from_segments(prefix, vec![scope_name])) | 238 | scope_name.map(|scope_name| ModPath::from_segments(prefix, vec![scope_name])) |
236 | }) | 239 | }) |
@@ -358,14 +361,14 @@ mod tests { | |||
358 | /// module the cursor is in. | 361 | /// module the cursor is in. |
359 | fn check_found_path_(ra_fixture: &str, path: &str, prefix_kind: Option<PrefixKind>) { | 362 | fn check_found_path_(ra_fixture: &str, path: &str, prefix_kind: Option<PrefixKind>) { |
360 | let (db, pos) = TestDB::with_position(ra_fixture); | 363 | let (db, pos) = TestDB::with_position(ra_fixture); |
361 | let module = db.module_for_file(pos.file_id); | 364 | let module = db.module_at_position(pos); |
362 | let parsed_path_file = syntax::SourceFile::parse(&format!("use {};", path)); | 365 | let parsed_path_file = syntax::SourceFile::parse(&format!("use {};", path)); |
363 | let ast_path = | 366 | let ast_path = |
364 | parsed_path_file.syntax_node().descendants().find_map(syntax::ast::Path::cast).unwrap(); | 367 | parsed_path_file.syntax_node().descendants().find_map(syntax::ast::Path::cast).unwrap(); |
365 | let mod_path = ModPath::from_src(ast_path, &Hygiene::new_unhygienic()).unwrap(); | 368 | let mod_path = ModPath::from_src(ast_path, &Hygiene::new_unhygienic()).unwrap(); |
366 | 369 | ||
367 | let crate_def_map = module.def_map(&db); | 370 | let def_map = module.def_map(&db); |
368 | let resolved = crate_def_map | 371 | let resolved = def_map |
369 | .resolve_path( | 372 | .resolve_path( |
370 | &db, | 373 | &db, |
371 | module.local_id, | 374 | module.local_id, |
@@ -788,4 +791,82 @@ mod tests { | |||
788 | check_found_path(code, "u8", "u8", "u8", "u8"); | 791 | check_found_path(code, "u8", "u8", "u8", "u8"); |
789 | check_found_path(code, "u16", "u16", "u16", "u16"); | 792 | check_found_path(code, "u16", "u16", "u16", "u16"); |
790 | } | 793 | } |
794 | |||
795 | #[test] | ||
796 | fn inner_items() { | ||
797 | check_found_path( | ||
798 | r#" | ||
799 | fn main() { | ||
800 | struct Inner {} | ||
801 | $0 | ||
802 | } | ||
803 | "#, | ||
804 | "Inner", | ||
805 | "Inner", | ||
806 | "Inner", | ||
807 | "Inner", | ||
808 | ); | ||
809 | } | ||
810 | |||
811 | #[test] | ||
812 | fn inner_items_from_outer_scope() { | ||
813 | check_found_path( | ||
814 | r#" | ||
815 | fn main() { | ||
816 | struct Struct {} | ||
817 | { | ||
818 | $0 | ||
819 | } | ||
820 | } | ||
821 | "#, | ||
822 | "Struct", | ||
823 | "Struct", | ||
824 | "Struct", | ||
825 | "Struct", | ||
826 | ); | ||
827 | } | ||
828 | |||
829 | #[test] | ||
830 | fn inner_items_from_inner_module() { | ||
831 | check_found_path( | ||
832 | r#" | ||
833 | fn main() { | ||
834 | mod module { | ||
835 | struct Struct {} | ||
836 | } | ||
837 | { | ||
838 | $0 | ||
839 | } | ||
840 | } | ||
841 | "#, | ||
842 | "module::Struct", | ||
843 | "module::Struct", | ||
844 | "module::Struct", | ||
845 | "module::Struct", | ||
846 | ); | ||
847 | } | ||
848 | |||
849 | #[test] | ||
850 | #[ignore] | ||
851 | fn inner_items_from_parent_module() { | ||
852 | // FIXME: ItemTree currently associates all inner items with `main`. Luckily, this sort of | ||
853 | // code is very rare, so this isn't terrible. | ||
854 | // To fix it, we should probably build dedicated `ItemTree`s for inner items, and not store | ||
855 | // them in the file's main ItemTree. This would also allow us to stop parsing function | ||
856 | // bodies when we only want to compute the crate's main DefMap. | ||
857 | check_found_path( | ||
858 | r#" | ||
859 | fn main() { | ||
860 | struct Struct {} | ||
861 | mod module { | ||
862 | $0 | ||
863 | } | ||
864 | } | ||
865 | "#, | ||
866 | "super::Struct", | ||
867 | "super::Struct", | ||
868 | "super::Struct", | ||
869 | "super::Struct", | ||
870 | ); | ||
871 | } | ||
791 | } | 872 | } |