diff --git a/crates/ide-db/src/search.rs b/crates/ide-db/src/search.rs index 82b85f2fa5edd..aa5d7e9beb54f 100644 --- a/crates/ide-db/src/search.rs +++ b/crates/ide-db/src/search.rs @@ -446,33 +446,47 @@ impl<'a> FindUsages<'a> { }) } - // FIXME: There should be optimization potential here - // Currently we try to descend everything we find which - // means we call `Semantics::descend_into_macros` on - // every textual hit. That function is notoriously - // expensive even for things that do not get down mapped - // into macros. + let find_nodes = move |name: &str, node: &syntax::SyntaxNode, offset: TextSize| { + node.token_at_offset(offset).find(|it| it.text() == name).map(|token| { + // FIXME: There should be optimization potential here + // Currently we try to descend everything we find which + // means we call `Semantics::descend_into_macros` on + // every textual hit. That function is notoriously + // expensive even for things that do not get down mapped + // into macros. + sema.descend_into_macros(token).into_iter().filter_map(|it| it.parent()) + }) + }; + for (text, file_id, search_range) in scope_files(sema, &search_scope) { let tree = Lazy::new(move || sema.parse(file_id).syntax().clone()); // Search for occurrences of the items name for offset in match_indices(&text, finder, search_range) { - for name in sema.find_nodes_at_offset_with_descend(&tree, offset) { - if match name { - ast::NameLike::NameRef(name_ref) => self.found_name_ref(&name_ref, sink), - ast::NameLike::Name(name) => self.found_name(&name, sink), - ast::NameLike::Lifetime(lifetime) => self.found_lifetime(&lifetime, sink), - } { - return; + if let Some(iter) = find_nodes(name, &tree, offset) { + for name in iter.filter_map(ast::NameLike::cast) { + if match name { + ast::NameLike::NameRef(name_ref) => { + self.found_name_ref(&name_ref, sink) + } + ast::NameLike::Name(name) => self.found_name(&name, sink), + ast::NameLike::Lifetime(lifetime) => { + self.found_lifetime(&lifetime, sink) + } + } { + return; + } } } } // Search for occurrences of the `Self` referring to our type if let Some((self_ty, finder)) = &include_self_kw_refs { for offset in match_indices(&text, finder, search_range) { - for name_ref in sema.find_nodes_at_offset_with_descend(&tree, offset) { - if self.found_self_ty_name_ref(self_ty, &name_ref, sink) { - return; + if let Some(iter) = find_nodes("Self", &tree, offset) { + for name_ref in iter.filter_map(ast::NameRef::cast) { + if self.found_self_ty_name_ref(self_ty, &name_ref, sink) { + return; + } } } } @@ -493,17 +507,21 @@ impl<'a> FindUsages<'a> { let tree = Lazy::new(move || sema.parse(file_id).syntax().clone()); for offset in match_indices(&text, finder, search_range) { - for name_ref in sema.find_nodes_at_offset_with_descend(&tree, offset) { - if self.found_name_ref(&name_ref, sink) { - return; + if let Some(iter) = find_nodes("super", &tree, offset) { + for name_ref in iter.filter_map(ast::NameRef::cast) { + if self.found_name_ref(&name_ref, sink) { + return; + } } } } if let Some(finder) = &is_crate_root { for offset in match_indices(&text, finder, search_range) { - for name_ref in sema.find_nodes_at_offset_with_descend(&tree, offset) { - if self.found_name_ref(&name_ref, sink) { - return; + if let Some(iter) = find_nodes("crate", &tree, offset) { + for name_ref in iter.filter_map(ast::NameRef::cast) { + if self.found_name_ref(&name_ref, sink) { + return; + } } } } @@ -544,9 +562,11 @@ impl<'a> FindUsages<'a> { let finder = &Finder::new("self"); for offset in match_indices(&text, finder, search_range) { - for name_ref in sema.find_nodes_at_offset_with_descend(&tree, offset) { - if self.found_self_module_name_ref(&name_ref, sink) { - return; + if let Some(iter) = find_nodes("self", &tree, offset) { + for name_ref in iter.filter_map(ast::NameRef::cast) { + if self.found_self_module_name_ref(&name_ref, sink) { + return; + } } } } diff --git a/crates/ide/src/rename.rs b/crates/ide/src/rename.rs index fe44856dcad2a..b4df0437050f4 100644 --- a/crates/ide/src/rename.rs +++ b/crates/ide/src/rename.rs @@ -40,7 +40,9 @@ pub(crate) fn prepare_rename( if def.range_for_rename(&sema).is_none() { bail!("No references found at position") } - let frange = sema.original_range(name_like.syntax()); + let Some(frange) = sema.original_range_opt(name_like.syntax()) else { + bail!("No references found at position"); + }; always!( frange.range.contains_inclusive(position.offset) @@ -51,7 +53,7 @@ pub(crate) fn prepare_rename( .reduce(|acc, cur| match (acc, cur) { // ensure all ranges are the same (Ok(acc_inner), Ok(cur_inner)) if acc_inner == cur_inner => Ok(acc_inner), - (Err(e), _) => Err(e), + (e @ Err(_), _) | (_, e @ Err(_)) => e, _ => bail!("inconsistent text range"), }); @@ -2249,4 +2251,33 @@ fn foo((bar | bar | bar): ()) { "#, ); } + + #[test] + fn regression_13498() { + check( + "Testing", + r" +mod foo { + pub struct Test$0; +} + +use foo::Test as Tester; + +fn main() { + let t = Tester; +} +", + r" +mod foo { + pub struct Testing; +} + +use foo::Testing as Tester; + +fn main() { + let t = Tester; +} +", + ) + } }