8549: Fix `TestDB::module_at_position` with submodules r=jonas-schievink a=jonas-schievink

Found while looking into https://github.com/rust-analyzer/rust-analyzer/issues/8519

bors r+

Co-authored-by: Jonas Schievink <jonasschievink@gmail.com>
This commit is contained in:
bors[bot] 2021-04-17 01:35:22 +00:00 committed by GitHub
commit df5b6f7d45
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 72 additions and 2 deletions

View File

@ -954,6 +954,29 @@ fn main() {
)
}
#[test]
fn from_inside_module() {
// This worked correctly, but the test suite logic was broken.
cov_mark::check!(submodule_in_testdb);
check_found_path(
r#"
mod baz {
pub struct Foo {}
}
mod bar {
fn bar() {
$0
}
}
"#,
"crate::baz::Foo",
"crate::baz::Foo",
"crate::baz::Foo",
"crate::baz::Foo",
)
}
#[test]
fn recursive_pub_mod_reexport() {
cov_mark::check!(recursive_imports);

View File

@ -15,7 +15,12 @@ use rustc_hash::FxHashSet;
use syntax::{algo, ast, AstNode, TextRange, TextSize};
use test_utils::extract_annotations;
use crate::{db::DefDatabase, nameres::DefMap, src::HasSource, Lookup, ModuleDefId, ModuleId};
use crate::{
db::DefDatabase,
nameres::{DefMap, ModuleSource},
src::HasSource,
LocalModuleId, Lookup, ModuleDefId, ModuleId,
};
#[salsa::database(
base_db::SourceDatabaseExtStorage,
@ -87,10 +92,11 @@ impl TestDB {
pub(crate) fn module_at_position(&self, position: FilePosition) -> ModuleId {
let file_module = self.module_for_file(position.file_id);
let mut def_map = file_module.def_map(self);
let module = self.mod_at_position(&def_map, position);
def_map = match self.block_at_position(&def_map, position) {
Some(it) => it,
None => return file_module,
None => return def_map.module_id(module),
};
loop {
let new_map = self.block_at_position(&def_map, position);
@ -106,6 +112,47 @@ impl TestDB {
}
}
/// Finds the smallest/innermost module in `def_map` containing `position`.
fn mod_at_position(&self, def_map: &DefMap, position: FilePosition) -> LocalModuleId {
let mut size = None;
let mut res = def_map.root();
for (module, data) in def_map.modules() {
let src = data.definition_source(self);
if src.file_id != position.file_id.into() {
continue;
}
let range = match src.value {
ModuleSource::SourceFile(it) => it.syntax().text_range(),
ModuleSource::Module(it) => it.syntax().text_range(),
ModuleSource::BlockExpr(it) => it.syntax().text_range(),
};
if !range.contains(position.offset) {
continue;
}
let new_size = match size {
None => range.len(),
Some(size) => {
if range.len() < size {
range.len()
} else {
size
}
}
};
if size != Some(new_size) {
cov_mark::hit!(submodule_in_testdb);
size = Some(new_size);
res = module;
}
}
res
}
fn block_at_position(&self, def_map: &DefMap, position: FilePosition) -> Option<Arc<DefMap>> {
// Find the smallest (innermost) function in `def_map` containing the cursor.
let mut size = None;