Future proof find-usages API

We might want to provide more efficient impls for check if usages
exist, limiting the search, filtering and cancellation, so let's
violate YAGNI a bit here.
This commit is contained in:
Aleksey Kladov 2020-08-19 18:58:48 +02:00
parent 686a6a26fd
commit 81b0976187
5 changed files with 41 additions and 17 deletions

View File

@ -53,7 +53,7 @@ pub(crate) fn extract_struct_from_enum_variant(
target,
|builder| {
let definition = Definition::ModuleDef(ModuleDef::EnumVariant(variant_hir));
let res = definition.find_usages(&ctx.sema, None);
let res = definition.usages(&ctx.sema).all();
let start_offset = variant.parent_enum().syntax().text_range().start();
let mut visited_modules_set = FxHashSet::default();
visited_modules_set.insert(current_module);

View File

@ -44,7 +44,7 @@ pub(crate) fn inline_local_variable(acc: &mut Assists, ctx: &AssistContext) -> O
let def = ctx.sema.to_def(&bind_pat)?;
let def = Definition::Local(def);
let refs = def.find_usages(&ctx.sema, None);
let refs = def.usages(&ctx.sema).all();
if refs.is_empty() {
mark::hit!(test_not_applicable_if_variable_unused);
return None;

View File

@ -106,7 +106,9 @@ pub(crate) fn find_all_refs(
let RangeInfo { range, info: def } = find_name(&sema, &syntax, position, opt_name)?;
let references = def
.find_usages(sema, search_scope)
.usages(sema)
.set_scope(search_scope)
.all()
.into_iter()
.filter(|r| search_kind == ReferenceKind::Other || search_kind == r.kind)
.collect();

View File

@ -181,22 +181,44 @@ impl Definition {
SearchScope::new(res)
}
pub fn find_usages(
&self,
sema: &Semantics<RootDatabase>,
search_scope: Option<SearchScope>,
) -> Vec<Reference> {
pub fn usages<'a>(&'a self, sema: &'a Semantics<RootDatabase>) -> FindUsages<'a> {
FindUsages { def: self, sema, scope: None }
}
}
pub struct FindUsages<'a> {
def: &'a Definition,
sema: &'a Semantics<'a, RootDatabase>,
scope: Option<SearchScope>,
}
impl<'a> FindUsages<'a> {
pub fn in_scope(self, scope: SearchScope) -> FindUsages<'a> {
self.set_scope(Some(scope))
}
pub fn set_scope(mut self, scope: Option<SearchScope>) -> FindUsages<'a> {
assert!(self.scope.is_none());
self.scope = scope;
self
}
pub fn at_least_one(self) -> bool {
self.all().is_empty()
}
pub fn all(self) -> Vec<Reference> {
let _p = profile::span("Definition::find_usages");
let sema = self.sema;
let search_scope = {
let base = self.search_scope(sema.db);
match search_scope {
let base = self.def.search_scope(sema.db);
match self.scope {
None => base,
Some(scope) => base.intersection(&scope),
}
};
let name = match self.name(sema.db) {
let name = match self.def.name(sema.db) {
None => return Vec::new(),
Some(it) => it.to_string(),
};
@ -225,7 +247,7 @@ impl Definition {
};
match classify_name_ref(&sema, &name_ref) {
Some(NameRefClass::Definition(def)) if &def == self => {
Some(NameRefClass::Definition(def)) if &def == self.def => {
let kind = if is_record_lit_name_ref(&name_ref)
|| is_call_expr_name_ref(&name_ref)
{
@ -242,14 +264,14 @@ impl Definition {
});
}
Some(NameRefClass::FieldShorthand { local, field }) => {
match self {
Definition::Field(_) if &field == self => refs.push(Reference {
file_range: sema.original_range(name_ref.syntax()),
match self.def {
Definition::Field(_) if &field == self.def => refs.push(Reference {
file_range: self.sema.original_range(name_ref.syntax()),
kind: ReferenceKind::FieldShorthandForField,
access: reference_access(&field, &name_ref),
}),
Definition::Local(l) if &local == l => refs.push(Reference {
file_range: sema.original_range(name_ref.syntax()),
file_range: self.sema.original_range(name_ref.syntax()),
kind: ReferenceKind::FieldShorthandForLocal,
access: reference_access(&Definition::Local(local), &name_ref),
}),

View File

@ -114,7 +114,7 @@ impl<'db> MatchFinder<'db> {
// cache miss. This is a limitation of NLL and is fixed with Polonius. For now we do two
// lookups in the case of a cache hit.
if usage_cache.find(&definition).is_none() {
let usages = definition.find_usages(&self.sema, Some(self.search_scope()));
let usages = definition.usages(&self.sema).in_scope(self.search_scope()).all();
usage_cache.usages.push((definition, usages));
return &usage_cache.usages.last().unwrap().1;
}