690: Fix module resolution for non standard filenames r=matklad a=regiontog

fixes #668

Co-authored-by: Erlend Tobiassen <erlend.tobiassen@gmail.com>
This commit is contained in:
bors[bot] 2019-01-27 15:55:47 +00:00
commit 3f4f50baaa
4 changed files with 48 additions and 10 deletions

View file

@ -172,6 +172,7 @@ impl ModuleTree {
file_id: HirFileId, file_id: HirFileId,
decl_id: Option<SourceFileItemId>, decl_id: Option<SourceFileItemId>,
) -> ModuleId { ) -> ModuleId {
let is_root = parent.is_none();
let id = self.alloc_mod(ModuleData { let id = self.alloc_mod(ModuleData {
file_id, file_id,
decl_id, decl_id,
@ -191,7 +192,7 @@ impl ModuleTree {
}); });
let (points_to, problem) = if sub.is_declaration { let (points_to, problem) = if sub.is_declaration {
let (points_to, problem) = resolve_submodule(db, file_id, &sub.name); let (points_to, problem) = resolve_submodule(db, file_id, &sub.name, is_root);
let points_to = points_to let points_to = points_to
.into_iter() .into_iter()
.map(|file_id| { .map(|file_id| {
@ -295,6 +296,7 @@ fn resolve_submodule(
db: &impl HirDatabase, db: &impl HirDatabase,
file_id: HirFileId, file_id: HirFileId,
name: &Name, name: &Name,
is_root: bool,
) -> (Vec<FileId>, Option<Problem>) { ) -> (Vec<FileId>, Option<Problem>) {
// FIXME: handle submodules of inline modules properly // FIXME: handle submodules of inline modules properly
let file_id = file_id.original_file(db); let file_id = file_id.original_file(db);
@ -303,7 +305,7 @@ fn resolve_submodule(
let root = RelativePathBuf::default(); let root = RelativePathBuf::default();
let dir_path = path.parent().unwrap_or(&root); let dir_path = path.parent().unwrap_or(&root);
let mod_name = path.file_stem().unwrap_or("unknown"); let mod_name = path.file_stem().unwrap_or("unknown");
let is_dir_owner = mod_name == "mod" || mod_name == "lib" || mod_name == "main"; let is_dir_owner = is_root || mod_name == "mod";
let file_mod = dir_path.join(format!("{}.rs", name)); let file_mod = dir_path.join(format!("{}.rs", name));
let dir_mod = dir_path.join(format!("{}/mod.rs", name)); let dir_mod = dir_path.join(format!("{}/mod.rs", name));

View file

@ -19,6 +19,20 @@ fn item_map(fixture: &str) -> (Arc<ItemMap>, ModuleId) {
(db.item_map(krate.crate_id), module_id) (db.item_map(krate.crate_id), module_id)
} }
/// Sets the crate root to the file of the cursor marker
fn item_map_custom_crate_root(fixture: &str) -> (Arc<ItemMap>, ModuleId) {
let (mut db, pos) = MockDatabase::with_position(fixture);
let mut crate_graph = CrateGraph::default();
crate_graph.add_crate_root(pos.file_id);
db.set_crate_graph(Arc::new(crate_graph));
let module = crate::source_binder::module_from_position(&db, pos).unwrap();
let krate = module.krate(&db).unwrap();
let module_id = module.module_id;
(db.item_map(krate.crate_id), module_id)
}
fn check_module_item_map(map: &ItemMap, module_id: ModuleId, expected: &str) { fn check_module_item_map(map: &ItemMap, module_id: ModuleId, expected: &str) {
let mut lines = map[module_id] let mut lines = map[module_id]
.items .items
@ -133,6 +147,28 @@ fn re_exports() {
); );
} }
#[test]
fn module_resolution_works_for_non_standard_filenames() {
let (item_map, module_id) = item_map_custom_crate_root(
"
//- /my_library.rs
mod foo;
use self::foo::Bar;
<|>
//- /foo/mod.rs
pub struct Bar;
",
);
check_module_item_map(
&item_map,
module_id,
"
Bar: t v
foo: t
",
);
}
#[test] #[test]
fn name_res_works_for_broken_modules() { fn name_res_works_for_broken_modules() {
covers!(name_res_works_for_broken_modules); covers!(name_res_works_for_broken_modules);

View file

@ -1,9 +1,9 @@
use insta::assert_debug_snapshot_matches;
use ra_ide_api::{ use ra_ide_api::{
AnalysisChange, mock_analysis::{single_file, single_file_with_position, MockAnalysis},
CrateGraph, FileId, mock_analysis::{MockAnalysis, single_file, single_file_with_position}, Query, AnalysisChange, CrateGraph, FileId, Query,
}; };
use ra_syntax::TextRange; use ra_syntax::TextRange;
use insta::assert_debug_snapshot_matches;
#[test] #[test]
fn test_unresolved_module_diagnostic() { fn test_unresolved_module_diagnostic() {
@ -26,12 +26,12 @@ fn test_resolve_crate_root() {
" "
//- /bar.rs //- /bar.rs
mod foo; mod foo;
//- /bar/foo.rs //- /foo.rs
// emtpy <|> // empty <|>
", ",
); );
let root_file = mock.id_of("/bar.rs"); let root_file = mock.id_of("/bar.rs");
let mod_file = mock.id_of("/bar/foo.rs"); let mod_file = mock.id_of("/foo.rs");
let mut host = mock.analysis_host(); let mut host = mock.analysis_host();
assert!(host.analysis().crate_for(mod_file).unwrap().is_empty()); assert!(host.analysis().crate_for(mod_file).unwrap().is_empty());

View file

@ -17,14 +17,14 @@ pub fn find_leaf_at_offset(node: &SyntaxNode, offset: TextUnit) -> LeafAtOffset<
} }
/// Finds a node of specific Ast type at offset. Note that this is slightly /// Finds a node of specific Ast type at offset. Note that this is slightly
/// impercise: if the cursor is strictly betwen two nodes of the desired type, /// imprecise: if the cursor is strictly between two nodes of the desired type,
/// as in /// as in
/// ///
/// ```no-run /// ```no-run
/// struct Foo {}|struct Bar; /// struct Foo {}|struct Bar;
/// ``` /// ```
/// ///
/// then the left node will be silently prefered. /// then the left node will be silently preferred.
pub fn find_node_at_offset<N: AstNode>(syntax: &SyntaxNode, offset: TextUnit) -> Option<&N> { pub fn find_node_at_offset<N: AstNode>(syntax: &SyntaxNode, offset: TextUnit) -> Option<&N> {
find_leaf_at_offset(syntax, offset).find_map(|leaf| leaf.ancestors().find_map(N::cast)) find_leaf_at_offset(syntax, offset).find_map(|leaf| leaf.ancestors().find_map(N::cast))
} }