aboutsummaryrefslogtreecommitdiff
path: root/crates/ide/src
diff options
context:
space:
mode:
authorLukas Wirth <[email protected]>2021-01-12 14:51:02 +0000
committerLukas Wirth <[email protected]>2021-01-12 14:51:02 +0000
commit2c1777a2e264e58fccd5ace94b238c8a497ddbda (patch)
treee7d47c95c6bcdeecd5f321f4ca969d04ca90dff7 /crates/ide/src
parentfbdb32adfc49e0d69b7fd8e44135bea59382d2cb (diff)
Ensure uniqueness of file ids in reference search via hashmap
Diffstat (limited to 'crates/ide/src')
-rw-r--r--crates/ide/src/call_hierarchy.rs4
-rw-r--r--crates/ide/src/references.rs97
-rw-r--r--crates/ide/src/references/rename.rs20
3 files changed, 62 insertions, 59 deletions
diff --git a/crates/ide/src/call_hierarchy.rs b/crates/ide/src/call_hierarchy.rs
index 90d3b9a31..e8999a7f3 100644
--- a/crates/ide/src/call_hierarchy.rs
+++ b/crates/ide/src/call_hierarchy.rs
@@ -3,8 +3,8 @@
3use indexmap::IndexMap; 3use indexmap::IndexMap;
4 4
5use hir::Semantics; 5use hir::Semantics;
6use ide_db::call_info::FnCallNode;
6use ide_db::RootDatabase; 7use ide_db::RootDatabase;
7use ide_db::{call_info::FnCallNode, search::FileReferences};
8use syntax::{ast, AstNode, TextRange}; 8use syntax::{ast, AstNode, TextRange};
9 9
10use crate::{ 10use crate::{
@@ -47,7 +47,7 @@ pub(crate) fn incoming_calls(db: &RootDatabase, position: FilePosition) -> Optio
47 47
48 let mut calls = CallLocations::default(); 48 let mut calls = CallLocations::default();
49 49
50 for &FileReferences { file_id, ref references } in refs.info.references() { 50 for (&file_id, references) in refs.info.references().iter() {
51 let file = sema.parse(file_id); 51 let file = sema.parse(file_id);
52 let file = file.syntax(); 52 let file = file.syntax();
53 for reference in references { 53 for reference in references {
diff --git a/crates/ide/src/references.rs b/crates/ide/src/references.rs
index 132680bfb..c7943dc95 100644
--- a/crates/ide/src/references.rs
+++ b/crates/ide/src/references.rs
@@ -13,6 +13,7 @@ pub(crate) mod rename;
13 13
14use hir::Semantics; 14use hir::Semantics;
15use ide_db::{ 15use ide_db::{
16 base_db::FileId,
16 defs::{Definition, NameClass, NameRefClass}, 17 defs::{Definition, NameClass, NameRefClass},
17 search::{FileReference, FileReferences, ReferenceAccess, ReferenceKind, SearchScope}, 18 search::{FileReference, FileReferences, ReferenceAccess, ReferenceKind, SearchScope},
18 RootDatabase, 19 RootDatabase,
@@ -28,7 +29,7 @@ use crate::{display::TryToNav, FilePosition, FileRange, NavigationTarget, RangeI
28#[derive(Debug, Clone)] 29#[derive(Debug, Clone)]
29pub struct ReferenceSearchResult { 30pub struct ReferenceSearchResult {
30 declaration: Declaration, 31 declaration: Declaration,
31 references: Vec<FileReferences>, 32 references: FileReferences,
32} 33}
33 34
34#[derive(Debug, Clone)] 35#[derive(Debug, Clone)]
@@ -47,10 +48,21 @@ impl ReferenceSearchResult {
47 &self.declaration.nav 48 &self.declaration.nav
48 } 49 }
49 50
50 pub fn references(&self) -> &[FileReferences] { 51 pub fn references(&self) -> &FileReferences {
51 &self.references 52 &self.references
52 } 53 }
53 54
55 pub fn references_with_declaration(mut self) -> FileReferences {
56 let decl_ref = FileReference {
57 range: self.declaration.nav.focus_or_full_range(),
58 kind: self.declaration.kind,
59 access: self.declaration.access,
60 };
61 let file_id = self.declaration.nav.file_id;
62 self.references.references.entry(file_id).or_default().push(decl_ref);
63 self.references
64 }
65
54 /// Total number of references 66 /// Total number of references
55 /// At least 1 since all valid references should 67 /// At least 1 since all valid references should
56 /// Have a declaration 68 /// Have a declaration
@@ -62,23 +74,11 @@ impl ReferenceSearchResult {
62// allow turning ReferenceSearchResult into an iterator 74// allow turning ReferenceSearchResult into an iterator
63// over References 75// over References
64impl IntoIterator for ReferenceSearchResult { 76impl IntoIterator for ReferenceSearchResult {
65 type Item = FileReferences; 77 type Item = (FileId, Vec<FileReference>);
66 type IntoIter = std::vec::IntoIter<FileReferences>; 78 type IntoIter = std::collections::hash_map::IntoIter<FileId, Vec<FileReference>>;
67 79
68 fn into_iter(mut self) -> Self::IntoIter { 80 fn into_iter(self) -> Self::IntoIter {
69 let mut v = Vec::with_capacity(self.len()); 81 self.references_with_declaration().into_iter()
70 v.append(&mut self.references);
71 let decl_ref = FileReference {
72 range: self.declaration.nav.focus_or_full_range(),
73 kind: self.declaration.kind,
74 access: self.declaration.access,
75 };
76 let file_id = self.declaration.nav.file_id;
77 match v.iter_mut().find(|it| it.file_id == file_id) {
78 Some(file_refs) => file_refs.references.push(decl_ref),
79 None => v.push(FileReferences { file_id, references: vec![decl_ref] }),
80 }
81 v.into_iter()
82 } 82 }
83} 83}
84 84
@@ -110,11 +110,12 @@ pub(crate) fn find_all_refs(
110 110
111 let RangeInfo { range, info: def } = find_name(&sema, &syntax, position, opt_name)?; 111 let RangeInfo { range, info: def } = find_name(&sema, &syntax, position, opt_name)?;
112 112
113 let mut references = def.usages(sema).set_scope(search_scope).all(); 113 let mut usages = def.usages(sema).set_scope(search_scope).all();
114 references.iter_mut().for_each(|it| { 114 usages
115 it.references.retain(|r| search_kind == ReferenceKind::Other || search_kind == r.kind) 115 .references
116 }); 116 .values_mut()
117 references.retain(|r| !r.references.is_empty()); 117 .for_each(|it| it.retain(|r| search_kind == ReferenceKind::Other || search_kind == r.kind));
118 usages.references.retain(|_, it| !it.is_empty());
118 119
119 let nav = def.try_to_nav(sema.db)?; 120 let nav = def.try_to_nav(sema.db)?;
120 let decl_range = nav.focus_or_full_range(); 121 let decl_range = nav.focus_or_full_range();
@@ -138,7 +139,7 @@ pub(crate) fn find_all_refs(
138 139
139 let declaration = Declaration { nav, kind, access: decl_access(&def, &syntax, decl_range) }; 140 let declaration = Declaration { nav, kind, access: decl_access(&def, &syntax, decl_range) };
140 141
141 Some(RangeInfo::new(range, ReferenceSearchResult { declaration, references })) 142 Some(RangeInfo::new(range, ReferenceSearchResult { declaration, references: usages }))
142} 143}
143 144
144fn find_name( 145fn find_name(
@@ -292,32 +293,30 @@ fn try_find_self_references(
292 ReferenceAccess::Read 293 ReferenceAccess::Read
293 }), 294 }),
294 }; 295 };
295 let references = function 296 let refs = function
296 .body() 297 .body()
297 .map(|body| { 298 .map(|body| {
298 FileReferences { 299 body.syntax()
299 file_id, 300 .descendants()
300 references: body 301 .filter_map(ast::PathExpr::cast)
301 .syntax() 302 .filter_map(|expr| {
302 .descendants() 303 let path = expr.path()?;
303 .filter_map(ast::PathExpr::cast) 304 if path.qualifier().is_none() {
304 .filter_map(|expr| { 305 path.segment()?.self_token()
305 let path = expr.path()?; 306 } else {
306 if path.qualifier().is_none() { 307 None
307 path.segment()?.self_token() 308 }
308 } else { 309 })
309 None 310 .map(|token| FileReference {
310 } 311 range: token.text_range(),
311 }) 312 kind: ReferenceKind::SelfKw,
312 .map(|token| FileReference { 313 access: declaration.access, // FIXME: properly check access kind here instead of copying it from the declaration
313 range: token.text_range(), 314 })
314 kind: ReferenceKind::SelfKw, 315 .collect()
315 access: declaration.access, // FIXME: properly check access kind here instead of copying it from the declaration
316 })
317 .collect(),
318 }
319 }) 316 })
320 .map_or_else(Vec::default, |it| vec![it]); 317 .unwrap_or_default();
318 let mut references = FileReferences::default();
319 references.references.insert(file_id, refs);
321 320
322 Some(RangeInfo::new( 321 Some(RangeInfo::new(
323 param_self_token.text_range(), 322 param_self_token.text_range(),
@@ -328,7 +327,7 @@ fn try_find_self_references(
328#[cfg(test)] 327#[cfg(test)]
329mod tests { 328mod tests {
330 use expect_test::{expect, Expect}; 329 use expect_test::{expect, Expect};
331 use ide_db::{base_db::FileId, search::FileReferences}; 330 use ide_db::base_db::FileId;
332 use stdx::format_to; 331 use stdx::format_to;
333 332
334 use crate::{fixture, SearchScope}; 333 use crate::{fixture, SearchScope};
@@ -1022,7 +1021,7 @@ impl Foo {
1022 actual += "\n\n"; 1021 actual += "\n\n";
1023 } 1022 }
1024 1023
1025 for FileReferences { file_id, references } in refs.references { 1024 for (file_id, references) in refs.references {
1026 for r in references { 1025 for r in references {
1027 format_to!(actual, "{:?} {:?} {:?}", file_id, r.range, r.kind); 1026 format_to!(actual, "{:?} {:?} {:?}", file_id, r.range, r.kind);
1028 if let Some(access) = r.access { 1027 if let Some(access) = r.access {
diff --git a/crates/ide/src/references/rename.rs b/crates/ide/src/references/rename.rs
index dd08e1c32..5207388b5 100644
--- a/crates/ide/src/references/rename.rs
+++ b/crates/ide/src/references/rename.rs
@@ -9,7 +9,7 @@ use hir::{Module, ModuleDef, ModuleSource, Semantics};
9use ide_db::{ 9use ide_db::{
10 base_db::{AnchoredPathBuf, FileId, FileRange, SourceDatabaseExt}, 10 base_db::{AnchoredPathBuf, FileId, FileRange, SourceDatabaseExt},
11 defs::{Definition, NameClass, NameRefClass}, 11 defs::{Definition, NameClass, NameRefClass},
12 search::FileReferences, 12 search::FileReference,
13 RootDatabase, 13 RootDatabase,
14}; 14};
15use syntax::{ 15use syntax::{
@@ -176,7 +176,8 @@ fn find_all_refs(
176 176
177fn source_edit_from_references( 177fn source_edit_from_references(
178 sema: &Semantics<RootDatabase>, 178 sema: &Semantics<RootDatabase>,
179 &FileReferences { file_id, ref references }: &FileReferences, 179 file_id: FileId,
180 references: &[FileReference],
180 new_name: &str, 181 new_name: &str,
181) -> SourceFileEdit { 182) -> SourceFileEdit {
182 let mut edit = TextEdit::builder(); 183 let mut edit = TextEdit::builder();
@@ -283,10 +284,9 @@ fn rename_mod(
283 } 284 }
284 285
285 let RangeInfo { range, info: refs } = find_all_refs(sema, position)?; 286 let RangeInfo { range, info: refs } = find_all_refs(sema, position)?;
286 let ref_edits = refs 287 let ref_edits = refs.references().iter().map(|(&file_id, references)| {
287 .references() 288 source_edit_from_references(sema, file_id, references, new_name)
288 .iter() 289 });
289 .map(|reference| source_edit_from_references(sema, reference, new_name));
290 source_file_edits.extend(ref_edits); 290 source_file_edits.extend(ref_edits);
291 291
292 Ok(RangeInfo::new(range, SourceChange::from_edits(source_file_edits, file_system_edits))) 292 Ok(RangeInfo::new(range, SourceChange::from_edits(source_file_edits, file_system_edits)))
@@ -341,7 +341,9 @@ fn rename_to_self(
341 let mut edits = refs 341 let mut edits = refs
342 .references() 342 .references()
343 .iter() 343 .iter()
344 .map(|reference| source_edit_from_references(sema, reference, "self")) 344 .map(|(&file_id, references)| {
345 source_edit_from_references(sema, file_id, references, "self")
346 })
345 .collect::<Vec<_>>(); 347 .collect::<Vec<_>>();
346 348
347 edits.push(SourceFileEdit { 349 edits.push(SourceFileEdit {
@@ -467,7 +469,9 @@ fn rename_reference(
467 469
468 let edit = refs 470 let edit = refs
469 .into_iter() 471 .into_iter()
470 .map(|reference| source_edit_from_references(sema, &reference, new_name)) 472 .map(|(file_id, references)| {
473 source_edit_from_references(sema, file_id, &references, new_name)
474 })
471 .collect::<Vec<_>>(); 475 .collect::<Vec<_>>();
472 476
473 Ok(RangeInfo::new(range, SourceChange::from(edit))) 477 Ok(RangeInfo::new(range, SourceChange::from(edit)))