diff options
Diffstat (limited to 'crates/ra_hir/src')
-rw-r--r-- | crates/ra_hir/src/nameres.rs | 4 | ||||
-rw-r--r-- | crates/ra_hir/src/nameres/collector.rs | 31 | ||||
-rw-r--r-- | crates/ra_hir/src/nameres/raw.rs | 22 | ||||
-rw-r--r-- | crates/ra_hir/src/nameres/tests.rs | 97 | ||||
-rw-r--r-- | crates/ra_hir/src/nameres/tests/mods.rs | 192 | ||||
-rw-r--r-- | crates/ra_hir/src/ty/method_resolution.rs | 2 |
6 files changed, 240 insertions, 108 deletions
diff --git a/crates/ra_hir/src/nameres.rs b/crates/ra_hir/src/nameres.rs index 53ef8d58a..c84d2eada 100644 --- a/crates/ra_hir/src/nameres.rs +++ b/crates/ra_hir/src/nameres.rs | |||
@@ -1,6 +1,6 @@ | |||
1 | /// This module implements import-resolution/macro expansion algorithm. | 1 | /// This module implements import-resolution/macro expansion algorithm. |
2 | /// | 2 | /// |
3 | /// The result of this module is `CrateDefMap`: a datastructure which contains: | 3 | /// The result of this module is `CrateDefMap`: a data structure which contains: |
4 | /// | 4 | /// |
5 | /// * a tree of modules for the crate | 5 | /// * a tree of modules for the crate |
6 | /// * for each module, a set of items visible in the module (directly declared | 6 | /// * for each module, a set of items visible in the module (directly declared |
@@ -76,7 +76,7 @@ pub use self::{ | |||
76 | raw::ImportId, | 76 | raw::ImportId, |
77 | }; | 77 | }; |
78 | 78 | ||
79 | /// Contans all top-level defs from a macro-expanded crate | 79 | /// Contains all top-level defs from a macro-expanded crate |
80 | #[derive(Debug, PartialEq, Eq)] | 80 | #[derive(Debug, PartialEq, Eq)] |
81 | pub struct CrateDefMap { | 81 | pub struct CrateDefMap { |
82 | krate: Crate, | 82 | krate: Crate, |
diff --git a/crates/ra_hir/src/nameres/collector.rs b/crates/ra_hir/src/nameres/collector.rs index d66be34db..9f197bb58 100644 --- a/crates/ra_hir/src/nameres/collector.rs +++ b/crates/ra_hir/src/nameres/collector.rs | |||
@@ -1,6 +1,6 @@ | |||
1 | use arrayvec::ArrayVec; | 1 | use arrayvec::ArrayVec; |
2 | use ra_db::FileId; | 2 | use ra_db::FileId; |
3 | use ra_syntax::ast; | 3 | use ra_syntax::{ast, SmolStr}; |
4 | use relative_path::RelativePathBuf; | 4 | use relative_path::RelativePathBuf; |
5 | use rustc_hash::FxHashMap; | 5 | use rustc_hash::FxHashMap; |
6 | use test_utils::tested_by; | 6 | use test_utils::tested_by; |
@@ -508,11 +508,17 @@ where | |||
508 | } | 508 | } |
509 | .collect(&*items); | 509 | .collect(&*items); |
510 | } | 510 | } |
511 | // out of line module, resovle, parse and recurse | 511 | // out of line module, resolve, parse and recurse |
512 | raw::ModuleData::Declaration { name, ast_id } => { | 512 | raw::ModuleData::Declaration { name, ast_id, attr_path } => { |
513 | let ast_id = ast_id.with_file_id(self.file_id); | 513 | let ast_id = ast_id.with_file_id(self.file_id); |
514 | let is_root = self.def_collector.def_map.modules[self.module_id].parent.is_none(); | 514 | let is_root = self.def_collector.def_map.modules[self.module_id].parent.is_none(); |
515 | match resolve_submodule(self.def_collector.db, self.file_id, name, is_root) { | 515 | match resolve_submodule( |
516 | self.def_collector.db, | ||
517 | self.file_id, | ||
518 | name, | ||
519 | is_root, | ||
520 | attr_path.as_ref(), | ||
521 | ) { | ||
516 | Ok(file_id) => { | 522 | Ok(file_id) => { |
517 | let module_id = self.push_child_module(name.clone(), ast_id, Some(file_id)); | 523 | let module_id = self.push_child_module(name.clone(), ast_id, Some(file_id)); |
518 | let raw_items = self.def_collector.db.raw_items(file_id.into()); | 524 | let raw_items = self.def_collector.db.raw_items(file_id.into()); |
@@ -626,6 +632,7 @@ fn resolve_submodule( | |||
626 | file_id: HirFileId, | 632 | file_id: HirFileId, |
627 | name: &Name, | 633 | name: &Name, |
628 | is_root: bool, | 634 | is_root: bool, |
635 | attr_path: Option<&SmolStr>, | ||
629 | ) -> Result<FileId, RelativePathBuf> { | 636 | ) -> Result<FileId, RelativePathBuf> { |
630 | // FIXME: handle submodules of inline modules properly | 637 | // FIXME: handle submodules of inline modules properly |
631 | let file_id = file_id.original_file(db); | 638 | let file_id = file_id.original_file(db); |
@@ -639,7 +646,13 @@ fn resolve_submodule( | |||
639 | let file_mod = dir_path.join(format!("{}.rs", name)); | 646 | let file_mod = dir_path.join(format!("{}.rs", name)); |
640 | let dir_mod = dir_path.join(format!("{}/mod.rs", name)); | 647 | let dir_mod = dir_path.join(format!("{}/mod.rs", name)); |
641 | let file_dir_mod = dir_path.join(format!("{}/{}.rs", mod_name, name)); | 648 | let file_dir_mod = dir_path.join(format!("{}/{}.rs", mod_name, name)); |
642 | let mut candidates = ArrayVec::<[_; 2]>::new(); | 649 | let mut candidates = ArrayVec::<[_; 3]>::new(); |
650 | let file_attr_mod = attr_path.map(|file_path| { | ||
651 | let file_attr_mod = dir_path.join(file_path.to_string()); | ||
652 | candidates.push(file_attr_mod.clone()); | ||
653 | |||
654 | file_attr_mod | ||
655 | }); | ||
643 | if is_dir_owner { | 656 | if is_dir_owner { |
644 | candidates.push(file_mod.clone()); | 657 | candidates.push(file_mod.clone()); |
645 | candidates.push(dir_mod); | 658 | candidates.push(dir_mod); |
@@ -651,7 +664,13 @@ fn resolve_submodule( | |||
651 | // FIXME: handle ambiguity | 664 | // FIXME: handle ambiguity |
652 | match points_to.next() { | 665 | match points_to.next() { |
653 | Some(file_id) => Ok(file_id), | 666 | Some(file_id) => Ok(file_id), |
654 | None => Err(if is_dir_owner { file_mod } else { file_dir_mod }), | 667 | None => { |
668 | if let Some(file_attr_mod) = file_attr_mod { | ||
669 | Err(file_attr_mod) | ||
670 | } else { | ||
671 | Err(if is_dir_owner { file_mod } else { file_dir_mod }) | ||
672 | } | ||
673 | } | ||
655 | } | 674 | } |
656 | } | 675 | } |
657 | 676 | ||
diff --git a/crates/ra_hir/src/nameres/raw.rs b/crates/ra_hir/src/nameres/raw.rs index 7ea59cb75..46b2bef5b 100644 --- a/crates/ra_hir/src/nameres/raw.rs +++ b/crates/ra_hir/src/nameres/raw.rs | |||
@@ -3,7 +3,7 @@ use std::{ops::Index, sync::Arc}; | |||
3 | use ra_arena::{impl_arena_id, map::ArenaMap, Arena, RawId}; | 3 | use ra_arena::{impl_arena_id, map::ArenaMap, Arena, RawId}; |
4 | use ra_syntax::{ | 4 | use ra_syntax::{ |
5 | ast::{self, AttrsOwner, NameOwner}, | 5 | ast::{self, AttrsOwner, NameOwner}, |
6 | AstNode, AstPtr, SourceFile, TreeArc, | 6 | AstNode, AstPtr, SmolStr, SourceFile, TreeArc, |
7 | }; | 7 | }; |
8 | use test_utils::tested_by; | 8 | use test_utils::tested_by; |
9 | 9 | ||
@@ -130,7 +130,7 @@ impl_arena_id!(Module); | |||
130 | 130 | ||
131 | #[derive(Debug, PartialEq, Eq)] | 131 | #[derive(Debug, PartialEq, Eq)] |
132 | pub(super) enum ModuleData { | 132 | pub(super) enum ModuleData { |
133 | Declaration { name: Name, ast_id: FileAstId<ast::Module> }, | 133 | Declaration { name: Name, ast_id: FileAstId<ast::Module>, attr_path: Option<SmolStr> }, |
134 | Definition { name: Name, ast_id: FileAstId<ast::Module>, items: Vec<RawItem> }, | 134 | Definition { name: Name, ast_id: FileAstId<ast::Module>, items: Vec<RawItem> }, |
135 | } | 135 | } |
136 | 136 | ||
@@ -255,9 +255,12 @@ impl RawItemsCollector { | |||
255 | Some(it) => it.as_name(), | 255 | Some(it) => it.as_name(), |
256 | None => return, | 256 | None => return, |
257 | }; | 257 | }; |
258 | |||
259 | let attr_path = extract_mod_path_attribute(module); | ||
258 | let ast_id = self.source_ast_id_map.ast_id(module); | 260 | let ast_id = self.source_ast_id_map.ast_id(module); |
259 | if module.has_semi() { | 261 | if module.has_semi() { |
260 | let item = self.raw_items.modules.alloc(ModuleData::Declaration { name, ast_id }); | 262 | let item = |
263 | self.raw_items.modules.alloc(ModuleData::Declaration { name, ast_id, attr_path }); | ||
261 | self.push_item(current_module, RawItem::Module(item)); | 264 | self.push_item(current_module, RawItem::Module(item)); |
262 | return; | 265 | return; |
263 | } | 266 | } |
@@ -339,3 +342,16 @@ impl RawItemsCollector { | |||
339 | .push(item) | 342 | .push(item) |
340 | } | 343 | } |
341 | } | 344 | } |
345 | |||
346 | fn extract_mod_path_attribute(module: &ast::Module) -> Option<SmolStr> { | ||
347 | module.attrs().into_iter().find_map(|attr| { | ||
348 | attr.as_key_value().and_then(|(name, value)| { | ||
349 | let is_path = name == "path"; | ||
350 | if is_path { | ||
351 | Some(value) | ||
352 | } else { | ||
353 | None | ||
354 | } | ||
355 | }) | ||
356 | }) | ||
357 | } | ||
diff --git a/crates/ra_hir/src/nameres/tests.rs b/crates/ra_hir/src/nameres/tests.rs index bd2d855cf..8b0887fb5 100644 --- a/crates/ra_hir/src/nameres/tests.rs +++ b/crates/ra_hir/src/nameres/tests.rs | |||
@@ -2,6 +2,7 @@ mod macros; | |||
2 | mod globs; | 2 | mod globs; |
3 | mod incremental; | 3 | mod incremental; |
4 | mod primitives; | 4 | mod primitives; |
5 | mod mods; | ||
5 | 6 | ||
6 | use std::sync::Arc; | 7 | use std::sync::Arc; |
7 | 8 | ||
@@ -313,83 +314,6 @@ fn edition_2015_imports() { | |||
313 | } | 314 | } |
314 | 315 | ||
315 | #[test] | 316 | #[test] |
316 | fn module_resolution_works_for_non_standard_filenames() { | ||
317 | let map = def_map_with_crate_graph( | ||
318 | " | ||
319 | //- /my_library.rs | ||
320 | mod foo; | ||
321 | use self::foo::Bar; | ||
322 | |||
323 | //- /foo/mod.rs | ||
324 | pub struct Bar; | ||
325 | ", | ||
326 | crate_graph! { | ||
327 | "my_library": ("/my_library.rs", []), | ||
328 | }, | ||
329 | ); | ||
330 | |||
331 | assert_snapshot_matches!(map, @r###" | ||
332 | ⋮crate | ||
333 | ⋮Bar: t v | ||
334 | ⋮foo: t | ||
335 | ⋮ | ||
336 | ⋮crate::foo | ||
337 | ⋮Bar: t v | ||
338 | "###); | ||
339 | } | ||
340 | |||
341 | #[test] | ||
342 | fn module_resolution_works_for_raw_modules() { | ||
343 | let map = def_map_with_crate_graph( | ||
344 | " | ||
345 | //- /library.rs | ||
346 | mod r#async; | ||
347 | use self::r#async::Bar; | ||
348 | |||
349 | //- /async.rs | ||
350 | pub struct Bar; | ||
351 | ", | ||
352 | crate_graph! { | ||
353 | "library": ("/library.rs", []), | ||
354 | }, | ||
355 | ); | ||
356 | |||
357 | assert_snapshot_matches!(map, @r###" | ||
358 | ⋮crate | ||
359 | ⋮Bar: t v | ||
360 | ⋮async: t | ||
361 | ⋮ | ||
362 | ⋮crate::async | ||
363 | ⋮Bar: t v | ||
364 | "###); | ||
365 | } | ||
366 | |||
367 | #[test] | ||
368 | fn name_res_works_for_broken_modules() { | ||
369 | covers!(name_res_works_for_broken_modules); | ||
370 | let map = def_map( | ||
371 | " | ||
372 | //- /lib.rs | ||
373 | mod foo // no `;`, no body | ||
374 | |||
375 | use self::foo::Baz; | ||
376 | |||
377 | //- /foo/mod.rs | ||
378 | pub mod bar; | ||
379 | |||
380 | pub use self::bar::Baz; | ||
381 | |||
382 | //- /foo/bar.rs | ||
383 | pub struct Baz; | ||
384 | ", | ||
385 | ); | ||
386 | assert_snapshot_matches!(map, @r###" | ||
387 | ⋮crate | ||
388 | ⋮Baz: _ | ||
389 | "###); | ||
390 | } | ||
391 | |||
392 | #[test] | ||
393 | fn item_map_using_self() { | 317 | fn item_map_using_self() { |
394 | let map = def_map( | 318 | let map = def_map( |
395 | " | 319 | " |
@@ -581,22 +505,3 @@ fn values_dont_shadow_extern_crates() { | |||
581 | ⋮foo: v | 505 | ⋮foo: v |
582 | "###); | 506 | "###); |
583 | } | 507 | } |
584 | |||
585 | #[test] | ||
586 | fn unresolved_module_diagnostics() { | ||
587 | let diagnostics = MockDatabase::with_files( | ||
588 | r" | ||
589 | //- /lib.rs | ||
590 | mod foo; | ||
591 | mod bar; | ||
592 | mod baz {} | ||
593 | //- /foo.rs | ||
594 | ", | ||
595 | ) | ||
596 | .diagnostics(); | ||
597 | |||
598 | assert_snapshot_matches!(diagnostics, @r###" | ||
599 | "mod bar;": unresolved module | ||
600 | "### | ||
601 | ); | ||
602 | } | ||
diff --git a/crates/ra_hir/src/nameres/tests/mods.rs b/crates/ra_hir/src/nameres/tests/mods.rs new file mode 100644 index 000000000..7c8c832fc --- /dev/null +++ b/crates/ra_hir/src/nameres/tests/mods.rs | |||
@@ -0,0 +1,192 @@ | |||
1 | use super::*; | ||
2 | |||
3 | #[test] | ||
4 | fn name_res_works_for_broken_modules() { | ||
5 | covers!(name_res_works_for_broken_modules); | ||
6 | let map = def_map( | ||
7 | " | ||
8 | //- /lib.rs | ||
9 | mod foo // no `;`, no body | ||
10 | |||
11 | use self::foo::Baz; | ||
12 | |||
13 | //- /foo/mod.rs | ||
14 | pub mod bar; | ||
15 | |||
16 | pub use self::bar::Baz; | ||
17 | |||
18 | //- /foo/bar.rs | ||
19 | pub struct Baz; | ||
20 | ", | ||
21 | ); | ||
22 | assert_snapshot_matches!(map, @r###" | ||
23 | ⋮crate | ||
24 | ⋮Baz: _ | ||
25 | "###); | ||
26 | } | ||
27 | |||
28 | #[test] | ||
29 | fn module_resolution_works_for_non_standard_filenames() { | ||
30 | let map = def_map_with_crate_graph( | ||
31 | " | ||
32 | //- /my_library.rs | ||
33 | mod foo; | ||
34 | use self::foo::Bar; | ||
35 | |||
36 | //- /foo/mod.rs | ||
37 | pub struct Bar; | ||
38 | ", | ||
39 | crate_graph! { | ||
40 | "my_library": ("/my_library.rs", []), | ||
41 | }, | ||
42 | ); | ||
43 | |||
44 | assert_snapshot_matches!(map, @r###" | ||
45 | ⋮crate | ||
46 | ⋮Bar: t v | ||
47 | ⋮foo: t | ||
48 | ⋮ | ||
49 | ⋮crate::foo | ||
50 | ⋮Bar: t v | ||
51 | "###); | ||
52 | } | ||
53 | |||
54 | #[test] | ||
55 | fn module_resolution_works_for_raw_modules() { | ||
56 | let map = def_map_with_crate_graph( | ||
57 | " | ||
58 | //- /library.rs | ||
59 | mod r#async; | ||
60 | use self::r#async::Bar; | ||
61 | |||
62 | //- /async.rs | ||
63 | pub struct Bar; | ||
64 | ", | ||
65 | crate_graph! { | ||
66 | "library": ("/library.rs", []), | ||
67 | }, | ||
68 | ); | ||
69 | |||
70 | assert_snapshot_matches!(map, @r###" | ||
71 | ⋮crate | ||
72 | ⋮Bar: t v | ||
73 | ⋮async: t | ||
74 | ⋮ | ||
75 | ⋮crate::async | ||
76 | ⋮Bar: t v | ||
77 | "###); | ||
78 | } | ||
79 | |||
80 | #[test] | ||
81 | fn module_resolution_decl_path() { | ||
82 | let map = def_map_with_crate_graph( | ||
83 | " | ||
84 | //- /library.rs | ||
85 | #[path = \"bar/baz/foo.rs\"] | ||
86 | mod foo; | ||
87 | use self::foo::Bar; | ||
88 | |||
89 | //- /bar/baz/foo.rs | ||
90 | pub struct Bar; | ||
91 | ", | ||
92 | crate_graph! { | ||
93 | "library": ("/library.rs", []), | ||
94 | }, | ||
95 | ); | ||
96 | |||
97 | assert_snapshot_matches!(map, @r###" | ||
98 | ⋮crate | ||
99 | ⋮Bar: t v | ||
100 | ⋮foo: t | ||
101 | ⋮ | ||
102 | ⋮crate::foo | ||
103 | ⋮Bar: t v | ||
104 | "###); | ||
105 | } | ||
106 | |||
107 | #[test] | ||
108 | fn module_resolution_module_with_path_in_mod_rs() { | ||
109 | let map = def_map_with_crate_graph( | ||
110 | " | ||
111 | //- /main.rs | ||
112 | mod foo; | ||
113 | |||
114 | //- /foo/mod.rs | ||
115 | #[path = \"baz.rs\"] | ||
116 | pub mod bar; | ||
117 | |||
118 | use self::bar::Baz; | ||
119 | |||
120 | //- /foo/baz.rs | ||
121 | pub struct Baz; | ||
122 | ", | ||
123 | crate_graph! { | ||
124 | "main": ("/main.rs", []), | ||
125 | }, | ||
126 | ); | ||
127 | |||
128 | assert_snapshot_matches!(map, @r###" | ||
129 | ⋮crate | ||
130 | ⋮foo: t | ||
131 | ⋮ | ||
132 | ⋮crate::foo | ||
133 | ⋮Baz: t v | ||
134 | ⋮bar: t | ||
135 | ⋮ | ||
136 | ⋮crate::foo::bar | ||
137 | ⋮Baz: t v | ||
138 | "###); | ||
139 | } | ||
140 | |||
141 | #[test] | ||
142 | fn module_resolution_module_with_path_non_crate_root() { | ||
143 | let map = def_map_with_crate_graph( | ||
144 | " | ||
145 | //- /main.rs | ||
146 | mod foo; | ||
147 | |||
148 | //- /foo.rs | ||
149 | #[path = \"baz.rs\"] | ||
150 | pub mod bar; | ||
151 | |||
152 | use self::bar::Baz; | ||
153 | |||
154 | //- /baz.rs | ||
155 | pub struct Baz; | ||
156 | ", | ||
157 | crate_graph! { | ||
158 | "main": ("/main.rs", []), | ||
159 | }, | ||
160 | ); | ||
161 | |||
162 | assert_snapshot_matches!(map, @r###" | ||
163 | ⋮crate | ||
164 | ⋮foo: t | ||
165 | ⋮ | ||
166 | ⋮crate::foo | ||
167 | ⋮Baz: t v | ||
168 | ⋮bar: t | ||
169 | ⋮ | ||
170 | ⋮crate::foo::bar | ||
171 | ⋮Baz: t v | ||
172 | "###); | ||
173 | } | ||
174 | |||
175 | #[test] | ||
176 | fn unresolved_module_diagnostics() { | ||
177 | let diagnostics = MockDatabase::with_files( | ||
178 | r" | ||
179 | //- /lib.rs | ||
180 | mod foo; | ||
181 | mod bar; | ||
182 | mod baz {} | ||
183 | //- /foo.rs | ||
184 | ", | ||
185 | ) | ||
186 | .diagnostics(); | ||
187 | |||
188 | assert_snapshot_matches!(diagnostics, @r###" | ||
189 | "mod bar;": unresolved module | ||
190 | "### | ||
191 | ); | ||
192 | } | ||
diff --git a/crates/ra_hir/src/ty/method_resolution.rs b/crates/ra_hir/src/ty/method_resolution.rs index 10a6e0b10..76ace66ea 100644 --- a/crates/ra_hir/src/ty/method_resolution.rs +++ b/crates/ra_hir/src/ty/method_resolution.rs | |||
@@ -116,7 +116,7 @@ impl CrateImplBlocks { | |||
116 | 116 | ||
117 | fn def_crates(db: &impl HirDatabase, cur_crate: Crate, ty: &Ty) -> Option<ArrayVec<[Crate; 2]>> { | 117 | fn def_crates(db: &impl HirDatabase, cur_crate: Crate, ty: &Ty) -> Option<ArrayVec<[Crate; 2]>> { |
118 | // Types like slice can have inherent impls in several crates, (core and alloc). | 118 | // Types like slice can have inherent impls in several crates, (core and alloc). |
119 | // The correspoinding impls are marked with lang items, so we can use them to find the required crates. | 119 | // The corresponding impls are marked with lang items, so we can use them to find the required crates. |
120 | macro_rules! lang_item_crate { | 120 | macro_rules! lang_item_crate { |
121 | ($db:expr, $cur_crate:expr, $($name:expr),+ $(,)?) => {{ | 121 | ($db:expr, $cur_crate:expr, $($name:expr),+ $(,)?) => {{ |
122 | let mut v = ArrayVec::<[Crate; 2]>::new(); | 122 | let mut v = ArrayVec::<[Crate; 2]>::new(); |