aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_ide/src/parent_module.rs
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_ide/src/parent_module.rs')
-rw-r--r--crates/ra_ide/src/parent_module.rs40
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
3use ra_db::{CrateId, FileId, FilePosition, SourceDatabase}; 3use ra_db::{CrateId, FileId, FilePosition, SourceDatabase};
4use ra_ide_db::RootDatabase;
4use ra_syntax::{ 5use ra_syntax::{
5 algo::find_node_at_offset, 6 algo::find_node_at_offset,
6 ast::{self, AstNode}, 7 ast::{self, AstNode},
7}; 8};
9use test_utils::tested_by;
8 10
9use crate::{db::RootDatabase, NavigationTarget}; 11use 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.
13pub(crate) fn parent_module(db: &RootDatabase, position: FilePosition) -> Vec<NavigationTarget> { 15pub(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> {
40mod tests { 56mod 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 "