From 09c7e22ec2705a91ee9da28c9e38810fab97eb3d Mon Sep 17 00:00:00 2001 From: TJ DeVries Date: Tue, 30 Nov 2021 11:16:11 -0500 Subject: [PATCH 1/3] fix: emit trait names in moniker identifier --- crates/ide/src/moniker.rs | 56 ++++++++++++++++++++++++++++++++++++--- 1 file changed, 53 insertions(+), 3 deletions(-) diff --git a/crates/ide/src/moniker.rs b/crates/ide/src/moniker.rs index 9d8c742fc466..5802dd10e5bd 100644 --- a/crates/ide/src/moniker.rs +++ b/crates/ide/src/moniker.rs @@ -1,7 +1,7 @@ //! This module generates [moniker](https://microsoft.github.io/language-server-protocol/specifications/lsif/0.6.0/specification/#exportsImports) //! for LSIF and LSP. -use hir::{db::DefDatabase, Crate, Name, Semantics}; +use hir::{db::DefDatabase, AsAssocItem, AssocItemContainer, Crate, Name, Semantics}; use ide_db::{ base_db::{CrateOrigin, FileId, FileLoader, FilePosition}, defs::Definition, @@ -106,9 +106,21 @@ pub(crate) fn def_to_moniker( let krate = module.krate(); let mut path = vec![]; path.extend(module.path_to_root(db).into_iter().filter_map(|x| x.name(db))); - if let Definition::Field(it) = def { - path.push(it.parent_def(db).name(db)); + + match def { + Definition::Field(it) => path.push(it.parent_def(db).name(db)), + Definition::Function(it) => { + // Ensure that trait functions are properly namespaced with the trait name + if let Some(assoc) = it.as_assoc_item(db) { + let container = assoc.container(db); + if let AssocItemContainer::Trait(parent_trait) = container { + path.push(parent_trait.name(db)); + } + } + } + _ => (), } + path.push(def.name(db)?); Some(MonikerResult { identifier: MonikerIdentifier { @@ -192,6 +204,44 @@ pub mod module { ); } + #[test] + fn moniker_for_trait() { + check_moniker( + r#" +//- /lib.rs crate:main deps:foo +use foo::module::func; +fn main() { + func(); +} +//- /foo/lib.rs crate:foo@CratesIo:0.1.0,https://a.b/foo.git +pub mod module { + pub trait MyTrait { + pub fn func$0() {} + } +} +"#, + "foo::module::MyTrait::func", + r#"PackageInformation { name: "foo", repo: "https://a.b/foo.git", version: "0.1.0" }"#, + MonikerKind::Export, + ); + check_moniker( + r#" +//- /lib.rs crate:main deps:foo +use foo::module::func; +fn main() { + func(); +} +//- /foo/lib.rs crate:foo@CratesIo:0.1.0,https://a.b/foo.git +pub mod module { + pub fn func$0() {} +} +"#, + "foo::module::func", + r#"PackageInformation { name: "foo", repo: "https://a.b/foo.git", version: "0.1.0" }"#, + MonikerKind::Export, + ); + } + #[test] fn moniker_for_field() { check_moniker( From d50f18fb65b2a4e991e765df0fcdfd8852a63eb1 Mon Sep 17 00:00:00 2001 From: TJ DeVries Date: Wed, 1 Dec 2021 11:43:52 -0500 Subject: [PATCH 2/3] fixup: properly handle all associated items --- crates/ide/src/moniker.rs | 57 +++++++++++++++++++++++---------------- 1 file changed, 34 insertions(+), 23 deletions(-) diff --git a/crates/ide/src/moniker.rs b/crates/ide/src/moniker.rs index 5802dd10e5bd..e691bfb06f10 100644 --- a/crates/ide/src/moniker.rs +++ b/crates/ide/src/moniker.rs @@ -107,18 +107,16 @@ pub(crate) fn def_to_moniker( let mut path = vec![]; path.extend(module.path_to_root(db).into_iter().filter_map(|x| x.name(db))); - match def { - Definition::Field(it) => path.push(it.parent_def(db).name(db)), - Definition::Function(it) => { - // Ensure that trait functions are properly namespaced with the trait name - if let Some(assoc) = it.as_assoc_item(db) { - let container = assoc.container(db); - if let AssocItemContainer::Trait(parent_trait) = container { - path.push(parent_trait.name(db)); - } - } + // Handle associated items within a trait + if let Some(assoc) = def.as_assoc_item(db) { + let container = assoc.container(db); + if let AssocItemContainer::Trait(parent_trait) = container { + path.push(parent_trait.name(db)); } - _ => (), + } + + if let Definition::Field(it) = def { + path.push(it.parent_def(db).name(db)); } path.push(def.name(db)?); @@ -208,11 +206,6 @@ pub mod module { fn moniker_for_trait() { check_moniker( r#" -//- /lib.rs crate:main deps:foo -use foo::module::func; -fn main() { - func(); -} //- /foo/lib.rs crate:foo@CratesIo:0.1.0,https://a.b/foo.git pub mod module { pub trait MyTrait { @@ -224,19 +217,37 @@ pub mod module { r#"PackageInformation { name: "foo", repo: "https://a.b/foo.git", version: "0.1.0" }"#, MonikerKind::Export, ); + } + + #[test] + fn moniker_for_trait_constant() { check_moniker( r#" -//- /lib.rs crate:main deps:foo -use foo::module::func; -fn main() { - func(); -} //- /foo/lib.rs crate:foo@CratesIo:0.1.0,https://a.b/foo.git pub mod module { - pub fn func$0() {} + pub trait MyTrait { + const MY_CONST$0: u8; + } } "#, - "foo::module::func", + "foo::module::MyTrait::MY_CONST", + r#"PackageInformation { name: "foo", repo: "https://a.b/foo.git", version: "0.1.0" }"#, + MonikerKind::Export, + ); + } + + #[test] + fn moniker_for_trait_type() { + check_moniker( + r#" +//- /foo/lib.rs crate:foo@CratesIo:0.1.0,https://a.b/foo.git +pub mod module { + pub trait MyTrait { + type MyType$0; + } +} +"#, + "foo::module::MyTrait::MyType", r#"PackageInformation { name: "foo", repo: "https://a.b/foo.git", version: "0.1.0" }"#, MonikerKind::Export, ); From 6870bfd09951896b7115cff4c6817dd7c29da86f Mon Sep 17 00:00:00 2001 From: TJ DeVries Date: Thu, 2 Dec 2021 00:04:03 -0500 Subject: [PATCH 3/3] fixup: include more information for impls --- crates/ide/src/moniker.rs | 42 +++++++++++++++++++++++++++++++++++++-- 1 file changed, 40 insertions(+), 2 deletions(-) diff --git a/crates/ide/src/moniker.rs b/crates/ide/src/moniker.rs index e691bfb06f10..c93c471f4948 100644 --- a/crates/ide/src/moniker.rs +++ b/crates/ide/src/moniker.rs @@ -110,8 +110,23 @@ pub(crate) fn def_to_moniker( // Handle associated items within a trait if let Some(assoc) = def.as_assoc_item(db) { let container = assoc.container(db); - if let AssocItemContainer::Trait(parent_trait) = container { - path.push(parent_trait.name(db)); + match container { + AssocItemContainer::Trait(trait_) => { + // Because different traits can have functions with the same name, + // we have to include the trait name as part of the moniker for uniqueness. + path.push(trait_.name(db)); + } + AssocItemContainer::Impl(impl_) => { + // Because a struct can implement multiple traits, for implementations + // we add both the struct name and the trait name to the path + if let Some(adt) = impl_.self_ty(db).as_adt() { + path.push(adt.name(db)); + } + + if let Some(trait_) = impl_.trait_(db) { + path.push(trait_.name(db)); + } + } } } @@ -253,6 +268,29 @@ pub mod module { ); } + #[test] + fn moniker_for_trait_impl_function() { + check_moniker( + r#" +//- /foo/lib.rs crate:foo@CratesIo:0.1.0,https://a.b/foo.git +pub mod module { + pub trait MyTrait { + pub fn func() {} + } + + struct MyStruct {} + + impl MyTrait for MyStruct { + pub fn func$0() {} + } +} +"#, + "foo::module::MyStruct::MyTrait::func", + r#"PackageInformation { name: "foo", repo: "https://a.b/foo.git", version: "0.1.0" }"#, + MonikerKind::Export, + ); + } + #[test] fn moniker_for_field() { check_moniker(