Skip to content

Commit 21d4416

Browse files
bors[bot]Veykril
andauthored
9218: Item search now respects trait impl items r=Veykril a=Veykril Fixes rust-lang#2977 Co-authored-by: Lukas Wirth <lukastw97@gmail.com>
2 parents 6ac3e66 + 48f65b3 commit 21d4416

File tree

3 files changed

+215
-11
lines changed

3 files changed

+215
-11
lines changed

crates/hir/src/lib.rs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1451,6 +1451,20 @@ impl AssocItem {
14511451
_ => None,
14521452
}
14531453
}
1454+
1455+
pub fn containing_trait_impl(self, db: &dyn HirDatabase) -> Option<Trait> {
1456+
match self.container(db) {
1457+
AssocItemContainer::Impl(i) => i.trait_(db),
1458+
_ => None,
1459+
}
1460+
}
1461+
1462+
pub fn containing_trait_or_trait_impl(self, db: &dyn HirDatabase) -> Option<Trait> {
1463+
match self.container(db) {
1464+
AssocItemContainer::Trait(t) => Some(t),
1465+
AssocItemContainer::Impl(i) => i.trait_(db),
1466+
}
1467+
}
14541468
}
14551469

14561470
impl HasVisibility for AssocItem {

crates/ide/src/references/rename.rs

Lines changed: 164 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -239,7 +239,7 @@ fn rename_mod(
239239

240240
fn rename_reference(
241241
sema: &Semantics<RootDatabase>,
242-
def: Definition,
242+
mut def: Definition,
243243
new_name: &str,
244244
) -> RenameResult<SourceChange> {
245245
let ident_kind = check_identifier(new_name)?;
@@ -285,7 +285,38 @@ fn rename_reference(
285285
}
286286
}
287287

288+
def = match def {
289+
// HACK: resolve trait impl items to the item def of the trait definition
290+
// so that we properly resolve all trait item references
291+
Definition::ModuleDef(mod_def) => mod_def
292+
.as_assoc_item(sema.db)
293+
.and_then(|it| it.containing_trait_impl(sema.db))
294+
.and_then(|it| {
295+
it.items(sema.db).into_iter().find_map(|it| match (it, mod_def) {
296+
(hir::AssocItem::Function(trait_func), ModuleDef::Function(func))
297+
if trait_func.name(sema.db) == func.name(sema.db) =>
298+
{
299+
Some(Definition::ModuleDef(ModuleDef::Function(trait_func)))
300+
}
301+
(hir::AssocItem::Const(trait_konst), ModuleDef::Const(konst))
302+
if trait_konst.name(sema.db) == konst.name(sema.db) =>
303+
{
304+
Some(Definition::ModuleDef(ModuleDef::Const(trait_konst)))
305+
}
306+
(
307+
hir::AssocItem::TypeAlias(trait_type_alias),
308+
ModuleDef::TypeAlias(type_alias),
309+
) if trait_type_alias.name(sema.db) == type_alias.name(sema.db) => {
310+
Some(Definition::ModuleDef(ModuleDef::TypeAlias(trait_type_alias)))
311+
}
312+
_ => None,
313+
})
314+
})
315+
.unwrap_or(def),
316+
_ => def,
317+
};
288318
let usages = def.usages(sema).all();
319+
289320
if !usages.is_empty() && ident_kind == IdentifierKind::Underscore {
290321
cov_mark::hit!(rename_underscore_multiple);
291322
bail!("Cannot rename reference to `_` as it is being referenced multiple times");
@@ -1938,4 +1969,136 @@ use Bar$0;
19381969
"error: Renaming aliases is currently unsupported",
19391970
);
19401971
}
1972+
1973+
#[test]
1974+
fn test_rename_trait_method() {
1975+
let res = r"
1976+
trait Foo {
1977+
fn foo(&self) {
1978+
self.foo();
1979+
}
1980+
}
1981+
1982+
impl Foo for () {
1983+
fn foo(&self) {
1984+
self.foo();
1985+
}
1986+
}";
1987+
check(
1988+
"foo",
1989+
r#"
1990+
trait Foo {
1991+
fn bar$0(&self) {
1992+
self.bar();
1993+
}
1994+
}
1995+
1996+
impl Foo for () {
1997+
fn bar(&self) {
1998+
self.bar();
1999+
}
2000+
}"#,
2001+
res,
2002+
);
2003+
check(
2004+
"foo",
2005+
r#"
2006+
trait Foo {
2007+
fn bar(&self) {
2008+
self.bar$0();
2009+
}
2010+
}
2011+
2012+
impl Foo for () {
2013+
fn bar(&self) {
2014+
self.bar();
2015+
}
2016+
}"#,
2017+
res,
2018+
);
2019+
check(
2020+
"foo",
2021+
r#"
2022+
trait Foo {
2023+
fn bar(&self) {
2024+
self.bar();
2025+
}
2026+
}
2027+
2028+
impl Foo for () {
2029+
fn bar$0(&self) {
2030+
self.bar();
2031+
}
2032+
}"#,
2033+
res,
2034+
);
2035+
check(
2036+
"foo",
2037+
r#"
2038+
trait Foo {
2039+
fn bar(&self) {
2040+
self.bar();
2041+
}
2042+
}
2043+
2044+
impl Foo for () {
2045+
fn bar(&self) {
2046+
self.bar$0();
2047+
}
2048+
}"#,
2049+
res,
2050+
);
2051+
}
2052+
2053+
#[test]
2054+
fn test_rename_trait_const() {
2055+
let res = r"
2056+
trait Foo {
2057+
const FOO: ();
2058+
}
2059+
2060+
impl Foo for () {
2061+
const FOO: ();
2062+
}
2063+
fn f() { <()>::FOO; }";
2064+
check(
2065+
"FOO",
2066+
r#"
2067+
trait Foo {
2068+
const BAR$0: ();
2069+
}
2070+
2071+
impl Foo for () {
2072+
const BAR: ();
2073+
}
2074+
fn f() { <()>::BAR; }"#,
2075+
res,
2076+
);
2077+
check(
2078+
"FOO",
2079+
r#"
2080+
trait Foo {
2081+
const BAR: ();
2082+
}
2083+
2084+
impl Foo for () {
2085+
const BAR$0: ();
2086+
}
2087+
fn f() { <()>::BAR; }"#,
2088+
res,
2089+
);
2090+
check(
2091+
"FOO",
2092+
r#"
2093+
trait Foo {
2094+
const BAR: ();
2095+
}
2096+
2097+
impl Foo for () {
2098+
const BAR: ();
2099+
}
2100+
fn f() { <()>::BAR$0; }"#,
2101+
res,
2102+
);
2103+
}
19412104
}

crates/ide_db/src/search.rs

Lines changed: 37 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,8 @@ use std::{convert::TryInto, mem};
88

99
use base_db::{FileId, FileRange, SourceDatabase, SourceDatabaseExt};
1010
use hir::{
11-
DefWithBody, HasAttrs, HasSource, InFile, ModuleDef, ModuleSource, Semantics, Visibility,
11+
AsAssocItem, DefWithBody, HasAttrs, HasSource, InFile, ModuleDef, ModuleSource, Semantics,
12+
Visibility,
1213
};
1314
use once_cell::unsync::Lazy;
1415
use rustc_hash::FxHashMap;
@@ -303,13 +304,13 @@ impl Definition {
303304
}
304305
}
305306

306-
pub fn usages<'a>(&'a self, sema: &'a Semantics<RootDatabase>) -> FindUsages<'a> {
307+
pub fn usages<'a>(self, sema: &'a Semantics<RootDatabase>) -> FindUsages<'a> {
307308
FindUsages { def: self, sema, scope: None, include_self_kw_refs: None }
308309
}
309310
}
310311

311312
pub struct FindUsages<'a> {
312-
def: &'a Definition,
313+
def: Definition,
313314
sema: &'a Semantics<'a, RootDatabase>,
314315
scope: Option<SearchScope>,
315316
include_self_kw_refs: Option<hir::Type>,
@@ -318,7 +319,7 @@ pub struct FindUsages<'a> {
318319
impl<'a> FindUsages<'a> {
319320
/// Enable searching for `Self` when the definition is a type.
320321
pub fn include_self_refs(mut self) -> FindUsages<'a> {
321-
self.include_self_kw_refs = def_to_ty(self.sema, self.def);
322+
self.include_self_kw_refs = def_to_ty(self.sema, &self.def);
322323
self
323324
}
324325

@@ -445,7 +446,7 @@ impl<'a> FindUsages<'a> {
445446
sink: &mut dyn FnMut(FileId, FileReference) -> bool,
446447
) -> bool {
447448
match NameRefClass::classify_lifetime(self.sema, lifetime) {
448-
Some(NameRefClass::Definition(def)) if &def == self.def => {
449+
Some(NameRefClass::Definition(def)) if def == self.def => {
449450
let FileRange { file_id, range } = self.sema.original_range(lifetime.syntax());
450451
let reference = FileReference {
451452
range,
@@ -464,7 +465,7 @@ impl<'a> FindUsages<'a> {
464465
sink: &mut dyn FnMut(FileId, FileReference) -> bool,
465466
) -> bool {
466467
match NameRefClass::classify(self.sema, &name_ref) {
467-
Some(NameRefClass::Definition(def)) if &def == self.def => {
468+
Some(NameRefClass::Definition(def)) if def == self.def => {
468469
let FileRange { file_id, range } = self.sema.original_range(name_ref.syntax());
469470
let reference = FileReference {
470471
range,
@@ -489,10 +490,10 @@ impl<'a> FindUsages<'a> {
489490
Some(NameRefClass::FieldShorthand { local_ref: local, field_ref: field }) => {
490491
let FileRange { file_id, range } = self.sema.original_range(name_ref.syntax());
491492
let access = match self.def {
492-
Definition::Field(_) if &field == self.def => {
493+
Definition::Field(_) if field == self.def => {
493494
reference_access(&field, &name_ref)
494495
}
495-
Definition::Local(l) if &local == l => {
496+
Definition::Local(l) if local == l => {
496497
reference_access(&Definition::Local(local), &name_ref)
497498
}
498499
_ => return false,
@@ -513,7 +514,7 @@ impl<'a> FindUsages<'a> {
513514
match NameClass::classify(self.sema, name) {
514515
Some(NameClass::PatFieldShorthand { local_def: _, field_ref })
515516
if matches!(
516-
self.def, Definition::Field(_) if &field_ref == self.def
517+
self.def, Definition::Field(_) if field_ref == self.def
517518
) =>
518519
{
519520
let FileRange { file_id, range } = self.sema.original_range(name.syntax());
@@ -525,12 +526,38 @@ impl<'a> FindUsages<'a> {
525526
};
526527
sink(file_id, reference)
527528
}
528-
Some(NameClass::ConstReference(def)) if *self.def == def => {
529+
Some(NameClass::ConstReference(def)) if self.def == def => {
529530
let FileRange { file_id, range } = self.sema.original_range(name.syntax());
530531
let reference =
531532
FileReference { range, name: ast::NameLike::Name(name.clone()), access: None };
532533
sink(file_id, reference)
533534
}
535+
// Resolve trait impl function definitions to the trait definition's version if self.def is the trait definition's
536+
Some(NameClass::Definition(Definition::ModuleDef(mod_def))) => {
537+
/* poor man's try block */
538+
(|| {
539+
let this = match self.def {
540+
Definition::ModuleDef(this) if this != mod_def => this,
541+
_ => return None,
542+
};
543+
let this_trait = this
544+
.as_assoc_item(self.sema.db)?
545+
.containing_trait_or_trait_impl(self.sema.db)?;
546+
let trait_ = mod_def
547+
.as_assoc_item(self.sema.db)?
548+
.containing_trait_or_trait_impl(self.sema.db)?;
549+
(trait_ == this_trait).then(|| {
550+
let FileRange { file_id, range } = self.sema.original_range(name.syntax());
551+
let reference = FileReference {
552+
range,
553+
name: ast::NameLike::Name(name.clone()),
554+
access: None,
555+
};
556+
sink(file_id, reference)
557+
})
558+
})()
559+
.unwrap_or(false)
560+
}
534561
_ => false,
535562
}
536563
}

0 commit comments

Comments
 (0)