diff options
Diffstat (limited to 'crates/ra_ide/src/parent_module.rs')
-rw-r--r-- | crates/ra_ide/src/parent_module.rs | 40 |
1 files changed, 38 insertions, 2 deletions
diff --git a/crates/ra_ide/src/parent_module.rs b/crates/ra_ide/src/parent_module.rs index 2dbccfc3b..af14d6ab3 100644 --- a/crates/ra_ide/src/parent_module.rs +++ b/crates/ra_ide/src/parent_module.rs | |||
@@ -1,19 +1,35 @@ | |||
1 | //! FIXME: write short doc here | 1 | //! FIXME: write short doc here |
2 | 2 | ||
3 | use ra_db::{CrateId, FileId, FilePosition, SourceDatabase}; | 3 | use ra_db::{CrateId, FileId, FilePosition, SourceDatabase}; |
4 | use ra_ide_db::RootDatabase; | ||
4 | use ra_syntax::{ | 5 | use ra_syntax::{ |
5 | algo::find_node_at_offset, | 6 | algo::find_node_at_offset, |
6 | ast::{self, AstNode}, | 7 | ast::{self, AstNode}, |
7 | }; | 8 | }; |
9 | use test_utils::tested_by; | ||
8 | 10 | ||
9 | use crate::{db::RootDatabase, NavigationTarget}; | 11 | use crate::NavigationTarget; |
10 | 12 | ||
11 | /// This returns `Vec` because a module may be included from several places. We | 13 | /// This returns `Vec` because a module may be included from several places. We |
12 | /// don't handle this case yet though, so the Vec has length at most one. | 14 | /// don't handle this case yet though, so the Vec has length at most one. |
13 | pub(crate) fn parent_module(db: &RootDatabase, position: FilePosition) -> Vec<NavigationTarget> { | 15 | pub(crate) fn parent_module(db: &RootDatabase, position: FilePosition) -> Vec<NavigationTarget> { |
14 | let mut sb = hir::SourceBinder::new(db); | 16 | let mut sb = hir::SourceBinder::new(db); |
15 | let parse = db.parse(position.file_id); | 17 | let parse = db.parse(position.file_id); |
16 | let module = match find_node_at_offset::<ast::Module>(parse.tree().syntax(), position.offset) { | 18 | |
19 | let mut module = find_node_at_offset::<ast::Module>(parse.tree().syntax(), position.offset); | ||
20 | |||
21 | // If cursor is literally on `mod foo`, go to the grandpa. | ||
22 | if let Some(m) = &module { | ||
23 | if !m | ||
24 | .item_list() | ||
25 | .map_or(false, |it| it.syntax().text_range().contains_inclusive(position.offset)) | ||
26 | { | ||
27 | tested_by!(test_resolve_parent_module_on_module_decl); | ||
28 | module = m.syntax().ancestors().skip(1).find_map(ast::Module::cast); | ||
29 | } | ||
30 | } | ||
31 | |||
32 | let module = match module { | ||
17 | Some(module) => sb.to_def(hir::InFile::new(position.file_id.into(), module)), | 33 | Some(module) => sb.to_def(hir::InFile::new(position.file_id.into(), module)), |
18 | None => sb.to_module_def(position.file_id), | 34 | None => sb.to_module_def(position.file_id), |
19 | }; | 35 | }; |
@@ -40,6 +56,7 @@ pub(crate) fn crate_for(db: &RootDatabase, file_id: FileId) -> Vec<CrateId> { | |||
40 | mod tests { | 56 | mod tests { |
41 | use ra_cfg::CfgOptions; | 57 | use ra_cfg::CfgOptions; |
42 | use ra_db::Env; | 58 | use ra_db::Env; |
59 | use test_utils::covers; | ||
43 | 60 | ||
44 | use crate::{ | 61 | use crate::{ |
45 | mock_analysis::{analysis_and_position, MockAnalysis}, | 62 | mock_analysis::{analysis_and_position, MockAnalysis}, |
@@ -62,6 +79,25 @@ mod tests { | |||
62 | } | 79 | } |
63 | 80 | ||
64 | #[test] | 81 | #[test] |
82 | fn test_resolve_parent_module_on_module_decl() { | ||
83 | covers!(test_resolve_parent_module_on_module_decl); | ||
84 | let (analysis, pos) = analysis_and_position( | ||
85 | " | ||
86 | //- /lib.rs | ||
87 | mod foo; | ||
88 | |||
89 | //- /foo.rs | ||
90 | mod <|>bar; | ||
91 | |||
92 | //- /foo/bar.rs | ||
93 | // empty | ||
94 | ", | ||
95 | ); | ||
96 | let nav = analysis.parent_module(pos).unwrap().pop().unwrap(); | ||
97 | nav.assert_match("foo MODULE FileId(1) [0; 8)"); | ||
98 | } | ||
99 | |||
100 | #[test] | ||
65 | fn test_resolve_parent_module_for_inline() { | 101 | fn test_resolve_parent_module_for_inline() { |
66 | let (analysis, pos) = analysis_and_position( | 102 | let (analysis, pos) = analysis_and_position( |
67 | " | 103 | " |