aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_ide_api/src/references.rs
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_ide_api/src/references.rs')
-rw-r--r--crates/ra_ide_api/src/references.rs106
1 files changed, 76 insertions, 30 deletions
diff --git a/crates/ra_ide_api/src/references.rs b/crates/ra_ide_api/src/references.rs
index e7ebf9f6e..b7784e577 100644
--- a/crates/ra_ide_api/src/references.rs
+++ b/crates/ra_ide_api/src/references.rs
@@ -1,42 +1,77 @@
1use relative_path::{RelativePath, RelativePathBuf}; 1use relative_path::{RelativePath, RelativePathBuf};
2use hir::{ModuleSource, source_binder}; 2use hir::{ModuleSource, source_binder};
3use ra_db::{FileId, SourceDatabase}; 3use ra_db::{SourceDatabase};
4use ra_syntax::{ 4use ra_syntax::{
5 AstNode, SyntaxNode, TextRange, SourceFile, 5 AstNode, SyntaxNode, SourceFile,
6 ast::{self, NameOwner}, 6 ast,
7 algo::find_node_at_offset, 7 algo::find_node_at_offset,
8}; 8};
9 9
10use crate::{ 10use crate::{
11 db::RootDatabase, 11 db::RootDatabase,
12 FilePosition, 12 FilePosition,
13 FileRange,
14 FileId,
15 NavigationTarget,
13 FileSystemEdit, 16 FileSystemEdit,
14 SourceChange, 17 SourceChange,
15 SourceFileEdit, 18 SourceFileEdit,
19 TextRange,
16}; 20};
17 21
18pub(crate) fn find_all_refs(db: &RootDatabase, position: FilePosition) -> Vec<(FileId, TextRange)> { 22#[derive(Debug, Clone)]
23pub struct ReferenceSearchResult {
24 declaration: NavigationTarget,
25 references: Vec<FileRange>,
26}
27
28impl ReferenceSearchResult {
29 pub fn declaration(&self) -> &NavigationTarget {
30 &self.declaration
31 }
32
33 pub fn references(&self) -> &[FileRange] {
34 &self.references
35 }
36
37 /// Total number of references
38 /// At least 1 since all valid references should
39 /// Have a declaration
40 pub fn len(&self) -> usize {
41 self.references.len() + 1
42 }
43}
44
45// allow turning ReferenceSearchResult into an iterator
46// over FileRanges
47impl IntoIterator for ReferenceSearchResult {
48 type Item = FileRange;
49 type IntoIter = std::vec::IntoIter<FileRange>;
50
51 fn into_iter(mut self) -> Self::IntoIter {
52 let mut v = Vec::with_capacity(self.len());
53 v.push(FileRange { file_id: self.declaration.file_id(), range: self.declaration.range() });
54 v.append(&mut self.references);
55 v.into_iter()
56 }
57}
58
59pub(crate) fn find_all_refs(
60 db: &RootDatabase,
61 position: FilePosition,
62) -> Option<ReferenceSearchResult> {
19 let file = db.parse(position.file_id); 63 let file = db.parse(position.file_id);
20 // Find the binding associated with the offset 64 let (binding, descr) = find_binding(db, &file, position)?;
21 let (binding, descr) = match find_binding(db, &file, position) { 65 let declaration = NavigationTarget::from_bind_pat(position.file_id, binding);
22 None => return Vec::new(),
23 Some(it) => it,
24 };
25 66
26 let mut ret = binding 67 let references = descr
27 .name() 68 .scopes(db)
69 .find_all_refs(binding)
28 .into_iter() 70 .into_iter()
29 .map(|name| (position.file_id, name.syntax().range())) 71 .map(move |ref_desc| FileRange { file_id: position.file_id, range: ref_desc.range })
30 .collect::<Vec<_>>(); 72 .collect::<Vec<_>>();
31 ret.extend(
32 descr
33 .scopes(db)
34 .find_all_refs(binding)
35 .into_iter()
36 .map(|ref_desc| (position.file_id, ref_desc.range)),
37 );
38 73
39 return ret; 74 return Some(ReferenceSearchResult { declaration, references });
40 75
41 fn find_binding<'a>( 76 fn find_binding<'a>(
42 db: &RootDatabase, 77 db: &RootDatabase,
@@ -88,6 +123,21 @@ fn find_name_and_module_at_offset(
88 None 123 None
89} 124}
90 125
126fn source_edit_from_fileid_range(
127 file_id: FileId,
128 range: TextRange,
129 new_name: &str,
130) -> SourceFileEdit {
131 SourceFileEdit {
132 file_id,
133 edit: {
134 let mut builder = ra_text_edit::TextEditBuilder::default();
135 builder.replace(range, new_name.into());
136 builder.finish()
137 },
138 }
139}
140
91fn rename_mod( 141fn rename_mod(
92 db: &RootDatabase, 142 db: &RootDatabase,
93 ast_name: &ast::Name, 143 ast_name: &ast::Name,
@@ -150,17 +200,13 @@ fn rename_reference(
150 position: FilePosition, 200 position: FilePosition,
151 new_name: &str, 201 new_name: &str,
152) -> Option<SourceChange> { 202) -> Option<SourceChange> {
153 let edit = find_all_refs(db, position) 203 let refs = find_all_refs(db, position)?;
154 .iter() 204
155 .map(|(file_id, text_range)| SourceFileEdit { 205 let edit = refs
156 file_id: *file_id, 206 .into_iter()
157 edit: { 207 .map(|range| source_edit_from_fileid_range(range.file_id, range.range, new_name))
158 let mut builder = ra_text_edit::TextEditBuilder::default();
159 builder.replace(*text_range, new_name.into());
160 builder.finish()
161 },
162 })
163 .collect::<Vec<_>>(); 208 .collect::<Vec<_>>();
209
164 if edit.is_empty() { 210 if edit.is_empty() {
165 return None; 211 return None;
166 } 212 }