diff --git a/crates/ide-db/src/imports/import_assets.rs b/crates/ide-db/src/imports/import_assets.rs index 08b0f9535d7..81467ab07a2 100644 --- a/crates/ide-db/src/imports/import_assets.rs +++ b/crates/ide-db/src/imports/import_assets.rs @@ -401,7 +401,7 @@ fn import_for_item( }) } -fn item_for_path_search(db: &RootDatabase, item: ItemInNs) -> Option { +pub fn item_for_path_search(db: &RootDatabase, item: ItemInNs) -> Option { Some(match item { ItemInNs::Types(_) | ItemInNs::Values(_) => match item_as_assoc(db, item) { Some(assoc_item) => match assoc_item.container(db) { diff --git a/crates/ide-db/src/rename.rs b/crates/ide-db/src/rename.rs index bade88c5783..f114d934e4f 100644 --- a/crates/ide-db/src/rename.rs +++ b/crates/ide-db/src/rename.rs @@ -24,7 +24,7 @@ use base_db::{AnchoredPathBuf, FileId, FileRange}; use either::Either; -use hir::{AsAssocItem, FieldSource, HasSource, InFile, ModuleSource, Semantics}; +use hir::{FieldSource, HasSource, InFile, ModuleSource, Semantics}; use stdx::never; use syntax::{ ast::{self, HasName}, @@ -37,6 +37,7 @@ search::FileReference, source_change::{FileSystemEdit, SourceChange}, syntax_helpers::node_ext::expr_as_name_ref, + traits::convert_to_def_in_trait, RootDatabase, }; @@ -271,7 +272,7 @@ fn rename_reference( } } - let def = convert_to_def_in_trait(def, sema); + let def = convert_to_def_in_trait(sema.db, def); let usages = def.usages(sema).all(); if !usages.is_empty() && ident_kind == IdentifierKind::Underscore { @@ -298,47 +299,6 @@ fn rename_reference( Ok(source_change) } -pub(crate) fn convert_to_def_in_trait( - def: Definition, - sema: &Semantics, -) -> Definition { - // HACK: resolve trait impl items to the item def of the trait definition - // so that we properly resolve all trait item references - let assoc_item = match def { - Definition::Function(it) => it.as_assoc_item(sema.db), - Definition::TypeAlias(it) => it.as_assoc_item(sema.db), - Definition::Const(it) => it.as_assoc_item(sema.db), - _ => None, - }; - match assoc_item { - Some(assoc) => assoc - .containing_trait_impl(sema.db) - .and_then(|trait_| { - trait_.items(sema.db).into_iter().find_map(|it| match (it, assoc) { - (hir::AssocItem::Function(trait_func), hir::AssocItem::Function(func)) - if trait_func.name(sema.db) == func.name(sema.db) => - { - Some(Definition::Function(trait_func)) - } - (hir::AssocItem::Const(trait_konst), hir::AssocItem::Const(konst)) - if trait_konst.name(sema.db) == konst.name(sema.db) => - { - Some(Definition::Const(trait_konst)) - } - ( - hir::AssocItem::TypeAlias(trait_type_alias), - hir::AssocItem::TypeAlias(type_alias), - ) if trait_type_alias.name(sema.db) == type_alias.name(sema.db) => { - Some(Definition::TypeAlias(trait_type_alias)) - } - _ => None, - }) - }) - .unwrap_or(def), - None => def, - } -} - pub fn source_edit_from_references( references: &[FileReference], def: Definition, diff --git a/crates/ide-db/src/search.rs b/crates/ide-db/src/search.rs index ce38fe145bd..b3b957c0ef2 100644 --- a/crates/ide-db/src/search.rs +++ b/crates/ide-db/src/search.rs @@ -16,6 +16,7 @@ use crate::{ defs::{Definition, NameClass, NameRefClass}, + traits::convert_to_def_in_trait, RootDatabase, }; @@ -620,7 +621,7 @@ fn found_name_ref( sink(file_id, reference) } Some(NameRefClass::Definition(def)) - if crate::rename::convert_to_def_in_trait(def, self.sema) == self.def => + if convert_to_def_in_trait(self.sema.db, def) == self.def => { let FileRange { file_id, range } = self.sema.original_range(name_ref.syntax()); let reference = FileReference { diff --git a/crates/ide-db/src/traits.rs b/crates/ide-db/src/traits.rs index 0fbfd869921..666499ed7a5 100644 --- a/crates/ide-db/src/traits.rs +++ b/crates/ide-db/src/traits.rs @@ -1,7 +1,7 @@ //! Functionality for obtaining data related to traits from the DB. -use crate::RootDatabase; -use hir::Semantics; +use crate::{defs::Definition, RootDatabase}; +use hir::{db::HirDatabase, AsAssocItem, Semantics}; use rustc_hash::FxHashSet; use syntax::{ast, AstNode}; @@ -69,6 +69,28 @@ pub fn get_missing_assoc_items( }) } +/// Converts associated trait impl items to their trait definition counterpart +pub(crate) fn convert_to_def_in_trait(db: &dyn HirDatabase, def: Definition) -> Definition { + use hir::AssocItem::*; + (|| { + let assoc = def.as_assoc_item(db)?; + let trait_ = assoc.containing_trait_impl(db)?; + let name = match assoc { + Function(it) => it.name(db), + Const(it) => it.name(db)?, + TypeAlias(it) => it.name(db), + }; + let item = trait_.items(db).into_iter().find(|it| match (it, assoc) { + (Function(trait_func), Function(_)) => trait_func.name(db) == name, + (Const(trait_konst), Const(_)) => trait_konst.name(db).map_or(false, |it| it == name), + (TypeAlias(trait_type_alias), TypeAlias(_)) => trait_type_alias.name(db) == name, + _ => false, + })?; + Some(Definition::from(item)) + })() + .unwrap_or(def) +} + #[cfg(test)] mod tests { use base_db::{fixture::ChangeFixture, FilePosition};