Skip to content

Commit 0ded8e7

Browse files
committed
Auto merge of rust-lang#12825 - Veykril:trait-assoc-search, r=Veykril
fix: Fix search for associated trait items being inconsistent
2 parents f3e9b38 + bb4bfae commit 0ded8e7

File tree

4 files changed

+125
-43
lines changed

4 files changed

+125
-43
lines changed

crates/ide-db/src/search.rs

+28-29
Original file line numberDiff line numberDiff line change
@@ -7,16 +7,14 @@
77
use std::{convert::TryInto, mem, sync::Arc};
88

99
use base_db::{FileId, FileRange, SourceDatabase, SourceDatabaseExt};
10-
use hir::{
11-
AsAssocItem, DefWithBody, HasAttrs, HasSource, InFile, ModuleSource, Semantics, Visibility,
12-
};
10+
use hir::{DefWithBody, HasAttrs, HasSource, InFile, ModuleSource, Semantics, Visibility};
1311
use once_cell::unsync::Lazy;
1412
use rustc_hash::FxHashMap;
1513
use syntax::{ast, match_ast, AstNode, TextRange, TextSize};
1614

1715
use crate::{
1816
defs::{Definition, NameClass, NameRefClass},
19-
traits::convert_to_def_in_trait,
17+
traits::{as_trait_assoc_def, convert_to_def_in_trait},
2018
RootDatabase,
2119
};
2220

@@ -314,6 +312,7 @@ impl Definition {
314312
_ => None,
315313
},
316314
def: self,
315+
trait_assoc_def: as_trait_assoc_def(sema.db, self),
317316
sema,
318317
scope: None,
319318
include_self_kw_refs: None,
@@ -325,6 +324,8 @@ impl Definition {
325324
#[derive(Clone)]
326325
pub struct FindUsages<'a> {
327326
def: Definition,
327+
/// If def is an assoc item from a trait or trait impl, this is the corresponding item of the trait definition
328+
trait_assoc_def: Option<Definition>,
328329
sema: &'a Semantics<'a, RootDatabase>,
329330
scope: Option<SearchScope>,
330331
include_self_kw_refs: Option<hir::Type>,
@@ -375,7 +376,7 @@ impl<'a> FindUsages<'a> {
375376
let sema = self.sema;
376377

377378
let search_scope = {
378-
let base = self.def.search_scope(sema.db);
379+
let base = self.trait_assoc_def.unwrap_or(self.def).search_scope(sema.db);
379380
match &self.scope {
380381
None => base,
381382
Some(scope) => base.intersection(scope),
@@ -621,7 +622,13 @@ impl<'a> FindUsages<'a> {
621622
sink(file_id, reference)
622623
}
623624
Some(NameRefClass::Definition(def))
624-
if convert_to_def_in_trait(self.sema.db, def) == self.def =>
625+
if match self.trait_assoc_def {
626+
Some(trait_assoc_def) => {
627+
// we have a trait assoc item, so force resolve all assoc items to their trait version
628+
convert_to_def_in_trait(self.sema.db, def) == trait_assoc_def
629+
}
630+
None => self.def == def,
631+
} =>
625632
{
626633
let FileRange { file_id, range } = self.sema.original_range(name_ref.syntax());
627634
let reference = FileReference {
@@ -711,30 +718,22 @@ impl<'a> FindUsages<'a> {
711718
}
712719
false
713720
}
714-
// Resolve trait impl function definitions to the trait definition's version if self.def is the trait definition's
715721
Some(NameClass::Definition(def)) if def != self.def => {
716-
/* poor man's try block */
717-
(|| {
718-
let this_trait = self
719-
.def
720-
.as_assoc_item(self.sema.db)?
721-
.containing_trait_or_trait_impl(self.sema.db)?;
722-
let trait_ = def
723-
.as_assoc_item(self.sema.db)?
724-
.containing_trait_or_trait_impl(self.sema.db)?;
725-
(trait_ == this_trait && self.def.name(self.sema.db) == def.name(self.sema.db))
726-
.then(|| {
727-
let FileRange { file_id, range } =
728-
self.sema.original_range(name.syntax());
729-
let reference = FileReference {
730-
range,
731-
name: ast::NameLike::Name(name.clone()),
732-
category: None,
733-
};
734-
sink(file_id, reference)
735-
})
736-
})()
737-
.unwrap_or(false)
722+
// if the def we are looking for is a trait (impl) assoc item, we'll have to resolve the items to trait definition assoc item
723+
if !matches!(
724+
self.trait_assoc_def,
725+
Some(trait_assoc_def)
726+
if convert_to_def_in_trait(self.sema.db, def) == trait_assoc_def
727+
) {
728+
return false;
729+
}
730+
let FileRange { file_id, range } = self.sema.original_range(name.syntax());
731+
let reference = FileReference {
732+
range,
733+
name: ast::NameLike::Name(name.clone()),
734+
category: None,
735+
};
736+
sink(file_id, reference)
738737
}
739738
_ => false,
740739
}

crates/ide-db/src/traits.rs

+31-13
Original file line numberDiff line numberDiff line change
@@ -71,26 +71,44 @@ pub fn get_missing_assoc_items(
7171

7272
/// Converts associated trait impl items to their trait definition counterpart
7373
pub(crate) fn convert_to_def_in_trait(db: &dyn HirDatabase, def: Definition) -> Definition {
74-
use hir::AssocItem::*;
7574
(|| {
7675
let assoc = def.as_assoc_item(db)?;
7776
let trait_ = assoc.containing_trait_impl(db)?;
78-
let name = match assoc {
79-
Function(it) => it.name(db),
80-
Const(it) => it.name(db)?,
81-
TypeAlias(it) => it.name(db),
82-
};
83-
let item = trait_.items(db).into_iter().find(|it| match (it, assoc) {
84-
(Function(trait_func), Function(_)) => trait_func.name(db) == name,
85-
(Const(trait_konst), Const(_)) => trait_konst.name(db).map_or(false, |it| it == name),
86-
(TypeAlias(trait_type_alias), TypeAlias(_)) => trait_type_alias.name(db) == name,
87-
_ => false,
88-
})?;
89-
Some(Definition::from(item))
77+
assoc_item_of_trait(db, assoc, trait_)
9078
})()
9179
.unwrap_or(def)
9280
}
9381

82+
/// If this is an trait (impl) assoc item, returns the assoc item of the corresponding trait definition.
83+
pub(crate) fn as_trait_assoc_def(db: &dyn HirDatabase, def: Definition) -> Option<Definition> {
84+
let assoc = def.as_assoc_item(db)?;
85+
let trait_ = match assoc.container(db) {
86+
hir::AssocItemContainer::Trait(_) => return Some(def),
87+
hir::AssocItemContainer::Impl(i) => i.trait_(db),
88+
}?;
89+
assoc_item_of_trait(db, assoc, trait_)
90+
}
91+
92+
fn assoc_item_of_trait(
93+
db: &dyn HirDatabase,
94+
assoc: hir::AssocItem,
95+
trait_: hir::Trait,
96+
) -> Option<Definition> {
97+
use hir::AssocItem::*;
98+
let name = match assoc {
99+
Function(it) => it.name(db),
100+
Const(it) => it.name(db)?,
101+
TypeAlias(it) => it.name(db),
102+
};
103+
let item = trait_.items(db).into_iter().find(|it| match (it, assoc) {
104+
(Function(trait_func), Function(_)) => trait_func.name(db) == name,
105+
(Const(trait_konst), Const(_)) => trait_konst.name(db).map_or(false, |it| it == name),
106+
(TypeAlias(trait_type_alias), TypeAlias(_)) => trait_type_alias.name(db) == name,
107+
_ => false,
108+
})?;
109+
Some(Definition::from(item))
110+
}
111+
94112
#[cfg(test)]
95113
mod tests {
96114
use base_db::{fixture::ChangeFixture, FilePosition};

crates/ide/src/highlight_related.rs

+64
Original file line numberDiff line numberDiff line change
@@ -1307,6 +1307,70 @@ fn foo((
13071307
//^^^read
13081308
let foo;
13091309
}
1310+
"#,
1311+
);
1312+
}
1313+
1314+
#[test]
1315+
fn test_hl_trait_impl_methods() {
1316+
check(
1317+
r#"
1318+
trait Trait {
1319+
fn func$0(self) {}
1320+
//^^^^
1321+
}
1322+
1323+
impl Trait for () {
1324+
fn func(self) {}
1325+
//^^^^
1326+
}
1327+
1328+
fn main() {
1329+
<()>::func(());
1330+
//^^^^
1331+
().func();
1332+
//^^^^
1333+
}
1334+
"#,
1335+
);
1336+
check(
1337+
r#"
1338+
trait Trait {
1339+
fn func(self) {}
1340+
//^^^^
1341+
}
1342+
1343+
impl Trait for () {
1344+
fn func$0(self) {}
1345+
//^^^^
1346+
}
1347+
1348+
fn main() {
1349+
<()>::func(());
1350+
//^^^^
1351+
().func();
1352+
//^^^^
1353+
}
1354+
"#,
1355+
);
1356+
check(
1357+
r#"
1358+
trait Trait {
1359+
fn func(self) {}
1360+
//^^^^
1361+
}
1362+
1363+
impl Trait for () {
1364+
fn func(self) {}
1365+
//^^^^
1366+
}
1367+
1368+
fn main() {
1369+
<()>::func(());
1370+
//^^^^
1371+
().func$0();
1372+
//^^^^
1373+
}
13101374
"#,
13111375
);
13121376
}

crates/ide/src/references.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,7 @@ pub(crate) fn find_all_refs(
7373
});
7474
let mut usages =
7575
def.usages(sema).set_scope(search_scope.clone()).include_self_refs().all();
76+
7677
if literal_search {
7778
retain_adt_literal_usages(&mut usages, def, sema);
7879
}
@@ -105,7 +106,7 @@ pub(crate) fn find_all_refs(
105106
}
106107
None => {
107108
let search = make_searcher(false);
108-
Some(find_defs(sema, &syntax, position.offset)?.into_iter().map(search).collect())
109+
Some(find_defs(sema, &syntax, position.offset)?.map(search).collect())
109110
}
110111
}
111112
}

0 commit comments

Comments
 (0)