aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_ide_api/src/impls.rs
diff options
context:
space:
mode:
authorJeremy Kolb <[email protected]>2019-01-28 14:26:32 +0000
committerJeremy Kolb <[email protected]>2019-01-30 00:13:02 +0000
commit3c17643b3085682a695f0e6d80483edc00d04cb3 (patch)
tree2e76d7be4f703a46608078228124285bc2c94e21 /crates/ra_ide_api/src/impls.rs
parent48d2acb297459fb06cbb49bdce2eccb4c2591714 (diff)
Go to Implementation for structs and enums
Diffstat (limited to 'crates/ra_ide_api/src/impls.rs')
-rw-r--r--crates/ra_ide_api/src/impls.rs121
1 files changed, 121 insertions, 0 deletions
diff --git a/crates/ra_ide_api/src/impls.rs b/crates/ra_ide_api/src/impls.rs
new file mode 100644
index 000000000..16a05758a
--- /dev/null
+++ b/crates/ra_ide_api/src/impls.rs
@@ -0,0 +1,121 @@
1use ra_db::{SourceDatabase};
2use ra_syntax::{
3 AstNode, ast,
4 algo::find_node_at_offset,
5};
6use hir::{db::HirDatabase, source_binder};
7
8use crate::{FilePosition, NavigationTarget, db::RootDatabase, RangeInfo};
9
10pub(crate) fn goto_implementation(
11 db: &RootDatabase,
12 position: FilePosition,
13) -> Option<RangeInfo<Vec<NavigationTarget>>> {
14 let file = db.parse(position.file_id);
15 let syntax = file.syntax();
16
17 let krate_id = db.crate_for(position.file_id).pop()?;
18 let krate = hir::Crate { crate_id: krate_id };
19 let module = source_binder::module_from_position(db, position)?;
20
21 let node = find_node_at_offset::<ast::NominalDef>(syntax, position.offset)?;
22 let ty = match node.kind() {
23 ast::NominalDefKind::StructDef(def) => {
24 source_binder::struct_from_module(db, module, &def).ty(db)
25 }
26 ast::NominalDefKind::EnumDef(def) => {
27 source_binder::enum_from_module(db, module, &def).ty(db)
28 }
29 };
30
31 let impls = db.impls_in_crate(krate);
32
33 let navs = impls
34 .lookup_impl_blocks(db, &ty)
35 .map(|(module, imp)| NavigationTarget::from_impl_block(db, module, &imp));
36
37 Some(RangeInfo::new(node.syntax().range(), navs.collect()))
38}
39
40#[cfg(test)]
41mod tests {
42 use crate::mock_analysis::analysis_and_position;
43
44 fn check_goto(fixuture: &str, expected: &[&str]) {
45 let (analysis, pos) = analysis_and_position(fixuture);
46
47 let navs = analysis.goto_implementation(pos).unwrap().unwrap().info;
48 assert_eq!(navs.len(), expected.len());
49 navs.into_iter()
50 .enumerate()
51 .for_each(|(i, nav)| nav.assert_match(expected[i]));
52 }
53
54 #[test]
55 fn goto_implementation_works() {
56 check_goto(
57 "
58 //- /lib.rs
59 struct Foo<|>;
60 impl Foo {}
61 ",
62 &["impl IMPL_BLOCK FileId(1) [12; 23)"],
63 );
64 }
65
66 #[test]
67 fn goto_implementation_works_multiple_blocks() {
68 check_goto(
69 "
70 //- /lib.rs
71 struct Foo<|>;
72 impl Foo {}
73 impl Foo {}
74 ",
75 &[
76 "impl IMPL_BLOCK FileId(1) [12; 23)",
77 "impl IMPL_BLOCK FileId(1) [24; 35)",
78 ],
79 );
80 }
81
82 #[test]
83 fn goto_implementation_works_multiple_mods() {
84 check_goto(
85 "
86 //- /lib.rs
87 struct Foo<|>;
88 mod a {
89 impl super::Foo {}
90 }
91 mod b {
92 impl super::Foo {}
93 }
94 ",
95 &[
96 "impl IMPL_BLOCK FileId(1) [24; 42)",
97 "impl IMPL_BLOCK FileId(1) [57; 75)",
98 ],
99 );
100 }
101
102 #[test]
103 fn goto_implementation_works_multiple_files() {
104 check_goto(
105 "
106 //- /lib.rs
107 struct Foo<|>;
108 mod a;
109 mod b;
110 //- /a.rs
111 impl crate::Foo {}
112 //- /b.rs
113 impl crate::Foo {}
114 ",
115 &[
116 "impl IMPL_BLOCK FileId(2) [0; 18)",
117 "impl IMPL_BLOCK FileId(3) [0; 18)",
118 ],
119 );
120 }
121}