diff options
author | Jeremy Kolb <[email protected]> | 2019-01-28 14:26:32 +0000 |
---|---|---|
committer | Jeremy Kolb <[email protected]> | 2019-01-30 00:13:02 +0000 |
commit | 3c17643b3085682a695f0e6d80483edc00d04cb3 (patch) | |
tree | 2e76d7be4f703a46608078228124285bc2c94e21 /crates | |
parent | 48d2acb297459fb06cbb49bdce2eccb4c2591714 (diff) |
Go to Implementation for structs and enums
Diffstat (limited to 'crates')
-rw-r--r-- | crates/ra_hir/src/code_model_api.rs | 18 | ||||
-rw-r--r-- | crates/ra_hir/src/code_model_impl/module.rs | 13 | ||||
-rw-r--r-- | crates/ra_hir/src/db.rs | 11 | ||||
-rw-r--r-- | crates/ra_hir/src/impl_block.rs | 57 | ||||
-rw-r--r-- | crates/ra_hir/src/source_binder.rs | 24 | ||||
-rw-r--r-- | crates/ra_hir/src/ty/method_resolution.rs | 6 | ||||
-rw-r--r-- | crates/ra_ide_api/src/impls.rs | 121 | ||||
-rw-r--r-- | crates/ra_ide_api/src/lib.rs | 8 | ||||
-rw-r--r-- | crates/ra_ide_api/src/navigation_target.rs | 10 | ||||
-rw-r--r-- | crates/ra_lsp_server/src/caps.rs | 4 | ||||
-rw-r--r-- | crates/ra_lsp_server/src/main_loop.rs | 1 | ||||
-rw-r--r-- | crates/ra_lsp_server/src/main_loop/handlers.rs | 20 | ||||
-rw-r--r-- | crates/ra_lsp_server/src/req.rs | 2 |
13 files changed, 278 insertions, 17 deletions
diff --git a/crates/ra_hir/src/code_model_api.rs b/crates/ra_hir/src/code_model_api.rs index e4008058c..691cd5798 100644 --- a/crates/ra_hir/src/code_model_api.rs +++ b/crates/ra_hir/src/code_model_api.rs | |||
@@ -10,12 +10,13 @@ use crate::{ | |||
10 | nameres::{ModuleScope, lower::ImportId}, | 10 | nameres::{ModuleScope, lower::ImportId}, |
11 | db::HirDatabase, | 11 | db::HirDatabase, |
12 | expr::BodySyntaxMapping, | 12 | expr::BodySyntaxMapping, |
13 | ty::InferenceResult, | 13 | ty::{InferenceResult}, |
14 | adt::{EnumVariantId, StructFieldId, VariantDef}, | 14 | adt::{EnumVariantId, StructFieldId, VariantDef}, |
15 | generics::GenericParams, | 15 | generics::GenericParams, |
16 | docs::{Documentation, Docs, docs_from_ast}, | 16 | docs::{Documentation, Docs, docs_from_ast}, |
17 | module_tree::ModuleId, | 17 | module_tree::ModuleId, |
18 | ids::{FunctionId, StructId, EnumId, AstItemDef, ConstId, StaticId, TraitId, TypeId}, | 18 | ids::{FunctionId, StructId, EnumId, AstItemDef, ConstId, StaticId, TraitId, TypeId}, |
19 | impl_block::ImplId, | ||
19 | }; | 20 | }; |
20 | 21 | ||
21 | /// hir::Crate describes a single crate. It's the main interface with which | 22 | /// hir::Crate describes a single crate. It's the main interface with which |
@@ -23,7 +24,7 @@ use crate::{ | |||
23 | /// root module. | 24 | /// root module. |
24 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] | 25 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] |
25 | pub struct Crate { | 26 | pub struct Crate { |
26 | pub(crate) crate_id: CrateId, | 27 | pub crate_id: CrateId, |
27 | } | 28 | } |
28 | 29 | ||
29 | #[derive(Debug)] | 30 | #[derive(Debug)] |
@@ -126,6 +127,11 @@ impl Module { | |||
126 | self.import_source_impl(db, import) | 127 | self.import_source_impl(db, import) |
127 | } | 128 | } |
128 | 129 | ||
130 | /// Returns the syntax of the impl block in this module | ||
131 | pub fn impl_source(&self, db: &impl HirDatabase, impl_id: ImplId) -> TreeArc<ast::ImplBlock> { | ||
132 | self.impl_source_impl(db, impl_id) | ||
133 | } | ||
134 | |||
129 | /// Returns the crate this module is part of. | 135 | /// Returns the crate this module is part of. |
130 | pub fn krate(&self, db: &impl HirDatabase) -> Option<Crate> { | 136 | pub fn krate(&self, db: &impl HirDatabase) -> Option<Crate> { |
131 | self.krate_impl(db) | 137 | self.krate_impl(db) |
@@ -272,6 +278,10 @@ impl Struct { | |||
272 | pub fn generic_params(&self, db: &impl HirDatabase) -> Arc<GenericParams> { | 278 | pub fn generic_params(&self, db: &impl HirDatabase) -> Arc<GenericParams> { |
273 | db.generic_params((*self).into()) | 279 | db.generic_params((*self).into()) |
274 | } | 280 | } |
281 | |||
282 | pub fn ty(&self, db: &impl HirDatabase) -> Ty { | ||
283 | db.type_for_def((*self).into()) | ||
284 | } | ||
275 | } | 285 | } |
276 | 286 | ||
277 | impl Docs for Struct { | 287 | impl Docs for Struct { |
@@ -317,6 +327,10 @@ impl Enum { | |||
317 | pub fn generic_params(&self, db: &impl HirDatabase) -> Arc<GenericParams> { | 327 | pub fn generic_params(&self, db: &impl HirDatabase) -> Arc<GenericParams> { |
318 | db.generic_params((*self).into()) | 328 | db.generic_params((*self).into()) |
319 | } | 329 | } |
330 | |||
331 | pub fn ty(&self, db: &impl HirDatabase) -> Ty { | ||
332 | db.type_for_def((*self).into()) | ||
333 | } | ||
320 | } | 334 | } |
321 | 335 | ||
322 | impl Docs for Enum { | 336 | impl Docs for Enum { |
diff --git a/crates/ra_hir/src/code_model_impl/module.rs b/crates/ra_hir/src/code_model_impl/module.rs index 418d59c91..c6f85ac82 100644 --- a/crates/ra_hir/src/code_model_impl/module.rs +++ b/crates/ra_hir/src/code_model_impl/module.rs | |||
@@ -5,6 +5,7 @@ use crate::{ | |||
5 | Module, ModuleSource, Problem, | 5 | Module, ModuleSource, Problem, |
6 | Crate, Name, | 6 | Crate, Name, |
7 | module_tree::ModuleId, | 7 | module_tree::ModuleId, |
8 | impl_block::ImplId, | ||
8 | nameres::{lower::ImportId}, | 9 | nameres::{lower::ImportId}, |
9 | db::HirDatabase, | 10 | db::HirDatabase, |
10 | }; | 11 | }; |
@@ -51,11 +52,21 @@ impl Module { | |||
51 | db: &impl HirDatabase, | 52 | db: &impl HirDatabase, |
52 | import: ImportId, | 53 | import: ImportId, |
53 | ) -> TreeArc<ast::PathSegment> { | 54 | ) -> TreeArc<ast::PathSegment> { |
54 | let source_map = db.lower_module_source_map(self.clone()); | 55 | let source_map = db.lower_module_source_map(*self); |
55 | let (_, source) = self.definition_source(db); | 56 | let (_, source) = self.definition_source(db); |
56 | source_map.get(&source, import) | 57 | source_map.get(&source, import) |
57 | } | 58 | } |
58 | 59 | ||
60 | pub(crate) fn impl_source_impl( | ||
61 | &self, | ||
62 | db: &impl HirDatabase, | ||
63 | impl_id: ImplId, | ||
64 | ) -> TreeArc<ast::ImplBlock> { | ||
65 | let source_map = db.impls_in_module_source_map(*self); | ||
66 | let (_, source) = self.definition_source(db); | ||
67 | source_map.get(&source, impl_id) | ||
68 | } | ||
69 | |||
59 | pub(crate) fn krate_impl(&self, _db: &impl HirDatabase) -> Option<Crate> { | 70 | pub(crate) fn krate_impl(&self, _db: &impl HirDatabase) -> Option<Crate> { |
60 | Some(Crate::new(self.krate)) | 71 | Some(Crate::new(self.krate)) |
61 | } | 72 | } |
diff --git a/crates/ra_hir/src/db.rs b/crates/ra_hir/src/db.rs index 3f76b769d..70d9de212 100644 --- a/crates/ra_hir/src/db.rs +++ b/crates/ra_hir/src/db.rs | |||
@@ -14,7 +14,7 @@ use crate::{ | |||
14 | nameres::{ItemMap, lower::{LoweredModule, ImportSourceMap}}, | 14 | nameres::{ItemMap, lower::{LoweredModule, ImportSourceMap}}, |
15 | ty::{InferenceResult, Ty, method_resolution::CrateImplBlocks, TypableDef}, | 15 | ty::{InferenceResult, Ty, method_resolution::CrateImplBlocks, TypableDef}, |
16 | adt::{StructData, EnumData}, | 16 | adt::{StructData, EnumData}, |
17 | impl_block::ModuleImplBlocks, | 17 | impl_block::{ModuleImplBlocks, ImplSourceMap}, |
18 | generics::{GenericParams, GenericDef}, | 18 | generics::{GenericParams, GenericDef}, |
19 | ids::SourceFileItemId, | 19 | ids::SourceFileItemId, |
20 | }; | 20 | }; |
@@ -73,9 +73,18 @@ pub trait HirDatabase: SourceDatabase + AsRef<HirInterner> { | |||
73 | #[salsa::invoke(crate::module_tree::ModuleTree::module_tree_query)] | 73 | #[salsa::invoke(crate::module_tree::ModuleTree::module_tree_query)] |
74 | fn module_tree(&self, crate_id: CrateId) -> Arc<ModuleTree>; | 74 | fn module_tree(&self, crate_id: CrateId) -> Arc<ModuleTree>; |
75 | 75 | ||
76 | #[salsa::invoke(crate::impl_block::impls_in_module_with_source_map_query)] | ||
77 | fn impls_in_module_with_source_map( | ||
78 | &self, | ||
79 | module: Module, | ||
80 | ) -> (Arc<ModuleImplBlocks>, Arc<ImplSourceMap>); | ||
81 | |||
76 | #[salsa::invoke(crate::impl_block::impls_in_module)] | 82 | #[salsa::invoke(crate::impl_block::impls_in_module)] |
77 | fn impls_in_module(&self, module: Module) -> Arc<ModuleImplBlocks>; | 83 | fn impls_in_module(&self, module: Module) -> Arc<ModuleImplBlocks>; |
78 | 84 | ||
85 | #[salsa::invoke(crate::impl_block::impls_in_module_source_map_query)] | ||
86 | fn impls_in_module_source_map(&self, module: Module) -> Arc<ImplSourceMap>; | ||
87 | |||
79 | #[salsa::invoke(crate::ty::method_resolution::CrateImplBlocks::impls_in_crate_query)] | 88 | #[salsa::invoke(crate::ty::method_resolution::CrateImplBlocks::impls_in_crate_query)] |
80 | fn impls_in_crate(&self, krate: Crate) -> Arc<CrateImplBlocks>; | 89 | fn impls_in_crate(&self, krate: Crate) -> Arc<CrateImplBlocks>; |
81 | 90 | ||
diff --git a/crates/ra_hir/src/impl_block.rs b/crates/ra_hir/src/impl_block.rs index 222e47349..5fc26324a 100644 --- a/crates/ra_hir/src/impl_block.rs +++ b/crates/ra_hir/src/impl_block.rs | |||
@@ -1,8 +1,10 @@ | |||
1 | use std::sync::Arc; | 1 | use std::sync::Arc; |
2 | use rustc_hash::FxHashMap; | 2 | use rustc_hash::FxHashMap; |
3 | 3 | ||
4 | use ra_arena::{Arena, RawId, impl_arena_id}; | 4 | use ra_arena::{Arena, RawId, impl_arena_id, map::ArenaMap}; |
5 | use ra_syntax::ast::{self, AstNode}; | 5 | use ra_syntax::{ |
6 | AstPtr, SourceFile, TreeArc, | ||
7 | ast::{self, AstNode}}; | ||
6 | 8 | ||
7 | use crate::{ | 9 | use crate::{ |
8 | Const, Type, | 10 | Const, Type, |
@@ -14,6 +16,26 @@ use crate::{ | |||
14 | 16 | ||
15 | use crate::code_model_api::{Module, ModuleSource}; | 17 | use crate::code_model_api::{Module, ModuleSource}; |
16 | 18 | ||
19 | #[derive(Debug, Default, PartialEq, Eq)] | ||
20 | pub struct ImplSourceMap { | ||
21 | map: ArenaMap<ImplId, AstPtr<ast::ImplBlock>>, | ||
22 | } | ||
23 | |||
24 | impl ImplSourceMap { | ||
25 | fn insert(&mut self, impl_id: ImplId, impl_block: &ast::ImplBlock) { | ||
26 | self.map.insert(impl_id, AstPtr::new(impl_block)) | ||
27 | } | ||
28 | |||
29 | pub fn get(&self, source: &ModuleSource, impl_id: ImplId) -> TreeArc<ast::ImplBlock> { | ||
30 | let file = match source { | ||
31 | ModuleSource::SourceFile(file) => &*file, | ||
32 | ModuleSource::Module(m) => m.syntax().ancestors().find_map(SourceFile::cast).unwrap(), | ||
33 | }; | ||
34 | |||
35 | self.map[impl_id].to_node(file).to_owned() | ||
36 | } | ||
37 | } | ||
38 | |||
17 | #[derive(Debug, Clone, PartialEq, Eq)] | 39 | #[derive(Debug, Clone, PartialEq, Eq)] |
18 | pub struct ImplBlock { | 40 | pub struct ImplBlock { |
19 | module_impl_blocks: Arc<ModuleImplBlocks>, | 41 | module_impl_blocks: Arc<ModuleImplBlocks>, |
@@ -39,6 +61,10 @@ impl ImplBlock { | |||
39 | } | 61 | } |
40 | } | 62 | } |
41 | 63 | ||
64 | pub fn id(&self) -> ImplId { | ||
65 | self.impl_id | ||
66 | } | ||
67 | |||
42 | fn impl_data(&self) -> &ImplData { | 68 | fn impl_data(&self) -> &ImplData { |
43 | &self.module_impl_blocks.impls[self.impl_id] | 69 | &self.module_impl_blocks.impls[self.impl_id] |
44 | } | 70 | } |
@@ -148,7 +174,7 @@ impl ModuleImplBlocks { | |||
148 | } | 174 | } |
149 | } | 175 | } |
150 | 176 | ||
151 | fn collect(&mut self, db: &impl HirDatabase, module: Module) { | 177 | fn collect(&mut self, db: &impl HirDatabase, module: Module, source_map: &mut ImplSourceMap) { |
152 | let (file_id, module_source) = module.definition_source(db); | 178 | let (file_id, module_source) = module.definition_source(db); |
153 | let file_id: HirFileId = file_id.into(); | 179 | let file_id: HirFileId = file_id.into(); |
154 | let node = match &module_source { | 180 | let node = match &module_source { |
@@ -165,12 +191,31 @@ impl ModuleImplBlocks { | |||
165 | for &impl_item in &self.impls[id].items { | 191 | for &impl_item in &self.impls[id].items { |
166 | self.impls_by_def.insert(impl_item, id); | 192 | self.impls_by_def.insert(impl_item, id); |
167 | } | 193 | } |
194 | |||
195 | source_map.insert(id, impl_block_ast); | ||
168 | } | 196 | } |
169 | } | 197 | } |
170 | } | 198 | } |
171 | 199 | ||
172 | pub(crate) fn impls_in_module(db: &impl HirDatabase, module: Module) -> Arc<ModuleImplBlocks> { | 200 | pub(crate) fn impls_in_module_with_source_map_query( |
201 | db: &impl HirDatabase, | ||
202 | module: Module, | ||
203 | ) -> (Arc<ModuleImplBlocks>, Arc<ImplSourceMap>) { | ||
204 | let mut source_map = ImplSourceMap::default(); | ||
205 | |||
173 | let mut result = ModuleImplBlocks::new(); | 206 | let mut result = ModuleImplBlocks::new(); |
174 | result.collect(db, module); | 207 | result.collect(db, module, &mut source_map); |
175 | Arc::new(result) | 208 | |
209 | (Arc::new(result), Arc::new(source_map)) | ||
210 | } | ||
211 | |||
212 | pub(crate) fn impls_in_module(db: &impl HirDatabase, module: Module) -> Arc<ModuleImplBlocks> { | ||
213 | db.impls_in_module_with_source_map(module).0 | ||
214 | } | ||
215 | |||
216 | pub(crate) fn impls_in_module_source_map_query( | ||
217 | db: &impl HirDatabase, | ||
218 | module: Module, | ||
219 | ) -> Arc<ImplSourceMap> { | ||
220 | db.impls_in_module_with_source_map(module).1 | ||
176 | } | 221 | } |
diff --git a/crates/ra_hir/src/source_binder.rs b/crates/ra_hir/src/source_binder.rs index f523f0647..589efd023 100644 --- a/crates/ra_hir/src/source_binder.rs +++ b/crates/ra_hir/src/source_binder.rs | |||
@@ -13,7 +13,7 @@ use ra_syntax::{ | |||
13 | }; | 13 | }; |
14 | 14 | ||
15 | use crate::{ | 15 | use crate::{ |
16 | HirDatabase, Function, ModuleDef, | 16 | HirDatabase, Function, ModuleDef, Struct, Enum, |
17 | AsName, Module, HirFileId, | 17 | AsName, Module, HirFileId, |
18 | ids::{LocationCtx, SourceFileItemId}, | 18 | ids::{LocationCtx, SourceFileItemId}, |
19 | }; | 19 | }; |
@@ -128,6 +128,28 @@ pub fn function_from_child_node( | |||
128 | function_from_source(db, file_id, fn_def) | 128 | function_from_source(db, file_id, fn_def) |
129 | } | 129 | } |
130 | 130 | ||
131 | pub fn struct_from_module( | ||
132 | db: &impl HirDatabase, | ||
133 | module: Module, | ||
134 | struct_def: &ast::StructDef, | ||
135 | ) -> Struct { | ||
136 | let (file_id, _) = module.definition_source(db); | ||
137 | let file_id = file_id.into(); | ||
138 | let ctx = LocationCtx::new(db, module, file_id); | ||
139 | Struct { | ||
140 | id: ctx.to_def(struct_def), | ||
141 | } | ||
142 | } | ||
143 | |||
144 | pub fn enum_from_module(db: &impl HirDatabase, module: Module, enum_def: &ast::EnumDef) -> Enum { | ||
145 | let (file_id, _) = module.definition_source(db); | ||
146 | let file_id = file_id.into(); | ||
147 | let ctx = LocationCtx::new(db, module, file_id); | ||
148 | Enum { | ||
149 | id: ctx.to_def(enum_def), | ||
150 | } | ||
151 | } | ||
152 | |||
131 | pub fn macro_symbols(db: &impl HirDatabase, file_id: FileId) -> Vec<(SmolStr, TextRange)> { | 153 | pub fn macro_symbols(db: &impl HirDatabase, file_id: FileId) -> Vec<(SmolStr, TextRange)> { |
132 | let module = match module_from_file_id(db, file_id) { | 154 | let module = match module_from_file_id(db, file_id) { |
133 | Some(it) => it, | 155 | Some(it) => it, |
diff --git a/crates/ra_hir/src/ty/method_resolution.rs b/crates/ra_hir/src/ty/method_resolution.rs index 9a571c2aa..d70a24582 100644 --- a/crates/ra_hir/src/ty/method_resolution.rs +++ b/crates/ra_hir/src/ty/method_resolution.rs | |||
@@ -44,7 +44,7 @@ impl CrateImplBlocks { | |||
44 | &'a self, | 44 | &'a self, |
45 | db: &'a impl HirDatabase, | 45 | db: &'a impl HirDatabase, |
46 | ty: &Ty, | 46 | ty: &Ty, |
47 | ) -> impl Iterator<Item = ImplBlock> + 'a { | 47 | ) -> impl Iterator<Item = (Module, ImplBlock)> + 'a { |
48 | let fingerprint = TyFingerprint::for_impl(ty); | 48 | let fingerprint = TyFingerprint::for_impl(ty); |
49 | fingerprint | 49 | fingerprint |
50 | .and_then(|f| self.impls.get(&f)) | 50 | .and_then(|f| self.impls.get(&f)) |
@@ -56,7 +56,7 @@ impl CrateImplBlocks { | |||
56 | module_id: *module_id, | 56 | module_id: *module_id, |
57 | }; | 57 | }; |
58 | let module_impl_blocks = db.impls_in_module(module); | 58 | let module_impl_blocks = db.impls_in_module(module); |
59 | ImplBlock::from_id(module_impl_blocks, *impl_id) | 59 | (module, ImplBlock::from_id(module_impl_blocks, *impl_id)) |
60 | }) | 60 | }) |
61 | } | 61 | } |
62 | 62 | ||
@@ -152,7 +152,7 @@ impl Ty { | |||
152 | }; | 152 | }; |
153 | let impls = db.impls_in_crate(krate); | 153 | let impls = db.impls_in_crate(krate); |
154 | 154 | ||
155 | for impl_block in impls.lookup_impl_blocks(db, &derefed_ty) { | 155 | for (_, impl_block) in impls.lookup_impl_blocks(db, &derefed_ty) { |
156 | for item in impl_block.items() { | 156 | for item in impl_block.items() { |
157 | match item { | 157 | match item { |
158 | ImplItem::Method(f) => { | 158 | ImplItem::Method(f) => { |
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 @@ | |||
1 | use ra_db::{SourceDatabase}; | ||
2 | use ra_syntax::{ | ||
3 | AstNode, ast, | ||
4 | algo::find_node_at_offset, | ||
5 | }; | ||
6 | use hir::{db::HirDatabase, source_binder}; | ||
7 | |||
8 | use crate::{FilePosition, NavigationTarget, db::RootDatabase, RangeInfo}; | ||
9 | |||
10 | pub(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)] | ||
41 | mod 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 | } | ||
diff --git a/crates/ra_ide_api/src/lib.rs b/crates/ra_ide_api/src/lib.rs index 51947e4cc..9ec4fdd95 100644 --- a/crates/ra_ide_api/src/lib.rs +++ b/crates/ra_ide_api/src/lib.rs | |||
@@ -25,6 +25,7 @@ mod call_info; | |||
25 | mod syntax_highlighting; | 25 | mod syntax_highlighting; |
26 | mod parent_module; | 26 | mod parent_module; |
27 | mod rename; | 27 | mod rename; |
28 | mod impls; | ||
28 | 29 | ||
29 | #[cfg(test)] | 30 | #[cfg(test)] |
30 | mod marks; | 31 | mod marks; |
@@ -415,6 +416,13 @@ impl Analysis { | |||
415 | self.with_db(|db| goto_definition::goto_definition(db, position)) | 416 | self.with_db(|db| goto_definition::goto_definition(db, position)) |
416 | } | 417 | } |
417 | 418 | ||
419 | pub fn goto_implementation( | ||
420 | &self, | ||
421 | position: FilePosition, | ||
422 | ) -> Cancelable<Option<RangeInfo<Vec<NavigationTarget>>>> { | ||
423 | self.with_db(|db| impls::goto_implementation(db, position)) | ||
424 | } | ||
425 | |||
418 | /// Finds all usages of the reference at point. | 426 | /// Finds all usages of the reference at point. |
419 | pub fn find_all_refs(&self, position: FilePosition) -> Cancelable<Vec<(FileId, TextRange)>> { | 427 | pub fn find_all_refs(&self, position: FilePosition) -> Cancelable<Vec<(FileId, TextRange)>> { |
420 | self.with_db(|db| db.find_all_refs(position)) | 428 | self.with_db(|db| db.find_all_refs(position)) |
diff --git a/crates/ra_ide_api/src/navigation_target.rs b/crates/ra_ide_api/src/navigation_target.rs index d73d4afa7..5ccb5cc2e 100644 --- a/crates/ra_ide_api/src/navigation_target.rs +++ b/crates/ra_ide_api/src/navigation_target.rs | |||
@@ -147,6 +147,16 @@ impl NavigationTarget { | |||
147 | } | 147 | } |
148 | } | 148 | } |
149 | 149 | ||
150 | pub(crate) fn from_impl_block( | ||
151 | db: &RootDatabase, | ||
152 | module: hir::Module, | ||
153 | impl_block: &hir::ImplBlock, | ||
154 | ) -> NavigationTarget { | ||
155 | let (file_id, _) = module.definition_source(db); | ||
156 | let node = module.impl_source(db, impl_block.id()); | ||
157 | NavigationTarget::from_syntax(file_id, "impl".into(), None, node.syntax()) | ||
158 | } | ||
159 | |||
150 | #[cfg(test)] | 160 | #[cfg(test)] |
151 | pub(crate) fn assert_match(&self, expected: &str) { | 161 | pub(crate) fn assert_match(&self, expected: &str) { |
152 | let actual = self.debug_render(); | 162 | let actual = self.debug_render(); |
diff --git a/crates/ra_lsp_server/src/caps.rs b/crates/ra_lsp_server/src/caps.rs index bca079d65..254624487 100644 --- a/crates/ra_lsp_server/src/caps.rs +++ b/crates/ra_lsp_server/src/caps.rs | |||
@@ -2,7 +2,7 @@ use lsp_types::{ | |||
2 | CodeActionProviderCapability, CodeLensOptions, CompletionOptions, DocumentOnTypeFormattingOptions, | 2 | CodeActionProviderCapability, CodeLensOptions, CompletionOptions, DocumentOnTypeFormattingOptions, |
3 | ExecuteCommandOptions, FoldingRangeProviderCapability, RenameOptions, RenameProviderCapability, | 3 | ExecuteCommandOptions, FoldingRangeProviderCapability, RenameOptions, RenameProviderCapability, |
4 | ServerCapabilities, SignatureHelpOptions, TextDocumentSyncCapability, TextDocumentSyncKind, | 4 | ServerCapabilities, SignatureHelpOptions, TextDocumentSyncCapability, TextDocumentSyncKind, |
5 | TextDocumentSyncOptions, | 5 | TextDocumentSyncOptions, ImplementationProviderCapability, |
6 | }; | 6 | }; |
7 | 7 | ||
8 | pub fn server_capabilities() -> ServerCapabilities { | 8 | pub fn server_capabilities() -> ServerCapabilities { |
@@ -26,7 +26,7 @@ pub fn server_capabilities() -> ServerCapabilities { | |||
26 | }), | 26 | }), |
27 | definition_provider: Some(true), | 27 | definition_provider: Some(true), |
28 | type_definition_provider: None, | 28 | type_definition_provider: None, |
29 | implementation_provider: None, | 29 | implementation_provider: Some(ImplementationProviderCapability::Simple(true)), |
30 | references_provider: Some(true), | 30 | references_provider: Some(true), |
31 | document_highlight_provider: Some(true), | 31 | document_highlight_provider: Some(true), |
32 | document_symbol_provider: Some(true), | 32 | document_symbol_provider: Some(true), |
diff --git a/crates/ra_lsp_server/src/main_loop.rs b/crates/ra_lsp_server/src/main_loop.rs index e430ac6de..df390c19e 100644 --- a/crates/ra_lsp_server/src/main_loop.rs +++ b/crates/ra_lsp_server/src/main_loop.rs | |||
@@ -305,6 +305,7 @@ fn on_request( | |||
305 | .on::<req::DocumentSymbolRequest>(handlers::handle_document_symbol)? | 305 | .on::<req::DocumentSymbolRequest>(handlers::handle_document_symbol)? |
306 | .on::<req::WorkspaceSymbol>(handlers::handle_workspace_symbol)? | 306 | .on::<req::WorkspaceSymbol>(handlers::handle_workspace_symbol)? |
307 | .on::<req::GotoDefinition>(handlers::handle_goto_definition)? | 307 | .on::<req::GotoDefinition>(handlers::handle_goto_definition)? |
308 | .on::<req::GotoImplementation>(handlers::handle_goto_implementation)? | ||
308 | .on::<req::ParentModule>(handlers::handle_parent_module)? | 309 | .on::<req::ParentModule>(handlers::handle_parent_module)? |
309 | .on::<req::Runnables>(handlers::handle_runnables)? | 310 | .on::<req::Runnables>(handlers::handle_runnables)? |
310 | .on::<req::DecorationsRequest>(handlers::handle_decorations)? | 311 | .on::<req::DecorationsRequest>(handlers::handle_decorations)? |
diff --git a/crates/ra_lsp_server/src/main_loop/handlers.rs b/crates/ra_lsp_server/src/main_loop/handlers.rs index 9478ebfb8..e94d76903 100644 --- a/crates/ra_lsp_server/src/main_loop/handlers.rs +++ b/crates/ra_lsp_server/src/main_loop/handlers.rs | |||
@@ -229,6 +229,26 @@ pub fn handle_goto_definition( | |||
229 | Ok(Some(req::GotoDefinitionResponse::Link(res))) | 229 | Ok(Some(req::GotoDefinitionResponse::Link(res))) |
230 | } | 230 | } |
231 | 231 | ||
232 | pub fn handle_goto_implementation( | ||
233 | world: ServerWorld, | ||
234 | params: req::TextDocumentPositionParams, | ||
235 | ) -> Result<Option<req::GotoImplementationResponse>> { | ||
236 | let position = params.try_conv_with(&world)?; | ||
237 | let line_index = world.analysis().file_line_index(position.file_id); | ||
238 | let nav_info = match world.analysis().goto_implementation(position)? { | ||
239 | None => return Ok(None), | ||
240 | Some(it) => it, | ||
241 | }; | ||
242 | let nav_range = nav_info.range; | ||
243 | let res = nav_info | ||
244 | .info | ||
245 | .into_iter() | ||
246 | .map(|nav| RangeInfo::new(nav_range, nav)) | ||
247 | .map(|nav| to_location_link(&nav, &world, &line_index)) | ||
248 | .collect::<Result<Vec<_>>>()?; | ||
249 | Ok(Some(req::GotoDefinitionResponse::Link(res))) | ||
250 | } | ||
251 | |||
232 | pub fn handle_parent_module( | 252 | pub fn handle_parent_module( |
233 | world: ServerWorld, | 253 | world: ServerWorld, |
234 | params: req::TextDocumentPositionParams, | 254 | params: req::TextDocumentPositionParams, |
diff --git a/crates/ra_lsp_server/src/req.rs b/crates/ra_lsp_server/src/req.rs index a4d890755..e224ede80 100644 --- a/crates/ra_lsp_server/src/req.rs +++ b/crates/ra_lsp_server/src/req.rs | |||
@@ -8,7 +8,7 @@ pub use lsp_types::{ | |||
8 | CompletionParams, CompletionResponse, DocumentOnTypeFormattingParams, DocumentSymbolParams, | 8 | CompletionParams, CompletionResponse, DocumentOnTypeFormattingParams, DocumentSymbolParams, |
9 | DocumentSymbolResponse, ExecuteCommandParams, Hover, InitializeResult, | 9 | DocumentSymbolResponse, ExecuteCommandParams, Hover, InitializeResult, |
10 | PublishDiagnosticsParams, ReferenceParams, SignatureHelp, TextDocumentEdit, | 10 | PublishDiagnosticsParams, ReferenceParams, SignatureHelp, TextDocumentEdit, |
11 | TextDocumentPositionParams, TextEdit, WorkspaceEdit, WorkspaceSymbolParams, | 11 | TextDocumentPositionParams, TextEdit, WorkspaceEdit, WorkspaceSymbolParams |
12 | }; | 12 | }; |
13 | 13 | ||
14 | pub enum AnalyzerStatus {} | 14 | pub enum AnalyzerStatus {} |