From 85a6bf342490f2a8be34ea53af9eb8fcdcad2b38 Mon Sep 17 00:00:00 2001 From: Ville Penttinen Date: Sun, 17 Feb 2019 13:38:32 +0200 Subject: Refactor find_all_refs to return ReferenceSearchResult --- crates/ra_ide_api/src/lib.rs | 6 +- crates/ra_ide_api/src/navigation_target.rs | 16 ++++- crates/ra_ide_api/src/references.rs | 106 +++++++++++++++++++++-------- 3 files changed, 94 insertions(+), 34 deletions(-) (limited to 'crates/ra_ide_api/src') diff --git a/crates/ra_ide_api/src/lib.rs b/crates/ra_ide_api/src/lib.rs index 1746b58ae..57a490fa7 100644 --- a/crates/ra_ide_api/src/lib.rs +++ b/crates/ra_ide_api/src/lib.rs @@ -56,6 +56,7 @@ pub use crate::{ completion::{CompletionItem, CompletionItemKind, InsertTextFormat}, runnables::{Runnable, RunnableKind}, navigation_target::NavigationTarget, + references::ReferenceSearchResult, }; pub use ra_ide_api_light::{ Fold, FoldKind, HighlightedRange, Severity, StructureNode, LocalEdit, @@ -319,7 +320,10 @@ impl Analysis { } /// Finds all usages of the reference at point. - pub fn find_all_refs(&self, position: FilePosition) -> Cancelable> { + pub fn find_all_refs( + &self, + position: FilePosition, + ) -> Cancelable> { self.with_db(|db| references::find_all_refs(db, position)) } diff --git a/crates/ra_ide_api/src/navigation_target.rs b/crates/ra_ide_api/src/navigation_target.rs index 004921863..fd001179a 100644 --- a/crates/ra_ide_api/src/navigation_target.rs +++ b/crates/ra_ide_api/src/navigation_target.rs @@ -23,6 +23,12 @@ pub struct NavigationTarget { } impl NavigationTarget { + /// When `focus_range` is specified, returns it. otherwise + /// returns `full_range` + pub fn range(&self) -> TextRange { + self.focus_range.unwrap_or(self.full_range) + } + pub fn name(&self) -> &SmolStr { &self.name } @@ -43,14 +49,18 @@ impl NavigationTarget { self.full_range } - /// A "most interesting" range withing the `range_full`. + /// A "most interesting" range withing the `full_range`. /// - /// Typically, `range` is the whole syntax node, including doc comments, and - /// `focus_range` is the range of the identifier. + /// Typically, `full_range` is the whole syntax node, + /// including doc comments, and `focus_range` is the range of the identifier. pub fn focus_range(&self) -> Option { self.focus_range } + pub(crate) fn from_bind_pat(file_id: FileId, pat: &ast::BindPat) -> NavigationTarget { + NavigationTarget::from_named(file_id, pat) + } + pub(crate) fn from_symbol(symbol: FileSymbol) -> NavigationTarget { NavigationTarget { file_id: symbol.file_id, diff --git a/crates/ra_ide_api/src/references.rs b/crates/ra_ide_api/src/references.rs index e7ebf9f6e..a6a0ef8ac 100644 --- a/crates/ra_ide_api/src/references.rs +++ b/crates/ra_ide_api/src/references.rs @@ -1,42 +1,77 @@ use relative_path::{RelativePath, RelativePathBuf}; use hir::{ModuleSource, source_binder}; -use ra_db::{FileId, SourceDatabase}; +use ra_db::{SourceDatabase}; use ra_syntax::{ - AstNode, SyntaxNode, TextRange, SourceFile, - ast::{self, NameOwner}, + AstNode, SyntaxNode, SourceFile, + ast, algo::find_node_at_offset, }; use crate::{ db::RootDatabase, FilePosition, + FileRange, + FileId, + NavigationTarget, FileSystemEdit, SourceChange, SourceFileEdit, + TextRange, }; -pub(crate) fn find_all_refs(db: &RootDatabase, position: FilePosition) -> Vec<(FileId, TextRange)> { +#[derive(Debug, Clone)] +pub struct ReferenceSearchResult { + declaration: NavigationTarget, + references: Vec, +} + +impl ReferenceSearchResult { + pub fn declaration(&self) -> &NavigationTarget { + &self.declaration + } + + pub fn references(&self) -> &[FileRange] { + &self.references + } + + /// Total number of references + /// At least 1 since all valid references should + /// Have a declaration + pub fn len(&self) -> usize { + self.references.len() + 1 + } +} + +// allow turning ReferenceSearchResult into an iterator +// over FileRanges +impl IntoIterator for ReferenceSearchResult { + type Item = FileRange; + type IntoIter = ::std::vec::IntoIter; + + fn into_iter(mut self) -> Self::IntoIter { + let mut v = Vec::with_capacity(self.len()); + v.push(FileRange { file_id: self.declaration.file_id(), range: self.declaration.range() }); + v.append(&mut self.references); + v.into_iter() + } +} + +pub(crate) fn find_all_refs( + db: &RootDatabase, + position: FilePosition, +) -> Option { let file = db.parse(position.file_id); - // Find the binding associated with the offset - let (binding, descr) = match find_binding(db, &file, position) { - None => return Vec::new(), - Some(it) => it, - }; + let (binding, descr) = find_binding(db, &file, position)?; + let declaration = NavigationTarget::from_bind_pat(position.file_id, binding); - let mut ret = binding - .name() + let references = descr + .scopes(db) + .find_all_refs(binding) .into_iter() - .map(|name| (position.file_id, name.syntax().range())) + .map(move |ref_desc| FileRange { file_id: position.file_id, range: ref_desc.range }) .collect::>(); - ret.extend( - descr - .scopes(db) - .find_all_refs(binding) - .into_iter() - .map(|ref_desc| (position.file_id, ref_desc.range)), - ); - return ret; + return Some(ReferenceSearchResult { declaration, references }); fn find_binding<'a>( db: &RootDatabase, @@ -88,6 +123,21 @@ fn find_name_and_module_at_offset( None } +fn source_edit_from_fileid_range( + file_id: FileId, + range: TextRange, + new_name: &str, +) -> SourceFileEdit { + SourceFileEdit { + file_id, + edit: { + let mut builder = ra_text_edit::TextEditBuilder::default(); + builder.replace(range, new_name.into()); + builder.finish() + }, + } +} + fn rename_mod( db: &RootDatabase, ast_name: &ast::Name, @@ -150,17 +200,13 @@ fn rename_reference( position: FilePosition, new_name: &str, ) -> Option { - let edit = find_all_refs(db, position) - .iter() - .map(|(file_id, text_range)| SourceFileEdit { - file_id: *file_id, - edit: { - let mut builder = ra_text_edit::TextEditBuilder::default(); - builder.replace(*text_range, new_name.into()); - builder.finish() - }, - }) + let refs = find_all_refs(db, position)?; + + let edit = refs + .into_iter() + .map(|range| source_edit_from_fileid_range(range.file_id, range.range, new_name)) .collect::>(); + if edit.is_empty() { return None; } -- cgit v1.2.3 From fd5307e60d268423f7026db28b15bd2b31575396 Mon Sep 17 00:00:00 2001 From: Ville Penttinen Date: Sun, 17 Feb 2019 17:25:19 +0200 Subject: Remove leading :: --- crates/ra_ide_api/src/references.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'crates/ra_ide_api/src') diff --git a/crates/ra_ide_api/src/references.rs b/crates/ra_ide_api/src/references.rs index a6a0ef8ac..b7784e577 100644 --- a/crates/ra_ide_api/src/references.rs +++ b/crates/ra_ide_api/src/references.rs @@ -46,7 +46,7 @@ impl ReferenceSearchResult { // over FileRanges impl IntoIterator for ReferenceSearchResult { type Item = FileRange; - type IntoIter = ::std::vec::IntoIter; + type IntoIter = std::vec::IntoIter; fn into_iter(mut self) -> Self::IntoIter { let mut v = Vec::with_capacity(self.len()); -- cgit v1.2.3