From fbdb32adfc49e0d69b7fd8e44135bea59382d2cb Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Tue, 12 Jan 2021 00:05:07 +0100 Subject: Group references by FileId --- crates/ide/src/call_hierarchy.rs | 31 ++++++------ crates/ide/src/lib.rs | 2 +- crates/ide/src/references.rs | 98 ++++++++++++++++++++----------------- crates/ide/src/references/rename.rs | 94 +++++++++++++++++------------------ 4 files changed, 116 insertions(+), 109 deletions(-) (limited to 'crates/ide/src') diff --git a/crates/ide/src/call_hierarchy.rs b/crates/ide/src/call_hierarchy.rs index b29d1fef9..90d3b9a31 100644 --- a/crates/ide/src/call_hierarchy.rs +++ b/crates/ide/src/call_hierarchy.rs @@ -3,8 +3,8 @@ use indexmap::IndexMap; use hir::Semantics; -use ide_db::call_info::FnCallNode; use ide_db::RootDatabase; +use ide_db::{call_info::FnCallNode, search::FileReferences}; use syntax::{ast, AstNode, TextRange}; use crate::{ @@ -47,22 +47,23 @@ pub(crate) fn incoming_calls(db: &RootDatabase, position: FilePosition) -> Optio let mut calls = CallLocations::default(); - for reference in refs.info.references() { - let file_id = reference.file_range.file_id; + for &FileReferences { file_id, ref references } in refs.info.references() { let file = sema.parse(file_id); let file = file.syntax(); - let token = file.token_at_offset(reference.file_range.range.start()).next()?; - let token = sema.descend_into_macros(token); - let syntax = token.parent(); - - // This target is the containing function - if let Some(nav) = syntax.ancestors().find_map(|node| { - let fn_ = ast::Fn::cast(node)?; - let def = sema.to_def(&fn_)?; - def.try_to_nav(sema.db) - }) { - let relative_range = reference.file_range.range; - calls.add(&nav, relative_range); + for reference in references { + let token = file.token_at_offset(reference.range.start()).next()?; + let token = sema.descend_into_macros(token); + let syntax = token.parent(); + + // This target is the containing function + if let Some(nav) = syntax.ancestors().find_map(|node| { + let fn_ = ast::Fn::cast(node)?; + let def = sema.to_def(&fn_)?; + def.try_to_nav(sema.db) + }) { + let relative_range = reference.range; + calls.add(&nav, relative_range); + } } } diff --git a/crates/ide/src/lib.rs b/crates/ide/src/lib.rs index 1f368cbd0..1e03832ec 100644 --- a/crates/ide/src/lib.rs +++ b/crates/ide/src/lib.rs @@ -92,7 +92,7 @@ pub use ide_db::base_db::{ }; pub use ide_db::{ call_info::CallInfo, - search::{Reference, ReferenceAccess, ReferenceKind}, + search::{FileReference, ReferenceAccess, ReferenceKind}, }; pub use ide_db::{ label::Label, diff --git a/crates/ide/src/references.rs b/crates/ide/src/references.rs index b774a2be1..132680bfb 100644 --- a/crates/ide/src/references.rs +++ b/crates/ide/src/references.rs @@ -14,8 +14,7 @@ pub(crate) mod rename; use hir::Semantics; use ide_db::{ defs::{Definition, NameClass, NameRefClass}, - search::Reference, - search::{ReferenceAccess, ReferenceKind, SearchScope}, + search::{FileReference, FileReferences, ReferenceAccess, ReferenceKind, SearchScope}, RootDatabase, }; use syntax::{ @@ -29,7 +28,7 @@ use crate::{display::TryToNav, FilePosition, FileRange, NavigationTarget, RangeI #[derive(Debug, Clone)] pub struct ReferenceSearchResult { declaration: Declaration, - references: Vec, + references: Vec, } #[derive(Debug, Clone)] @@ -48,7 +47,7 @@ impl ReferenceSearchResult { &self.declaration.nav } - pub fn references(&self) -> &[Reference] { + pub fn references(&self) -> &[FileReferences] { &self.references } @@ -63,20 +62,22 @@ impl ReferenceSearchResult { // allow turning ReferenceSearchResult into an iterator // over References impl IntoIterator for ReferenceSearchResult { - type Item = Reference; - type IntoIter = std::vec::IntoIter; + type Item = FileReferences; + type IntoIter = std::vec::IntoIter; fn into_iter(mut self) -> Self::IntoIter { let mut v = Vec::with_capacity(self.len()); - v.push(Reference { - file_range: FileRange { - file_id: self.declaration.nav.file_id, - range: self.declaration.nav.focus_or_full_range(), - }, + v.append(&mut self.references); + let decl_ref = FileReference { + range: self.declaration.nav.focus_or_full_range(), kind: self.declaration.kind, access: self.declaration.access, - }); - v.append(&mut self.references); + }; + let file_id = self.declaration.nav.file_id; + match v.iter_mut().find(|it| it.file_id == file_id) { + Some(file_refs) => file_refs.references.push(decl_ref), + None => v.push(FileReferences { file_id, references: vec![decl_ref] }), + } v.into_iter() } } @@ -109,13 +110,11 @@ pub(crate) fn find_all_refs( let RangeInfo { range, info: def } = find_name(&sema, &syntax, position, opt_name)?; - let references = def - .usages(sema) - .set_scope(search_scope) - .all() - .into_iter() - .filter(|r| search_kind == ReferenceKind::Other || search_kind == r.kind) - .collect(); + let mut references = def.usages(sema).set_scope(search_scope).all(); + references.iter_mut().for_each(|it| { + it.references.retain(|r| search_kind == ReferenceKind::Other || search_kind == r.kind) + }); + references.retain(|r| !r.references.is_empty()); let nav = def.try_to_nav(sema.db)?; let decl_range = nav.focus_or_full_range(); @@ -255,7 +254,8 @@ fn try_find_self_references( syntax: &SyntaxNode, position: FilePosition, ) -> Option> { - let self_token = syntax.token_at_offset(position.offset).find(|t| t.kind() == T![self])?; + let FilePosition { file_id, offset } = position; + let self_token = syntax.token_at_offset(offset).find(|t| t.kind() == T![self])?; let parent = self_token.parent(); match_ast! { match parent { @@ -276,7 +276,7 @@ fn try_find_self_references( let declaration = Declaration { nav: NavigationTarget { - file_id: position.file_id, + file_id, full_range: self_param.syntax().text_range(), focus_range: Some(param_self_token.text_range()), name: param_self_token.text().clone(), @@ -295,25 +295,29 @@ fn try_find_self_references( let references = function .body() .map(|body| { - body.syntax() - .descendants() - .filter_map(ast::PathExpr::cast) - .filter_map(|expr| { - let path = expr.path()?; - if path.qualifier().is_none() { - path.segment()?.self_token() - } else { - None - } - }) - .map(|token| Reference { - file_range: FileRange { file_id: position.file_id, range: token.text_range() }, - kind: ReferenceKind::SelfKw, - access: declaration.access, // FIXME: properly check access kind here instead of copying it from the declaration - }) - .collect() + FileReferences { + file_id, + references: body + .syntax() + .descendants() + .filter_map(ast::PathExpr::cast) + .filter_map(|expr| { + let path = expr.path()?; + if path.qualifier().is_none() { + path.segment()?.self_token() + } else { + None + } + }) + .map(|token| FileReference { + range: token.text_range(), + kind: ReferenceKind::SelfKw, + access: declaration.access, // FIXME: properly check access kind here instead of copying it from the declaration + }) + .collect(), + } }) - .unwrap_or_default(); + .map_or_else(Vec::default, |it| vec![it]); Some(RangeInfo::new( param_self_token.text_range(), @@ -324,7 +328,7 @@ fn try_find_self_references( #[cfg(test)] mod tests { use expect_test::{expect, Expect}; - use ide_db::base_db::FileId; + use ide_db::{base_db::FileId, search::FileReferences}; use stdx::format_to; use crate::{fixture, SearchScope}; @@ -1018,12 +1022,14 @@ impl Foo { actual += "\n\n"; } - for r in &refs.references { - format_to!(actual, "{:?} {:?} {:?}", r.file_range.file_id, r.file_range.range, r.kind); - if let Some(access) = r.access { - format_to!(actual, " {:?}", access); + for FileReferences { file_id, references } in refs.references { + for r in references { + format_to!(actual, "{:?} {:?} {:?}", file_id, r.range, r.kind); + if let Some(access) = r.access { + format_to!(actual, " {:?}", access); + } + actual += "\n"; } - actual += "\n"; } expect.assert_eq(&actual) } diff --git a/crates/ide/src/references/rename.rs b/crates/ide/src/references/rename.rs index 3edc43e08..dd08e1c32 100644 --- a/crates/ide/src/references/rename.rs +++ b/crates/ide/src/references/rename.rs @@ -6,9 +6,10 @@ use std::{ }; use hir::{Module, ModuleDef, ModuleSource, Semantics}; -use ide_db::base_db::{AnchoredPathBuf, FileId, FileRange, SourceDatabaseExt}; use ide_db::{ + base_db::{AnchoredPathBuf, FileId, FileRange, SourceDatabaseExt}, defs::{Definition, NameClass, NameRefClass}, + search::FileReferences, RootDatabase, }; use syntax::{ @@ -20,8 +21,8 @@ use test_utils::mark; use text_edit::TextEdit; use crate::{ - FilePosition, FileSystemEdit, RangeInfo, Reference, ReferenceKind, ReferenceSearchResult, - SourceChange, SourceFileEdit, TextRange, TextSize, + FilePosition, FileSystemEdit, RangeInfo, ReferenceKind, ReferenceSearchResult, SourceChange, + SourceFileEdit, TextRange, TextSize, }; type RenameResult = Result; @@ -173,39 +174,45 @@ fn find_all_refs( .ok_or_else(|| format_err!("No references found at position")) } -fn source_edit_from_reference( +fn source_edit_from_references( sema: &Semantics, - reference: Reference, + &FileReferences { file_id, ref references }: &FileReferences, new_name: &str, ) -> SourceFileEdit { - let mut replacement_text = String::new(); - let range = match reference.kind { - ReferenceKind::FieldShorthandForField => { - mark::hit!(test_rename_struct_field_for_shorthand); - replacement_text.push_str(new_name); - replacement_text.push_str(": "); - TextRange::new(reference.file_range.range.start(), reference.file_range.range.start()) - } - ReferenceKind::FieldShorthandForLocal => { - mark::hit!(test_rename_local_for_field_shorthand); - replacement_text.push_str(": "); - replacement_text.push_str(new_name); - TextRange::new(reference.file_range.range.end(), reference.file_range.range.end()) - } - ReferenceKind::RecordFieldExprOrPat => { - mark::hit!(test_rename_field_expr_pat); - replacement_text.push_str(new_name); - edit_text_range_for_record_field_expr_or_pat(sema, reference.file_range, new_name) - } - _ => { - replacement_text.push_str(new_name); - reference.file_range.range - } - }; - SourceFileEdit { - file_id: reference.file_range.file_id, - edit: TextEdit::replace(range, replacement_text), + let mut edit = TextEdit::builder(); + for reference in references { + let mut replacement_text = String::new(); + let range = match reference.kind { + ReferenceKind::FieldShorthandForField => { + mark::hit!(test_rename_struct_field_for_shorthand); + replacement_text.push_str(new_name); + replacement_text.push_str(": "); + TextRange::new(reference.range.start(), reference.range.start()) + } + ReferenceKind::FieldShorthandForLocal => { + mark::hit!(test_rename_local_for_field_shorthand); + replacement_text.push_str(": "); + replacement_text.push_str(new_name); + TextRange::new(reference.range.end(), reference.range.end()) + } + ReferenceKind::RecordFieldExprOrPat => { + mark::hit!(test_rename_field_expr_pat); + replacement_text.push_str(new_name); + edit_text_range_for_record_field_expr_or_pat( + sema, + FileRange { file_id, range: reference.range }, + new_name, + ) + } + _ => { + replacement_text.push_str(new_name); + reference.range + } + }; + edit.replace(range, replacement_text); } + + SourceFileEdit { file_id, edit: edit.finish() } } fn edit_text_range_for_record_field_expr_or_pat( @@ -277,9 +284,9 @@ fn rename_mod( let RangeInfo { range, info: refs } = find_all_refs(sema, position)?; let ref_edits = refs - .references - .into_iter() - .map(|reference| source_edit_from_reference(sema, reference, new_name)); + .references() + .iter() + .map(|reference| source_edit_from_references(sema, reference, new_name)); source_file_edits.extend(ref_edits); Ok(RangeInfo::new(range, SourceChange::from_edits(source_file_edits, file_system_edits))) @@ -331,17 +338,10 @@ fn rename_to_self( let RangeInfo { range, info: refs } = find_all_refs(sema, position)?; - let (param_ref, usages): (Vec, Vec) = refs - .into_iter() - .partition(|reference| param_range.intersect(reference.file_range.range).is_some()); - - if param_ref.is_empty() { - bail!("Parameter to rename not found"); - } - - let mut edits = usages - .into_iter() - .map(|reference| source_edit_from_reference(sema, reference, "self")) + let mut edits = refs + .references() + .iter() + .map(|reference| source_edit_from_references(sema, reference, "self")) .collect::>(); edits.push(SourceFileEdit { @@ -467,7 +467,7 @@ fn rename_reference( let edit = refs .into_iter() - .map(|reference| source_edit_from_reference(sema, reference, new_name)) + .map(|reference| source_edit_from_references(sema, &reference, new_name)) .collect::>(); Ok(RangeInfo::new(range, SourceChange::from(edit))) -- cgit v1.2.3 From 2c1777a2e264e58fccd5ace94b238c8a497ddbda Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Tue, 12 Jan 2021 15:51:02 +0100 Subject: Ensure uniqueness of file ids in reference search via hashmap --- crates/ide/src/call_hierarchy.rs | 4 +- crates/ide/src/references.rs | 97 ++++++++++++++++++------------------- crates/ide/src/references/rename.rs | 20 +++++--- 3 files changed, 62 insertions(+), 59 deletions(-) (limited to 'crates/ide/src') 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 @@ use indexmap::IndexMap; use hir::Semantics; +use ide_db::call_info::FnCallNode; use ide_db::RootDatabase; -use ide_db::{call_info::FnCallNode, search::FileReferences}; use syntax::{ast, AstNode, TextRange}; use crate::{ @@ -47,7 +47,7 @@ pub(crate) fn incoming_calls(db: &RootDatabase, position: FilePosition) -> Optio let mut calls = CallLocations::default(); - for &FileReferences { file_id, ref references } in refs.info.references() { + for (&file_id, references) in refs.info.references().iter() { let file = sema.parse(file_id); let file = file.syntax(); 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; use hir::Semantics; use ide_db::{ + base_db::FileId, defs::{Definition, NameClass, NameRefClass}, search::{FileReference, FileReferences, ReferenceAccess, ReferenceKind, SearchScope}, RootDatabase, @@ -28,7 +29,7 @@ use crate::{display::TryToNav, FilePosition, FileRange, NavigationTarget, RangeI #[derive(Debug, Clone)] pub struct ReferenceSearchResult { declaration: Declaration, - references: Vec, + references: FileReferences, } #[derive(Debug, Clone)] @@ -47,10 +48,21 @@ impl ReferenceSearchResult { &self.declaration.nav } - pub fn references(&self) -> &[FileReferences] { + pub fn references(&self) -> &FileReferences { &self.references } + pub fn references_with_declaration(mut self) -> FileReferences { + let decl_ref = FileReference { + range: self.declaration.nav.focus_or_full_range(), + kind: self.declaration.kind, + access: self.declaration.access, + }; + let file_id = self.declaration.nav.file_id; + self.references.references.entry(file_id).or_default().push(decl_ref); + self.references + } + /// Total number of references /// At least 1 since all valid references should /// Have a declaration @@ -62,23 +74,11 @@ impl ReferenceSearchResult { // allow turning ReferenceSearchResult into an iterator // over References impl IntoIterator for ReferenceSearchResult { - type Item = FileReferences; - type IntoIter = std::vec::IntoIter; + type Item = (FileId, Vec); + type IntoIter = std::collections::hash_map::IntoIter>; - fn into_iter(mut self) -> Self::IntoIter { - let mut v = Vec::with_capacity(self.len()); - v.append(&mut self.references); - let decl_ref = FileReference { - range: self.declaration.nav.focus_or_full_range(), - kind: self.declaration.kind, - access: self.declaration.access, - }; - let file_id = self.declaration.nav.file_id; - match v.iter_mut().find(|it| it.file_id == file_id) { - Some(file_refs) => file_refs.references.push(decl_ref), - None => v.push(FileReferences { file_id, references: vec![decl_ref] }), - } - v.into_iter() + fn into_iter(self) -> Self::IntoIter { + self.references_with_declaration().into_iter() } } @@ -110,11 +110,12 @@ pub(crate) fn find_all_refs( let RangeInfo { range, info: def } = find_name(&sema, &syntax, position, opt_name)?; - let mut references = def.usages(sema).set_scope(search_scope).all(); - references.iter_mut().for_each(|it| { - it.references.retain(|r| search_kind == ReferenceKind::Other || search_kind == r.kind) - }); - references.retain(|r| !r.references.is_empty()); + let mut usages = def.usages(sema).set_scope(search_scope).all(); + usages + .references + .values_mut() + .for_each(|it| it.retain(|r| search_kind == ReferenceKind::Other || search_kind == r.kind)); + usages.references.retain(|_, it| !it.is_empty()); let nav = def.try_to_nav(sema.db)?; let decl_range = nav.focus_or_full_range(); @@ -138,7 +139,7 @@ pub(crate) fn find_all_refs( let declaration = Declaration { nav, kind, access: decl_access(&def, &syntax, decl_range) }; - Some(RangeInfo::new(range, ReferenceSearchResult { declaration, references })) + Some(RangeInfo::new(range, ReferenceSearchResult { declaration, references: usages })) } fn find_name( @@ -292,32 +293,30 @@ fn try_find_self_references( ReferenceAccess::Read }), }; - let references = function + let refs = function .body() .map(|body| { - FileReferences { - file_id, - references: body - .syntax() - .descendants() - .filter_map(ast::PathExpr::cast) - .filter_map(|expr| { - let path = expr.path()?; - if path.qualifier().is_none() { - path.segment()?.self_token() - } else { - None - } - }) - .map(|token| FileReference { - range: token.text_range(), - kind: ReferenceKind::SelfKw, - access: declaration.access, // FIXME: properly check access kind here instead of copying it from the declaration - }) - .collect(), - } + body.syntax() + .descendants() + .filter_map(ast::PathExpr::cast) + .filter_map(|expr| { + let path = expr.path()?; + if path.qualifier().is_none() { + path.segment()?.self_token() + } else { + None + } + }) + .map(|token| FileReference { + range: token.text_range(), + kind: ReferenceKind::SelfKw, + access: declaration.access, // FIXME: properly check access kind here instead of copying it from the declaration + }) + .collect() }) - .map_or_else(Vec::default, |it| vec![it]); + .unwrap_or_default(); + let mut references = FileReferences::default(); + references.references.insert(file_id, refs); Some(RangeInfo::new( param_self_token.text_range(), @@ -328,7 +327,7 @@ fn try_find_self_references( #[cfg(test)] mod tests { use expect_test::{expect, Expect}; - use ide_db::{base_db::FileId, search::FileReferences}; + use ide_db::base_db::FileId; use stdx::format_to; use crate::{fixture, SearchScope}; @@ -1022,7 +1021,7 @@ impl Foo { actual += "\n\n"; } - for FileReferences { file_id, references } in refs.references { + for (file_id, references) in refs.references { for r in references { format_to!(actual, "{:?} {:?} {:?}", file_id, r.range, r.kind); 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}; use ide_db::{ base_db::{AnchoredPathBuf, FileId, FileRange, SourceDatabaseExt}, defs::{Definition, NameClass, NameRefClass}, - search::FileReferences, + search::FileReference, RootDatabase, }; use syntax::{ @@ -176,7 +176,8 @@ fn find_all_refs( fn source_edit_from_references( sema: &Semantics, - &FileReferences { file_id, ref references }: &FileReferences, + file_id: FileId, + references: &[FileReference], new_name: &str, ) -> SourceFileEdit { let mut edit = TextEdit::builder(); @@ -283,10 +284,9 @@ fn rename_mod( } let RangeInfo { range, info: refs } = find_all_refs(sema, position)?; - let ref_edits = refs - .references() - .iter() - .map(|reference| source_edit_from_references(sema, reference, new_name)); + let ref_edits = refs.references().iter().map(|(&file_id, references)| { + source_edit_from_references(sema, file_id, references, new_name) + }); source_file_edits.extend(ref_edits); Ok(RangeInfo::new(range, SourceChange::from_edits(source_file_edits, file_system_edits))) @@ -341,7 +341,9 @@ fn rename_to_self( let mut edits = refs .references() .iter() - .map(|reference| source_edit_from_references(sema, reference, "self")) + .map(|(&file_id, references)| { + source_edit_from_references(sema, file_id, references, "self") + }) .collect::>(); edits.push(SourceFileEdit { @@ -467,7 +469,9 @@ fn rename_reference( let edit = refs .into_iter() - .map(|reference| source_edit_from_references(sema, &reference, new_name)) + .map(|(file_id, references)| { + source_edit_from_references(sema, file_id, &references, new_name) + }) .collect::>(); Ok(RangeInfo::new(range, SourceChange::from(edit))) -- cgit v1.2.3 From aff9102afb2b6756b3935dedb9be30401975b262 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Tue, 12 Jan 2021 15:56:24 +0100 Subject: Rename FileReferences -> UsageSearchResult --- crates/ide/src/references.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'crates/ide/src') diff --git a/crates/ide/src/references.rs b/crates/ide/src/references.rs index c7943dc95..7d4757e02 100644 --- a/crates/ide/src/references.rs +++ b/crates/ide/src/references.rs @@ -15,7 +15,7 @@ use hir::Semantics; use ide_db::{ base_db::FileId, defs::{Definition, NameClass, NameRefClass}, - search::{FileReference, FileReferences, ReferenceAccess, ReferenceKind, SearchScope}, + search::{FileReference, ReferenceAccess, ReferenceKind, SearchScope, UsageSearchResult}, RootDatabase, }; use syntax::{ @@ -29,7 +29,7 @@ use crate::{display::TryToNav, FilePosition, FileRange, NavigationTarget, RangeI #[derive(Debug, Clone)] pub struct ReferenceSearchResult { declaration: Declaration, - references: FileReferences, + references: UsageSearchResult, } #[derive(Debug, Clone)] @@ -48,11 +48,11 @@ impl ReferenceSearchResult { &self.declaration.nav } - pub fn references(&self) -> &FileReferences { + pub fn references(&self) -> &UsageSearchResult { &self.references } - pub fn references_with_declaration(mut self) -> FileReferences { + pub fn references_with_declaration(mut self) -> UsageSearchResult { let decl_ref = FileReference { range: self.declaration.nav.focus_or_full_range(), kind: self.declaration.kind, @@ -315,7 +315,7 @@ fn try_find_self_references( .collect() }) .unwrap_or_default(); - let mut references = FileReferences::default(); + let mut references = UsageSearchResult::default(); references.references.insert(file_id, refs); Some(RangeInfo::new( -- cgit v1.2.3