aboutsummaryrefslogtreecommitdiff
path: root/crates/ide/src
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ide/src')
-rw-r--r--crates/ide/src/call_hierarchy.rs29
-rw-r--r--crates/ide/src/inlay_hints.rs37
-rw-r--r--crates/ide/src/lib.rs2
-rw-r--r--crates/ide/src/references.rs79
-rw-r--r--crates/ide/src/references/rename.rs103
-rw-r--r--crates/ide/src/syntax_highlighting/highlights.rs14
-rw-r--r--crates/ide/src/syntax_highlighting/injector.rs4
7 files changed, 150 insertions, 118 deletions
diff --git a/crates/ide/src/call_hierarchy.rs b/crates/ide/src/call_hierarchy.rs
index b29d1fef9..e8999a7f3 100644
--- a/crates/ide/src/call_hierarchy.rs
+++ b/crates/ide/src/call_hierarchy.rs
@@ -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 (&file_id, references) in refs.info.references().iter() {
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/inlay_hints.rs b/crates/ide/src/inlay_hints.rs
index 3e9a65d9c..a2039fcc7 100644
--- a/crates/ide/src/inlay_hints.rs
+++ b/crates/ide/src/inlay_hints.rs
@@ -1401,4 +1401,41 @@ fn main() {
1401"#, 1401"#,
1402 ) 1402 )
1403 } 1403 }
1404
1405 #[test]
1406 fn fn_hints() {
1407 check(
1408 r#"
1409trait Sized {}
1410
1411fn foo() -> impl Fn() { loop {} }
1412fn foo1() -> impl Fn(f64) { loop {} }
1413fn foo2() -> impl Fn(f64, f64) { loop {} }
1414fn foo3() -> impl Fn(f64, f64) -> u32 { loop {} }
1415fn foo4() -> &'static dyn Fn(f64, f64) -> u32 { loop {} }
1416fn foo5() -> &'static dyn Fn(&'static dyn Fn(f64, f64) -> u32, f64) -> u32 { loop {} }
1417fn foo6() -> impl Fn(f64, f64) -> u32 + Sized { loop {} }
1418fn foo7() -> *const (impl Fn(f64, f64) -> u32 + Sized) { loop {} }
1419
1420fn main() {
1421 let foo = foo();
1422 // ^^^ impl Fn()
1423 let foo = foo1();
1424 // ^^^ impl Fn(f64)
1425 let foo = foo2();
1426 // ^^^ impl Fn(f64, f64)
1427 let foo = foo3();
1428 // ^^^ impl Fn(f64, f64) -> u32
1429 let foo = foo4();
1430 // ^^^ &dyn Fn(f64, f64) -> u32
1431 let foo = foo5();
1432 // ^^^ &dyn Fn(&dyn Fn(f64, f64) -> u32, f64) -> u32
1433 let foo = foo6();
1434 // ^^^ impl Fn(f64, f64) -> u32 + Sized
1435 let foo = foo7();
1436 // ^^^ *const (impl Fn(f64, f64) -> u32 + Sized)
1437}
1438"#,
1439 )
1440 }
1404} 1441}
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..7d4757e02 100644
--- a/crates/ide/src/references.rs
+++ b/crates/ide/src/references.rs
@@ -13,9 +13,9 @@ pub(crate) mod rename;
13 13
14use hir::Semantics; 14use hir::Semantics;
15use ide_db::{ 15use ide_db::{
16 base_db::FileId,
16 defs::{Definition, NameClass, NameRefClass}, 17 defs::{Definition, NameClass, NameRefClass},
17 search::Reference, 18 search::{FileReference, ReferenceAccess, ReferenceKind, SearchScope, UsageSearchResult},
18 search::{ReferenceAccess, ReferenceKind, SearchScope},
19 RootDatabase, 19 RootDatabase,
20}; 20};
21use syntax::{ 21use syntax::{
@@ -29,7 +29,7 @@ use crate::{display::TryToNav, FilePosition, FileRange, NavigationTarget, RangeI
29#[derive(Debug, Clone)] 29#[derive(Debug, Clone)]
30pub struct ReferenceSearchResult { 30pub struct ReferenceSearchResult {
31 declaration: Declaration, 31 declaration: Declaration,
32 references: Vec<Reference>, 32 references: UsageSearchResult,
33} 33}
34 34
35#[derive(Debug, Clone)] 35#[derive(Debug, Clone)]
@@ -48,10 +48,21 @@ impl ReferenceSearchResult {
48 &self.declaration.nav 48 &self.declaration.nav
49 } 49 }
50 50
51 pub fn references(&self) -> &[Reference] { 51 pub fn references(&self) -> &UsageSearchResult {
52 &self.references 52 &self.references
53 } 53 }
54 54
55 pub fn references_with_declaration(mut self) -> UsageSearchResult {
56 let decl_ref = FileReference {
57 range: self.declaration.nav.focus_or_full_range(),
58 kind: self.declaration.kind,
59 access: self.declaration.access,
60 };
61 let file_id = self.declaration.nav.file_id;
62 self.references.references.entry(file_id).or_default().push(decl_ref);
63 self.references
64 }
65
55 /// Total number of references 66 /// Total number of references
56 /// At least 1 since all valid references should 67 /// At least 1 since all valid references should
57 /// Have a declaration 68 /// Have a declaration
@@ -63,21 +74,11 @@ impl ReferenceSearchResult {
63// allow turning ReferenceSearchResult into an iterator 74// allow turning ReferenceSearchResult into an iterator
64// over References 75// over References
65impl IntoIterator for ReferenceSearchResult { 76impl IntoIterator for ReferenceSearchResult {
66 type Item = Reference; 77 type Item = (FileId, Vec<FileReference>);
67 type IntoIter = std::vec::IntoIter<Reference>; 78 type IntoIter = std::collections::hash_map::IntoIter<FileId, Vec<FileReference>>;
68 79
69 fn into_iter(mut self) -> Self::IntoIter { 80 fn into_iter(self) -> Self::IntoIter {
70 let mut v = Vec::with_capacity(self.len()); 81 self.references_with_declaration().into_iter()
71 v.push(Reference {
72 file_range: FileRange {
73 file_id: self.declaration.nav.file_id,
74 range: self.declaration.nav.focus_or_full_range(),
75 },
76 kind: self.declaration.kind,
77 access: self.declaration.access,
78 });
79 v.append(&mut self.references);
80 v.into_iter()
81 } 82 }
82} 83}
83 84
@@ -109,13 +110,12 @@ 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 usages = def.usages(sema).set_scope(search_scope).all();
113 .usages(sema) 114 usages
114 .set_scope(search_scope) 115 .references
115 .all() 116 .values_mut()
116 .into_iter() 117 .for_each(|it| it.retain(|r| search_kind == ReferenceKind::Other || search_kind == r.kind));
117 .filter(|r| search_kind == ReferenceKind::Other || search_kind == r.kind) 118 usages.references.retain(|_, it| !it.is_empty());
118 .collect();
119 119
120 let nav = def.try_to_nav(sema.db)?; 120 let nav = def.try_to_nav(sema.db)?;
121 let decl_range = nav.focus_or_full_range(); 121 let decl_range = nav.focus_or_full_range();
@@ -139,7 +139,7 @@ pub(crate) fn find_all_refs(
139 139
140 let declaration = Declaration { nav, kind, access: decl_access(&def, &syntax, decl_range) }; 140 let declaration = Declaration { nav, kind, access: decl_access(&def, &syntax, decl_range) };
141 141
142 Some(RangeInfo::new(range, ReferenceSearchResult { declaration, references })) 142 Some(RangeInfo::new(range, ReferenceSearchResult { declaration, references: usages }))
143} 143}
144 144
145fn find_name( 145fn find_name(
@@ -255,7 +255,8 @@ fn try_find_self_references(
255 syntax: &SyntaxNode, 255 syntax: &SyntaxNode,
256 position: FilePosition, 256 position: FilePosition,
257) -> Option<RangeInfo<ReferenceSearchResult>> { 257) -> Option<RangeInfo<ReferenceSearchResult>> {
258 let self_token = syntax.token_at_offset(position.offset).find(|t| t.kind() == T![self])?; 258 let FilePosition { file_id, offset } = position;
259 let self_token = syntax.token_at_offset(offset).find(|t| t.kind() == T![self])?;
259 let parent = self_token.parent(); 260 let parent = self_token.parent();
260 match_ast! { 261 match_ast! {
261 match parent { 262 match parent {
@@ -276,7 +277,7 @@ fn try_find_self_references(
276 277
277 let declaration = Declaration { 278 let declaration = Declaration {
278 nav: NavigationTarget { 279 nav: NavigationTarget {
279 file_id: position.file_id, 280 file_id,
280 full_range: self_param.syntax().text_range(), 281 full_range: self_param.syntax().text_range(),
281 focus_range: Some(param_self_token.text_range()), 282 focus_range: Some(param_self_token.text_range()),
282 name: param_self_token.text().clone(), 283 name: param_self_token.text().clone(),
@@ -292,7 +293,7 @@ fn try_find_self_references(
292 ReferenceAccess::Read 293 ReferenceAccess::Read
293 }), 294 }),
294 }; 295 };
295 let references = function 296 let refs = function
296 .body() 297 .body()
297 .map(|body| { 298 .map(|body| {
298 body.syntax() 299 body.syntax()
@@ -306,14 +307,16 @@ fn try_find_self_references(
306 None 307 None
307 } 308 }
308 }) 309 })
309 .map(|token| Reference { 310 .map(|token| FileReference {
310 file_range: FileRange { file_id: position.file_id, range: token.text_range() }, 311 range: token.text_range(),
311 kind: ReferenceKind::SelfKw, 312 kind: ReferenceKind::SelfKw,
312 access: declaration.access, // FIXME: properly check access kind here instead of copying it from the declaration 313 access: declaration.access, // FIXME: properly check access kind here instead of copying it from the declaration
313 }) 314 })
314 .collect() 315 .collect()
315 }) 316 })
316 .unwrap_or_default(); 317 .unwrap_or_default();
318 let mut references = UsageSearchResult::default();
319 references.references.insert(file_id, refs);
317 320
318 Some(RangeInfo::new( 321 Some(RangeInfo::new(
319 param_self_token.text_range(), 322 param_self_token.text_range(),
@@ -1018,12 +1021,14 @@ impl Foo {
1018 actual += "\n\n"; 1021 actual += "\n\n";
1019 } 1022 }
1020 1023
1021 for r in &refs.references { 1024 for (file_id, references) in refs.references {
1022 format_to!(actual, "{:?} {:?} {:?}", r.file_range.file_id, r.file_range.range, r.kind); 1025 for r in references {
1023 if let Some(access) = r.access { 1026 format_to!(actual, "{:?} {:?} {:?}", file_id, r.range, r.kind);
1024 format_to!(actual, " {:?}", access); 1027 if let Some(access) = r.access {
1028 format_to!(actual, " {:?}", access);
1029 }
1030 actual += "\n";
1025 } 1031 }
1026 actual += "\n";
1027 } 1032 }
1028 expect.assert_eq(&actual) 1033 expect.assert_eq(&actual)
1029 } 1034 }
diff --git a/crates/ide/src/references/rename.rs b/crates/ide/src/references/rename.rs
index 3edc43e08..c3ae568c2 100644
--- a/crates/ide/src/references/rename.rs
+++ b/crates/ide/src/references/rename.rs
@@ -1,14 +1,14 @@
1//! FIXME: write short doc here 1//! FIXME: write short doc here
2use std::{ 2use std::{
3 convert::TryInto, 3 convert::TryInto,
4 error::Error,
5 fmt::{self, Display}, 4 fmt::{self, Display},
6}; 5};
7 6
8use hir::{Module, ModuleDef, ModuleSource, Semantics}; 7use hir::{Module, ModuleDef, ModuleSource, Semantics};
9use ide_db::base_db::{AnchoredPathBuf, FileId, FileRange, SourceDatabaseExt};
10use ide_db::{ 8use ide_db::{
9 base_db::{AnchoredPathBuf, FileId, FileRange, SourceDatabaseExt},
11 defs::{Definition, NameClass, NameRefClass}, 10 defs::{Definition, NameClass, NameRefClass},
11 search::FileReference,
12 RootDatabase, 12 RootDatabase,
13}; 13};
14use syntax::{ 14use syntax::{
@@ -20,8 +20,8 @@ use test_utils::mark;
20use text_edit::TextEdit; 20use text_edit::TextEdit;
21 21
22use crate::{ 22use crate::{
23 FilePosition, FileSystemEdit, RangeInfo, Reference, ReferenceKind, ReferenceSearchResult, 23 FilePosition, FileSystemEdit, RangeInfo, ReferenceKind, ReferenceSearchResult, SourceChange,
24 SourceChange, SourceFileEdit, TextRange, TextSize, 24 SourceFileEdit, TextRange, TextSize,
25}; 25};
26 26
27type RenameResult<T> = Result<T, RenameError>; 27type RenameResult<T> = Result<T, RenameError>;
@@ -34,8 +34,6 @@ impl fmt::Display for RenameError {
34 } 34 }
35} 35}
36 36
37impl Error for RenameError {}
38
39macro_rules! format_err { 37macro_rules! format_err {
40 ($fmt:expr) => {RenameError(format!($fmt))}; 38 ($fmt:expr) => {RenameError(format!($fmt))};
41 ($fmt:expr, $($arg:tt)+) => {RenameError(format!($fmt, $($arg)+))} 39 ($fmt:expr, $($arg:tt)+) => {RenameError(format!($fmt, $($arg)+))}
@@ -173,39 +171,46 @@ fn find_all_refs(
173 .ok_or_else(|| format_err!("No references found at position")) 171 .ok_or_else(|| format_err!("No references found at position"))
174} 172}
175 173
176fn source_edit_from_reference( 174fn source_edit_from_references(
177 sema: &Semantics<RootDatabase>, 175 sema: &Semantics<RootDatabase>,
178 reference: Reference, 176 file_id: FileId,
177 references: &[FileReference],
179 new_name: &str, 178 new_name: &str,
180) -> SourceFileEdit { 179) -> SourceFileEdit {
181 let mut replacement_text = String::new(); 180 let mut edit = TextEdit::builder();
182 let range = match reference.kind { 181 for reference in references {
183 ReferenceKind::FieldShorthandForField => { 182 let mut replacement_text = String::new();
184 mark::hit!(test_rename_struct_field_for_shorthand); 183 let range = match reference.kind {
185 replacement_text.push_str(new_name); 184 ReferenceKind::FieldShorthandForField => {
186 replacement_text.push_str(": "); 185 mark::hit!(test_rename_struct_field_for_shorthand);
187 TextRange::new(reference.file_range.range.start(), reference.file_range.range.start()) 186 replacement_text.push_str(new_name);
188 } 187 replacement_text.push_str(": ");
189 ReferenceKind::FieldShorthandForLocal => { 188 TextRange::new(reference.range.start(), reference.range.start())
190 mark::hit!(test_rename_local_for_field_shorthand); 189 }
191 replacement_text.push_str(": "); 190 ReferenceKind::FieldShorthandForLocal => {
192 replacement_text.push_str(new_name); 191 mark::hit!(test_rename_local_for_field_shorthand);
193 TextRange::new(reference.file_range.range.end(), reference.file_range.range.end()) 192 replacement_text.push_str(": ");
194 } 193 replacement_text.push_str(new_name);
195 ReferenceKind::RecordFieldExprOrPat => { 194 TextRange::new(reference.range.end(), reference.range.end())
196 mark::hit!(test_rename_field_expr_pat); 195 }
197 replacement_text.push_str(new_name); 196 ReferenceKind::RecordFieldExprOrPat => {
198 edit_text_range_for_record_field_expr_or_pat(sema, reference.file_range, new_name) 197 mark::hit!(test_rename_field_expr_pat);
199 } 198 replacement_text.push_str(new_name);
200 _ => { 199 edit_text_range_for_record_field_expr_or_pat(
201 replacement_text.push_str(new_name); 200 sema,
202 reference.file_range.range 201 FileRange { file_id, range: reference.range },
203 } 202 new_name,
204 }; 203 )
205 SourceFileEdit { 204 }
206 file_id: reference.file_range.file_id, 205 _ => {
207 edit: TextEdit::replace(range, replacement_text), 206 replacement_text.push_str(new_name);
207 reference.range
208 }
209 };
210 edit.replace(range, replacement_text);
208 } 211 }
212
213 SourceFileEdit { file_id, edit: edit.finish() }
209} 214}
210 215
211fn edit_text_range_for_record_field_expr_or_pat( 216fn edit_text_range_for_record_field_expr_or_pat(
@@ -276,10 +281,9 @@ fn rename_mod(
276 } 281 }
277 282
278 let RangeInfo { range, info: refs } = find_all_refs(sema, position)?; 283 let RangeInfo { range, info: refs } = find_all_refs(sema, position)?;
279 let ref_edits = refs 284 let ref_edits = refs.references().iter().map(|(&file_id, references)| {
280 .references 285 source_edit_from_references(sema, file_id, references, new_name)
281 .into_iter() 286 });
282 .map(|reference| source_edit_from_reference(sema, reference, new_name));
283 source_file_edits.extend(ref_edits); 287 source_file_edits.extend(ref_edits);
284 288
285 Ok(RangeInfo::new(range, SourceChange::from_edits(source_file_edits, file_system_edits))) 289 Ok(RangeInfo::new(range, SourceChange::from_edits(source_file_edits, file_system_edits)))
@@ -331,17 +335,12 @@ fn rename_to_self(
331 335
332 let RangeInfo { range, info: refs } = find_all_refs(sema, position)?; 336 let RangeInfo { range, info: refs } = find_all_refs(sema, position)?;
333 337
334 let (param_ref, usages): (Vec<Reference>, Vec<Reference>) = refs 338 let mut edits = refs
335 .into_iter() 339 .references()
336 .partition(|reference| param_range.intersect(reference.file_range.range).is_some()); 340 .iter()
337 341 .map(|(&file_id, references)| {
338 if param_ref.is_empty() { 342 source_edit_from_references(sema, file_id, references, "self")
339 bail!("Parameter to rename not found"); 343 })
340 }
341
342 let mut edits = usages
343 .into_iter()
344 .map(|reference| source_edit_from_reference(sema, reference, "self"))
345 .collect::<Vec<_>>(); 344 .collect::<Vec<_>>();
346 345
347 edits.push(SourceFileEdit { 346 edits.push(SourceFileEdit {
@@ -467,7 +466,9 @@ fn rename_reference(
467 466
468 let edit = refs 467 let edit = refs
469 .into_iter() 468 .into_iter()
470 .map(|reference| source_edit_from_reference(sema, reference, new_name)) 469 .map(|(file_id, references)| {
470 source_edit_from_references(sema, file_id, &references, new_name)
471 })
471 .collect::<Vec<_>>(); 472 .collect::<Vec<_>>();
472 473
473 Ok(RangeInfo::new(range, SourceChange::from(edit))) 474 Ok(RangeInfo::new(range, SourceChange::from(edit)))
diff --git a/crates/ide/src/syntax_highlighting/highlights.rs b/crates/ide/src/syntax_highlighting/highlights.rs
index c6f0417ec..882a685a5 100644
--- a/crates/ide/src/syntax_highlighting/highlights.rs
+++ b/crates/ide/src/syntax_highlighting/highlights.rs
@@ -1,5 +1,5 @@
1//! Collects a tree of highlighted ranges and flattens it. 1//! Collects a tree of highlighted ranges and flattens it.
2use std::{cmp::Ordering, iter}; 2use std::iter;
3 3
4use stdx::equal_range_by; 4use stdx::equal_range_by;
5use syntax::TextRange; 5use syntax::TextRange;
@@ -52,7 +52,7 @@ impl Node {
52 } 52 }
53 53
54 let overlapping = 54 let overlapping =
55 equal_range_by(&self.nested, |n| ordering(n.hl_range.range, hl_range.range)); 55 equal_range_by(&self.nested, |n| TextRange::ordering(n.hl_range.range, hl_range.range));
56 56
57 if overlapping.len() == 1 57 if overlapping.len() == 1
58 && self.nested[overlapping.start].hl_range.range.contains_range(hl_range.range) 58 && self.nested[overlapping.start].hl_range.range.contains_range(hl_range.range)
@@ -90,13 +90,3 @@ impl Node {
90 } 90 }
91 } 91 }
92} 92}
93
94pub(super) fn ordering(r1: TextRange, r2: TextRange) -> Ordering {
95 if r1.end() <= r2.start() {
96 Ordering::Less
97 } else if r2.end() <= r1.start() {
98 Ordering::Greater
99 } else {
100 Ordering::Equal
101 }
102}
diff --git a/crates/ide/src/syntax_highlighting/injector.rs b/crates/ide/src/syntax_highlighting/injector.rs
index fd4025694..24ff473ec 100644
--- a/crates/ide/src/syntax_highlighting/injector.rs
+++ b/crates/ide/src/syntax_highlighting/injector.rs
@@ -5,8 +5,6 @@ use std::ops::{self, Sub};
5use stdx::equal_range_by; 5use stdx::equal_range_by;
6use syntax::{TextRange, TextSize}; 6use syntax::{TextRange, TextSize};
7 7
8use super::highlights::ordering;
9
10#[derive(Default)] 8#[derive(Default)]
11pub(super) struct Injector { 9pub(super) struct Injector {
12 buf: String, 10 buf: String,
@@ -33,7 +31,7 @@ impl Injector {
33 &self.buf 31 &self.buf
34 } 32 }
35 pub(super) fn map_range_up(&self, range: TextRange) -> impl Iterator<Item = TextRange> + '_ { 33 pub(super) fn map_range_up(&self, range: TextRange) -> impl Iterator<Item = TextRange> + '_ {
36 equal_range_by(&self.ranges, |&(r, _)| ordering(r, range)).filter_map(move |i| { 34 equal_range_by(&self.ranges, |&(r, _)| TextRange::ordering(r, range)).filter_map(move |i| {
37 let (target_range, delta) = self.ranges[i]; 35 let (target_range, delta) = self.ranges[i];
38 let intersection = target_range.intersect(range).unwrap(); 36 let intersection = target_range.intersect(range).unwrap();
39 Some(intersection + delta?) 37 Some(intersection + delta?)