Unnamed repository; edit this file 'description' to name the repository.
Merge #11069
11069: fix: Partially fix `ide_db::search` for crate roots r=Veykril a=Veykril Fixes https://github.com/rust-analyzer/rust-analyzer/issues/10007 bors r+ Co-authored-by: Lukas Wirth <[email protected]>
bors[bot] 2021-12-20
parent 8dc3a27 · parent 5206946 · commit d3aa257
-rw-r--r--crates/base_db/src/input.rs4
-rw-r--r--crates/ide/src/highlight_related.rs17
-rw-r--r--crates/ide/src/references.rs2
-rw-r--r--crates/ide_db/src/search.rs129
4 files changed, 118 insertions, 34 deletions
diff --git a/crates/base_db/src/input.rs b/crates/base_db/src/input.rs
index f182427e47..08d3bc93ff 100644
--- a/crates/base_db/src/input.rs
+++ b/crates/base_db/src/input.rs
@@ -97,6 +97,10 @@ impl CrateName {
pub fn normalize_dashes(name: &str) -> CrateName {
Self(SmolStr::new(name.replace('-', "_")))
}
+
+ pub fn as_smol_str(&self) -> &SmolStr {
+ &self.0
+ }
}
impl fmt::Display for CrateName {
diff --git a/crates/ide/src/highlight_related.rs b/crates/ide/src/highlight_related.rs
index de6afaef8e..054b8f297b 100644
--- a/crates/ide/src/highlight_related.rs
+++ b/crates/ide/src/highlight_related.rs
@@ -378,7 +378,22 @@ struct Foo;
fn test_hl_self_in_crate_root() {
check(
r#"
-use self$0;
+use crate$0;
+ //^^^^^
+use self;
+ //^^^^
+mod __ {
+ use super;
+ //^^^^^
+}
+"#,
+ );
+ check(
+ r#"
+//- /main.rs crate:main deps:lib
+use lib$0;
+ //^^^
+//- /lib.rs crate:lib
"#,
);
}
diff --git a/crates/ide/src/references.rs b/crates/ide/src/references.rs
index c5fe7d30c9..949c6dc686 100644
--- a/crates/ide/src/references.rs
+++ b/crates/ide/src/references.rs
@@ -756,7 +756,7 @@ use self$0;
expect![[r#"
Module FileId(0) 0..10
- (no references)
+ FileId(0) 4..8
"#]],
);
}
diff --git a/crates/ide_db/src/search.rs b/crates/ide_db/src/search.rs
index 0d0f7b78d8..dcfc2b7bfc 100644
--- a/crates/ide_db/src/search.rs
+++ b/crates/ide_db/src/search.rs
@@ -4,7 +4,7 @@
//! get a super-set of matches. Then, we we confirm each match using precise
//! name resolution.
-use std::{convert::TryInto, mem};
+use std::{convert::TryInto, mem, sync::Arc};
use base_db::{FileId, FileRange, SourceDatabase, SourceDatabaseExt};
use hir::{
@@ -376,32 +376,63 @@ impl<'a> FindUsages<'a> {
}
};
- let name = self.def.name(sema.db).or_else(|| {
- self.include_self_kw_refs.as_ref().and_then(|ty| {
- ty.as_adt()
- .map(|adt| adt.name(self.sema.db))
- .or_else(|| ty.as_builtin().map(|builtin| builtin.name()))
- })
- });
- let name = match name {
- Some(name) => name.to_smol_str(),
+ let name = match self.def {
+ // special case crate modules as these do not have a proper name
+ Definition::Module(module) if module.crate_root(self.sema.db) == module => {
+ // FIXME: This assumes the crate name is always equal to its display name when it really isn't
+ module
+ .krate()
+ .display_name(self.sema.db)
+ .map(|crate_name| crate_name.crate_name().as_smol_str().clone())
+ }
+ _ => {
+ let self_kw_refs = || {
+ self.include_self_kw_refs.as_ref().and_then(|ty| {
+ ty.as_adt()
+ .map(|adt| adt.name(self.sema.db))
+ .or_else(|| ty.as_builtin().map(|builtin| builtin.name()))
+ })
+ };
+ self.def.name(sema.db).or_else(self_kw_refs).map(|it| it.to_smol_str())
+ }
+ };
+ let name = match &name {
+ Some(s) => s.as_str(),
None => return,
};
- let name = name.as_str();
-
- for (file_id, search_range) in search_scope {
- let text = sema.db.file_text(file_id);
- let search_range =
- search_range.unwrap_or_else(|| TextRange::up_to(TextSize::of(text.as_str())));
-
- let tree = Lazy::new(|| sema.parse(file_id).syntax().clone());
- for (idx, _) in text.match_indices(name) {
+ // these can't be closures because rust infers the lifetimes wrong ...
+ fn match_indices<'a>(
+ text: &'a str,
+ name: &'a str,
+ search_range: TextRange,
+ ) -> impl Iterator<Item = TextSize> + 'a {
+ text.match_indices(name).filter_map(move |(idx, _)| {
let offset: TextSize = idx.try_into().unwrap();
if !search_range.contains_inclusive(offset) {
- continue;
+ return None;
}
+ Some(offset)
+ })
+ }
+ fn scope_files<'a>(
+ sema: &'a Semantics<RootDatabase>,
+ scope: &'a SearchScope,
+ ) -> impl Iterator<Item = (Arc<String>, FileId, TextRange)> + 'a {
+ scope.entries.iter().map(|(&file_id, &search_range)| {
+ let text = sema.db.file_text(file_id);
+ let search_range =
+ search_range.unwrap_or_else(|| TextRange::up_to(TextSize::of(text.as_str())));
+
+ (text, file_id, search_range)
+ })
+ }
+
+ 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, name, 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),
@@ -412,13 +443,9 @@ impl<'a> FindUsages<'a> {
}
}
}
+ // Search for occurrences of the `Self` referring to our type
if let Some(self_ty) = &self.include_self_kw_refs {
- for (idx, _) in text.match_indices("Self") {
- let offset: TextSize = idx.try_into().unwrap();
- if !search_range.contains_inclusive(offset) {
- continue;
- }
-
+ for offset in match_indices(&text, "Self", 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;
@@ -428,6 +455,37 @@ impl<'a> FindUsages<'a> {
}
}
+ // Search for `super` and `crate` resolving to our module
+ match self.def {
+ Definition::Module(module) => {
+ let scope = search_scope.intersection(&SearchScope::module(self.sema.db, module));
+
+ let is_crate_root = module.crate_root(self.sema.db) == module;
+
+ for (text, file_id, search_range) in scope_files(sema, &scope) {
+ let tree = Lazy::new(move || sema.parse(file_id).syntax().clone());
+
+ for offset in match_indices(&text, "super", 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 is_crate_root {
+ for offset in match_indices(&text, "crate", search_range) {
+ for name_ref in sema.find_nodes_at_offset_with_descend(&tree, offset) {
+ if self.found_name_ref(&name_ref, sink) {
+ return;
+ }
+ }
+ }
+ }
+ }
+ }
+ _ => (),
+ }
+
// search for module `self` references in our module's definition source
match self.def {
Definition::Module(module) if self.search_self_mod => {
@@ -439,18 +497,25 @@ impl<'a> FindUsages<'a> {
ModuleSource::SourceFile(_) => (file_id, None),
};
+ let search_range = if let Some(&range) = search_scope.entries.get(&file_id) {
+ match (range, search_range) {
+ (None, range) | (range, None) => range,
+ (Some(range), Some(search_range)) => match range.intersect(search_range) {
+ Some(range) => Some(range),
+ None => return,
+ },
+ }
+ } else {
+ return;
+ };
+
let text = sema.db.file_text(file_id);
let search_range =
search_range.unwrap_or_else(|| TextRange::up_to(TextSize::of(text.as_str())));
let tree = Lazy::new(|| sema.parse(file_id).syntax().clone());
- for (idx, _) in text.match_indices("self") {
- let offset: TextSize = idx.try_into().unwrap();
- if !search_range.contains_inclusive(offset) {
- continue;
- }
-
+ for offset in match_indices(&text, "self", 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;