feat: goto def on impl items also goes to the defn in the trait

It was trivial to extend this to associated consts/associated types and
I just didn't think of it.
This commit is contained in:
Jade 2021-06-06 21:48:06 -07:00
parent 8a57c73640
commit 34ce05781f

View file

@ -57,7 +57,7 @@ pub(crate) fn goto_definition(
}, },
ast::Name(name) => { ast::Name(name) => {
let def = NameClass::classify(&sema, &name)?.referenced_or_defined(sema.db); let def = NameClass::classify(&sema, &name)?.referenced_or_defined(sema.db);
try_find_trait_fn_definition(&sema.db, &def) try_find_trait_item_definition(&sema.db, &def)
.or_else(|| def.try_to_nav(sema.db)) .or_else(|| def.try_to_nav(sema.db))
}, },
ast::Lifetime(lt) => if let Some(name_class) = NameClass::classify_lifetime(&sema, &lt) { ast::Lifetime(lt) => if let Some(name_class) = NameClass::classify_lifetime(&sema, &lt) {
@ -100,31 +100,33 @@ fn try_lookup_include_path(
}) })
} }
/// finds the trait definition of an impl'd function /// finds the trait definition of an impl'd item
/// e.g. /// e.g.
/// ```rust /// ```rust
/// trait A { fn a(); } /// trait A { fn a(); }
/// struct S; /// struct S;
/// impl A for S { fn a(); } // <-- on this function, will get the location of a() in the trait /// impl A for S { fn a(); } // <-- on this function, will get the location of a() in the trait
/// ``` /// ```
fn try_find_trait_fn_definition(db: &RootDatabase, def: &Definition) -> Option<NavigationTarget> { fn try_find_trait_item_definition(db: &RootDatabase, def: &Definition) -> Option<NavigationTarget> {
match def {
Definition::ModuleDef(ModuleDef::Function(f)) => {
let name = def.name(db)?; let name = def.name(db)?;
let assoc = f.as_assoc_item(db)?; let assoc = match def {
Definition::ModuleDef(ModuleDef::Function(f)) => f.as_assoc_item(db),
Definition::ModuleDef(ModuleDef::Const(c)) => c.as_assoc_item(db),
Definition::ModuleDef(ModuleDef::TypeAlias(ty)) => ty.as_assoc_item(db),
_ => None,
}?;
let imp = match assoc.container(db) { let imp = match assoc.container(db) {
hir::AssocItemContainer::Impl(imp) => imp, hir::AssocItemContainer::Impl(imp) => imp,
_ => return None, _ => return None,
}; };
let trait_ = imp.trait_(db)?; let trait_ = imp.trait_(db)?;
trait_ trait_
.items(db) .items(db)
.iter() .iter()
.find_map(|itm| (itm.name(db)? == name).then(|| itm.try_to_nav(db)).flatten()) .find_map(|itm| (itm.name(db)? == name).then(|| itm.try_to_nav(db)).flatten())
} }
_ => None,
}
}
fn pick_best(tokens: TokenAtOffset<SyntaxToken>) -> Option<SyntaxToken> { fn pick_best(tokens: TokenAtOffset<SyntaxToken>) -> Option<SyntaxToken> {
return tokens.max_by_key(priority); return tokens.max_by_key(priority);
@ -1304,6 +1306,42 @@ struct Stwuct;
impl Twait for Stwuct { impl Twait for Stwuct {
fn a$0(); fn a$0();
} }
"#,
);
}
#[test]
fn goto_def_of_trait_impl_const() {
check(
r#"
trait Twait {
const NOMS: bool;
// ^^^^
}
struct Stwuct;
impl Twait for Stwuct {
const NOMS$0: bool = true;
}
"#,
);
}
#[test]
fn goto_def_of_trait_impl_type_alias() {
check(
r#"
trait Twait {
type IsBad;
// ^^^^^
}
struct Stwuct;
impl Twait for Stwuct {
type IsBad$0 = !;
}
"#, "#,
); );
} }