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.rs104
1 files changed, 104 insertions, 0 deletions
diff --git a/crates/ra_ide/src/parent_module.rs b/crates/ra_ide/src/parent_module.rs
new file mode 100644
index 000000000..6027e7d54
--- /dev/null
+++ b/crates/ra_ide/src/parent_module.rs
@@ -0,0 +1,104 @@
1//! FIXME: write short doc here
2
3use ra_db::{CrateId, FileId, FilePosition};
4
5use crate::{db::RootDatabase, NavigationTarget};
6
7/// This returns `Vec` because a module may be included from several places. We
8/// don't handle this case yet though, so the Vec has length at most one.
9pub(crate) fn parent_module(db: &RootDatabase, position: FilePosition) -> Vec<NavigationTarget> {
10 let src = hir::ModuleSource::from_position(db, position);
11 let module = match hir::Module::from_definition(
12 db,
13 hir::Source { file_id: position.file_id.into(), value: src },
14 ) {
15 None => return Vec::new(),
16 Some(it) => it,
17 };
18 let nav = NavigationTarget::from_module_to_decl(db, module);
19 vec![nav]
20}
21
22/// Returns `Vec` for the same reason as `parent_module`
23pub(crate) fn crate_for(db: &RootDatabase, file_id: FileId) -> Vec<CrateId> {
24 let src = hir::ModuleSource::from_file_id(db, file_id);
25 let module =
26 match hir::Module::from_definition(db, hir::Source { file_id: file_id.into(), value: src })
27 {
28 Some(it) => it,
29 None => return Vec::new(),
30 };
31 let krate = module.krate();
32 vec![krate.crate_id()]
33}
34
35#[cfg(test)]
36mod tests {
37 use ra_cfg::CfgOptions;
38 use ra_db::Env;
39
40 use crate::{
41 mock_analysis::{analysis_and_position, MockAnalysis},
42 AnalysisChange, CrateGraph,
43 Edition::Edition2018,
44 };
45
46 #[test]
47 fn test_resolve_parent_module() {
48 let (analysis, pos) = analysis_and_position(
49 "
50 //- /lib.rs
51 mod foo;
52 //- /foo.rs
53 <|>// empty
54 ",
55 );
56 let nav = analysis.parent_module(pos).unwrap().pop().unwrap();
57 nav.assert_match("foo MODULE FileId(1) [0; 8)");
58 }
59
60 #[test]
61 fn test_resolve_parent_module_for_inline() {
62 let (analysis, pos) = analysis_and_position(
63 "
64 //- /lib.rs
65 mod foo {
66 mod bar {
67 mod baz { <|> }
68 }
69 }
70 ",
71 );
72 let nav = analysis.parent_module(pos).unwrap().pop().unwrap();
73 nav.assert_match("baz MODULE FileId(1) [32; 44)");
74 }
75
76 #[test]
77 fn test_resolve_crate_root() {
78 let mock = MockAnalysis::with_files(
79 "
80 //- /bar.rs
81 mod foo;
82 //- /foo.rs
83 // empty <|>
84 ",
85 );
86 let root_file = mock.id_of("/bar.rs");
87 let mod_file = mock.id_of("/foo.rs");
88 let mut host = mock.analysis_host();
89 assert!(host.analysis().crate_for(mod_file).unwrap().is_empty());
90
91 let mut crate_graph = CrateGraph::default();
92 let crate_id = crate_graph.add_crate_root(
93 root_file,
94 Edition2018,
95 CfgOptions::default(),
96 Env::default(),
97 );
98 let mut change = AnalysisChange::new();
99 change.set_crate_graph(crate_graph);
100 host.apply_change(change);
101
102 assert_eq!(host.analysis().crate_for(mod_file).unwrap(), vec![crate_id]);
103 }
104}