aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAleksey Kladov <[email protected]>2020-08-19 17:58:48 +0100
committerAleksey Kladov <[email protected]>2020-08-19 17:58:48 +0100
commit81b0976187d73eba4f9b14d8a0b8539ab8f06dcd (patch)
tree15017f0b41ea44614d603f0b9e029e7bc86a5c44
parent686a6a26fd2263e4bb958fbcf94b04244ed73e08 (diff)
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.
-rw-r--r--crates/assists/src/handlers/extract_struct_from_enum_variant.rs2
-rw-r--r--crates/assists/src/handlers/inline_local_variable.rs2
-rw-r--r--crates/ide/src/references.rs4
-rw-r--r--crates/ide_db/src/search.rs48
-rw-r--r--crates/ssr/src/search.rs2
5 files changed, 41 insertions, 17 deletions
diff --git a/crates/assists/src/handlers/extract_struct_from_enum_variant.rs b/crates/assists/src/handlers/extract_struct_from_enum_variant.rs
index d62e06b4a..c1124b9e2 100644
--- a/crates/assists/src/handlers/extract_struct_from_enum_variant.rs
+++ b/crates/assists/src/handlers/extract_struct_from_enum_variant.rs
@@ -53,7 +53,7 @@ pub(crate) fn extract_struct_from_enum_variant(
53 target, 53 target,
54 |builder| { 54 |builder| {
55 let definition = Definition::ModuleDef(ModuleDef::EnumVariant(variant_hir)); 55 let definition = Definition::ModuleDef(ModuleDef::EnumVariant(variant_hir));
56 let res = definition.find_usages(&ctx.sema, None); 56 let res = definition.usages(&ctx.sema).all();
57 let start_offset = variant.parent_enum().syntax().text_range().start(); 57 let start_offset = variant.parent_enum().syntax().text_range().start();
58 let mut visited_modules_set = FxHashSet::default(); 58 let mut visited_modules_set = FxHashSet::default();
59 visited_modules_set.insert(current_module); 59 visited_modules_set.insert(current_module);
diff --git a/crates/assists/src/handlers/inline_local_variable.rs b/crates/assists/src/handlers/inline_local_variable.rs
index 2b52b333b..164bbce86 100644
--- a/crates/assists/src/handlers/inline_local_variable.rs
+++ b/crates/assists/src/handlers/inline_local_variable.rs
@@ -44,7 +44,7 @@ pub(crate) fn inline_local_variable(acc: &mut Assists, ctx: &AssistContext) -> O
44 44
45 let def = ctx.sema.to_def(&bind_pat)?; 45 let def = ctx.sema.to_def(&bind_pat)?;
46 let def = Definition::Local(def); 46 let def = Definition::Local(def);
47 let refs = def.find_usages(&ctx.sema, None); 47 let refs = def.usages(&ctx.sema).all();
48 if refs.is_empty() { 48 if refs.is_empty() {
49 mark::hit!(test_not_applicable_if_variable_unused); 49 mark::hit!(test_not_applicable_if_variable_unused);
50 return None; 50 return None;
diff --git a/crates/ide/src/references.rs b/crates/ide/src/references.rs
index 0a76ec6b4..722c8f406 100644
--- a/crates/ide/src/references.rs
+++ b/crates/ide/src/references.rs
@@ -106,7 +106,9 @@ pub(crate) fn find_all_refs(
106 let RangeInfo { range, info: def } = find_name(&sema, &syntax, position, opt_name)?; 106 let RangeInfo { range, info: def } = find_name(&sema, &syntax, position, opt_name)?;
107 107
108 let references = def 108 let references = def
109 .find_usages(sema, search_scope) 109 .usages(sema)
110 .set_scope(search_scope)
111 .all()
110 .into_iter() 112 .into_iter()
111 .filter(|r| search_kind == ReferenceKind::Other || search_kind == r.kind) 113 .filter(|r| search_kind == ReferenceKind::Other || search_kind == r.kind)
112 .collect(); 114 .collect();
diff --git a/crates/ide_db/src/search.rs b/crates/ide_db/src/search.rs
index b9360bf12..ce7631c69 100644
--- a/crates/ide_db/src/search.rs
+++ b/crates/ide_db/src/search.rs
@@ -181,22 +181,44 @@ impl Definition {
181 SearchScope::new(res) 181 SearchScope::new(res)
182 } 182 }
183 183
184 pub fn find_usages( 184 pub fn usages<'a>(&'a self, sema: &'a Semantics<RootDatabase>) -> FindUsages<'a> {
185 &self, 185 FindUsages { def: self, sema, scope: None }
186 sema: &Semantics<RootDatabase>, 186 }
187 search_scope: Option<SearchScope>, 187}
188 ) -> Vec<Reference> { 188
189pub struct FindUsages<'a> {
190 def: &'a Definition,
191 sema: &'a Semantics<'a, RootDatabase>,
192 scope: Option<SearchScope>,
193}
194
195impl<'a> FindUsages<'a> {
196 pub fn in_scope(self, scope: SearchScope) -> FindUsages<'a> {
197 self.set_scope(Some(scope))
198 }
199 pub fn set_scope(mut self, scope: Option<SearchScope>) -> FindUsages<'a> {
200 assert!(self.scope.is_none());
201 self.scope = scope;
202 self
203 }
204
205 pub fn at_least_one(self) -> bool {
206 self.all().is_empty()
207 }
208
209 pub fn all(self) -> Vec<Reference> {
189 let _p = profile::span("Definition::find_usages"); 210 let _p = profile::span("Definition::find_usages");
211 let sema = self.sema;
190 212
191 let search_scope = { 213 let search_scope = {
192 let base = self.search_scope(sema.db); 214 let base = self.def.search_scope(sema.db);
193 match search_scope { 215 match self.scope {
194 None => base, 216 None => base,
195 Some(scope) => base.intersection(&scope), 217 Some(scope) => base.intersection(&scope),
196 } 218 }
197 }; 219 };
198 220
199 let name = match self.name(sema.db) { 221 let name = match self.def.name(sema.db) {
200 None => return Vec::new(), 222 None => return Vec::new(),
201 Some(it) => it.to_string(), 223 Some(it) => it.to_string(),
202 }; 224 };
@@ -225,7 +247,7 @@ impl Definition {
225 }; 247 };
226 248
227 match classify_name_ref(&sema, &name_ref) { 249 match classify_name_ref(&sema, &name_ref) {
228 Some(NameRefClass::Definition(def)) if &def == self => { 250 Some(NameRefClass::Definition(def)) if &def == self.def => {
229 let kind = if is_record_lit_name_ref(&name_ref) 251 let kind = if is_record_lit_name_ref(&name_ref)
230 || is_call_expr_name_ref(&name_ref) 252 || is_call_expr_name_ref(&name_ref)
231 { 253 {
@@ -242,14 +264,14 @@ impl Definition {
242 }); 264 });
243 } 265 }
244 Some(NameRefClass::FieldShorthand { local, field }) => { 266 Some(NameRefClass::FieldShorthand { local, field }) => {
245 match self { 267 match self.def {
246 Definition::Field(_) if &field == self => refs.push(Reference { 268 Definition::Field(_) if &field == self.def => refs.push(Reference {
247 file_range: sema.original_range(name_ref.syntax()), 269 file_range: self.sema.original_range(name_ref.syntax()),
248 kind: ReferenceKind::FieldShorthandForField, 270 kind: ReferenceKind::FieldShorthandForField,
249 access: reference_access(&field, &name_ref), 271 access: reference_access(&field, &name_ref),
250 }), 272 }),
251 Definition::Local(l) if &local == l => refs.push(Reference { 273 Definition::Local(l) if &local == l => refs.push(Reference {
252 file_range: sema.original_range(name_ref.syntax()), 274 file_range: self.sema.original_range(name_ref.syntax()),
253 kind: ReferenceKind::FieldShorthandForLocal, 275 kind: ReferenceKind::FieldShorthandForLocal,
254 access: reference_access(&Definition::Local(local), &name_ref), 276 access: reference_access(&Definition::Local(local), &name_ref),
255 }), 277 }),
diff --git a/crates/ssr/src/search.rs b/crates/ssr/src/search.rs
index 8509cfa4d..a595fd269 100644
--- a/crates/ssr/src/search.rs
+++ b/crates/ssr/src/search.rs
@@ -114,7 +114,7 @@ impl<'db> MatchFinder<'db> {
114 // cache miss. This is a limitation of NLL and is fixed with Polonius. For now we do two 114 // cache miss. This is a limitation of NLL and is fixed with Polonius. For now we do two
115 // lookups in the case of a cache hit. 115 // lookups in the case of a cache hit.
116 if usage_cache.find(&definition).is_none() { 116 if usage_cache.find(&definition).is_none() {
117 let usages = definition.find_usages(&self.sema, Some(self.search_scope())); 117 let usages = definition.usages(&self.sema).in_scope(self.search_scope()).all();
118 usage_cache.usages.push((definition, usages)); 118 usage_cache.usages.push((definition, usages));
119 return &usage_cache.usages.last().unwrap().1; 119 return &usage_cache.usages.last().unwrap().1;
120 } 120 }