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/tests.rs68
-rw-r--r--crates/hir_def/src/nameres/tests/block.rs186
2 files changed, 252 insertions, 2 deletions
diff --git a/crates/hir_def/src/nameres/tests.rs b/crates/hir_def/src/nameres/tests.rs
index 723481c36..b36d0b59b 100644
--- a/crates/hir_def/src/nameres/tests.rs
+++ b/crates/hir_def/src/nameres/tests.rs
@@ -4,14 +4,16 @@ mod macros;
4mod mod_resolution; 4mod mod_resolution;
5mod diagnostics; 5mod diagnostics;
6mod primitives; 6mod primitives;
7mod block;
7 8
8use std::sync::Arc; 9use std::sync::Arc;
9 10
10use base_db::{fixture::WithFixture, SourceDatabase}; 11use base_db::{fixture::WithFixture, FilePosition, SourceDatabase};
11use expect_test::{expect, Expect}; 12use expect_test::{expect, Expect};
13use syntax::AstNode;
12use test_utils::mark; 14use test_utils::mark;
13 15
14use crate::{db::DefDatabase, nameres::*, test_db::TestDB}; 16use crate::{db::DefDatabase, nameres::*, test_db::TestDB, Lookup};
15 17
16fn compute_crate_def_map(ra_fixture: &str) -> Arc<DefMap> { 18fn 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);
@@ -19,12 +21,74 @@ fn compute_crate_def_map(ra_fixture: &str) -> Arc<DefMap> {
19 db.crate_def_map(krate) 21 db.crate_def_map(krate)
20} 22}
21 23
24fn compute_block_def_map(ra_fixture: &str) -> Arc<DefMap> {
25 let (db, position) = TestDB::with_position(ra_fixture);
26
27 // FIXME: perhaps we should make this use body lowering tests instead?
28
29 let module = db.module_for_file(position.file_id);
30 let mut def_map = db.crate_def_map(module.krate);
31 while let Some(new_def_map) = descend_def_map_at_position(&db, position, def_map.clone()) {
32 def_map = new_def_map;
33 }
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 }
76
77 None
78}
79
22fn check(ra_fixture: &str, expect: Expect) { 80fn check(ra_fixture: &str, expect: Expect) {
23 let def_map = compute_crate_def_map(ra_fixture); 81 let def_map = compute_crate_def_map(ra_fixture);
24 let actual = def_map.dump(); 82 let actual = def_map.dump();
25 expect.assert_eq(&actual); 83 expect.assert_eq(&actual);
26} 84}
27 85
86fn check_at(ra_fixture: &str, expect: Expect) {
87 let def_map = compute_block_def_map(ra_fixture);
88 let actual = def_map.dump();
89 expect.assert_eq(&actual);
90}
91
28#[test] 92#[test]
29fn crate_def_map_smoke_test() { 93fn crate_def_map_smoke_test() {
30 check( 94 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..6cc659513
--- /dev/null
+++ b/crates/hir_def/src/nameres/tests/block.rs
@@ -0,0 +1,186 @@
1use super::*;
2
3#[test]
4fn inner_item_smoke() {
5 check_at(
6 r#"
7struct inner {}
8fn 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]
24fn use_from_crate() {
25 check_at(
26 r#"
27struct Struct;
28fn 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]
48fn merge_namespaces() {
49 check_at(
50 r#"
51struct name {}
52fn 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]
72fn nested_blocks() {
73 check_at(
74 r#"
75fn 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}
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}
124
125#[test]
126fn legacy_macro_items() {
127 // Checks that legacy-scoped `macro_rules!` from parent namespaces are resolved and expanded
128 // correctly.
129 check_at(
130 r#"
131macro_rules! hit {
132 () => {
133 struct Hit {}
134 }
135}
136
137fn f() {
138 hit!();
139 $0
140}
141"#,
142 expect![[r#"
143 block scope
144 Hit: t
145 crate
146 f: v
147 "#]],
148 );
149}
150
151#[test]
152fn macro_resolve() {
153 check_at(
154 r#"
155//- /lib.rs crate:lib deps:core
156use core::mark;
157
158fn f() {
159 fn nested() {
160 mark::hit!(Hit);
161 $0
162 }
163}
164//- /core.rs crate:core
165pub mod mark {
166 #[macro_export]
167 macro_rules! _hit {
168 ($name:ident) => {
169 struct $name {}
170 }
171 }
172
173 pub use crate::_hit as hit;
174}
175"#,
176 expect![[r#"
177 block scope
178 Hit: t
179 block scope
180 nested: v
181 crate
182 f: v
183 mark: t
184 "#]],
185 );
186}