mirror of
https://github.com/rust-lang/rust-analyzer.git
synced 2025-10-01 06:11:35 +00:00
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:
parent
686a6a26fd
commit
81b0976187
5 changed files with 41 additions and 17 deletions
|
@ -53,7 +53,7 @@ pub(crate) fn extract_struct_from_enum_variant(
|
||||||
target,
|
target,
|
||||||
|builder| {
|
|builder| {
|
||||||
let definition = Definition::ModuleDef(ModuleDef::EnumVariant(variant_hir));
|
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 start_offset = variant.parent_enum().syntax().text_range().start();
|
||||||
let mut visited_modules_set = FxHashSet::default();
|
let mut visited_modules_set = FxHashSet::default();
|
||||||
visited_modules_set.insert(current_module);
|
visited_modules_set.insert(current_module);
|
||||||
|
|
|
@ -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 = ctx.sema.to_def(&bind_pat)?;
|
||||||
let def = Definition::Local(def);
|
let def = Definition::Local(def);
|
||||||
let refs = def.find_usages(&ctx.sema, None);
|
let refs = def.usages(&ctx.sema).all();
|
||||||
if refs.is_empty() {
|
if refs.is_empty() {
|
||||||
mark::hit!(test_not_applicable_if_variable_unused);
|
mark::hit!(test_not_applicable_if_variable_unused);
|
||||||
return None;
|
return None;
|
||||||
|
|
|
@ -106,7 +106,9 @@ pub(crate) fn find_all_refs(
|
||||||
let RangeInfo { range, info: def } = find_name(&sema, &syntax, position, opt_name)?;
|
let RangeInfo { range, info: def } = find_name(&sema, &syntax, position, opt_name)?;
|
||||||
|
|
||||||
let references = def
|
let references = def
|
||||||
.find_usages(sema, search_scope)
|
.usages(sema)
|
||||||
|
.set_scope(search_scope)
|
||||||
|
.all()
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.filter(|r| search_kind == ReferenceKind::Other || search_kind == r.kind)
|
.filter(|r| search_kind == ReferenceKind::Other || search_kind == r.kind)
|
||||||
.collect();
|
.collect();
|
||||||
|
|
|
@ -181,22 +181,44 @@ impl Definition {
|
||||||
SearchScope::new(res)
|
SearchScope::new(res)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn find_usages(
|
pub fn usages<'a>(&'a self, sema: &'a Semantics<RootDatabase>) -> FindUsages<'a> {
|
||||||
&self,
|
FindUsages { def: self, sema, scope: None }
|
||||||
sema: &Semantics<RootDatabase>,
|
}
|
||||||
search_scope: Option<SearchScope>,
|
}
|
||||||
) -> Vec<Reference> {
|
|
||||||
|
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 _p = profile::span("Definition::find_usages");
|
||||||
|
let sema = self.sema;
|
||||||
|
|
||||||
let search_scope = {
|
let search_scope = {
|
||||||
let base = self.search_scope(sema.db);
|
let base = self.def.search_scope(sema.db);
|
||||||
match search_scope {
|
match self.scope {
|
||||||
None => base,
|
None => base,
|
||||||
Some(scope) => base.intersection(&scope),
|
Some(scope) => base.intersection(&scope),
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let name = match self.name(sema.db) {
|
let name = match self.def.name(sema.db) {
|
||||||
None => return Vec::new(),
|
None => return Vec::new(),
|
||||||
Some(it) => it.to_string(),
|
Some(it) => it.to_string(),
|
||||||
};
|
};
|
||||||
|
@ -225,7 +247,7 @@ impl Definition {
|
||||||
};
|
};
|
||||||
|
|
||||||
match classify_name_ref(&sema, &name_ref) {
|
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)
|
let kind = if is_record_lit_name_ref(&name_ref)
|
||||||
|| is_call_expr_name_ref(&name_ref)
|
|| is_call_expr_name_ref(&name_ref)
|
||||||
{
|
{
|
||||||
|
@ -242,14 +264,14 @@ impl Definition {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
Some(NameRefClass::FieldShorthand { local, field }) => {
|
Some(NameRefClass::FieldShorthand { local, field }) => {
|
||||||
match self {
|
match self.def {
|
||||||
Definition::Field(_) if &field == self => refs.push(Reference {
|
Definition::Field(_) if &field == self.def => refs.push(Reference {
|
||||||
file_range: sema.original_range(name_ref.syntax()),
|
file_range: self.sema.original_range(name_ref.syntax()),
|
||||||
kind: ReferenceKind::FieldShorthandForField,
|
kind: ReferenceKind::FieldShorthandForField,
|
||||||
access: reference_access(&field, &name_ref),
|
access: reference_access(&field, &name_ref),
|
||||||
}),
|
}),
|
||||||
Definition::Local(l) if &local == l => refs.push(Reference {
|
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,
|
kind: ReferenceKind::FieldShorthandForLocal,
|
||||||
access: reference_access(&Definition::Local(local), &name_ref),
|
access: reference_access(&Definition::Local(local), &name_ref),
|
||||||
}),
|
}),
|
||||||
|
|
|
@ -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
|
// 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.
|
// lookups in the case of a cache hit.
|
||||||
if usage_cache.find(&definition).is_none() {
|
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));
|
usage_cache.usages.push((definition, usages));
|
||||||
return &usage_cache.usages.last().unwrap().1;
|
return &usage_cache.usages.last().unwrap().1;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue