aboutsummaryrefslogtreecommitdiff
path: root/crates/hir_def/src/nameres
diff options
context:
space:
mode:
authorbors[bot] <26634292+bors[bot]@users.noreply.github.com>2021-02-03 14:41:13 +0000
committerGitHub <[email protected]>2021-02-03 14:41:13 +0000
commitfd84df9e1bb231f7aa4bcf760e0aff0a6bd10e9f (patch)
tree57fbfe241dcd571b9376b23260299160e0312246 /crates/hir_def/src/nameres
parent93ecef53a370703a67f87b90c4640d3e8bf73934 (diff)
parent63744fe128193464eb0ce63fbe6c30c4f98b6135 (diff)
Merge #7541
7541: Use block_def_map in body lowering (third time's the charm) r=jonas-schievink a=jonas-schievink After https://github.com/rust-analyzer/rust-analyzer/pull/7380 and https://github.com/rust-analyzer/rust-analyzer/pull/7506 both had to be reverted, this should have finally resolved all remaining bugs. Most importantly, the optimization to skip `block_def_map` computation when the block contains no inner items was fixed (which fortunately was simpler than expected). I've ran `analysis-stats` on libstd locally, which works fine, and also ran this PR locally for a short while without issues. Note that this *still* has no (or almost no) user-facing impact, because the rest of r-a still relies on some local item support hacks. bors r+ Co-authored-by: Jonas Schievink <[email protected]>
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, 2 insertions, 252 deletions
diff --git a/crates/hir_def/src/nameres/tests.rs b/crates/hir_def/src/nameres/tests.rs
index b36d0b59b..723481c36 100644
--- a/crates/hir_def/src/nameres/tests.rs
+++ b/crates/hir_def/src/nameres/tests.rs
@@ -4,16 +4,14 @@ mod macros;
4mod mod_resolution; 4mod mod_resolution;
5mod diagnostics; 5mod diagnostics;
6mod primitives; 6mod primitives;
7mod block;
8 7
9use std::sync::Arc; 8use std::sync::Arc;
10 9
11use base_db::{fixture::WithFixture, FilePosition, SourceDatabase}; 10use base_db::{fixture::WithFixture, SourceDatabase};
12use expect_test::{expect, Expect}; 11use expect_test::{expect, Expect};
13use syntax::AstNode;
14use test_utils::mark; 12use test_utils::mark;
15 13
16use crate::{db::DefDatabase, nameres::*, test_db::TestDB, Lookup}; 14use crate::{db::DefDatabase, nameres::*, test_db::TestDB};
17 15
18fn compute_crate_def_map(ra_fixture: &str) -> Arc<DefMap> { 16fn compute_crate_def_map(ra_fixture: &str) -> Arc<DefMap> {
19 let db = TestDB::with_files(ra_fixture); 17 let db = TestDB::with_files(ra_fixture);
@@ -21,74 +19,12 @@ fn compute_crate_def_map(ra_fixture: &str) -> Arc<DefMap> {
21 db.crate_def_map(krate) 19 db.crate_def_map(krate)
22} 20}
23 21
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
80fn check(ra_fixture: &str, expect: Expect) { 22fn check(ra_fixture: &str, expect: Expect) {
81 let def_map = compute_crate_def_map(ra_fixture); 23 let def_map = compute_crate_def_map(ra_fixture);
82 let actual = def_map.dump(); 24 let actual = def_map.dump();
83 expect.assert_eq(&actual); 25 expect.assert_eq(&actual);
84} 26}
85 27
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
92#[test] 28#[test]
93fn crate_def_map_smoke_test() { 29fn crate_def_map_smoke_test() {
94 check( 30 check(
diff --git a/crates/hir_def/src/nameres/tests/block.rs b/crates/hir_def/src/nameres/tests/block.rs
deleted file mode 100644
index 6cc659513..000000000
--- a/crates/hir_def/src/nameres/tests/block.rs
+++ /dev/null
@@ -1,186 +0,0 @@
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}