aboutsummaryrefslogtreecommitdiff
path: root/crates/hir_def/src/nameres
diff options
context:
space:
mode:
Diffstat (limited to 'crates/hir_def/src/nameres')
-rw-r--r--crates/hir_def/src/nameres/collector.rs27
-rw-r--r--crates/hir_def/src/nameres/path_resolution.rs63
-rw-r--r--crates/hir_def/src/nameres/tests.rs62
-rw-r--r--crates/hir_def/src/nameres/tests/block.rs26
-rw-r--r--crates/hir_def/src/nameres/tests/diagnostics.rs16
5 files changed, 144 insertions, 50 deletions
diff --git a/crates/hir_def/src/nameres/collector.rs b/crates/hir_def/src/nameres/collector.rs
index adfcf879a..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
44const GLOB_RECURSION_LIMIT: usize = 100; 44const 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
@@ -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 82528b792..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
13use std::iter::successors;
14
15use base_db::Edition; 13use base_db::Edition;
14use hir_expand::name;
16use hir_expand::name::Name; 15use hir_expand::name::Name;
17use test_utils::mark; 16use 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
64impl DefMap { 63impl 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 &current_map.parent { 132 match &current_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
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
9use std::sync::Arc; 9use std::sync::Arc;
10 10
11use base_db::{fixture::WithFixture, SourceDatabase}; 11use base_db::{fixture::WithFixture, FilePosition, SourceDatabase};
12use expect_test::{expect, Expect}; 12use expect_test::{expect, Expect};
13use hir_expand::db::AstDatabase; 13use syntax::AstNode;
14use test_utils::mark; 14use test_utils::mark;
15 15
16use crate::{db::DefDatabase, nameres::*, test_db::TestDB}; 16use crate::{db::DefDatabase, nameres::*, test_db::TestDB, Lookup};
17 17
18fn compute_crate_def_map(ra_fixture: &str) -> Arc<DefMap> { 18fn 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
24fn compute_block_def_map(ra_fixture: &str) -> Arc<DefMap> { 24fn 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
40fn 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
36fn check(ra_fixture: &str, expect: Expect) { 80fn 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]
100fn super_imports() {
101 check_at(
102 r#"
103mod module {
104 fn f() {
105 use super::Struct;
106 $0
107 }
108}
109
110struct 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]
65fn 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]
65fn dedup_unresolved_import_from_unresolved_crate() { 81fn dedup_unresolved_import_from_unresolved_crate() {
66 check_diagnostics( 82 check_diagnostics(
67 r" 83 r"