mirror of
https://github.com/rust-lang/rust-analyzer
synced 2024-12-26 04:53:34 +00:00
Merge #690
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:
commit
3f4f50baaa
4 changed files with 48 additions and 10 deletions
|
@ -172,6 +172,7 @@ impl ModuleTree {
|
|||
file_id: HirFileId,
|
||||
decl_id: Option<SourceFileItemId>,
|
||||
) -> 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<FileId>, Option<Problem>) {
|
||||
// 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));
|
||||
|
|
|
@ -19,6 +19,20 @@ fn item_map(fixture: &str) -> (Arc<ItemMap>, 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<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) {
|
||||
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);
|
||||
|
|
|
@ -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());
|
||||
|
||||
|
|
|
@ -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<N: AstNode>(syntax: &SyntaxNode, offset: TextUnit) -> Option<&N> {
|
||||
find_leaf_at_offset(syntax, offset).find_map(|leaf| leaf.ancestors().find_map(N::cast))
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue