Unnamed repository; edit this file 'description' to name the repository.
Auto merge of #14020 - Veykril:search-fix, r=Veykril
fix: Fix assoc item search finding unrelated definitions Fixes https://github.com/rust-lang/rust-analyzer/issues/14014
bors 2023-01-24
parent 86f73a0 · parent 951ee3d · commit cd4ac0d
-rw-r--r--crates/ide-db/src/search.rs33
-rw-r--r--crates/ide/src/references.rs119
2 files changed, 141 insertions, 11 deletions
diff --git a/crates/ide-db/src/search.rs b/crates/ide-db/src/search.rs
index fd09fdeb0b..ada2821d6b 100644
--- a/crates/ide-db/src/search.rs
+++ b/crates/ide-db/src/search.rs
@@ -330,11 +330,16 @@ impl Definition {
#[derive(Clone)]
pub struct FindUsages<'a> {
def: Definition,
- assoc_item_container: Option<hir::AssocItemContainer>,
sema: &'a Semantics<'a, RootDatabase>,
scope: Option<SearchScope>,
+ /// The container of our definition should it be an assoc item
+ assoc_item_container: Option<hir::AssocItemContainer>,
+ /// whether to search for the `Self` type of the definition
include_self_kw_refs: Option<hir::Type>,
+ /// the local representative for the local definition we are searching for
+ /// (this is required for finding all local declarations in a or-pattern)
local_repr: Option<hir::Local>,
+ /// whether to search for the `self` module
search_self_mod: bool,
}
@@ -655,7 +660,7 @@ impl<'a> FindUsages<'a> {
}
Some(NameRefClass::Definition(def))
if self.def == def
- // is our def a trait assoc item? then we want to find everything
+ // is our def a trait assoc item? then we want to find all assoc items from trait impls of our trait
|| matches!(self.assoc_item_container, Some(hir::AssocItemContainer::Trait(_)))
&& convert_to_def_in_trait(self.sema.db, def) == self.def =>
{
@@ -764,15 +769,21 @@ impl<'a> FindUsages<'a> {
false
}
Some(NameClass::Definition(def)) if def != self.def => {
- // only when looking for trait assoc items, we want to find other assoc items
- if !matches!(self.assoc_item_container, Some(hir::AssocItemContainer::Trait(_)))
- // FIXME: special case type aliases, we can't filter between impl and trait defs here as we lack the substitutions
- // so we always resolve all assoc type aliases to both their trait def and impl defs
- && !(matches!(self.def, Definition::TypeAlias(_))
- && convert_to_def_in_trait(self.sema.db, def)
- == convert_to_def_in_trait(self.sema.db, self.def))
- {
- return false;
+ match (&self.assoc_item_container, self.def) {
+ // for type aliases we always want to reference the trait def and all the trait impl counterparts
+ // FIXME: only until we can resolve them correctly, see FIXME above
+ (Some(_), Definition::TypeAlias(_))
+ if convert_to_def_in_trait(self.sema.db, def)
+ != convert_to_def_in_trait(self.sema.db, self.def) =>
+ {
+ return false
+ }
+ (Some(_), Definition::TypeAlias(_)) => {}
+ // We looking at an assoc item of a trait definition, so reference all the
+ // corresponding assoc items belonging to this trait's trait implementations
+ (Some(hir::AssocItemContainer::Trait(_)), _)
+ if convert_to_def_in_trait(self.sema.db, def) == self.def => {}
+ _ => return false,
}
let FileRange { file_id, range } = self.sema.original_range(name.syntax());
let reference = FileReference {
diff --git a/crates/ide/src/references.rs b/crates/ide/src/references.rs
index e49f68c57b..60fb1544a8 100644
--- a/crates/ide/src/references.rs
+++ b/crates/ide/src/references.rs
@@ -1897,4 +1897,123 @@ fn f<T: Trait>() {
"#]],
);
}
+
+ #[test]
+ fn name_clashes() {
+ check(
+ r#"
+trait Foo {
+ fn method$0(&self) -> u8;
+}
+
+struct Bar {
+ method: u8,
+}
+
+impl Foo for Bar {
+ fn method(&self) -> u8 {
+ self.method
+ }
+}
+fn method() {}
+"#,
+ expect![[r#"
+ method Function FileId(0) 16..39 19..25
+
+ FileId(0) 101..107
+ "#]],
+ );
+ check(
+ r#"
+trait Foo {
+ fn method(&self) -> u8;
+}
+
+struct Bar {
+ method$0: u8,
+}
+
+impl Foo for Bar {
+ fn method(&self) -> u8 {
+ self.method
+ }
+}
+fn method() {}
+"#,
+ expect![[r#"
+ method Field FileId(0) 60..70 60..66
+
+ FileId(0) 136..142 Read
+ "#]],
+ );
+ check(
+ r#"
+trait Foo {
+ fn method(&self) -> u8;
+}
+
+struct Bar {
+ method: u8,
+}
+
+impl Foo for Bar {
+ fn method$0(&self) -> u8 {
+ self.method
+ }
+}
+fn method() {}
+"#,
+ expect![[r#"
+ method Function FileId(0) 98..148 101..107
+
+ (no references)
+ "#]],
+ );
+ check(
+ r#"
+trait Foo {
+ fn method(&self) -> u8;
+}
+
+struct Bar {
+ method: u8,
+}
+
+impl Foo for Bar {
+ fn method(&self) -> u8 {
+ self.method$0
+ }
+}
+fn method() {}
+"#,
+ expect![[r#"
+ method Field FileId(0) 60..70 60..66
+
+ FileId(0) 136..142 Read
+ "#]],
+ );
+ check(
+ r#"
+trait Foo {
+ fn method(&self) -> u8;
+}
+
+struct Bar {
+ method: u8,
+}
+
+impl Foo for Bar {
+ fn method(&self) -> u8 {
+ self.method
+ }
+}
+fn method$0() {}
+"#,
+ expect![[r#"
+ method Function FileId(0) 151..165 154..160
+
+ (no references)
+ "#]],
+ );
+ }
}