Unnamed repository; edit this file 'description' to name the repository.
Diffstat (limited to 'crates/ide-db/src/search.rs')
-rw-r--r--crates/ide-db/src/search.rs115
1 files changed, 70 insertions, 45 deletions
diff --git a/crates/ide-db/src/search.rs b/crates/ide-db/src/search.rs
index b2b0e49085..ada2821d6b 100644
--- a/crates/ide-db/src/search.rs
+++ b/crates/ide-db/src/search.rs
@@ -7,7 +7,9 @@
use std::{mem, sync::Arc};
use base_db::{FileId, FileRange, SourceDatabase, SourceDatabaseExt};
-use hir::{DefWithBody, HasAttrs, HasSource, InFile, ModuleSource, Semantics, Visibility};
+use hir::{
+ AsAssocItem, DefWithBody, HasAttrs, HasSource, InFile, ModuleSource, Semantics, Visibility,
+};
use memchr::memmem::Finder;
use once_cell::unsync::Lazy;
use parser::SyntaxKind;
@@ -311,15 +313,15 @@ impl Definition {
pub fn usages<'a>(self, sema: &'a Semantics<'_, RootDatabase>) -> FindUsages<'a> {
FindUsages {
- local_repr: match self {
- Definition::Local(local) => Some(local.representative(sema.db)),
- _ => None,
- },
def: self,
- trait_assoc_def: as_trait_assoc_def(sema.db, self),
+ assoc_item_container: self.as_assoc_item(sema.db).map(|a| a.container(sema.db)),
sema,
scope: None,
include_self_kw_refs: None,
+ local_repr: match self {
+ Definition::Local(local) => Some(local.representative(sema.db)),
+ _ => None,
+ },
search_self_mod: false,
}
}
@@ -328,12 +330,16 @@ impl Definition {
#[derive(Clone)]
pub struct FindUsages<'a> {
def: Definition,
- /// If def is an assoc item from a trait or trait impl, this is the corresponding item of the trait definition
- trait_assoc_def: Option<Definition>,
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,
}
@@ -380,7 +386,9 @@ impl<'a> FindUsages<'a> {
let sema = self.sema;
let search_scope = {
- let base = self.trait_assoc_def.unwrap_or(self.def).search_scope(sema.db);
+ // FIXME: Is the trait scope needed for trait impl assoc items?
+ let base =
+ as_trait_assoc_def(sema.db, self.def).unwrap_or(self.def).search_scope(sema.db);
match &self.scope {
None => base,
Some(scope) => base.intersection(scope),
@@ -494,20 +502,28 @@ impl<'a> FindUsages<'a> {
}
// Search for `super` and `crate` resolving to our module
- match self.def {
- Definition::Module(module) => {
- let scope = search_scope
- .intersection(&SearchScope::module_and_children(self.sema.db, module));
+ if let Definition::Module(module) = self.def {
+ let scope =
+ search_scope.intersection(&SearchScope::module_and_children(self.sema.db, module));
- let is_crate_root =
- module.is_crate_root(self.sema.db).then(|| Finder::new("crate"));
- let finder = &Finder::new("super");
+ let is_crate_root = module.is_crate_root(self.sema.db).then(|| Finder::new("crate"));
+ let finder = &Finder::new("super");
- for (text, file_id, search_range) in scope_files(sema, &scope) {
- let tree = Lazy::new(move || sema.parse(file_id).syntax().clone());
+ for (text, file_id, search_range) in scope_files(sema, &scope) {
+ let tree = Lazy::new(move || sema.parse(file_id).syntax().clone());
+ for offset in match_indices(&text, finder, search_range) {
+ if let Some(iter) = find_nodes("super", &tree, offset) {
+ for name_ref in iter.filter_map(ast::NameRef::cast) {
+ if self.found_name_ref(&name_ref, sink) {
+ return;
+ }
+ }
+ }
+ }
+ if let Some(finder) = &is_crate_root {
for offset in match_indices(&text, finder, search_range) {
- if let Some(iter) = find_nodes("super", &tree, offset) {
+ if let Some(iter) = find_nodes("crate", &tree, offset) {
for name_ref in iter.filter_map(ast::NameRef::cast) {
if self.found_name_ref(&name_ref, sink) {
return;
@@ -515,20 +531,8 @@ impl<'a> FindUsages<'a> {
}
}
}
- if let Some(finder) = &is_crate_root {
- for offset in match_indices(&text, finder, search_range) {
- if let Some(iter) = find_nodes("crate", &tree, offset) {
- for name_ref in iter.filter_map(ast::NameRef::cast) {
- if self.found_name_ref(&name_ref, sink) {
- return;
- }
- }
- }
- }
- }
}
}
- _ => (),
}
// search for module `self` references in our module's definition source
@@ -655,13 +659,26 @@ impl<'a> FindUsages<'a> {
sink(file_id, reference)
}
Some(NameRefClass::Definition(def))
- if match self.trait_assoc_def {
- Some(trait_assoc_def) => {
- // we have a trait assoc item, so force resolve all assoc items to their trait version
- convert_to_def_in_trait(self.sema.db, def) == trait_assoc_def
- }
- None => self.def == def,
- } =>
+ if self.def == def
+ // 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 =>
+ {
+ let FileRange { file_id, range } = self.sema.original_range(name_ref.syntax());
+ let reference = FileReference {
+ range,
+ name: ast::NameLike::NameRef(name_ref.clone()),
+ category: ReferenceCategory::new(&def, name_ref),
+ };
+ sink(file_id, reference)
+ }
+ // 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
+ Some(NameRefClass::Definition(def))
+ if self.assoc_item_container.is_some()
+ && matches!(self.def, Definition::TypeAlias(_))
+ && convert_to_def_in_trait(self.sema.db, def)
+ == convert_to_def_in_trait(self.sema.db, self.def) =>
{
let FileRange { file_id, range } = self.sema.original_range(name_ref.syntax());
let reference = FileReference {
@@ -752,13 +769,21 @@ impl<'a> FindUsages<'a> {
false
}
Some(NameClass::Definition(def)) if def != self.def => {
- // 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
- if !matches!(
- self.trait_assoc_def,
- Some(trait_assoc_def)
- if convert_to_def_in_trait(self.sema.db, def) == trait_assoc_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 {