diff --git a/crates/ra_hir/src/module_tree.rs b/crates/ra_hir/src/module_tree.rs index d1dc3fa4b7..893c375b55 100644 --- a/crates/ra_hir/src/module_tree.rs +++ b/crates/ra_hir/src/module_tree.rs @@ -172,6 +172,7 @@ impl ModuleTree { file_id: HirFileId, decl_id: Option, ) -> ModuleId { + let is_root = parent.is_none(); let id = self.alloc_mod(ModuleData { file_id, decl_id, @@ -191,7 +192,7 @@ impl ModuleTree { }); 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 .into_iter() .map(|file_id| { @@ -295,6 +296,7 @@ fn resolve_submodule( db: &impl HirDatabase, file_id: HirFileId, name: &Name, + is_root: bool, ) -> (Vec, Option) { // FIXME: handle submodules of inline modules properly let file_id = file_id.original_file(db); @@ -303,7 +305,7 @@ fn resolve_submodule( let root = RelativePathBuf::default(); let dir_path = path.parent().unwrap_or(&root); 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 dir_mod = dir_path.join(format!("{}/mod.rs", name)); diff --git a/crates/ra_hir/src/nameres/tests.rs b/crates/ra_hir/src/nameres/tests.rs index e72781f512..3d420467c1 100644 --- a/crates/ra_hir/src/nameres/tests.rs +++ b/crates/ra_hir/src/nameres/tests.rs @@ -19,6 +19,20 @@ fn item_map(fixture: &str) -> (Arc, ModuleId) { (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, 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) { let mut lines = map[module_id] .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] fn name_res_works_for_broken_modules() { covers!(name_res_works_for_broken_modules); diff --git a/crates/ra_ide_api/tests/test/main.rs b/crates/ra_ide_api/tests/test/main.rs index 7560751909..c2cb38f7e9 100644 --- a/crates/ra_ide_api/tests/test/main.rs +++ b/crates/ra_ide_api/tests/test/main.rs @@ -1,9 +1,9 @@ +use insta::assert_debug_snapshot_matches; use ra_ide_api::{ - AnalysisChange, - CrateGraph, FileId, mock_analysis::{MockAnalysis, single_file, single_file_with_position}, Query, + mock_analysis::{single_file, single_file_with_position, MockAnalysis}, + AnalysisChange, CrateGraph, FileId, Query, }; use ra_syntax::TextRange; -use insta::assert_debug_snapshot_matches; #[test] fn test_unresolved_module_diagnostic() { @@ -26,12 +26,12 @@ fn test_resolve_crate_root() { " //- /bar.rs mod foo; - //- /bar/foo.rs - // emtpy <|> + //- /foo.rs + // empty <|> ", ); 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(); assert!(host.analysis().crate_for(mod_file).unwrap().is_empty()); diff --git a/crates/ra_syntax/src/algo.rs b/crates/ra_syntax/src/algo.rs index 45747e21d4..99b0983b0d 100644 --- a/crates/ra_syntax/src/algo.rs +++ b/crates/ra_syntax/src/algo.rs @@ -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 -/// 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 /// /// ```no-run /// 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(syntax: &SyntaxNode, offset: TextUnit) -> Option<&N> { find_leaf_at_offset(syntax, offset).find_map(|leaf| leaf.ancestors().find_map(N::cast)) }