Include self in usage search for modules in their definition source

This commit is contained in:
Lukas Wirth 2021-06-28 16:41:35 +02:00
parent 1fa82adfdc
commit 34c28c1bbc
4 changed files with 79 additions and 5 deletions

View File

@ -59,7 +59,11 @@ fn highlight_references(
FilePosition { offset, file_id }: FilePosition,
) -> Option<Vec<HighlightedRange>> {
let def = references::find_def(sema, syntax, offset)?;
let usages = def.usages(sema).set_scope(Some(SearchScope::single_file(file_id))).all();
let usages = def
.usages(sema)
.set_scope(Some(SearchScope::single_file(file_id)))
.include_self_refs()
.all();
let declaration = match def {
Definition::ModuleDef(hir::ModuleDef::Module(module)) => {
@ -315,6 +319,7 @@ use self$0;
mod foo;
//- /foo.rs
use self$0;
// ^^^^
"#,
);
}

View File

@ -707,6 +707,7 @@ use self$0;
expect![[r#"
foo Module FileId(0) 0..8 4..7
FileId(1) 4..8
"#]],
);
}

View File

@ -934,12 +934,18 @@ mod outer { mod fo$0o; }
check(
"baz",
r#"
mod $0foo { pub fn bar() {} }
mod $0foo {
pub use self::bar as qux;
pub fn bar() {}
}
fn main() { foo::bar(); }
"#,
r#"
mod baz { pub fn bar() {} }
mod baz {
pub use self::bar as qux;
pub fn bar() {}
}
fn main() { baz::bar(); }
"#,

View File

@ -305,7 +305,13 @@ impl Definition {
}
pub fn usages<'a>(self, sema: &'a Semantics<RootDatabase>) -> FindUsages<'a> {
FindUsages { def: self, sema, scope: None, include_self_kw_refs: None }
FindUsages {
def: self,
sema,
scope: None,
include_self_kw_refs: None,
search_self_mod: false,
}
}
}
@ -314,12 +320,14 @@ pub struct FindUsages<'a> {
sema: &'a Semantics<'a, RootDatabase>,
scope: Option<SearchScope>,
include_self_kw_refs: Option<hir::Type>,
search_self_mod: bool,
}
impl<'a> FindUsages<'a> {
/// Enable searching for `Self` when the definition is a type.
/// Enable searching for `Self` when the definition is a type or `self` for modules.
pub fn include_self_refs(mut self) -> FindUsages<'a> {
self.include_self_kw_refs = def_to_ty(self.sema, &self.def);
self.search_self_mod = true;
self
}
@ -416,6 +424,41 @@ impl<'a> FindUsages<'a> {
}
}
}
// search for module `self` references in our module's definition source
match self.def {
Definition::ModuleDef(hir::ModuleDef::Module(module)) if self.search_self_mod => {
let src = module.definition_source(sema.db);
let file_id = src.file_id.original_file(sema.db);
let (file_id, search_range) = match src.value {
ModuleSource::Module(m) => (file_id, Some(m.syntax().text_range())),
ModuleSource::BlockExpr(b) => (file_id, Some(b.syntax().text_range())),
ModuleSource::SourceFile(_) => (file_id, None),
};
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;
}
if let Some(ast::NameLike::NameRef(name_ref)) =
sema.find_node_at_offset_with_descend(&tree, offset)
{
if self.found_self_module_name_ref(&name_ref, sink) {
return;
}
}
}
}
_ => {}
}
}
fn found_self_ty_name_ref(
@ -440,6 +483,25 @@ impl<'a> FindUsages<'a> {
}
}
fn found_self_module_name_ref(
&self,
name_ref: &ast::NameRef,
sink: &mut dyn FnMut(FileId, FileReference) -> bool,
) -> bool {
match NameRefClass::classify(self.sema, name_ref) {
Some(NameRefClass::Definition(def @ Definition::ModuleDef(_))) if def == self.def => {
let FileRange { file_id, range } = self.sema.original_range(name_ref.syntax());
let reference = FileReference {
range,
name: ast::NameLike::NameRef(name_ref.clone()),
access: None,
};
sink(file_id, reference)
}
_ => false,
}
}
fn found_lifetime(
&self,
lifetime: &ast::Lifetime,