summaryrefslogtreecommitdiffstats
path: root/src/tools/rust-analyzer/crates/ide-db/src/search.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/tools/rust-analyzer/crates/ide-db/src/search.rs')
-rw-r--r--src/tools/rust-analyzer/crates/ide-db/src/search.rs183
1 files changed, 103 insertions, 80 deletions
diff --git a/src/tools/rust-analyzer/crates/ide-db/src/search.rs b/src/tools/rust-analyzer/crates/ide-db/src/search.rs
index b2b0e4908..c18a27f17 100644
--- a/src/tools/rust-analyzer/crates/ide-db/src/search.rs
+++ b/src/tools/rust-analyzer/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),
@@ -447,15 +455,21 @@ impl<'a> FindUsages<'a> {
}
let find_nodes = move |name: &str, node: &syntax::SyntaxNode, offset: TextSize| {
- node.token_at_offset(offset).find(|it| it.text() == name).map(|token| {
- // FIXME: There should be optimization potential here
- // Currently we try to descend everything we find which
- // means we call `Semantics::descend_into_macros` on
- // every textual hit. That function is notoriously
- // expensive even for things that do not get down mapped
- // into macros.
- sema.descend_into_macros(token).into_iter().filter_map(|it| it.parent())
- })
+ node.token_at_offset(offset)
+ .find(|it| {
+ // `name` is stripped of raw ident prefix. See the comment on name retrieval above.
+ it.text().trim_start_matches("r#") == name
+ })
+ .into_iter()
+ .flat_map(|token| {
+ // FIXME: There should be optimization potential here
+ // Currently we try to descend everything we find which
+ // means we call `Semantics::descend_into_macros` on
+ // every textual hit. That function is notoriously
+ // expensive even for things that do not get down mapped
+ // into macros.
+ sema.descend_into_macros(token).into_iter().filter_map(|it| it.parent())
+ })
};
for (text, file_id, search_range) in scope_files(sema, &search_scope) {
@@ -463,30 +477,23 @@ impl<'a> FindUsages<'a> {
// Search for occurrences of the items name
for offset in match_indices(&text, finder, search_range) {
- if let Some(iter) = find_nodes(name, &tree, offset) {
- for name in iter.filter_map(ast::NameLike::cast) {
- if match name {
- ast::NameLike::NameRef(name_ref) => {
- self.found_name_ref(&name_ref, sink)
- }
- ast::NameLike::Name(name) => self.found_name(&name, sink),
- ast::NameLike::Lifetime(lifetime) => {
- self.found_lifetime(&lifetime, sink)
- }
- } {
- return;
- }
+ for name in find_nodes(name, &tree, offset).filter_map(ast::NameLike::cast) {
+ if match name {
+ ast::NameLike::NameRef(name_ref) => self.found_name_ref(&name_ref, sink),
+ ast::NameLike::Name(name) => self.found_name(&name, sink),
+ ast::NameLike::Lifetime(lifetime) => self.found_lifetime(&lifetime, sink),
+ } {
+ return;
}
}
}
// Search for occurrences of the `Self` referring to our type
if let Some((self_ty, finder)) = &include_self_kw_refs {
for offset in match_indices(&text, finder, search_range) {
- if let Some(iter) = find_nodes("Self", &tree, offset) {
- for name_ref in iter.filter_map(ast::NameRef::cast) {
- if self.found_self_ty_name_ref(self_ty, &name_ref, sink) {
- return;
- }
+ for name_ref in find_nodes("Self", &tree, offset).filter_map(ast::NameRef::cast)
+ {
+ if self.found_self_ty_name_ref(self_ty, &name_ref, sink) {
+ return;
}
}
}
@@ -494,41 +501,37 @@ 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;
- }
- }
+ for offset in match_indices(&text, finder, search_range) {
+ for name_ref in
+ find_nodes("super", &tree, offset).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("crate", &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) {
+ for name_ref in
+ find_nodes("crate", &tree, offset).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
@@ -562,11 +565,10 @@ impl<'a> FindUsages<'a> {
let finder = &Finder::new("self");
for offset in match_indices(&text, finder, search_range) {
- if let Some(iter) = find_nodes("self", &tree, offset) {
- for name_ref in iter.filter_map(ast::NameRef::cast) {
- if self.found_self_module_name_ref(&name_ref, sink) {
- return;
- }
+ for name_ref in find_nodes("self", &tree, offset).filter_map(ast::NameRef::cast)
+ {
+ if self.found_self_module_name_ref(&name_ref, sink) {
+ return;
}
}
}
@@ -655,13 +657,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 +767,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 {