From f0fdc9d5c0b5c8712bbd94da20289fda4259d793 Mon Sep 17 00:00:00 2001 From: kjeremy Date: Thu, 31 Jan 2019 18:34:52 -0500 Subject: Go To Implementation for Trait --- crates/ra_ide_api/src/impls.rs | 84 +++++++++++++++++++++++++++++++++++++++--- 1 file changed, 78 insertions(+), 6 deletions(-) (limited to 'crates/ra_ide_api/src') diff --git a/crates/ra_ide_api/src/impls.rs b/crates/ra_ide_api/src/impls.rs index 469d56d63..91fa41f1f 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::(syntax, position.offset)?; + if let Some(nominal_def) = find_node_at_offset::(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::(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> { 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> { + 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)", + ], + ); + } } -- cgit v1.2.3