diff options
Diffstat (limited to 'crates/hir_def/src/nameres')
-rw-r--r-- | crates/hir_def/src/nameres/collector.rs | 68 | ||||
-rw-r--r-- | crates/hir_def/src/nameres/path_resolution.rs | 41 | ||||
-rw-r--r-- | crates/hir_def/src/nameres/tests.rs | 22 | ||||
-rw-r--r-- | crates/hir_def/src/nameres/tests/block.rs | 97 |
4 files changed, 203 insertions, 25 deletions
diff --git a/crates/hir_def/src/nameres/collector.rs b/crates/hir_def/src/nameres/collector.rs index 0cd61698c..cd68efbe6 100644 --- a/crates/hir_def/src/nameres/collector.rs +++ b/crates/hir_def/src/nameres/collector.rs | |||
@@ -31,7 +31,7 @@ use crate::{ | |||
31 | }, | 31 | }, |
32 | nameres::{ | 32 | nameres::{ |
33 | diagnostics::DefDiagnostic, mod_resolution::ModDir, path_resolution::ReachedFixedPoint, | 33 | diagnostics::DefDiagnostic, mod_resolution::ModDir, path_resolution::ReachedFixedPoint, |
34 | BuiltinShadowMode, CrateDefMap, ModuleData, ModuleOrigin, ResolveMode, | 34 | BuiltinShadowMode, DefMap, ModuleData, ModuleOrigin, ResolveMode, |
35 | }, | 35 | }, |
36 | path::{ImportAlias, ModPath, PathKind}, | 36 | path::{ImportAlias, ModPath, PathKind}, |
37 | per_ns::PerNs, | 37 | per_ns::PerNs, |
@@ -45,7 +45,11 @@ const GLOB_RECURSION_LIMIT: usize = 100; | |||
45 | const EXPANSION_DEPTH_LIMIT: usize = 128; | 45 | const EXPANSION_DEPTH_LIMIT: usize = 128; |
46 | const FIXED_POINT_LIMIT: usize = 8192; | 46 | const FIXED_POINT_LIMIT: usize = 8192; |
47 | 47 | ||
48 | pub(super) fn collect_defs(db: &dyn DefDatabase, mut def_map: CrateDefMap) -> CrateDefMap { | 48 | pub(super) fn collect_defs( |
49 | db: &dyn DefDatabase, | ||
50 | mut def_map: DefMap, | ||
51 | block: Option<FileAstId<ast::BlockExpr>>, | ||
52 | ) -> DefMap { | ||
49 | let crate_graph = db.crate_graph(); | 53 | let crate_graph = db.crate_graph(); |
50 | 54 | ||
51 | // populate external prelude | 55 | // populate external prelude |
@@ -93,6 +97,14 @@ pub(super) fn collect_defs(db: &dyn DefDatabase, mut def_map: CrateDefMap) -> Cr | |||
93 | exports_proc_macros: false, | 97 | exports_proc_macros: false, |
94 | from_glob_import: Default::default(), | 98 | from_glob_import: Default::default(), |
95 | }; | 99 | }; |
100 | match block { | ||
101 | Some(block) => { | ||
102 | collector.seed_with_inner(block); | ||
103 | } | ||
104 | None => { | ||
105 | collector.seed_with_top_level(); | ||
106 | } | ||
107 | } | ||
96 | collector.collect(); | 108 | collector.collect(); |
97 | collector.finish() | 109 | collector.finish() |
98 | } | 110 | } |
@@ -210,7 +222,7 @@ struct DefData<'a> { | |||
210 | /// Walks the tree of module recursively | 222 | /// Walks the tree of module recursively |
211 | struct DefCollector<'a> { | 223 | struct DefCollector<'a> { |
212 | db: &'a dyn DefDatabase, | 224 | db: &'a dyn DefDatabase, |
213 | def_map: CrateDefMap, | 225 | def_map: DefMap, |
214 | glob_imports: FxHashMap<LocalModuleId, Vec<(LocalModuleId, Visibility)>>, | 226 | glob_imports: FxHashMap<LocalModuleId, Vec<(LocalModuleId, Visibility)>>, |
215 | unresolved_imports: Vec<ImportDirective>, | 227 | unresolved_imports: Vec<ImportDirective>, |
216 | resolved_imports: Vec<ImportDirective>, | 228 | resolved_imports: Vec<ImportDirective>, |
@@ -228,7 +240,7 @@ struct DefCollector<'a> { | |||
228 | } | 240 | } |
229 | 241 | ||
230 | impl DefCollector<'_> { | 242 | impl DefCollector<'_> { |
231 | fn collect(&mut self) { | 243 | fn seed_with_top_level(&mut self) { |
232 | let file_id = self.db.crate_graph()[self.def_map.krate].root_file_id; | 244 | let file_id = self.db.crate_graph()[self.def_map.krate].root_file_id; |
233 | let item_tree = self.db.item_tree(file_id.into()); | 245 | let item_tree = self.db.item_tree(file_id.into()); |
234 | let module_id = self.def_map.root; | 246 | let module_id = self.def_map.root; |
@@ -248,7 +260,31 @@ impl DefCollector<'_> { | |||
248 | } | 260 | } |
249 | .collect(item_tree.top_level_items()); | 261 | .collect(item_tree.top_level_items()); |
250 | } | 262 | } |
263 | } | ||
264 | |||
265 | fn seed_with_inner(&mut self, block: FileAstId<ast::BlockExpr>) { | ||
266 | let file_id = self.db.crate_graph()[self.def_map.krate].root_file_id; | ||
267 | let item_tree = self.db.item_tree(file_id.into()); | ||
268 | let module_id = self.def_map.root; | ||
269 | self.def_map.modules[module_id].origin = ModuleOrigin::CrateRoot { definition: file_id }; | ||
270 | if item_tree | ||
271 | .top_level_attrs(self.db, self.def_map.krate) | ||
272 | .cfg() | ||
273 | .map_or(true, |cfg| self.cfg_options.check(&cfg) != Some(false)) | ||
274 | { | ||
275 | ModCollector { | ||
276 | def_collector: &mut *self, | ||
277 | macro_depth: 0, | ||
278 | module_id, | ||
279 | file_id: file_id.into(), | ||
280 | item_tree: &item_tree, | ||
281 | mod_dir: ModDir::root(), | ||
282 | } | ||
283 | .collect(item_tree.inner_items_of_block(block)); | ||
284 | } | ||
285 | } | ||
251 | 286 | ||
287 | fn collect(&mut self) { | ||
252 | // main name resolution fixed-point loop. | 288 | // main name resolution fixed-point loop. |
253 | let mut i = 0; | 289 | let mut i = 0; |
254 | loop { | 290 | loop { |
@@ -859,7 +895,7 @@ impl DefCollector<'_> { | |||
859 | .collect(item_tree.top_level_items()); | 895 | .collect(item_tree.top_level_items()); |
860 | } | 896 | } |
861 | 897 | ||
862 | fn finish(mut self) -> CrateDefMap { | 898 | fn finish(mut self) -> DefMap { |
863 | // Emit diagnostics for all remaining unexpanded macros. | 899 | // Emit diagnostics for all remaining unexpanded macros. |
864 | 900 | ||
865 | for directive in &self.unexpanded_macros { | 901 | for directive in &self.unexpanded_macros { |
@@ -1470,11 +1506,10 @@ impl ModCollector<'_, '_> { | |||
1470 | mod tests { | 1506 | mod tests { |
1471 | use crate::{db::DefDatabase, test_db::TestDB}; | 1507 | use crate::{db::DefDatabase, test_db::TestDB}; |
1472 | use base_db::{fixture::WithFixture, SourceDatabase}; | 1508 | use base_db::{fixture::WithFixture, SourceDatabase}; |
1473 | use la_arena::Arena; | ||
1474 | 1509 | ||
1475 | use super::*; | 1510 | use super::*; |
1476 | 1511 | ||
1477 | fn do_collect_defs(db: &dyn DefDatabase, def_map: CrateDefMap) -> CrateDefMap { | 1512 | fn do_collect_defs(db: &dyn DefDatabase, def_map: DefMap) -> DefMap { |
1478 | let mut collector = DefCollector { | 1513 | let mut collector = DefCollector { |
1479 | db, | 1514 | db, |
1480 | def_map, | 1515 | def_map, |
@@ -1489,28 +1524,17 @@ mod tests { | |||
1489 | exports_proc_macros: false, | 1524 | exports_proc_macros: false, |
1490 | from_glob_import: Default::default(), | 1525 | from_glob_import: Default::default(), |
1491 | }; | 1526 | }; |
1527 | collector.seed_with_top_level(); | ||
1492 | collector.collect(); | 1528 | collector.collect(); |
1493 | collector.def_map | 1529 | collector.def_map |
1494 | } | 1530 | } |
1495 | 1531 | ||
1496 | fn do_resolve(code: &str) -> CrateDefMap { | 1532 | fn do_resolve(code: &str) -> DefMap { |
1497 | let (db, _file_id) = TestDB::with_single_file(&code); | 1533 | let (db, _file_id) = TestDB::with_single_file(&code); |
1498 | let krate = db.test_crate(); | 1534 | let krate = db.test_crate(); |
1499 | 1535 | ||
1500 | let def_map = { | 1536 | let edition = db.crate_graph()[krate].edition; |
1501 | let edition = db.crate_graph()[krate].edition; | 1537 | let def_map = DefMap::empty(krate, edition); |
1502 | let mut modules: Arena<ModuleData> = Arena::default(); | ||
1503 | let root = modules.alloc(ModuleData::default()); | ||
1504 | CrateDefMap { | ||
1505 | krate, | ||
1506 | edition, | ||
1507 | extern_prelude: FxHashMap::default(), | ||
1508 | prelude: None, | ||
1509 | root, | ||
1510 | modules, | ||
1511 | diagnostics: Vec::new(), | ||
1512 | } | ||
1513 | }; | ||
1514 | do_collect_defs(&db, def_map) | 1538 | do_collect_defs(&db, def_map) |
1515 | } | 1539 | } |
1516 | 1540 | ||
diff --git a/crates/hir_def/src/nameres/path_resolution.rs b/crates/hir_def/src/nameres/path_resolution.rs index 88e10574e..ec90f4e65 100644 --- a/crates/hir_def/src/nameres/path_resolution.rs +++ b/crates/hir_def/src/nameres/path_resolution.rs | |||
@@ -19,7 +19,7 @@ use test_utils::mark; | |||
19 | use crate::{ | 19 | use crate::{ |
20 | db::DefDatabase, | 20 | db::DefDatabase, |
21 | item_scope::BUILTIN_SCOPE, | 21 | item_scope::BUILTIN_SCOPE, |
22 | nameres::{BuiltinShadowMode, CrateDefMap}, | 22 | nameres::{BuiltinShadowMode, DefMap}, |
23 | path::{ModPath, PathKind}, | 23 | path::{ModPath, PathKind}, |
24 | per_ns::PerNs, | 24 | per_ns::PerNs, |
25 | visibility::{RawVisibility, Visibility}, | 25 | visibility::{RawVisibility, Visibility}, |
@@ -61,7 +61,7 @@ impl ResolvePathResult { | |||
61 | } | 61 | } |
62 | } | 62 | } |
63 | 63 | ||
64 | impl CrateDefMap { | 64 | impl DefMap { |
65 | pub(super) fn resolve_name_in_extern_prelude(&self, name: &Name) -> PerNs { | 65 | pub(super) fn resolve_name_in_extern_prelude(&self, name: &Name) -> PerNs { |
66 | self.extern_prelude | 66 | self.extern_prelude |
67 | .get(name) | 67 | .get(name) |
@@ -104,6 +104,43 @@ impl CrateDefMap { | |||
104 | path: &ModPath, | 104 | path: &ModPath, |
105 | shadow: BuiltinShadowMode, | 105 | shadow: BuiltinShadowMode, |
106 | ) -> ResolvePathResult { | 106 | ) -> ResolvePathResult { |
107 | let mut result = ResolvePathResult::empty(ReachedFixedPoint::No); | ||
108 | result.segment_index = Some(usize::max_value()); | ||
109 | |||
110 | let mut current_map = self; | ||
111 | loop { | ||
112 | let new = current_map.resolve_path_fp_with_macro_single( | ||
113 | db, | ||
114 | mode, | ||
115 | original_module, | ||
116 | path, | ||
117 | shadow, | ||
118 | ); | ||
119 | |||
120 | // Merge `new` into `result`. | ||
121 | result.resolved_def = result.resolved_def.or(new.resolved_def); | ||
122 | if result.reached_fixedpoint == ReachedFixedPoint::No { | ||
123 | result.reached_fixedpoint = new.reached_fixedpoint; | ||
124 | } | ||
125 | // FIXME: this doesn't seem right; what if the different namespace resolutions come from different crates? | ||
126 | result.krate = result.krate.or(new.krate); | ||
127 | result.segment_index = result.segment_index.min(new.segment_index); | ||
128 | |||
129 | match ¤t_map.parent { | ||
130 | Some(map) => current_map = map, | ||
131 | None => return result, | ||
132 | } | ||
133 | } | ||
134 | } | ||
135 | |||
136 | pub(super) fn resolve_path_fp_with_macro_single( | ||
137 | &self, | ||
138 | db: &dyn DefDatabase, | ||
139 | mode: ResolveMode, | ||
140 | original_module: LocalModuleId, | ||
141 | path: &ModPath, | ||
142 | shadow: BuiltinShadowMode, | ||
143 | ) -> ResolvePathResult { | ||
107 | let mut segments = path.segments.iter().enumerate(); | 144 | let mut segments = path.segments.iter().enumerate(); |
108 | let mut curr_per_ns: PerNs = match path.kind { | 145 | let mut curr_per_ns: PerNs = match path.kind { |
109 | PathKind::DollarCrate(krate) => { | 146 | PathKind::DollarCrate(krate) => { |
diff --git a/crates/hir_def/src/nameres/tests.rs b/crates/hir_def/src/nameres/tests.rs index c459fa66d..73e3a4702 100644 --- a/crates/hir_def/src/nameres/tests.rs +++ b/crates/hir_def/src/nameres/tests.rs | |||
@@ -4,27 +4,47 @@ mod macros; | |||
4 | mod mod_resolution; | 4 | mod mod_resolution; |
5 | mod diagnostics; | 5 | mod diagnostics; |
6 | mod primitives; | 6 | mod primitives; |
7 | mod block; | ||
7 | 8 | ||
8 | use std::sync::Arc; | 9 | use std::sync::Arc; |
9 | 10 | ||
10 | use base_db::{fixture::WithFixture, SourceDatabase}; | 11 | use base_db::{fixture::WithFixture, SourceDatabase}; |
11 | use expect_test::{expect, Expect}; | 12 | use expect_test::{expect, Expect}; |
13 | use hir_expand::db::AstDatabase; | ||
12 | use test_utils::mark; | 14 | use test_utils::mark; |
13 | 15 | ||
14 | use crate::{db::DefDatabase, nameres::*, test_db::TestDB}; | 16 | use crate::{db::DefDatabase, nameres::*, test_db::TestDB}; |
15 | 17 | ||
16 | fn compute_crate_def_map(ra_fixture: &str) -> Arc<CrateDefMap> { | 18 | fn compute_crate_def_map(ra_fixture: &str) -> Arc<DefMap> { |
17 | let db = TestDB::with_files(ra_fixture); | 19 | let db = TestDB::with_files(ra_fixture); |
18 | let krate = db.crate_graph().iter().next().unwrap(); | 20 | let krate = db.crate_graph().iter().next().unwrap(); |
19 | db.crate_def_map(krate) | 21 | db.crate_def_map(krate) |
20 | } | 22 | } |
21 | 23 | ||
24 | fn compute_block_def_map(ra_fixture: &str) -> Arc<DefMap> { | ||
25 | let (db, position) = TestDB::with_position(ra_fixture); | ||
26 | let module = db.module_for_file(position.file_id); | ||
27 | let ast_map = db.ast_id_map(position.file_id.into()); | ||
28 | let ast = db.parse(position.file_id); | ||
29 | let block: ast::BlockExpr = | ||
30 | syntax::algo::find_node_at_offset(&ast.syntax_node(), position.offset).unwrap(); | ||
31 | let block_id = ast_map.ast_id(&block); | ||
32 | |||
33 | db.block_def_map(module.krate, InFile::new(position.file_id.into(), block_id)) | ||
34 | } | ||
35 | |||
22 | fn check(ra_fixture: &str, expect: Expect) { | 36 | fn check(ra_fixture: &str, expect: Expect) { |
23 | let def_map = compute_crate_def_map(ra_fixture); | 37 | let def_map = compute_crate_def_map(ra_fixture); |
24 | let actual = def_map.dump(); | 38 | let actual = def_map.dump(); |
25 | expect.assert_eq(&actual); | 39 | expect.assert_eq(&actual); |
26 | } | 40 | } |
27 | 41 | ||
42 | fn check_at(ra_fixture: &str, expect: Expect) { | ||
43 | let def_map = compute_block_def_map(ra_fixture); | ||
44 | let actual = def_map.dump(); | ||
45 | expect.assert_eq(&actual); | ||
46 | } | ||
47 | |||
28 | #[test] | 48 | #[test] |
29 | fn crate_def_map_smoke_test() { | 49 | fn crate_def_map_smoke_test() { |
30 | check( | 50 | check( |
diff --git a/crates/hir_def/src/nameres/tests/block.rs b/crates/hir_def/src/nameres/tests/block.rs new file mode 100644 index 000000000..01d6326a7 --- /dev/null +++ b/crates/hir_def/src/nameres/tests/block.rs | |||
@@ -0,0 +1,97 @@ | |||
1 | use super::*; | ||
2 | |||
3 | #[test] | ||
4 | fn inner_item_smoke() { | ||
5 | check_at( | ||
6 | r#" | ||
7 | struct inner {} | ||
8 | fn outer() { | ||
9 | $0 | ||
10 | fn inner() {} | ||
11 | } | ||
12 | "#, | ||
13 | expect![[r#" | ||
14 | block scope | ||
15 | inner: v | ||
16 | crate | ||
17 | inner: t | ||
18 | outer: v | ||
19 | "#]], | ||
20 | ); | ||
21 | } | ||
22 | |||
23 | #[test] | ||
24 | fn use_from_crate() { | ||
25 | check_at( | ||
26 | r#" | ||
27 | struct Struct; | ||
28 | fn outer() { | ||
29 | use Struct; | ||
30 | use crate::Struct as CrateStruct; | ||
31 | use self::Struct as SelfStruct; | ||
32 | $0 | ||
33 | } | ||
34 | "#, | ||
35 | expect![[r#" | ||
36 | block scope | ||
37 | CrateStruct: t v | ||
38 | SelfStruct: t v | ||
39 | Struct: t v | ||
40 | crate | ||
41 | Struct: t v | ||
42 | outer: v | ||
43 | "#]], | ||
44 | ); | ||
45 | } | ||
46 | |||
47 | #[test] | ||
48 | fn merge_namespaces() { | ||
49 | check_at( | ||
50 | r#" | ||
51 | struct name {} | ||
52 | fn outer() { | ||
53 | fn name() {} | ||
54 | |||
55 | use name as imported; // should import both `name`s | ||
56 | |||
57 | $0 | ||
58 | } | ||
59 | "#, | ||
60 | expect![[r#" | ||
61 | block scope | ||
62 | imported: t v | ||
63 | name: v | ||
64 | crate | ||
65 | name: t | ||
66 | outer: v | ||
67 | "#]], | ||
68 | ); | ||
69 | } | ||
70 | |||
71 | #[test] | ||
72 | fn nested_blocks() { | ||
73 | check_at( | ||
74 | r#" | ||
75 | fn outer() { | ||
76 | struct inner1 {} | ||
77 | fn inner() { | ||
78 | use inner1; | ||
79 | use outer; | ||
80 | fn inner2() {} | ||
81 | $0 | ||
82 | } | ||
83 | } | ||
84 | "#, | ||
85 | expect![[r#" | ||
86 | block scope | ||
87 | inner1: t | ||
88 | inner2: v | ||
89 | outer: v | ||
90 | block scope | ||
91 | inner: v | ||
92 | inner1: t | ||
93 | crate | ||
94 | outer: v | ||
95 | "#]], | ||
96 | ); | ||
97 | } | ||