diff options
| author | kjeremy <kjeremy@gmail.com> | 2019-01-31 18:34:52 -0500 |
|---|---|---|
| committer | kjeremy <kjeremy@gmail.com> | 2019-01-31 18:34:52 -0500 |
| commit | f0fdc9d5c0b5c8712bbd94da20289fda4259d793 (patch) | |
| tree | 0015874d918f8be2ec848ab2b110d4478890388b /crates/ra_ide_api/src/impls.rs | |
| parent | 4c0ab7db85d2084870db4a2f92d92a3ae67a3bb1 (diff) | |
| download | rust-f0fdc9d5c0b5c8712bbd94da20289fda4259d793.tar.gz rust-f0fdc9d5c0b5c8712bbd94da20289fda4259d793.zip | |
Go To Implementation for Trait
Diffstat (limited to 'crates/ra_ide_api/src/impls.rs')
| -rw-r--r-- | crates/ra_ide_api/src/impls.rs | 84 |
1 files changed, 78 insertions, 6 deletions
diff --git a/crates/ra_ide_api/src/impls.rs b/crates/ra_ide_api/src/impls.rs index 469d56d63ac..91fa41f1f4b 100644 --- a/crates/ra_ide_api/src/impls.rs +++ b/crates/ra_ide_api/src/impls.rs @@ -15,9 +15,27 @@ pub(crate) fn goto_implementation( let syntax = file.syntax(); let module = source_binder::module_from_position(db, position)?; - let krate = module.krate(db)?; - let node = find_node_at_offset::<ast::NominalDef>(syntax, position.offset)?; + if let Some(nominal_def) = find_node_at_offset::<ast::NominalDef>(syntax, position.offset) { + return Some(RangeInfo::new( + nominal_def.syntax().range(), + impls_for_def(db, nominal_def, module)?, + )); + } else if let Some(trait_def) = find_node_at_offset::<ast::TraitDef>(syntax, position.offset) { + return Some(RangeInfo::new( + trait_def.syntax().range(), + impls_for_trait(db, trait_def, module)?, + )); + } + + None +} + +fn impls_for_def( + db: &RootDatabase, + node: &ast::NominalDef, + module: hir::Module, +) -> Option<Vec<NavigationTarget>> { let ty = match node.kind() { ast::NominalDefKind::StructDef(def) => { source_binder::struct_from_module(db, module, &def).ty(db) @@ -27,13 +45,33 @@ pub(crate) fn goto_implementation( } }; + let krate = module.krate(db)?; let impls = db.impls_in_crate(krate); - let navs = impls - .lookup_impl_blocks(db, &ty) - .map(|(module, imp)| NavigationTarget::from_impl_block(db, module, &imp)); + Some( + impls + .lookup_impl_blocks(db, &ty) + .map(|(module, imp)| NavigationTarget::from_impl_block(db, module, &imp)) + .collect(), + ) +} + +fn impls_for_trait( + db: &RootDatabase, + node: &ast::TraitDef, + module: hir::Module, +) -> Option<Vec<NavigationTarget>> { + let tr = source_binder::trait_from_module(db, module, node); - Some(RangeInfo::new(node.syntax().range(), navs.collect())) + let krate = module.krate(db)?; + let impls = db.impls_in_crate(krate); + + Some( + impls + .lookup_impl_blocks_for_trait(db, &tr) + .map(|(module, imp)| NavigationTarget::from_impl_block(db, module, &imp)) + .collect(), + ) } #[cfg(test)] @@ -117,4 +155,38 @@ mod tests { ], ); } + + #[test] + fn goto_implementation_for_trait() { + check_goto( + " + //- /lib.rs + trait T<|> {} + struct Foo; + impl T for Foo {} + ", + &["impl IMPL_BLOCK FileId(1) [23; 40)"], + ); + } + + #[test] + fn goto_implementation_for_trait_multiple_files() { + check_goto( + " + //- /lib.rs + trait T<|> {}; + struct Foo; + mod a; + mod b; + //- /a.rs + impl crate::T for crate::Foo {} + //- /b.rs + impl crate::T for crate::Foo {} + ", + &[ + "impl IMPL_BLOCK FileId(2) [0; 31)", + "impl IMPL_BLOCK FileId(3) [0; 31)", + ], + ); + } } |
