aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_hir
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_hir')
-rw-r--r--crates/ra_hir/src/nameres.rs4
-rw-r--r--crates/ra_hir/src/nameres/collector.rs31
-rw-r--r--crates/ra_hir/src/nameres/raw.rs22
-rw-r--r--crates/ra_hir/src/nameres/tests.rs97
-rw-r--r--crates/ra_hir/src/nameres/tests/mods.rs192
-rw-r--r--crates/ra_hir/src/ty/method_resolution.rs2
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)]
81pub struct CrateDefMap { 81pub 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 @@
1use arrayvec::ArrayVec; 1use arrayvec::ArrayVec;
2use ra_db::FileId; 2use ra_db::FileId;
3use ra_syntax::ast; 3use ra_syntax::{ast, SmolStr};
4use relative_path::RelativePathBuf; 4use relative_path::RelativePathBuf;
5use rustc_hash::FxHashMap; 5use rustc_hash::FxHashMap;
6use test_utils::tested_by; 6use 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};
3use ra_arena::{impl_arena_id, map::ArenaMap, Arena, RawId}; 3use ra_arena::{impl_arena_id, map::ArenaMap, Arena, RawId};
4use ra_syntax::{ 4use 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};
8use test_utils::tested_by; 8use 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)]
132pub(super) enum ModuleData { 132pub(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
346fn 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;
2mod globs; 2mod globs;
3mod incremental; 3mod incremental;
4mod primitives; 4mod primitives;
5mod mods;
5 6
6use std::sync::Arc; 7use std::sync::Arc;
7 8
@@ -313,83 +314,6 @@ fn edition_2015_imports() {
313} 314}
314 315
315#[test] 316#[test]
316fn 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]
342fn 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]
368fn 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]
393fn item_map_using_self() { 317fn 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]
586fn 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 @@
1use super::*;
2
3#[test]
4fn 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]
29fn 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]
55fn 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]
81fn 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]
108fn 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]
142fn 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]
176fn 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
117fn def_crates(db: &impl HirDatabase, cur_crate: Crate, ty: &Ty) -> Option<ArrayVec<[Crate; 2]>> { 117fn 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();