ide/
child_modules.rs
1use hir::Semantics;
2use ide_db::{FilePosition, RootDatabase};
3use syntax::{
4 algo::find_node_at_offset,
5 ast::{self, AstNode},
6};
7
8use crate::NavigationTarget;
9
10pub(crate) fn child_modules(db: &RootDatabase, position: FilePosition) -> Vec<NavigationTarget> {
20 let sema = Semantics::new(db);
21 let source_file = sema.parse_guess_edition(position.file_id);
22 let module = find_node_at_offset::<ast::Module>(source_file.syntax(), position.offset);
24
25 match module {
26 Some(module) => {
27 sema.to_def(&module)
29 .into_iter()
30 .flat_map(|module| module.children(db))
31 .map(|module| NavigationTarget::from_module_to_decl(db, module).call_site())
32 .collect()
33 }
34 None => {
35 sema.file_to_module_defs(position.file_id)
37 .flat_map(|module| module.children(db))
38 .map(|module| NavigationTarget::from_module_to_decl(db, module).call_site())
39 .collect()
40 }
41 }
42}
43
44#[cfg(test)]
45mod tests {
46 use ide_db::FileRange;
47
48 use crate::fixture;
49
50 fn check_child_module(#[rust_analyzer::rust_fixture] ra_fixture: &str) {
51 let (analysis, position, expected) = fixture::annotations(ra_fixture);
52 let navs = analysis.child_modules(position).unwrap();
53 let navs = navs
54 .iter()
55 .map(|nav| FileRange { file_id: nav.file_id, range: nav.focus_or_full_range() })
56 .collect::<Vec<_>>();
57 assert_eq!(expected.into_iter().map(|(fr, _)| fr).collect::<Vec<_>>(), navs);
58 }
59
60 #[test]
61 fn test_resolve_child_module() {
62 check_child_module(
63 r#"
64//- /lib.rs
65$0
66mod foo;
67 //^^^
68
69//- /foo.rs
70// empty
71"#,
72 );
73 }
74
75 #[test]
76 fn test_resolve_child_module_on_module_decl() {
77 check_child_module(
78 r#"
79//- /lib.rs
80mod $0foo;
81//- /foo.rs
82mod bar;
83 //^^^
84
85//- /foo/bar.rs
86// empty
87"#,
88 );
89 }
90
91 #[test]
92 fn test_resolve_child_module_for_inline() {
93 check_child_module(
94 r#"
95//- /lib.rs
96mod foo {
97 mod $0bar {
98 mod baz {}
99 } //^^^
100}
101"#,
102 );
103 }
104
105 #[test]
106 fn test_resolve_multi_child_module() {
107 check_child_module(
108 r#"
109//- /main.rs
110$0
111mod foo;
112 //^^^
113mod bar;
114 //^^^
115//- /foo.rs
116// empty
117
118//- /bar.rs
119// empty
120"#,
121 );
122 }
123}