Unnamed repository; edit this file 'description' to name the repository.
Diffstat (limited to 'crates/ide-db/src/search.rs')
| -rw-r--r-- | crates/ide-db/src/search.rs | 123 |
1 files changed, 108 insertions, 15 deletions
diff --git a/crates/ide-db/src/search.rs b/crates/ide-db/src/search.rs index 22438a203b..dbef360268 100644 --- a/crates/ide-db/src/search.rs +++ b/crates/ide-db/src/search.rs @@ -8,13 +8,14 @@ use std::mem; use base_db::{salsa::Database, FileId, FileRange, SourceDatabase, SourceDatabaseExt}; use hir::{ - AsAssocItem, DefWithBody, HasAttrs, HasSource, InFile, ModuleSource, Semantics, Visibility, + AsAssocItem, DefWithBody, DescendPreference, HasAttrs, HasSource, HirFileIdExt, InFile, + InRealFile, ModuleSource, PathResolution, Semantics, Visibility, }; use memchr::memmem::Finder; use nohash_hasher::IntMap; use once_cell::unsync::Lazy; use parser::SyntaxKind; -use syntax::{ast, match_ast, AstNode, TextRange, TextSize}; +use syntax::{ast, match_ast, AstNode, AstToken, SyntaxElement, TextRange, TextSize}; use triomphe::Arc; use crate::{ @@ -62,10 +63,67 @@ pub struct FileReference { /// The range of the reference in the original file pub range: TextRange, /// The node of the reference in the (macro-)file - pub name: ast::NameLike, + pub name: FileReferenceNode, pub category: Option<ReferenceCategory>, } +#[derive(Debug, Clone)] +pub enum FileReferenceNode { + Name(ast::Name), + NameRef(ast::NameRef), + Lifetime(ast::Lifetime), + FormatStringEntry(ast::String, TextRange), +} + +impl FileReferenceNode { + pub fn text_range(&self) -> TextRange { + match self { + FileReferenceNode::Name(it) => it.syntax().text_range(), + FileReferenceNode::NameRef(it) => it.syntax().text_range(), + FileReferenceNode::Lifetime(it) => it.syntax().text_range(), + FileReferenceNode::FormatStringEntry(_, range) => *range, + } + } + pub fn syntax(&self) -> SyntaxElement { + match self { + FileReferenceNode::Name(it) => it.syntax().clone().into(), + FileReferenceNode::NameRef(it) => it.syntax().clone().into(), + FileReferenceNode::Lifetime(it) => it.syntax().clone().into(), + FileReferenceNode::FormatStringEntry(it, _) => it.syntax().clone().into(), + } + } + pub fn into_name_like(self) -> Option<ast::NameLike> { + match self { + FileReferenceNode::Name(it) => Some(ast::NameLike::Name(it)), + FileReferenceNode::NameRef(it) => Some(ast::NameLike::NameRef(it)), + FileReferenceNode::Lifetime(it) => Some(ast::NameLike::Lifetime(it)), + FileReferenceNode::FormatStringEntry(_, _) => None, + } + } + pub fn as_name_ref(&self) -> Option<&ast::NameRef> { + match self { + FileReferenceNode::NameRef(name_ref) => Some(name_ref), + _ => None, + } + } + pub fn as_lifetime(&self) -> Option<&ast::Lifetime> { + match self { + FileReferenceNode::Lifetime(lifetime) => Some(lifetime), + _ => None, + } + } + pub fn text(&self) -> syntax::TokenText<'_> { + match self { + FileReferenceNode::NameRef(name_ref) => name_ref.text(), + FileReferenceNode::Name(name) => name.text(), + FileReferenceNode::Lifetime(lifetime) => lifetime.text(), + FileReferenceNode::FormatStringEntry(it, range) => { + syntax::TokenText::borrowed(&it.text()[*range - it.syntax().text_range().start()]) + } + } + } +} + #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] pub enum ReferenceCategory { // FIXME: Add this variant and delete the `retain_adt_literal_usages` function. @@ -132,7 +190,8 @@ impl SearchScope { let (file_id, range) = { let InFile { file_id, value } = module.definition_source(db); - if let Some((file_id, call_source)) = file_id.original_call_node(db) { + if let Some(InRealFile { file_id, value: call_source }) = file_id.original_call_node(db) + { (file_id, Some(call_source.text_range())) } else { ( @@ -465,7 +524,9 @@ impl<'a> FindUsages<'a> { // every textual hit. That function is notoriously // expensive even for things that do not get down mapped // into macros. - sema.descend_into_macros(token, offset).into_iter().filter_map(|it| it.parent()) + sema.descend_into_macros(DescendPreference::None, token) + .into_iter() + .filter_map(|it| it.parent()) }) }; @@ -475,6 +536,17 @@ impl<'a> FindUsages<'a> { // Search for occurrences of the items name for offset in match_indices(&text, finder, search_range) { + tree.token_at_offset(offset).into_iter().for_each(|token| { + let Some(str_token) = ast::String::cast(token.clone()) else { return }; + if let Some((range, nameres)) = + sema.check_for_format_args_template(token.clone(), offset) + { + if self.found_format_args_ref(file_id, range, str_token, nameres, sink) { + return; + } + } + }); + for name in find_nodes(name, &tree, offset).filter_map(ast::NameLike::cast) { if match name { ast::NameLike::NameRef(name_ref) => self.found_name_ref(&name_ref, sink), @@ -589,7 +661,7 @@ impl<'a> FindUsages<'a> { let FileRange { file_id, range } = self.sema.original_range(name_ref.syntax()); let reference = FileReference { range, - name: ast::NameLike::NameRef(name_ref.clone()), + name: FileReferenceNode::NameRef(name_ref.clone()), category: None, }; sink(file_id, reference) @@ -608,7 +680,7 @@ impl<'a> FindUsages<'a> { let FileRange { file_id, range } = self.sema.original_range(name_ref.syntax()); let reference = FileReference { range, - name: ast::NameLike::NameRef(name_ref.clone()), + name: FileReferenceNode::NameRef(name_ref.clone()), category: is_name_ref_in_import(name_ref).then_some(ReferenceCategory::Import), }; sink(file_id, reference) @@ -617,6 +689,27 @@ impl<'a> FindUsages<'a> { } } + fn found_format_args_ref( + &self, + file_id: FileId, + range: TextRange, + token: ast::String, + res: Option<PathResolution>, + sink: &mut dyn FnMut(FileId, FileReference) -> bool, + ) -> bool { + match res.map(Definition::from) { + Some(def) if def == self.def => { + let reference = FileReference { + range, + name: FileReferenceNode::FormatStringEntry(token, range), + category: Some(ReferenceCategory::Read), + }; + sink(file_id, reference) + } + _ => false, + } + } + fn found_lifetime( &self, lifetime: &ast::Lifetime, @@ -627,7 +720,7 @@ impl<'a> FindUsages<'a> { let FileRange { file_id, range } = self.sema.original_range(lifetime.syntax()); let reference = FileReference { range, - name: ast::NameLike::Lifetime(lifetime.clone()), + name: FileReferenceNode::Lifetime(lifetime.clone()), category: None, }; sink(file_id, reference) @@ -651,7 +744,7 @@ impl<'a> FindUsages<'a> { let FileRange { file_id, range } = self.sema.original_range(name_ref.syntax()); let reference = FileReference { range, - name: ast::NameLike::NameRef(name_ref.clone()), + name: FileReferenceNode::NameRef(name_ref.clone()), category: ReferenceCategory::new(&def, name_ref), }; sink(file_id, reference) @@ -667,7 +760,7 @@ impl<'a> FindUsages<'a> { let FileRange { file_id, range } = self.sema.original_range(name_ref.syntax()); let reference = FileReference { range, - name: ast::NameLike::NameRef(name_ref.clone()), + name: FileReferenceNode::NameRef(name_ref.clone()), category: ReferenceCategory::new(&def, name_ref), }; sink(file_id, reference) @@ -677,7 +770,7 @@ impl<'a> FindUsages<'a> { let FileRange { file_id, range } = self.sema.original_range(name_ref.syntax()); let reference = FileReference { range, - name: ast::NameLike::NameRef(name_ref.clone()), + name: FileReferenceNode::NameRef(name_ref.clone()), category: ReferenceCategory::new(&def, name_ref), }; sink(file_id, reference) @@ -701,7 +794,7 @@ impl<'a> FindUsages<'a> { }; let reference = FileReference { range, - name: ast::NameLike::NameRef(name_ref.clone()), + name: FileReferenceNode::NameRef(name_ref.clone()), category: access, }; sink(file_id, reference) @@ -724,7 +817,7 @@ impl<'a> FindUsages<'a> { let FileRange { file_id, range } = self.sema.original_range(name.syntax()); let reference = FileReference { range, - name: ast::NameLike::Name(name.clone()), + name: FileReferenceNode::Name(name.clone()), // FIXME: mutable patterns should have `Write` access category: Some(ReferenceCategory::Read), }; @@ -734,7 +827,7 @@ impl<'a> FindUsages<'a> { let FileRange { file_id, range } = self.sema.original_range(name.syntax()); let reference = FileReference { range, - name: ast::NameLike::Name(name.clone()), + name: FileReferenceNode::Name(name.clone()), category: None, }; sink(file_id, reference) @@ -759,7 +852,7 @@ impl<'a> FindUsages<'a> { let FileRange { file_id, range } = self.sema.original_range(name.syntax()); let reference = FileReference { range, - name: ast::NameLike::Name(name.clone()), + name: FileReferenceNode::Name(name.clone()), category: None, }; sink(file_id, reference) |