diff options
Diffstat (limited to 'crates/ra_ide_api/src/references.rs')
-rw-r--r-- | crates/ra_ide_api/src/references.rs | 106 |
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 @@ | |||
1 | use relative_path::{RelativePath, RelativePathBuf}; | 1 | use relative_path::{RelativePath, RelativePathBuf}; |
2 | use hir::{ModuleSource, source_binder}; | 2 | use hir::{ModuleSource, source_binder}; |
3 | use ra_db::{FileId, SourceDatabase}; | 3 | use ra_db::{SourceDatabase}; |
4 | use ra_syntax::{ | 4 | use 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 | ||
10 | use crate::{ | 10 | use 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 | ||
18 | pub(crate) fn find_all_refs(db: &RootDatabase, position: FilePosition) -> Vec<(FileId, TextRange)> { | 22 | #[derive(Debug, Clone)] |
23 | pub struct ReferenceSearchResult { | ||
24 | declaration: NavigationTarget, | ||
25 | references: Vec<FileRange>, | ||
26 | } | ||
27 | |||
28 | impl 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 | ||
47 | impl 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 | |||
59 | pub(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 | ||
126 | fn 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 | |||
91 | fn rename_mod( | 141 | fn 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 | } |