diff options
Diffstat (limited to 'crates/hir_def/src/nameres')
-rw-r--r-- | crates/hir_def/src/nameres/collector.rs | 29 | ||||
-rw-r--r-- | crates/hir_def/src/nameres/path_resolution.rs | 67 | ||||
-rw-r--r-- | crates/hir_def/src/nameres/tests.rs | 62 | ||||
-rw-r--r-- | crates/hir_def/src/nameres/tests/block.rs | 26 | ||||
-rw-r--r-- | crates/hir_def/src/nameres/tests/diagnostics.rs | 16 |
5 files changed, 147 insertions, 53 deletions
diff --git a/crates/hir_def/src/nameres/collector.rs b/crates/hir_def/src/nameres/collector.rs index cd68efbe6..393170b32 100644 --- a/crates/hir_def/src/nameres/collector.rs +++ b/crates/hir_def/src/nameres/collector.rs | |||
@@ -37,8 +37,8 @@ use crate::{ | |||
37 | per_ns::PerNs, | 37 | per_ns::PerNs, |
38 | visibility::{RawVisibility, Visibility}, | 38 | visibility::{RawVisibility, Visibility}, |
39 | AdtId, AsMacroCall, AstId, AstIdWithPath, ConstLoc, ContainerId, EnumLoc, EnumVariantId, | 39 | AdtId, AsMacroCall, AstId, AstIdWithPath, ConstLoc, ContainerId, EnumLoc, EnumVariantId, |
40 | FunctionLoc, ImplLoc, Intern, LocalModuleId, ModuleDefId, ModuleId, StaticLoc, StructLoc, | 40 | FunctionLoc, ImplLoc, Intern, LocalModuleId, ModuleDefId, StaticLoc, StructLoc, TraitLoc, |
41 | TraitLoc, TypeAliasLoc, UnionLoc, | 41 | TypeAliasLoc, UnionLoc, |
42 | }; | 42 | }; |
43 | 43 | ||
44 | const GLOB_RECURSION_LIMIT: usize = 100; | 44 | const GLOB_RECURSION_LIMIT: usize = 100; |
@@ -56,10 +56,9 @@ pub(super) fn collect_defs( | |||
56 | for dep in &crate_graph[def_map.krate].dependencies { | 56 | for dep in &crate_graph[def_map.krate].dependencies { |
57 | log::debug!("crate dep {:?} -> {:?}", dep.name, dep.crate_id); | 57 | log::debug!("crate dep {:?} -> {:?}", dep.name, dep.crate_id); |
58 | let dep_def_map = db.crate_def_map(dep.crate_id); | 58 | let dep_def_map = db.crate_def_map(dep.crate_id); |
59 | def_map.extern_prelude.insert( | 59 | def_map |
60 | dep.as_name(), | 60 | .extern_prelude |
61 | ModuleId { krate: dep.crate_id, local_id: dep_def_map.root }.into(), | 61 | .insert(dep.as_name(), dep_def_map.module_id(dep_def_map.root).into()); |
62 | ); | ||
63 | 62 | ||
64 | // look for the prelude | 63 | // look for the prelude |
65 | // If the dependency defines a prelude, we overwrite an already defined | 64 | // If the dependency defines a prelude, we overwrite an already defined |
@@ -332,11 +331,9 @@ impl DefCollector<'_> { | |||
332 | // exported in type/value namespace. This function reduces the visibility of all items | 331 | // exported in type/value namespace. This function reduces the visibility of all items |
333 | // in the crate root that aren't proc macros. | 332 | // in the crate root that aren't proc macros. |
334 | let root = self.def_map.root; | 333 | let root = self.def_map.root; |
334 | let module_id = self.def_map.module_id(root); | ||
335 | let root = &mut self.def_map.modules[root]; | 335 | let root = &mut self.def_map.modules[root]; |
336 | root.scope.censor_non_proc_macros(ModuleId { | 336 | root.scope.censor_non_proc_macros(module_id); |
337 | krate: self.def_map.krate, | ||
338 | local_id: self.def_map.root, | ||
339 | }); | ||
340 | } | 337 | } |
341 | } | 338 | } |
342 | 339 | ||
@@ -578,7 +575,7 @@ impl DefCollector<'_> { | |||
578 | } else if m.krate != self.def_map.krate { | 575 | } else if m.krate != self.def_map.krate { |
579 | mark::hit!(glob_across_crates); | 576 | mark::hit!(glob_across_crates); |
580 | // glob import from other crate => we can just import everything once | 577 | // glob import from other crate => we can just import everything once |
581 | let item_map = self.db.crate_def_map(m.krate); | 578 | let item_map = m.def_map(self.db); |
582 | let scope = &item_map[m.local_id].scope; | 579 | let scope = &item_map[m.local_id].scope; |
583 | 580 | ||
584 | // Module scoped macros is included | 581 | // Module scoped macros is included |
@@ -1029,8 +1026,7 @@ impl ModCollector<'_, '_> { | |||
1029 | continue; | 1026 | continue; |
1030 | } | 1027 | } |
1031 | } | 1028 | } |
1032 | let module = | 1029 | let module = self.def_collector.def_map.module_id(self.module_id); |
1033 | ModuleId { krate: self.def_collector.def_map.krate, local_id: self.module_id }; | ||
1034 | let container = ContainerId::ModuleId(module); | 1030 | let container = ContainerId::ModuleId(module); |
1035 | 1031 | ||
1036 | let mut def = None; | 1032 | let mut def = None; |
@@ -1097,10 +1093,7 @@ impl ModCollector<'_, '_> { | |||
1097 | } | 1093 | } |
1098 | } | 1094 | } |
1099 | ModItem::Impl(imp) => { | 1095 | ModItem::Impl(imp) => { |
1100 | let module = ModuleId { | 1096 | let module = self.def_collector.def_map.module_id(self.module_id); |
1101 | krate: self.def_collector.def_map.krate, | ||
1102 | local_id: self.module_id, | ||
1103 | }; | ||
1104 | let container = ContainerId::ModuleId(module); | 1097 | let container = ContainerId::ModuleId(module); |
1105 | let impl_id = ImplLoc { container, id: ItemTreeId::new(self.file_id, imp) } | 1098 | let impl_id = ImplLoc { container, id: ItemTreeId::new(self.file_id, imp) } |
1106 | .intern(self.def_collector.db); | 1099 | .intern(self.def_collector.db); |
@@ -1343,7 +1336,7 @@ impl ModCollector<'_, '_> { | |||
1343 | modules[res].scope.define_legacy_macro(name, mac) | 1336 | modules[res].scope.define_legacy_macro(name, mac) |
1344 | } | 1337 | } |
1345 | modules[self.module_id].children.insert(name.clone(), res); | 1338 | modules[self.module_id].children.insert(name.clone(), res); |
1346 | let module = ModuleId { krate: self.def_collector.def_map.krate, local_id: res }; | 1339 | let module = self.def_collector.def_map.module_id(res); |
1347 | let def: ModuleDefId = module.into(); | 1340 | let def: ModuleDefId = module.into(); |
1348 | self.def_collector.def_map.modules[self.module_id].scope.define_def(def); | 1341 | self.def_collector.def_map.modules[self.module_id].scope.define_def(def); |
1349 | self.def_collector.update( | 1342 | self.def_collector.update( |
diff --git a/crates/hir_def/src/nameres/path_resolution.rs b/crates/hir_def/src/nameres/path_resolution.rs index ec90f4e65..419e465ed 100644 --- a/crates/hir_def/src/nameres/path_resolution.rs +++ b/crates/hir_def/src/nameres/path_resolution.rs | |||
@@ -10,9 +10,8 @@ | |||
10 | //! | 10 | //! |
11 | //! `ReachedFixedPoint` signals about this. | 11 | //! `ReachedFixedPoint` signals about this. |
12 | 12 | ||
13 | use std::iter::successors; | ||
14 | |||
15 | use base_db::Edition; | 13 | use base_db::Edition; |
14 | use hir_expand::name; | ||
16 | use hir_expand::name::Name; | 15 | use hir_expand::name::Name; |
17 | use test_utils::mark; | 16 | use test_utils::mark; |
18 | 17 | ||
@@ -23,7 +22,7 @@ use crate::{ | |||
23 | path::{ModPath, PathKind}, | 22 | path::{ModPath, PathKind}, |
24 | per_ns::PerNs, | 23 | per_ns::PerNs, |
25 | visibility::{RawVisibility, Visibility}, | 24 | visibility::{RawVisibility, Visibility}, |
26 | AdtId, CrateId, EnumVariantId, LocalModuleId, ModuleDefId, ModuleId, | 25 | AdtId, CrateId, EnumVariantId, LocalModuleId, ModuleDefId, |
27 | }; | 26 | }; |
28 | 27 | ||
29 | #[derive(Debug, Clone, Copy, PartialEq, Eq)] | 28 | #[derive(Debug, Clone, Copy, PartialEq, Eq)] |
@@ -63,6 +62,10 @@ impl ResolvePathResult { | |||
63 | 62 | ||
64 | impl DefMap { | 63 | impl DefMap { |
65 | pub(super) fn resolve_name_in_extern_prelude(&self, name: &Name) -> PerNs { | 64 | pub(super) fn resolve_name_in_extern_prelude(&self, name: &Name) -> PerNs { |
65 | if name == &name!(self) { | ||
66 | mark::hit!(extern_crate_self_as); | ||
67 | return PerNs::types(self.module_id(self.root).into(), Visibility::Public); | ||
68 | } | ||
66 | self.extern_prelude | 69 | self.extern_prelude |
67 | .get(name) | 70 | .get(name) |
68 | .map_or(PerNs::none(), |&it| PerNs::types(it, Visibility::Public)) | 71 | .map_or(PerNs::none(), |&it| PerNs::types(it, Visibility::Public)) |
@@ -126,8 +129,8 @@ impl DefMap { | |||
126 | result.krate = result.krate.or(new.krate); | 129 | result.krate = result.krate.or(new.krate); |
127 | result.segment_index = result.segment_index.min(new.segment_index); | 130 | result.segment_index = result.segment_index.min(new.segment_index); |
128 | 131 | ||
129 | match ¤t_map.parent { | 132 | match ¤t_map.block { |
130 | Some(map) => current_map = map, | 133 | Some(block) => current_map = &block.parent, |
131 | None => return result, | 134 | None => return result, |
132 | } | 135 | } |
133 | } | 136 | } |
@@ -146,21 +149,15 @@ impl DefMap { | |||
146 | PathKind::DollarCrate(krate) => { | 149 | PathKind::DollarCrate(krate) => { |
147 | if krate == self.krate { | 150 | if krate == self.krate { |
148 | mark::hit!(macro_dollar_crate_self); | 151 | mark::hit!(macro_dollar_crate_self); |
149 | PerNs::types( | 152 | PerNs::types(self.module_id(self.root).into(), Visibility::Public) |
150 | ModuleId { krate: self.krate, local_id: self.root }.into(), | ||
151 | Visibility::Public, | ||
152 | ) | ||
153 | } else { | 153 | } else { |
154 | let def_map = db.crate_def_map(krate); | 154 | let def_map = db.crate_def_map(krate); |
155 | let module = ModuleId { krate, local_id: def_map.root }; | 155 | let module = def_map.module_id(def_map.root); |
156 | mark::hit!(macro_dollar_crate_other); | 156 | mark::hit!(macro_dollar_crate_other); |
157 | PerNs::types(module.into(), Visibility::Public) | 157 | PerNs::types(module.into(), Visibility::Public) |
158 | } | 158 | } |
159 | } | 159 | } |
160 | PathKind::Crate => PerNs::types( | 160 | PathKind::Crate => PerNs::types(self.module_id(self.root).into(), Visibility::Public), |
161 | ModuleId { krate: self.krate, local_id: self.root }.into(), | ||
162 | Visibility::Public, | ||
163 | ), | ||
164 | // plain import or absolute path in 2015: crate-relative with | 161 | // plain import or absolute path in 2015: crate-relative with |
165 | // fallback to extern prelude (with the simplification in | 162 | // fallback to extern prelude (with the simplification in |
166 | // rust-lang/rust#57745) | 163 | // rust-lang/rust#57745) |
@@ -194,17 +191,35 @@ impl DefMap { | |||
194 | self.resolve_name_in_module(db, original_module, &segment, prefer_module) | 191 | self.resolve_name_in_module(db, original_module, &segment, prefer_module) |
195 | } | 192 | } |
196 | PathKind::Super(lvl) => { | 193 | PathKind::Super(lvl) => { |
197 | let m = successors(Some(original_module), |m| self.modules[*m].parent) | 194 | let mut module = original_module; |
198 | .nth(lvl as usize); | 195 | for i in 0..lvl { |
199 | if let Some(local_id) = m { | 196 | match self.modules[module].parent { |
200 | PerNs::types( | 197 | Some(it) => module = it, |
201 | ModuleId { krate: self.krate, local_id }.into(), | 198 | None => match &self.block { |
202 | Visibility::Public, | 199 | Some(block) => { |
203 | ) | 200 | // Look up remaining path in parent `DefMap` |
204 | } else { | 201 | let new_path = ModPath { |
205 | log::debug!("super path in root module"); | 202 | kind: PathKind::Super(lvl - i), |
206 | return ResolvePathResult::empty(ReachedFixedPoint::Yes); | 203 | segments: path.segments.clone(), |
204 | }; | ||
205 | log::debug!("`super` path: {} -> {} in parent map", path, new_path); | ||
206 | return block.parent.resolve_path_fp_with_macro( | ||
207 | db, | ||
208 | mode, | ||
209 | block.parent_module, | ||
210 | &new_path, | ||
211 | shadow, | ||
212 | ); | ||
213 | } | ||
214 | None => { | ||
215 | log::debug!("super path in root module"); | ||
216 | return ResolvePathResult::empty(ReachedFixedPoint::Yes); | ||
217 | } | ||
218 | }, | ||
219 | } | ||
207 | } | 220 | } |
221 | |||
222 | PerNs::types(self.module_id(module).into(), Visibility::Public) | ||
208 | } | 223 | } |
209 | PathKind::Abs => { | 224 | PathKind::Abs => { |
210 | // 2018-style absolute path -- only extern prelude | 225 | // 2018-style absolute path -- only extern prelude |
@@ -243,7 +258,7 @@ impl DefMap { | |||
243 | kind: PathKind::Super(0), | 258 | kind: PathKind::Super(0), |
244 | }; | 259 | }; |
245 | log::debug!("resolving {:?} in other crate", path); | 260 | log::debug!("resolving {:?} in other crate", path); |
246 | let defp_map = db.crate_def_map(module.krate); | 261 | let defp_map = module.def_map(db); |
247 | let (def, s) = defp_map.resolve_path(db, module.local_id, &path, shadow); | 262 | let (def, s) = defp_map.resolve_path(db, module.local_id, &path, shadow); |
248 | return ResolvePathResult::with( | 263 | return ResolvePathResult::with( |
249 | def, | 264 | def, |
@@ -356,7 +371,7 @@ impl DefMap { | |||
356 | self | 371 | self |
357 | } else { | 372 | } else { |
358 | // Extend lifetime | 373 | // Extend lifetime |
359 | keep = db.crate_def_map(prelude.krate); | 374 | keep = prelude.def_map(db); |
360 | &keep | 375 | &keep |
361 | }; | 376 | }; |
362 | def_map[prelude.local_id].scope.get(name) | 377 | def_map[prelude.local_id].scope.get(name) |
diff --git a/crates/hir_def/src/nameres/tests.rs b/crates/hir_def/src/nameres/tests.rs index 73e3a4702..b36d0b59b 100644 --- a/crates/hir_def/src/nameres/tests.rs +++ b/crates/hir_def/src/nameres/tests.rs | |||
@@ -8,12 +8,12 @@ mod block; | |||
8 | 8 | ||
9 | use std::sync::Arc; | 9 | use std::sync::Arc; |
10 | 10 | ||
11 | use base_db::{fixture::WithFixture, SourceDatabase}; | 11 | use base_db::{fixture::WithFixture, FilePosition, SourceDatabase}; |
12 | use expect_test::{expect, Expect}; | 12 | use expect_test::{expect, Expect}; |
13 | use hir_expand::db::AstDatabase; | 13 | use syntax::AstNode; |
14 | use test_utils::mark; | 14 | use test_utils::mark; |
15 | 15 | ||
16 | use crate::{db::DefDatabase, nameres::*, test_db::TestDB}; | 16 | use crate::{db::DefDatabase, nameres::*, test_db::TestDB, Lookup}; |
17 | 17 | ||
18 | fn compute_crate_def_map(ra_fixture: &str) -> Arc<DefMap> { | 18 | fn compute_crate_def_map(ra_fixture: &str) -> Arc<DefMap> { |
19 | let db = TestDB::with_files(ra_fixture); | 19 | let db = TestDB::with_files(ra_fixture); |
@@ -23,14 +23,58 @@ fn compute_crate_def_map(ra_fixture: &str) -> Arc<DefMap> { | |||
23 | 23 | ||
24 | fn compute_block_def_map(ra_fixture: &str) -> Arc<DefMap> { | 24 | fn compute_block_def_map(ra_fixture: &str) -> Arc<DefMap> { |
25 | let (db, position) = TestDB::with_position(ra_fixture); | 25 | let (db, position) = TestDB::with_position(ra_fixture); |
26 | |||
27 | // FIXME: perhaps we should make this use body lowering tests instead? | ||
28 | |||
26 | let module = db.module_for_file(position.file_id); | 29 | let module = db.module_for_file(position.file_id); |
27 | let ast_map = db.ast_id_map(position.file_id.into()); | 30 | let mut def_map = db.crate_def_map(module.krate); |
28 | let ast = db.parse(position.file_id); | 31 | while let Some(new_def_map) = descend_def_map_at_position(&db, position, def_map.clone()) { |
29 | let block: ast::BlockExpr = | 32 | def_map = new_def_map; |
30 | syntax::algo::find_node_at_offset(&ast.syntax_node(), position.offset).unwrap(); | 33 | } |
31 | let block_id = ast_map.ast_id(&block); | 34 | |
35 | // FIXME: select the right module, not the root | ||
36 | |||
37 | def_map | ||
38 | } | ||
39 | |||
40 | fn descend_def_map_at_position( | ||
41 | db: &dyn DefDatabase, | ||
42 | position: FilePosition, | ||
43 | def_map: Arc<DefMap>, | ||
44 | ) -> Option<Arc<DefMap>> { | ||
45 | for (local_id, module_data) in def_map.modules() { | ||
46 | let mod_def = module_data.origin.definition_source(db); | ||
47 | let ast_map = db.ast_id_map(mod_def.file_id); | ||
48 | let item_tree = db.item_tree(mod_def.file_id); | ||
49 | let root = db.parse_or_expand(mod_def.file_id).unwrap(); | ||
50 | for item in module_data.scope.declarations() { | ||
51 | match item { | ||
52 | ModuleDefId::FunctionId(it) => { | ||
53 | // Technically blocks can be inside any type (due to arrays and const generics), | ||
54 | // and also in const/static initializers. For tests we only really care about | ||
55 | // functions though. | ||
56 | |||
57 | let ast = ast_map.get(item_tree[it.lookup(db).id.value].ast_id).to_node(&root); | ||
58 | |||
59 | if ast.syntax().text_range().contains(position.offset) { | ||
60 | // Cursor inside function, descend into its body's DefMap. | ||
61 | // Note that we don't handle block *expressions* inside function bodies. | ||
62 | let ast_map = db.ast_id_map(position.file_id.into()); | ||
63 | let ast_id = ast_map.ast_id(&ast.body().unwrap()); | ||
64 | let block = BlockLoc { | ||
65 | ast_id: InFile::new(position.file_id.into(), ast_id), | ||
66 | module: def_map.module_id(local_id), | ||
67 | }; | ||
68 | let block_id = db.intern_block(block); | ||
69 | return Some(db.block_def_map(block_id)); | ||
70 | } | ||
71 | } | ||
72 | _ => continue, | ||
73 | } | ||
74 | } | ||
75 | } | ||
32 | 76 | ||
33 | db.block_def_map(module.krate, InFile::new(position.file_id.into(), block_id)) | 77 | None |
34 | } | 78 | } |
35 | 79 | ||
36 | fn check(ra_fixture: &str, expect: Expect) { | 80 | fn check(ra_fixture: &str, expect: Expect) { |
diff --git a/crates/hir_def/src/nameres/tests/block.rs b/crates/hir_def/src/nameres/tests/block.rs index 01d6326a7..470ca593e 100644 --- a/crates/hir_def/src/nameres/tests/block.rs +++ b/crates/hir_def/src/nameres/tests/block.rs | |||
@@ -95,3 +95,29 @@ fn outer() { | |||
95 | "#]], | 95 | "#]], |
96 | ); | 96 | ); |
97 | } | 97 | } |
98 | |||
99 | #[test] | ||
100 | fn super_imports() { | ||
101 | check_at( | ||
102 | r#" | ||
103 | mod module { | ||
104 | fn f() { | ||
105 | use super::Struct; | ||
106 | $0 | ||
107 | } | ||
108 | } | ||
109 | |||
110 | struct Struct {} | ||
111 | "#, | ||
112 | expect![[r#" | ||
113 | block scope | ||
114 | Struct: t | ||
115 | crate | ||
116 | Struct: t | ||
117 | module: t | ||
118 | |||
119 | crate::module | ||
120 | f: v | ||
121 | "#]], | ||
122 | ); | ||
123 | } | ||
diff --git a/crates/hir_def/src/nameres/tests/diagnostics.rs b/crates/hir_def/src/nameres/tests/diagnostics.rs index 58d69d3c6..e8e72e5ef 100644 --- a/crates/hir_def/src/nameres/tests/diagnostics.rs +++ b/crates/hir_def/src/nameres/tests/diagnostics.rs | |||
@@ -62,6 +62,22 @@ fn unresolved_extern_crate() { | |||
62 | } | 62 | } |
63 | 63 | ||
64 | #[test] | 64 | #[test] |
65 | fn extern_crate_self_as() { | ||
66 | mark::check!(extern_crate_self_as); | ||
67 | check_diagnostics( | ||
68 | r" | ||
69 | //- /lib.rs | ||
70 | extern crate doesnotexist; | ||
71 | //^^^^^^^^^^^^^^^^^^^^^^^^^^ unresolved extern crate | ||
72 | // Should not error. | ||
73 | extern crate self as foo; | ||
74 | struct Foo; | ||
75 | use foo::Foo as Bar; | ||
76 | ", | ||
77 | ); | ||
78 | } | ||
79 | |||
80 | #[test] | ||
65 | fn dedup_unresolved_import_from_unresolved_crate() { | 81 | fn dedup_unresolved_import_from_unresolved_crate() { |
66 | check_diagnostics( | 82 | check_diagnostics( |
67 | r" | 83 | r" |