aboutsummaryrefslogtreecommitdiff
path: root/crates/ide
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ide')
-rw-r--r--crates/ide/src/call_hierarchy.rs31
-rw-r--r--crates/ide/src/lib.rs2
-rw-r--r--crates/ide/src/references.rs98
-rw-r--r--crates/ide/src/references/rename.rs94
4 files changed, 116 insertions, 109 deletions
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 @@
3use indexmap::IndexMap; 3use indexmap::IndexMap;
4 4
5use hir::Semantics; 5use hir::Semantics;
6use ide_db::call_info::FnCallNode;
7use ide_db::RootDatabase; 6use 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,22 +47,23 @@ 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 reference in refs.info.references() { 50 for &FileReferences { file_id, ref references } in refs.info.references() {
51 let file_id = reference.file_range.file_id;
52 let file = sema.parse(file_id); 51 let file = sema.parse(file_id);
53 let file = file.syntax(); 52 let file = file.syntax();
54 let token = file.token_at_offset(reference.file_range.range.start()).next()?; 53 for reference in references {
55 let token = sema.descend_into_macros(token); 54 let token = file.token_at_offset(reference.range.start()).next()?;
56 let syntax = token.parent(); 55 let token = sema.descend_into_macros(token);
57 56 let syntax = token.parent();
58 // This target is the containing function 57
59 if let Some(nav) = syntax.ancestors().find_map(|node| { 58 // This target is the containing function
60 let fn_ = ast::Fn::cast(node)?; 59 if let Some(nav) = syntax.ancestors().find_map(|node| {
61 let def = sema.to_def(&fn_)?; 60 let fn_ = ast::Fn::cast(node)?;
62 def.try_to_nav(sema.db) 61 let def = sema.to_def(&fn_)?;
63 }) { 62 def.try_to_nav(sema.db)
64 let relative_range = reference.file_range.range; 63 }) {
65 calls.add(&nav, relative_range); 64 let relative_range = reference.range;
65 calls.add(&nav, relative_range);
66 }
66 } 67 }
67 } 68 }
68 69
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::{
92}; 92};
93pub use ide_db::{ 93pub use ide_db::{
94 call_info::CallInfo, 94 call_info::CallInfo,
95 search::{Reference, ReferenceAccess, ReferenceKind}, 95 search::{FileReference, ReferenceAccess, ReferenceKind},
96}; 96};
97pub use ide_db::{ 97pub use ide_db::{
98 label::Label, 98 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;
14use hir::Semantics; 14use hir::Semantics;
15use ide_db::{ 15use ide_db::{
16 defs::{Definition, NameClass, NameRefClass}, 16 defs::{Definition, NameClass, NameRefClass},
17 search::Reference, 17 search::{FileReference, FileReferences, ReferenceAccess, ReferenceKind, SearchScope},
18 search::{ReferenceAccess, ReferenceKind, SearchScope},
19 RootDatabase, 18 RootDatabase,
20}; 19};
21use syntax::{ 20use syntax::{
@@ -29,7 +28,7 @@ use crate::{display::TryToNav, FilePosition, FileRange, NavigationTarget, RangeI
29#[derive(Debug, Clone)] 28#[derive(Debug, Clone)]
30pub struct ReferenceSearchResult { 29pub struct ReferenceSearchResult {
31 declaration: Declaration, 30 declaration: Declaration,
32 references: Vec<Reference>, 31 references: Vec<FileReferences>,
33} 32}
34 33
35#[derive(Debug, Clone)] 34#[derive(Debug, Clone)]
@@ -48,7 +47,7 @@ impl ReferenceSearchResult {
48 &self.declaration.nav 47 &self.declaration.nav
49 } 48 }
50 49
51 pub fn references(&self) -> &[Reference] { 50 pub fn references(&self) -> &[FileReferences] {
52 &self.references 51 &self.references
53 } 52 }
54 53
@@ -63,20 +62,22 @@ impl ReferenceSearchResult {
63// allow turning ReferenceSearchResult into an iterator 62// allow turning ReferenceSearchResult into an iterator
64// over References 63// over References
65impl IntoIterator for ReferenceSearchResult { 64impl IntoIterator for ReferenceSearchResult {
66 type Item = Reference; 65 type Item = FileReferences;
67 type IntoIter = std::vec::IntoIter<Reference>; 66 type IntoIter = std::vec::IntoIter<FileReferences>;
68 67
69 fn into_iter(mut self) -> Self::IntoIter { 68 fn into_iter(mut self) -> Self::IntoIter {
70 let mut v = Vec::with_capacity(self.len()); 69 let mut v = Vec::with_capacity(self.len());
71 v.push(Reference { 70 v.append(&mut self.references);
72 file_range: FileRange { 71 let decl_ref = FileReference {
73 file_id: self.declaration.nav.file_id, 72 range: self.declaration.nav.focus_or_full_range(),
74 range: self.declaration.nav.focus_or_full_range(),
75 },
76 kind: self.declaration.kind, 73 kind: self.declaration.kind,
77 access: self.declaration.access, 74 access: self.declaration.access,
78 }); 75 };
79 v.append(&mut self.references); 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 }
80 v.into_iter() 81 v.into_iter()
81 } 82 }
82} 83}
@@ -109,13 +110,11 @@ pub(crate) fn find_all_refs(
109 110
110 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)?;
111 112
112 let references = def 113 let mut references = def.usages(sema).set_scope(search_scope).all();
113 .usages(sema) 114 references.iter_mut().for_each(|it| {
114 .set_scope(search_scope) 115 it.references.retain(|r| search_kind == ReferenceKind::Other || search_kind == r.kind)
115 .all() 116 });
116 .into_iter() 117 references.retain(|r| !r.references.is_empty());
117 .filter(|r| search_kind == ReferenceKind::Other || search_kind == r.kind)
118 .collect();
119 118
120 let nav = def.try_to_nav(sema.db)?; 119 let nav = def.try_to_nav(sema.db)?;
121 let decl_range = nav.focus_or_full_range(); 120 let decl_range = nav.focus_or_full_range();
@@ -255,7 +254,8 @@ fn try_find_self_references(
255 syntax: &SyntaxNode, 254 syntax: &SyntaxNode,
256 position: FilePosition, 255 position: FilePosition,
257) -> Option<RangeInfo<ReferenceSearchResult>> { 256) -> Option<RangeInfo<ReferenceSearchResult>> {
258 let self_token = syntax.token_at_offset(position.offset).find(|t| t.kind() == T![self])?; 257 let FilePosition { file_id, offset } = position;
258 let self_token = syntax.token_at_offset(offset).find(|t| t.kind() == T![self])?;
259 let parent = self_token.parent(); 259 let parent = self_token.parent();
260 match_ast! { 260 match_ast! {
261 match parent { 261 match parent {
@@ -276,7 +276,7 @@ fn try_find_self_references(
276 276
277 let declaration = Declaration { 277 let declaration = Declaration {
278 nav: NavigationTarget { 278 nav: NavigationTarget {
279 file_id: position.file_id, 279 file_id,
280 full_range: self_param.syntax().text_range(), 280 full_range: self_param.syntax().text_range(),
281 focus_range: Some(param_self_token.text_range()), 281 focus_range: Some(param_self_token.text_range()),
282 name: param_self_token.text().clone(), 282 name: param_self_token.text().clone(),
@@ -295,25 +295,29 @@ fn try_find_self_references(
295 let references = function 295 let references = function
296 .body() 296 .body()
297 .map(|body| { 297 .map(|body| {
298 body.syntax() 298 FileReferences {
299 .descendants() 299 file_id,
300 .filter_map(ast::PathExpr::cast) 300 references: body
301 .filter_map(|expr| { 301 .syntax()
302 let path = expr.path()?; 302 .descendants()
303 if path.qualifier().is_none() { 303 .filter_map(ast::PathExpr::cast)
304 path.segment()?.self_token() 304 .filter_map(|expr| {
305 } else { 305 let path = expr.path()?;
306 None 306 if path.qualifier().is_none() {
307 } 307 path.segment()?.self_token()
308 }) 308 } else {
309 .map(|token| Reference { 309 None
310 file_range: FileRange { file_id: position.file_id, range: token.text_range() }, 310 }
311 kind: ReferenceKind::SelfKw, 311 })
312 access: declaration.access, // FIXME: properly check access kind here instead of copying it from the declaration 312 .map(|token| FileReference {
313 }) 313 range: token.text_range(),
314 .collect() 314 kind: ReferenceKind::SelfKw,
315 access: declaration.access, // FIXME: properly check access kind here instead of copying it from the declaration
316 })
317 .collect(),
318 }
315 }) 319 })
316 .unwrap_or_default(); 320 .map_or_else(Vec::default, |it| vec![it]);
317 321
318 Some(RangeInfo::new( 322 Some(RangeInfo::new(
319 param_self_token.text_range(), 323 param_self_token.text_range(),
@@ -324,7 +328,7 @@ fn try_find_self_references(
324#[cfg(test)] 328#[cfg(test)]
325mod tests { 329mod tests {
326 use expect_test::{expect, Expect}; 330 use expect_test::{expect, Expect};
327 use ide_db::base_db::FileId; 331 use ide_db::{base_db::FileId, search::FileReferences};
328 use stdx::format_to; 332 use stdx::format_to;
329 333
330 use crate::{fixture, SearchScope}; 334 use crate::{fixture, SearchScope};
@@ -1018,12 +1022,14 @@ impl Foo {
1018 actual += "\n\n"; 1022 actual += "\n\n";
1019 } 1023 }
1020 1024
1021 for r in &refs.references { 1025 for FileReferences { file_id, references } in refs.references {
1022 format_to!(actual, "{:?} {:?} {:?}", r.file_range.file_id, r.file_range.range, r.kind); 1026 for r in references {
1023 if let Some(access) = r.access { 1027 format_to!(actual, "{:?} {:?} {:?}", file_id, r.range, r.kind);
1024 format_to!(actual, " {:?}", access); 1028 if let Some(access) = r.access {
1029 format_to!(actual, " {:?}", access);
1030 }
1031 actual += "\n";
1025 } 1032 }
1026 actual += "\n";
1027 } 1033 }
1028 expect.assert_eq(&actual) 1034 expect.assert_eq(&actual)
1029 } 1035 }
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::{
6}; 6};
7 7
8use hir::{Module, ModuleDef, ModuleSource, Semantics}; 8use hir::{Module, ModuleDef, ModuleSource, Semantics};
9use ide_db::base_db::{AnchoredPathBuf, FileId, FileRange, SourceDatabaseExt};
10use ide_db::{ 9use ide_db::{
10 base_db::{AnchoredPathBuf, FileId, FileRange, SourceDatabaseExt},
11 defs::{Definition, NameClass, NameRefClass}, 11 defs::{Definition, NameClass, NameRefClass},
12 search::FileReferences,
12 RootDatabase, 13 RootDatabase,
13}; 14};
14use syntax::{ 15use syntax::{
@@ -20,8 +21,8 @@ use test_utils::mark;
20use text_edit::TextEdit; 21use text_edit::TextEdit;
21 22
22use crate::{ 23use crate::{
23 FilePosition, FileSystemEdit, RangeInfo, Reference, ReferenceKind, ReferenceSearchResult, 24 FilePosition, FileSystemEdit, RangeInfo, ReferenceKind, ReferenceSearchResult, SourceChange,
24 SourceChange, SourceFileEdit, TextRange, TextSize, 25 SourceFileEdit, TextRange, TextSize,
25}; 26};
26 27
27type RenameResult<T> = Result<T, RenameError>; 28type RenameResult<T> = Result<T, RenameError>;
@@ -173,39 +174,45 @@ fn find_all_refs(
173 .ok_or_else(|| format_err!("No references found at position")) 174 .ok_or_else(|| format_err!("No references found at position"))
174} 175}
175 176
176fn source_edit_from_reference( 177fn source_edit_from_references(
177 sema: &Semantics<RootDatabase>, 178 sema: &Semantics<RootDatabase>,
178 reference: Reference, 179 &FileReferences { file_id, ref references }: &FileReferences,
179 new_name: &str, 180 new_name: &str,
180) -> SourceFileEdit { 181) -> SourceFileEdit {
181 let mut replacement_text = String::new(); 182 let mut edit = TextEdit::builder();
182 let range = match reference.kind { 183 for reference in references {
183 ReferenceKind::FieldShorthandForField => { 184 let mut replacement_text = String::new();
184 mark::hit!(test_rename_struct_field_for_shorthand); 185 let range = match reference.kind {
185 replacement_text.push_str(new_name); 186 ReferenceKind::FieldShorthandForField => {
186 replacement_text.push_str(": "); 187 mark::hit!(test_rename_struct_field_for_shorthand);
187 TextRange::new(reference.file_range.range.start(), reference.file_range.range.start()) 188 replacement_text.push_str(new_name);
188 } 189 replacement_text.push_str(": ");
189 ReferenceKind::FieldShorthandForLocal => { 190 TextRange::new(reference.range.start(), reference.range.start())
190 mark::hit!(test_rename_local_for_field_shorthand); 191 }
191 replacement_text.push_str(": "); 192 ReferenceKind::FieldShorthandForLocal => {
192 replacement_text.push_str(new_name); 193 mark::hit!(test_rename_local_for_field_shorthand);
193 TextRange::new(reference.file_range.range.end(), reference.file_range.range.end()) 194 replacement_text.push_str(": ");
194 } 195 replacement_text.push_str(new_name);
195 ReferenceKind::RecordFieldExprOrPat => { 196 TextRange::new(reference.range.end(), reference.range.end())
196 mark::hit!(test_rename_field_expr_pat); 197 }
197 replacement_text.push_str(new_name); 198 ReferenceKind::RecordFieldExprOrPat => {
198 edit_text_range_for_record_field_expr_or_pat(sema, reference.file_range, new_name) 199 mark::hit!(test_rename_field_expr_pat);
199 } 200 replacement_text.push_str(new_name);
200 _ => { 201 edit_text_range_for_record_field_expr_or_pat(
201 replacement_text.push_str(new_name); 202 sema,
202 reference.file_range.range 203 FileRange { file_id, range: reference.range },
203 } 204 new_name,
204 }; 205 )
205 SourceFileEdit { 206 }
206 file_id: reference.file_range.file_id, 207 _ => {
207 edit: TextEdit::replace(range, replacement_text), 208 replacement_text.push_str(new_name);
209 reference.range
210 }
211 };
212 edit.replace(range, replacement_text);
208 } 213 }
214
215 SourceFileEdit { file_id, edit: edit.finish() }
209} 216}
210 217
211fn edit_text_range_for_record_field_expr_or_pat( 218fn edit_text_range_for_record_field_expr_or_pat(
@@ -277,9 +284,9 @@ fn rename_mod(
277 284
278 let RangeInfo { range, info: refs } = find_all_refs(sema, position)?; 285 let RangeInfo { range, info: refs } = find_all_refs(sema, position)?;
279 let ref_edits = refs 286 let ref_edits = refs
280 .references 287 .references()
281 .into_iter() 288 .iter()
282 .map(|reference| source_edit_from_reference(sema, reference, new_name)); 289 .map(|reference| source_edit_from_references(sema, reference, new_name));
283 source_file_edits.extend(ref_edits); 290 source_file_edits.extend(ref_edits);
284 291
285 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)))
@@ -331,17 +338,10 @@ fn rename_to_self(
331 338
332 let RangeInfo { range, info: refs } = find_all_refs(sema, position)?; 339 let RangeInfo { range, info: refs } = find_all_refs(sema, position)?;
333 340
334 let (param_ref, usages): (Vec<Reference>, Vec<Reference>) = refs 341 let mut edits = refs
335 .into_iter() 342 .references()
336 .partition(|reference| param_range.intersect(reference.file_range.range).is_some()); 343 .iter()
337 344 .map(|reference| source_edit_from_references(sema, reference, "self"))
338 if param_ref.is_empty() {
339 bail!("Parameter to rename not found");
340 }
341
342 let mut edits = usages
343 .into_iter()
344 .map(|reference| source_edit_from_reference(sema, reference, "self"))
345 .collect::<Vec<_>>(); 345 .collect::<Vec<_>>();
346 346
347 edits.push(SourceFileEdit { 347 edits.push(SourceFileEdit {
@@ -467,7 +467,7 @@ fn rename_reference(
467 467
468 let edit = refs 468 let edit = refs
469 .into_iter() 469 .into_iter()
470 .map(|reference| source_edit_from_reference(sema, reference, new_name)) 470 .map(|reference| source_edit_from_references(sema, &reference, new_name))
471 .collect::<Vec<_>>(); 471 .collect::<Vec<_>>();
472 472
473 Ok(RangeInfo::new(range, SourceChange::from(edit))) 473 Ok(RangeInfo::new(range, SourceChange::from(edit)))