mirror of
https://github.com/rust-lang/rust-analyzer
synced 2024-12-26 13:03:31 +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,
|
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));
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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());
|
||||||
|
|
||||||
|
|
|
@ -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))
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue