mirror of
https://github.com/rust-lang/rust-analyzer.git
synced 2025-09-30 13:51:31 +00:00
fix: Partially fix ide_db::search
for crate roots
This commit is contained in:
parent
2ca3834c9f
commit
5206946674
4 changed files with 118 additions and 34 deletions
|
@ -97,6 +97,10 @@ impl CrateName {
|
||||||
pub fn normalize_dashes(name: &str) -> CrateName {
|
pub fn normalize_dashes(name: &str) -> CrateName {
|
||||||
Self(SmolStr::new(name.replace('-', "_")))
|
Self(SmolStr::new(name.replace('-', "_")))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn as_smol_str(&self) -> &SmolStr {
|
||||||
|
&self.0
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl fmt::Display for CrateName {
|
impl fmt::Display for CrateName {
|
||||||
|
|
|
@ -378,7 +378,22 @@ struct Foo;
|
||||||
fn test_hl_self_in_crate_root() {
|
fn test_hl_self_in_crate_root() {
|
||||||
check(
|
check(
|
||||||
r#"
|
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
|
||||||
"#,
|
"#,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -756,7 +756,7 @@ use self$0;
|
||||||
expect![[r#"
|
expect![[r#"
|
||||||
Module FileId(0) 0..10
|
Module FileId(0) 0..10
|
||||||
|
|
||||||
(no references)
|
FileId(0) 4..8
|
||||||
"#]],
|
"#]],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
//! get a super-set of matches. Then, we we confirm each match using precise
|
//! get a super-set of matches. Then, we we confirm each match using precise
|
||||||
//! name resolution.
|
//! name resolution.
|
||||||
|
|
||||||
use std::{convert::TryInto, mem};
|
use std::{convert::TryInto, mem, sync::Arc};
|
||||||
|
|
||||||
use base_db::{FileId, FileRange, SourceDatabase, SourceDatabaseExt};
|
use base_db::{FileId, FileRange, SourceDatabase, SourceDatabaseExt};
|
||||||
use hir::{
|
use hir::{
|
||||||
|
@ -376,32 +376,63 @@ impl<'a> FindUsages<'a> {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let name = self.def.name(sema.db).or_else(|| {
|
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| {
|
self.include_self_kw_refs.as_ref().and_then(|ty| {
|
||||||
ty.as_adt()
|
ty.as_adt()
|
||||||
.map(|adt| adt.name(self.sema.db))
|
.map(|adt| adt.name(self.sema.db))
|
||||||
.or_else(|| ty.as_builtin().map(|builtin| builtin.name()))
|
.or_else(|| ty.as_builtin().map(|builtin| builtin.name()))
|
||||||
})
|
})
|
||||||
});
|
};
|
||||||
let name = match name {
|
self.def.name(sema.db).or_else(self_kw_refs).map(|it| it.to_smol_str())
|
||||||
Some(name) => name.to_smol_str(),
|
}
|
||||||
|
};
|
||||||
|
let name = match &name {
|
||||||
|
Some(s) => s.as_str(),
|
||||||
None => return,
|
None => return,
|
||||||
};
|
};
|
||||||
let name = name.as_str();
|
|
||||||
|
|
||||||
for (file_id, search_range) in search_scope {
|
// 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) {
|
||||||
|
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 text = sema.db.file_text(file_id);
|
||||||
let search_range =
|
let search_range =
|
||||||
search_range.unwrap_or_else(|| TextRange::up_to(TextSize::of(text.as_str())));
|
search_range.unwrap_or_else(|| TextRange::up_to(TextSize::of(text.as_str())));
|
||||||
|
|
||||||
let tree = Lazy::new(|| sema.parse(file_id).syntax().clone());
|
(text, file_id, search_range)
|
||||||
|
})
|
||||||
for (idx, _) in text.match_indices(name) {
|
|
||||||
let offset: TextSize = idx.try_into().unwrap();
|
|
||||||
if !search_range.contains_inclusive(offset) {
|
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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) {
|
for name in sema.find_nodes_at_offset_with_descend(&tree, offset) {
|
||||||
if match name {
|
if match name {
|
||||||
ast::NameLike::NameRef(name_ref) => self.found_name_ref(&name_ref, sink),
|
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 {
|
if let Some(self_ty) = &self.include_self_kw_refs {
|
||||||
for (idx, _) in text.match_indices("Self") {
|
for offset in match_indices(&text, "Self", search_range) {
|
||||||
let offset: TextSize = idx.try_into().unwrap();
|
|
||||||
if !search_range.contains_inclusive(offset) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
for name_ref in sema.find_nodes_at_offset_with_descend(&tree, offset) {
|
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) {
|
if self.found_self_ty_name_ref(self_ty, &name_ref, sink) {
|
||||||
return;
|
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
|
// search for module `self` references in our module's definition source
|
||||||
match self.def {
|
match self.def {
|
||||||
Definition::Module(module) if self.search_self_mod => {
|
Definition::Module(module) if self.search_self_mod => {
|
||||||
|
@ -439,18 +497,25 @@ impl<'a> FindUsages<'a> {
|
||||||
ModuleSource::SourceFile(_) => (file_id, None),
|
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 text = sema.db.file_text(file_id);
|
||||||
let search_range =
|
let search_range =
|
||||||
search_range.unwrap_or_else(|| TextRange::up_to(TextSize::of(text.as_str())));
|
search_range.unwrap_or_else(|| TextRange::up_to(TextSize::of(text.as_str())));
|
||||||
|
|
||||||
let tree = Lazy::new(|| sema.parse(file_id).syntax().clone());
|
let tree = Lazy::new(|| sema.parse(file_id).syntax().clone());
|
||||||
|
|
||||||
for (idx, _) in text.match_indices("self") {
|
for offset in match_indices(&text, "self", search_range) {
|
||||||
let offset: TextSize = idx.try_into().unwrap();
|
|
||||||
if !search_range.contains_inclusive(offset) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
for name_ref in sema.find_nodes_at_offset_with_descend(&tree, offset) {
|
for name_ref in sema.find_nodes_at_offset_with_descend(&tree, offset) {
|
||||||
if self.found_self_module_name_ref(&name_ref, sink) {
|
if self.found_self_module_name_ref(&name_ref, sink) {
|
||||||
return;
|
return;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue