Unnamed repository; edit this file 'description' to name the repository.
Diffstat (limited to 'crates/ide/src/references.rs')
-rw-r--r--crates/ide/src/references.rs103
1 files changed, 75 insertions, 28 deletions
diff --git a/crates/ide/src/references.rs b/crates/ide/src/references.rs
index f387bbf6b0..6c0fb0baf2 100644
--- a/crates/ide/src/references.rs
+++ b/crates/ide/src/references.rs
@@ -9,7 +9,9 @@
//! at the index that the match starts at and its tree parent is
//! resolved to the search element definition, we get a reference.
-use hir::{PathResolution, Semantics};
+use std::collections::HashMap;
+
+use hir::{DescendPreference, PathResolution, Semantics};
use ide_db::{
base_db::FileId,
defs::{Definition, NameClass, NameRefClass},
@@ -60,19 +62,6 @@ pub(crate) fn find_all_refs(
let syntax = sema.parse(position.file_id).syntax().clone();
let make_searcher = |literal_search: bool| {
move |def: Definition| {
- let declaration = match def {
- Definition::Module(module) => {
- Some(NavigationTarget::from_module_to_decl(sema.db, module))
- }
- def => def.try_to_nav(sema.db),
- }
- .map(|nav| {
- let decl_range = nav.focus_or_full_range();
- Declaration {
- is_mut: decl_mutability(&def, sema.parse(nav.file_id).syntax(), decl_range),
- nav,
- }
- });
let mut usages =
def.usages(sema).set_scope(search_scope.as_ref()).include_self_refs().all();
@@ -80,7 +69,7 @@ pub(crate) fn find_all_refs(
retain_adt_literal_usages(&mut usages, def, sema);
}
- let references = usages
+ let mut references = usages
.into_iter()
.map(|(file_id, refs)| {
(
@@ -91,8 +80,30 @@ pub(crate) fn find_all_refs(
.collect(),
)
})
- .collect();
-
+ .collect::<HashMap<_, Vec<_>, _>>();
+ let declaration = match def {
+ Definition::Module(module) => {
+ Some(NavigationTarget::from_module_to_decl(sema.db, module))
+ }
+ def => def.try_to_nav(sema.db),
+ }
+ .map(|nav| {
+ let (nav, extra_ref) = match nav.def_site {
+ Some(call) => (call, Some(nav.call_site)),
+ None => (nav.call_site, None),
+ };
+ if let Some(extra_ref) = extra_ref {
+ references
+ .entry(extra_ref.file_id)
+ .or_default()
+ .push((extra_ref.focus_or_full_range(), None));
+ }
+ let decl_range = nav.focus_or_full_range();
+ Declaration {
+ is_mut: decl_mutability(&def, sema.parse(nav.file_id).syntax(), decl_range),
+ nav,
+ }
+ });
ReferenceSearchResult { declaration, references }
}
};
@@ -109,7 +120,7 @@ pub(crate) fn find_all_refs(
}
None => {
let search = make_searcher(false);
- Some(find_defs(sema, &syntax, position.offset)?.map(search).collect())
+ Some(find_defs(sema, &syntax, position.offset)?.into_iter().map(search).collect())
}
}
}
@@ -118,15 +129,27 @@ pub(crate) fn find_defs<'a>(
sema: &'a Semantics<'_, RootDatabase>,
syntax: &SyntaxNode,
offset: TextSize,
-) -> Option<impl Iterator<Item = Definition> + 'a> {
+) -> Option<impl IntoIterator<Item = Definition> + 'a> {
let token = syntax.token_at_offset(offset).find(|t| {
matches!(
t.kind(),
- IDENT | INT_NUMBER | LIFETIME_IDENT | T![self] | T![super] | T![crate] | T![Self]
+ IDENT
+ | INT_NUMBER
+ | LIFETIME_IDENT
+ | STRING
+ | T![self]
+ | T![super]
+ | T![crate]
+ | T![Self]
)
- });
- token.map(|token| {
- sema.descend_into_macros_with_same_text(token, offset)
+ })?;
+
+ if let Some((_, resolution)) = sema.check_for_format_args_template(token.clone(), offset) {
+ return resolution.map(Definition::from).map(|it| vec![it]);
+ }
+
+ Some(
+ sema.descend_into_macros(DescendPreference::SameText, token)
.into_iter()
.filter_map(|it| ast::NameLike::cast(it.parent()?))
.filter_map(move |name_like| {
@@ -162,7 +185,8 @@ pub(crate) fn find_defs<'a>(
};
Some(def)
})
- })
+ .collect(),
+ )
}
pub(crate) fn decl_mutability(def: &Definition, syntax: &SyntaxNode, range: TextRange) -> bool {
@@ -869,7 +893,7 @@ pub(super) struct Foo$0 {
check_with_scope(
code,
- Some(SearchScope::single_file(FileId(2))),
+ Some(SearchScope::single_file(FileId::from_raw(2))),
expect![[r#"
quux Function FileId(0) 19..35 26..30
@@ -1168,7 +1192,7 @@ fn foo<'a, 'b: 'a>(x: &'a$0 ()) -> &'a () where &'a (): Foo<'a> {
}
"#,
expect![[r#"
- 'a LifetimeParam FileId(0) 55..57 55..57
+ 'a LifetimeParam FileId(0) 55..57
FileId(0) 63..65
FileId(0) 71..73
@@ -1186,7 +1210,7 @@ fn foo<'a, 'b: 'a>(x: &'a$0 ()) -> &'a () where &'a (): Foo<'a> {
type Foo<'a, T> where T: 'a$0 = &'a T;
"#,
expect![[r#"
- 'a LifetimeParam FileId(0) 9..11 9..11
+ 'a LifetimeParam FileId(0) 9..11
FileId(0) 25..27
FileId(0) 31..33
@@ -1208,7 +1232,7 @@ impl<'a> Foo<'a> for &'a () {
}
"#,
expect![[r#"
- 'a LifetimeParam FileId(0) 47..49 47..49
+ 'a LifetimeParam FileId(0) 47..49
FileId(0) 55..57
FileId(0) 64..66
@@ -2092,4 +2116,27 @@ fn main() { r#fn(); }
"#]],
);
}
+
+ #[test]
+ fn implicit_format_args() {
+ check(
+ r#"
+//- minicore: fmt
+fn test() {
+ let a = "foo";
+ format_args!("hello {a} {a$0} {}", a);
+ // ^
+ // ^
+ // ^
+}
+"#,
+ expect![[r#"
+ a Local FileId(0) 20..21 20..21
+
+ FileId(0) 56..57 Read
+ FileId(0) 60..61 Read
+ FileId(0) 68..69 Read
+ "#]],
+ );
+ }
}