diff options
Diffstat (limited to 'crates/ra_hir_def')
-rw-r--r-- | crates/ra_hir_def/src/find_path.rs | 455 | ||||
-rw-r--r-- | crates/ra_hir_def/src/item_scope.rs | 39 | ||||
-rw-r--r-- | crates/ra_hir_def/src/lib.rs | 1 | ||||
-rw-r--r-- | crates/ra_hir_def/src/path.rs | 42 | ||||
-rw-r--r-- | crates/ra_hir_def/src/resolver.rs | 15 | ||||
-rw-r--r-- | crates/ra_hir_def/src/test_db.rs | 13 |
6 files changed, 559 insertions, 6 deletions
diff --git a/crates/ra_hir_def/src/find_path.rs b/crates/ra_hir_def/src/find_path.rs new file mode 100644 index 000000000..f7dc8acb7 --- /dev/null +++ b/crates/ra_hir_def/src/find_path.rs | |||
@@ -0,0 +1,455 @@ | |||
1 | //! An algorithm to find a path to refer to a certain item. | ||
2 | |||
3 | use crate::{ | ||
4 | db::DefDatabase, | ||
5 | item_scope::ItemInNs, | ||
6 | path::{ModPath, PathKind}, | ||
7 | visibility::Visibility, | ||
8 | CrateId, ModuleDefId, ModuleId, | ||
9 | }; | ||
10 | use hir_expand::name::Name; | ||
11 | |||
12 | const MAX_PATH_LEN: usize = 15; | ||
13 | |||
14 | // FIXME: handle local items | ||
15 | |||
16 | /// Find a path that can be used to refer to a certain item. This can depend on | ||
17 | /// *from where* you're referring to the item, hence the `from` parameter. | ||
18 | pub fn find_path(db: &impl DefDatabase, item: ItemInNs, from: ModuleId) -> Option<ModPath> { | ||
19 | find_path_inner(db, item, from, MAX_PATH_LEN) | ||
20 | } | ||
21 | |||
22 | fn find_path_inner( | ||
23 | db: &impl DefDatabase, | ||
24 | item: ItemInNs, | ||
25 | from: ModuleId, | ||
26 | max_len: usize, | ||
27 | ) -> Option<ModPath> { | ||
28 | if max_len == 0 { | ||
29 | return None; | ||
30 | } | ||
31 | |||
32 | // Base cases: | ||
33 | |||
34 | // - if the item is already in scope, return the name under which it is | ||
35 | let def_map = db.crate_def_map(from.krate); | ||
36 | let from_scope: &crate::item_scope::ItemScope = &def_map.modules[from.local_id].scope; | ||
37 | if let Some((name, _)) = from_scope.name_of(item) { | ||
38 | return Some(ModPath::from_simple_segments(PathKind::Plain, vec![name.clone()])); | ||
39 | } | ||
40 | |||
41 | // - if the item is the crate root, return `crate` | ||
42 | if item | ||
43 | == ItemInNs::Types(ModuleDefId::ModuleId(ModuleId { | ||
44 | krate: from.krate, | ||
45 | local_id: def_map.root, | ||
46 | })) | ||
47 | { | ||
48 | return Some(ModPath::from_simple_segments(PathKind::Crate, Vec::new())); | ||
49 | } | ||
50 | |||
51 | // - if the item is the module we're in, use `self` | ||
52 | if item == ItemInNs::Types(from.into()) { | ||
53 | return Some(ModPath::from_simple_segments(PathKind::Super(0), Vec::new())); | ||
54 | } | ||
55 | |||
56 | // - if the item is the parent module, use `super` (this is not used recursively, since `super::super` is ugly) | ||
57 | if let Some(parent_id) = def_map.modules[from.local_id].parent { | ||
58 | if item | ||
59 | == ItemInNs::Types(ModuleDefId::ModuleId(ModuleId { | ||
60 | krate: from.krate, | ||
61 | local_id: parent_id, | ||
62 | })) | ||
63 | { | ||
64 | return Some(ModPath::from_simple_segments(PathKind::Super(1), Vec::new())); | ||
65 | } | ||
66 | } | ||
67 | |||
68 | // - if the item is the crate root of a dependency crate, return the name from the extern prelude | ||
69 | for (name, def_id) in &def_map.extern_prelude { | ||
70 | if item == ItemInNs::Types(*def_id) { | ||
71 | return Some(ModPath::from_simple_segments(PathKind::Plain, vec![name.clone()])); | ||
72 | } | ||
73 | } | ||
74 | |||
75 | // - if the item is in the prelude, return the name from there | ||
76 | if let Some(prelude_module) = def_map.prelude { | ||
77 | let prelude_def_map = db.crate_def_map(prelude_module.krate); | ||
78 | let prelude_scope: &crate::item_scope::ItemScope = | ||
79 | &prelude_def_map.modules[prelude_module.local_id].scope; | ||
80 | if let Some((name, vis)) = prelude_scope.name_of(item) { | ||
81 | if vis.is_visible_from(db, from) { | ||
82 | return Some(ModPath::from_simple_segments(PathKind::Plain, vec![name.clone()])); | ||
83 | } | ||
84 | } | ||
85 | } | ||
86 | |||
87 | // Recursive case: | ||
88 | // - if the item is an enum variant, refer to it via the enum | ||
89 | if let Some(ModuleDefId::EnumVariantId(variant)) = item.as_module_def_id() { | ||
90 | if let Some(mut path) = find_path(db, ItemInNs::Types(variant.parent.into()), from) { | ||
91 | let data = db.enum_data(variant.parent); | ||
92 | path.segments.push(data.variants[variant.local_id].name.clone()); | ||
93 | return Some(path); | ||
94 | } | ||
95 | // If this doesn't work, it seems we have no way of referring to the | ||
96 | // enum; that's very weird, but there might still be a reexport of the | ||
97 | // variant somewhere | ||
98 | } | ||
99 | |||
100 | // - otherwise, look for modules containing (reexporting) it and import it from one of those | ||
101 | let importable_locations = find_importable_locations(db, item, from); | ||
102 | let mut best_path = None; | ||
103 | let mut best_path_len = max_len; | ||
104 | for (module_id, name) in importable_locations { | ||
105 | let mut path = match find_path_inner( | ||
106 | db, | ||
107 | ItemInNs::Types(ModuleDefId::ModuleId(module_id)), | ||
108 | from, | ||
109 | best_path_len - 1, | ||
110 | ) { | ||
111 | None => continue, | ||
112 | Some(path) => path, | ||
113 | }; | ||
114 | path.segments.push(name); | ||
115 | if path_len(&path) < best_path_len { | ||
116 | best_path_len = path_len(&path); | ||
117 | best_path = Some(path); | ||
118 | } | ||
119 | } | ||
120 | best_path | ||
121 | } | ||
122 | |||
123 | fn path_len(path: &ModPath) -> usize { | ||
124 | path.segments.len() | ||
125 | + match path.kind { | ||
126 | PathKind::Plain => 0, | ||
127 | PathKind::Super(i) => i as usize, | ||
128 | PathKind::Crate => 1, | ||
129 | PathKind::Abs => 0, | ||
130 | PathKind::DollarCrate(_) => 1, | ||
131 | } | ||
132 | } | ||
133 | |||
134 | fn find_importable_locations( | ||
135 | db: &impl DefDatabase, | ||
136 | item: ItemInNs, | ||
137 | from: ModuleId, | ||
138 | ) -> Vec<(ModuleId, Name)> { | ||
139 | let crate_graph = db.crate_graph(); | ||
140 | let mut result = Vec::new(); | ||
141 | // We only look in the crate from which we are importing, and the direct | ||
142 | // dependencies. We cannot refer to names from transitive dependencies | ||
143 | // directly (only through reexports in direct dependencies). | ||
144 | for krate in Some(from.krate) | ||
145 | .into_iter() | ||
146 | .chain(crate_graph.dependencies(from.krate).map(|dep| dep.crate_id)) | ||
147 | { | ||
148 | result.extend( | ||
149 | importable_locations_in_crate(db, item, krate) | ||
150 | .iter() | ||
151 | .filter(|(_, _, vis)| vis.is_visible_from(db, from)) | ||
152 | .map(|(m, n, _)| (*m, n.clone())), | ||
153 | ); | ||
154 | } | ||
155 | result | ||
156 | } | ||
157 | |||
158 | /// Collects all locations from which we might import the item in a particular | ||
159 | /// crate. These include the original definition of the item, and any | ||
160 | /// non-private `use`s. | ||
161 | /// | ||
162 | /// Note that the crate doesn't need to be the one in which the item is defined; | ||
163 | /// it might be re-exported in other crates. | ||
164 | fn importable_locations_in_crate( | ||
165 | db: &impl DefDatabase, | ||
166 | item: ItemInNs, | ||
167 | krate: CrateId, | ||
168 | ) -> Vec<(ModuleId, Name, Visibility)> { | ||
169 | let def_map = db.crate_def_map(krate); | ||
170 | let mut result = Vec::new(); | ||
171 | for (local_id, data) in def_map.modules.iter() { | ||
172 | if let Some((name, vis)) = data.scope.name_of(item) { | ||
173 | let is_private = if let Visibility::Module(private_to) = vis { | ||
174 | private_to.local_id == local_id | ||
175 | } else { | ||
176 | false | ||
177 | }; | ||
178 | let is_original_def = if let Some(module_def_id) = item.as_module_def_id() { | ||
179 | data.scope.declarations().any(|it| it == module_def_id) | ||
180 | } else { | ||
181 | false | ||
182 | }; | ||
183 | if is_private && !is_original_def { | ||
184 | // Ignore private imports. these could be used if we are | ||
185 | // in a submodule of this module, but that's usually not | ||
186 | // what the user wants; and if this module can import | ||
187 | // the item and we're a submodule of it, so can we. | ||
188 | // Also this keeps the cached data smaller. | ||
189 | continue; | ||
190 | } | ||
191 | result.push((ModuleId { krate, local_id }, name.clone(), vis)); | ||
192 | } | ||
193 | } | ||
194 | result | ||
195 | } | ||
196 | |||
197 | #[cfg(test)] | ||
198 | mod tests { | ||
199 | use super::*; | ||
200 | use crate::test_db::TestDB; | ||
201 | use hir_expand::hygiene::Hygiene; | ||
202 | use ra_db::fixture::WithFixture; | ||
203 | use ra_syntax::ast::AstNode; | ||
204 | |||
205 | /// `code` needs to contain a cursor marker; checks that `find_path` for the | ||
206 | /// item the `path` refers to returns that same path when called from the | ||
207 | /// module the cursor is in. | ||
208 | fn check_found_path(code: &str, path: &str) { | ||
209 | let (db, pos) = TestDB::with_position(code); | ||
210 | let module = db.module_for_file(pos.file_id); | ||
211 | let parsed_path_file = ra_syntax::SourceFile::parse(&format!("use {};", path)); | ||
212 | let ast_path = parsed_path_file | ||
213 | .syntax_node() | ||
214 | .descendants() | ||
215 | .find_map(ra_syntax::ast::Path::cast) | ||
216 | .unwrap(); | ||
217 | let mod_path = ModPath::from_src(ast_path, &Hygiene::new_unhygienic()).unwrap(); | ||
218 | |||
219 | let crate_def_map = db.crate_def_map(module.krate); | ||
220 | let resolved = crate_def_map | ||
221 | .resolve_path( | ||
222 | &db, | ||
223 | module.local_id, | ||
224 | &mod_path, | ||
225 | crate::item_scope::BuiltinShadowMode::Module, | ||
226 | ) | ||
227 | .0 | ||
228 | .take_types() | ||
229 | .unwrap(); | ||
230 | |||
231 | let found_path = find_path(&db, ItemInNs::Types(resolved), module); | ||
232 | |||
233 | assert_eq!(found_path, Some(mod_path)); | ||
234 | } | ||
235 | |||
236 | #[test] | ||
237 | fn same_module() { | ||
238 | let code = r#" | ||
239 | //- /main.rs | ||
240 | struct S; | ||
241 | <|> | ||
242 | "#; | ||
243 | check_found_path(code, "S"); | ||
244 | } | ||
245 | |||
246 | #[test] | ||
247 | fn enum_variant() { | ||
248 | let code = r#" | ||
249 | //- /main.rs | ||
250 | enum E { A } | ||
251 | <|> | ||
252 | "#; | ||
253 | check_found_path(code, "E::A"); | ||
254 | } | ||
255 | |||
256 | #[test] | ||
257 | fn sub_module() { | ||
258 | let code = r#" | ||
259 | //- /main.rs | ||
260 | mod foo { | ||
261 | pub struct S; | ||
262 | } | ||
263 | <|> | ||
264 | "#; | ||
265 | check_found_path(code, "foo::S"); | ||
266 | } | ||
267 | |||
268 | #[test] | ||
269 | fn super_module() { | ||
270 | let code = r#" | ||
271 | //- /main.rs | ||
272 | mod foo; | ||
273 | //- /foo.rs | ||
274 | mod bar; | ||
275 | struct S; | ||
276 | //- /foo/bar.rs | ||
277 | <|> | ||
278 | "#; | ||
279 | check_found_path(code, "super::S"); | ||
280 | } | ||
281 | |||
282 | #[test] | ||
283 | fn self_module() { | ||
284 | let code = r#" | ||
285 | //- /main.rs | ||
286 | mod foo; | ||
287 | //- /foo.rs | ||
288 | <|> | ||
289 | "#; | ||
290 | check_found_path(code, "self"); | ||
291 | } | ||
292 | |||
293 | #[test] | ||
294 | fn crate_root() { | ||
295 | let code = r#" | ||
296 | //- /main.rs | ||
297 | mod foo; | ||
298 | //- /foo.rs | ||
299 | <|> | ||
300 | "#; | ||
301 | check_found_path(code, "crate"); | ||
302 | } | ||
303 | |||
304 | #[test] | ||
305 | fn same_crate() { | ||
306 | let code = r#" | ||
307 | //- /main.rs | ||
308 | mod foo; | ||
309 | struct S; | ||
310 | //- /foo.rs | ||
311 | <|> | ||
312 | "#; | ||
313 | check_found_path(code, "crate::S"); | ||
314 | } | ||
315 | |||
316 | #[test] | ||
317 | fn different_crate() { | ||
318 | let code = r#" | ||
319 | //- /main.rs crate:main deps:std | ||
320 | <|> | ||
321 | //- /std.rs crate:std | ||
322 | pub struct S; | ||
323 | "#; | ||
324 | check_found_path(code, "std::S"); | ||
325 | } | ||
326 | |||
327 | #[test] | ||
328 | fn different_crate_renamed() { | ||
329 | let code = r#" | ||
330 | //- /main.rs crate:main deps:std | ||
331 | extern crate std as std_renamed; | ||
332 | <|> | ||
333 | //- /std.rs crate:std | ||
334 | pub struct S; | ||
335 | "#; | ||
336 | check_found_path(code, "std_renamed::S"); | ||
337 | } | ||
338 | |||
339 | #[test] | ||
340 | fn same_crate_reexport() { | ||
341 | let code = r#" | ||
342 | //- /main.rs | ||
343 | mod bar { | ||
344 | mod foo { pub(super) struct S; } | ||
345 | pub(crate) use foo::*; | ||
346 | } | ||
347 | <|> | ||
348 | "#; | ||
349 | check_found_path(code, "bar::S"); | ||
350 | } | ||
351 | |||
352 | #[test] | ||
353 | fn same_crate_reexport_rename() { | ||
354 | let code = r#" | ||
355 | //- /main.rs | ||
356 | mod bar { | ||
357 | mod foo { pub(super) struct S; } | ||
358 | pub(crate) use foo::S as U; | ||
359 | } | ||
360 | <|> | ||
361 | "#; | ||
362 | check_found_path(code, "bar::U"); | ||
363 | } | ||
364 | |||
365 | #[test] | ||
366 | fn different_crate_reexport() { | ||
367 | let code = r#" | ||
368 | //- /main.rs crate:main deps:std | ||
369 | <|> | ||
370 | //- /std.rs crate:std deps:core | ||
371 | pub use core::S; | ||
372 | //- /core.rs crate:core | ||
373 | pub struct S; | ||
374 | "#; | ||
375 | check_found_path(code, "std::S"); | ||
376 | } | ||
377 | |||
378 | #[test] | ||
379 | fn prelude() { | ||
380 | let code = r#" | ||
381 | //- /main.rs crate:main deps:std | ||
382 | <|> | ||
383 | //- /std.rs crate:std | ||
384 | pub mod prelude { pub struct S; } | ||
385 | #[prelude_import] | ||
386 | pub use prelude::*; | ||
387 | "#; | ||
388 | check_found_path(code, "S"); | ||
389 | } | ||
390 | |||
391 | #[test] | ||
392 | fn enum_variant_from_prelude() { | ||
393 | let code = r#" | ||
394 | //- /main.rs crate:main deps:std | ||
395 | <|> | ||
396 | //- /std.rs crate:std | ||
397 | pub mod prelude { | ||
398 | pub enum Option<T> { Some(T), None } | ||
399 | pub use Option::*; | ||
400 | } | ||
401 | #[prelude_import] | ||
402 | pub use prelude::*; | ||
403 | "#; | ||
404 | check_found_path(code, "None"); | ||
405 | check_found_path(code, "Some"); | ||
406 | } | ||
407 | |||
408 | #[test] | ||
409 | fn shortest_path() { | ||
410 | let code = r#" | ||
411 | //- /main.rs | ||
412 | pub mod foo; | ||
413 | pub mod baz; | ||
414 | struct S; | ||
415 | <|> | ||
416 | //- /foo.rs | ||
417 | pub mod bar { pub struct S; } | ||
418 | //- /baz.rs | ||
419 | pub use crate::foo::bar::S; | ||
420 | "#; | ||
421 | check_found_path(code, "baz::S"); | ||
422 | } | ||
423 | |||
424 | #[test] | ||
425 | fn discount_private_imports() { | ||
426 | let code = r#" | ||
427 | //- /main.rs | ||
428 | mod foo; | ||
429 | pub mod bar { pub struct S; } | ||
430 | use bar::S; | ||
431 | //- /foo.rs | ||
432 | <|> | ||
433 | "#; | ||
434 | // crate::S would be shorter, but using private imports seems wrong | ||
435 | check_found_path(code, "crate::bar::S"); | ||
436 | } | ||
437 | |||
438 | #[test] | ||
439 | fn import_cycle() { | ||
440 | let code = r#" | ||
441 | //- /main.rs | ||
442 | pub mod foo; | ||
443 | pub mod bar; | ||
444 | pub mod baz; | ||
445 | //- /bar.rs | ||
446 | <|> | ||
447 | //- /foo.rs | ||
448 | pub use super::baz; | ||
449 | pub struct S; | ||
450 | //- /baz.rs | ||
451 | pub use super::foo; | ||
452 | "#; | ||
453 | check_found_path(code, "crate::foo::S"); | ||
454 | } | ||
455 | } | ||
diff --git a/crates/ra_hir_def/src/item_scope.rs b/crates/ra_hir_def/src/item_scope.rs index fe7bb9779..d74a1cef2 100644 --- a/crates/ra_hir_def/src/item_scope.rs +++ b/crates/ra_hir_def/src/item_scope.rs | |||
@@ -104,6 +104,15 @@ impl ItemScope { | |||
104 | } | 104 | } |
105 | } | 105 | } |
106 | 106 | ||
107 | pub(crate) fn name_of(&self, item: ItemInNs) -> Option<(&Name, Visibility)> { | ||
108 | for (name, per_ns) in &self.visible { | ||
109 | if let Some(vis) = item.match_with(*per_ns) { | ||
110 | return Some((name, vis)); | ||
111 | } | ||
112 | } | ||
113 | None | ||
114 | } | ||
115 | |||
107 | pub(crate) fn traits<'a>(&'a self) -> impl Iterator<Item = TraitId> + 'a { | 116 | pub(crate) fn traits<'a>(&'a self) -> impl Iterator<Item = TraitId> + 'a { |
108 | self.visible.values().filter_map(|def| match def.take_types() { | 117 | self.visible.values().filter_map(|def| match def.take_types() { |
109 | Some(ModuleDefId::TraitId(t)) => Some(t), | 118 | Some(ModuleDefId::TraitId(t)) => Some(t), |
@@ -173,3 +182,33 @@ impl PerNs { | |||
173 | } | 182 | } |
174 | } | 183 | } |
175 | } | 184 | } |
185 | |||
186 | #[derive(Clone, Copy, PartialEq, Eq, Debug, Hash)] | ||
187 | pub enum ItemInNs { | ||
188 | Types(ModuleDefId), | ||
189 | Values(ModuleDefId), | ||
190 | Macros(MacroDefId), | ||
191 | } | ||
192 | |||
193 | impl ItemInNs { | ||
194 | fn match_with(self, per_ns: PerNs) -> Option<Visibility> { | ||
195 | match self { | ||
196 | ItemInNs::Types(def) => { | ||
197 | per_ns.types.filter(|(other_def, _)| *other_def == def).map(|(_, vis)| vis) | ||
198 | } | ||
199 | ItemInNs::Values(def) => { | ||
200 | per_ns.values.filter(|(other_def, _)| *other_def == def).map(|(_, vis)| vis) | ||
201 | } | ||
202 | ItemInNs::Macros(def) => { | ||
203 | per_ns.macros.filter(|(other_def, _)| *other_def == def).map(|(_, vis)| vis) | ||
204 | } | ||
205 | } | ||
206 | } | ||
207 | |||
208 | pub fn as_module_def_id(self) -> Option<ModuleDefId> { | ||
209 | match self { | ||
210 | ItemInNs::Types(id) | ItemInNs::Values(id) => Some(id), | ||
211 | ItemInNs::Macros(_) => None, | ||
212 | } | ||
213 | } | ||
214 | } | ||
diff --git a/crates/ra_hir_def/src/lib.rs b/crates/ra_hir_def/src/lib.rs index 61f044ecf..ebc12e891 100644 --- a/crates/ra_hir_def/src/lib.rs +++ b/crates/ra_hir_def/src/lib.rs | |||
@@ -37,6 +37,7 @@ pub mod src; | |||
37 | pub mod child_by_source; | 37 | pub mod child_by_source; |
38 | 38 | ||
39 | pub mod visibility; | 39 | pub mod visibility; |
40 | pub mod find_path; | ||
40 | 41 | ||
41 | #[cfg(test)] | 42 | #[cfg(test)] |
42 | mod test_db; | 43 | mod test_db; |
diff --git a/crates/ra_hir_def/src/path.rs b/crates/ra_hir_def/src/path.rs index 82cfa67a9..9f93a5424 100644 --- a/crates/ra_hir_def/src/path.rs +++ b/crates/ra_hir_def/src/path.rs | |||
@@ -1,7 +1,11 @@ | |||
1 | //! A desugared representation of paths like `crate::foo` or `<Type as Trait>::bar`. | 1 | //! A desugared representation of paths like `crate::foo` or `<Type as Trait>::bar`. |
2 | mod lower; | 2 | mod lower; |
3 | 3 | ||
4 | use std::{iter, sync::Arc}; | 4 | use std::{ |
5 | fmt::{self, Display}, | ||
6 | iter, | ||
7 | sync::Arc, | ||
8 | }; | ||
5 | 9 | ||
6 | use hir_expand::{ | 10 | use hir_expand::{ |
7 | hygiene::Hygiene, | 11 | hygiene::Hygiene, |
@@ -248,6 +252,42 @@ impl From<Name> for ModPath { | |||
248 | } | 252 | } |
249 | } | 253 | } |
250 | 254 | ||
255 | impl Display for ModPath { | ||
256 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { | ||
257 | let mut first_segment = true; | ||
258 | let mut add_segment = |s| { | ||
259 | if !first_segment { | ||
260 | f.write_str("::")?; | ||
261 | } | ||
262 | first_segment = false; | ||
263 | f.write_str(s)?; | ||
264 | Ok(()) | ||
265 | }; | ||
266 | match self.kind { | ||
267 | PathKind::Plain => {} | ||
268 | PathKind::Super(n) => { | ||
269 | if n == 0 { | ||
270 | add_segment("self")?; | ||
271 | } | ||
272 | for _ in 0..n { | ||
273 | add_segment("super")?; | ||
274 | } | ||
275 | } | ||
276 | PathKind::Crate => add_segment("crate")?, | ||
277 | PathKind::Abs => add_segment("")?, | ||
278 | PathKind::DollarCrate(_) => add_segment("$crate")?, | ||
279 | } | ||
280 | for segment in &self.segments { | ||
281 | if !first_segment { | ||
282 | f.write_str("::")?; | ||
283 | } | ||
284 | first_segment = false; | ||
285 | write!(f, "{}", segment)?; | ||
286 | } | ||
287 | Ok(()) | ||
288 | } | ||
289 | } | ||
290 | |||
251 | pub use hir_expand::name as __name; | 291 | pub use hir_expand::name as __name; |
252 | 292 | ||
253 | #[macro_export] | 293 | #[macro_export] |
diff --git a/crates/ra_hir_def/src/resolver.rs b/crates/ra_hir_def/src/resolver.rs index 5d16dd087..f7bac5801 100644 --- a/crates/ra_hir_def/src/resolver.rs +++ b/crates/ra_hir_def/src/resolver.rs | |||
@@ -128,7 +128,7 @@ impl Resolver { | |||
128 | path: &ModPath, | 128 | path: &ModPath, |
129 | shadow: BuiltinShadowMode, | 129 | shadow: BuiltinShadowMode, |
130 | ) -> PerNs { | 130 | ) -> PerNs { |
131 | let (item_map, module) = match self.module() { | 131 | let (item_map, module) = match self.module_scope() { |
132 | Some(it) => it, | 132 | Some(it) => it, |
133 | None => return PerNs::none(), | 133 | None => return PerNs::none(), |
134 | }; | 134 | }; |
@@ -239,7 +239,7 @@ impl Resolver { | |||
239 | ) -> Option<Visibility> { | 239 | ) -> Option<Visibility> { |
240 | match visibility { | 240 | match visibility { |
241 | RawVisibility::Module(_) => { | 241 | RawVisibility::Module(_) => { |
242 | let (item_map, module) = match self.module() { | 242 | let (item_map, module) = match self.module_scope() { |
243 | Some(it) => it, | 243 | Some(it) => it, |
244 | None => return None, | 244 | None => return None, |
245 | }; | 245 | }; |
@@ -379,7 +379,7 @@ impl Resolver { | |||
379 | db: &impl DefDatabase, | 379 | db: &impl DefDatabase, |
380 | path: &ModPath, | 380 | path: &ModPath, |
381 | ) -> Option<MacroDefId> { | 381 | ) -> Option<MacroDefId> { |
382 | let (item_map, module) = self.module()?; | 382 | let (item_map, module) = self.module_scope()?; |
383 | item_map.resolve_path(db, module, &path, BuiltinShadowMode::Other).0.take_macros() | 383 | item_map.resolve_path(db, module, &path, BuiltinShadowMode::Other).0.take_macros() |
384 | } | 384 | } |
385 | 385 | ||
@@ -403,7 +403,7 @@ impl Resolver { | |||
403 | traits | 403 | traits |
404 | } | 404 | } |
405 | 405 | ||
406 | fn module(&self) -> Option<(&CrateDefMap, LocalModuleId)> { | 406 | fn module_scope(&self) -> Option<(&CrateDefMap, LocalModuleId)> { |
407 | self.scopes.iter().rev().find_map(|scope| match scope { | 407 | self.scopes.iter().rev().find_map(|scope| match scope { |
408 | Scope::ModuleScope(m) => Some((&*m.crate_def_map, m.module_id)), | 408 | Scope::ModuleScope(m) => Some((&*m.crate_def_map, m.module_id)), |
409 | 409 | ||
@@ -411,8 +411,13 @@ impl Resolver { | |||
411 | }) | 411 | }) |
412 | } | 412 | } |
413 | 413 | ||
414 | pub fn module(&self) -> Option<ModuleId> { | ||
415 | let (def_map, local_id) = self.module_scope()?; | ||
416 | Some(ModuleId { krate: def_map.krate, local_id }) | ||
417 | } | ||
418 | |||
414 | pub fn krate(&self) -> Option<CrateId> { | 419 | pub fn krate(&self) -> Option<CrateId> { |
415 | self.module().map(|t| t.0.krate) | 420 | self.module_scope().map(|t| t.0.krate) |
416 | } | 421 | } |
417 | 422 | ||
418 | pub fn where_predicates_in_scope<'a>( | 423 | pub fn where_predicates_in_scope<'a>( |
diff --git a/crates/ra_hir_def/src/test_db.rs b/crates/ra_hir_def/src/test_db.rs index 54e3a84bd..1568820e9 100644 --- a/crates/ra_hir_def/src/test_db.rs +++ b/crates/ra_hir_def/src/test_db.rs | |||
@@ -5,6 +5,7 @@ use std::{ | |||
5 | sync::{Arc, Mutex}, | 5 | sync::{Arc, Mutex}, |
6 | }; | 6 | }; |
7 | 7 | ||
8 | use crate::db::DefDatabase; | ||
8 | use ra_db::{salsa, CrateId, FileId, FileLoader, FileLoaderDelegate, RelativePath}; | 9 | use ra_db::{salsa, CrateId, FileId, FileLoader, FileLoaderDelegate, RelativePath}; |
9 | 10 | ||
10 | #[salsa::database( | 11 | #[salsa::database( |
@@ -54,6 +55,18 @@ impl FileLoader for TestDB { | |||
54 | } | 55 | } |
55 | 56 | ||
56 | impl TestDB { | 57 | impl TestDB { |
58 | pub fn module_for_file(&self, file_id: FileId) -> crate::ModuleId { | ||
59 | for &krate in self.relevant_crates(file_id).iter() { | ||
60 | let crate_def_map = self.crate_def_map(krate); | ||
61 | for (local_id, data) in crate_def_map.modules.iter() { | ||
62 | if data.origin.file_id() == Some(file_id) { | ||
63 | return crate::ModuleId { krate, local_id }; | ||
64 | } | ||
65 | } | ||
66 | } | ||
67 | panic!("Can't find module for file") | ||
68 | } | ||
69 | |||
57 | pub fn log(&self, f: impl FnOnce()) -> Vec<salsa::Event<TestDB>> { | 70 | pub fn log(&self, f: impl FnOnce()) -> Vec<salsa::Event<TestDB>> { |
58 | *self.events.lock().unwrap() = Some(Vec::new()); | 71 | *self.events.lock().unwrap() = Some(Vec::new()); |
59 | f(); | 72 | f(); |