diff --git a/crates/ra_hir/src/nameres/collector.rs b/crates/ra_hir/src/nameres/collector.rs index 552a1b6d9ea4..7f765caf36ad 100644 --- a/crates/ra_hir/src/nameres/collector.rs +++ b/crates/ra_hir/src/nameres/collector.rs @@ -1,3 +1,5 @@ +use std::borrow::Cow; + use arrayvec::ArrayVec; use ra_db::FileId; use ra_syntax::{ast, SmolStr}; @@ -84,7 +86,7 @@ struct DefCollector { global_macro_scope: FxHashMap, /// Some macro use `$tt:tt which mean we have to handle the macro perfectly - /// To prevent stackoverflow, we add a deep counter here for prevent that. + /// To prevent stack overflow, we add a deep counter here for prevent that. macro_stack_monitor: MacroStackMonitor, } @@ -649,7 +651,8 @@ fn resolve_submodule( let file_dir_mod = dir_path.join(format!("{}/{}.rs", mod_name, name)); let mut candidates = ArrayVec::<[_; 3]>::new(); let file_attr_mod = attr_path.map(|file_path| { - let file_attr_mod = dir_path.join(file_path.to_string()); + let file_path = normalize_attribute_path(file_path); + let file_attr_mod = dir_path.join(file_path.as_ref()).normalize(); candidates.push(file_attr_mod.clone()); file_attr_mod @@ -675,6 +678,21 @@ fn resolve_submodule( } } +fn normalize_attribute_path(file_path: &SmolStr) -> Cow { + let current_dir = "./"; + let windows_path_separator = r#"\"#; + let current_dir_normalize = if file_path.starts_with(current_dir) { + &file_path[current_dir.len()..] + } else { + file_path.as_str() + }; + if current_dir_normalize.contains(windows_path_separator) { + Cow::Owned(current_dir_normalize.replace(windows_path_separator, "/")) + } else { + Cow::Borrowed(current_dir_normalize) + } +} + #[cfg(test)] mod tests { use ra_db::SourceDatabase; diff --git a/crates/ra_hir/src/nameres/tests/mods.rs b/crates/ra_hir/src/nameres/tests/mods.rs index 7c8c832fc178..d714a3276acb 100644 --- a/crates/ra_hir/src/nameres/tests/mods.rs +++ b/crates/ra_hir/src/nameres/tests/mods.rs @@ -80,15 +80,15 @@ fn module_resolution_works_for_raw_modules() { #[test] fn module_resolution_decl_path() { let map = def_map_with_crate_graph( - " + r###" //- /library.rs - #[path = \"bar/baz/foo.rs\"] + #[path = "bar/baz/foo.rs"] mod foo; use self::foo::Bar; //- /bar/baz/foo.rs pub struct Bar; - ", + "###, crate_graph! { "library": ("/library.rs", []), }, @@ -107,19 +107,19 @@ fn module_resolution_decl_path() { #[test] fn module_resolution_module_with_path_in_mod_rs() { let map = def_map_with_crate_graph( - " + r###" //- /main.rs mod foo; //- /foo/mod.rs - #[path = \"baz.rs\"] + #[path = "baz.rs"] pub mod bar; use self::bar::Baz; //- /foo/baz.rs pub struct Baz; - ", + "###, crate_graph! { "main": ("/main.rs", []), }, @@ -141,19 +141,19 @@ fn module_resolution_module_with_path_in_mod_rs() { #[test] fn module_resolution_module_with_path_non_crate_root() { let map = def_map_with_crate_graph( - " + r###" //- /main.rs mod foo; //- /foo.rs - #[path = \"baz.rs\"] + #[path = "baz.rs"] pub mod bar; use self::bar::Baz; //- /baz.rs pub struct Baz; - ", + "###, crate_graph! { "main": ("/main.rs", []), }, @@ -172,6 +172,511 @@ fn module_resolution_module_with_path_non_crate_root() { "###); } +#[test] +fn module_resolution_module_decl_path_super() { + let map = def_map_with_crate_graph( + r###" + //- /main.rs + #[path = "bar/baz/module.rs"] + mod foo; + pub struct Baz; + + //- /bar/baz/module.rs + use super::Baz; + "###, + crate_graph! { + "main": ("/main.rs", []), + }, + ); + + assert_snapshot_matches!(map, @r###" + ⋮crate + ⋮Baz: t v + ⋮foo: t + ⋮ + ⋮crate::foo + ⋮Baz: t v + "###); +} + +#[test] +fn module_resolution_explicit_path_mod_rs() { + let map = def_map_with_crate_graph( + r###" + //- /main.rs + #[path = "module/mod.rs"] + mod foo; + + //- /module/mod.rs + pub struct Baz; + "###, + crate_graph! { + "main": ("/main.rs", []), + }, + ); + + assert_snapshot_matches!(map, @r###" + ⋮crate + ⋮foo: t + ⋮ + ⋮crate::foo + ⋮Baz: t v + "###); +} + +#[test] +fn module_resolution_relative_path() { + let map = def_map_with_crate_graph( + r###" + //- /main.rs + mod foo; + + //- /foo.rs + #[path = "./sub.rs"] + pub mod foo_bar; + + //- /sub.rs + pub struct Baz; + "###, + crate_graph! { + "main": ("/main.rs", []), + }, + ); + + assert_snapshot_matches!(map, @r###" + ⋮crate + ⋮foo: t + ⋮ + ⋮crate::foo + ⋮foo_bar: t + ⋮ + ⋮crate::foo::foo_bar + ⋮Baz: t v + "###); +} + +#[test] +fn module_resolution_relative_path_2() { + let map = def_map_with_crate_graph( + r###" + //- /main.rs + mod foo; + + //- /foo/mod.rs + #[path="../sub.rs"] + pub mod foo_bar; + + //- /sub.rs + pub struct Baz; + "###, + crate_graph! { + "main": ("/main.rs", []), + }, + ); + + assert_snapshot_matches!(map, @r###" + ⋮crate + ⋮foo: t + ⋮ + ⋮crate::foo + ⋮foo_bar: t + ⋮ + ⋮crate::foo::foo_bar + ⋮Baz: t v + "###); +} + +#[test] +fn module_resolution_explicit_path_mod_rs_2() { + let map = def_map_with_crate_graph( + r###" + //- /main.rs + #[path = "module/bar/mod.rs"] + mod foo; + + //- /module/bar/mod.rs + pub struct Baz; + "###, + crate_graph! { + "main": ("/main.rs", []), + }, + ); + + assert_snapshot_matches!(map, @r###" + ⋮crate + ⋮foo: t + ⋮ + ⋮crate::foo + ⋮Baz: t v + "###); +} + +#[test] +fn module_resolution_explicit_path_mod_rs_with_win_separator() { + let map = def_map_with_crate_graph( + r###" + //- /main.rs + #[path = "module\bar\mod.rs"] + mod foo; + + //- /module/bar/mod.rs + pub struct Baz; + "###, + crate_graph! { + "main": ("/main.rs", []), + }, + ); + + assert_snapshot_matches!(map, @r###" + ⋮crate + ⋮foo: t + ⋮ + ⋮crate::foo + ⋮Baz: t v + "###); +} + +// FIXME: issue #1510. not support out-of-line modules inside inline. +#[test] +#[ignore] +fn module_resolution_decl_inside_inline_module() { + let map = def_map_with_crate_graph( + r###" + //- /main.rs + #[path = "models"] + mod foo { + mod bar; + } + + //- /models/bar.rs + pub struct Baz; + "###, + crate_graph! { + "main": ("/main.rs", []), + }, + ); + + assert_snapshot_matches!(map, @r###" + ⋮crate + ⋮foo: t + ⋮ + ⋮crate::foo + ⋮bar: t + ⋮ + ⋮crate::foo::bar + ⋮Baz: t v + "###); +} + +// FIXME: issue #1510. not support out-of-line modules inside inline. +#[test] +#[ignore] +fn module_resolution_decl_inside_inline_module_2() { + let map = def_map_with_crate_graph( + r###" + //- /main.rs + #[path = "models/db"] + mod foo { + mod bar; + } + + //- /models/db/bar.rs + pub struct Baz; + "###, + crate_graph! { + "main": ("/main.rs", []), + }, + ); + + assert_snapshot_matches!(map, @r###" + ⋮crate + ⋮foo: t + ⋮ + ⋮crate::foo + ⋮bar: t + ⋮ + ⋮crate::foo::bar + ⋮Baz: t v + "###); +} + +// FIXME: issue #1510. not support out-of-line modules inside inline. +#[test] +#[ignore] +fn module_resolution_decl_inside_inline_module_3() { + let map = def_map_with_crate_graph( + r###" + //- /main.rs + #[path = "models/db"] + mod foo { + #[path = "users.rs"] + mod bar; + } + + //- /models/db/users.rs + pub struct Baz; + "###, + crate_graph! { + "main": ("/main.rs", []), + }, + ); + + assert_snapshot_matches!(map, @r###" + ⋮crate + ⋮foo: t + ⋮ + ⋮crate::foo + ⋮bar: t + ⋮ + ⋮crate::foo::bar + ⋮Baz: t v + "###); +} + +// FIXME: issue #1510. not support out-of-line modules inside inline. +#[test] +#[ignore] +fn module_resolution_decl_inside_inline_module_empty_path() { + let map = def_map_with_crate_graph( + r###" + //- /main.rs + #[path = ""] + mod foo { + #[path = "users.rs"] + mod bar; + } + + //- /users.rs + pub struct Baz; + "###, + crate_graph! { + "main": ("/main.rs", []), + }, + ); + + assert_snapshot_matches!(map, @r###" + ⋮crate + ⋮foo: t + ⋮ + ⋮crate::foo + ⋮bar: t + ⋮ + ⋮crate::foo::bar + ⋮Baz: t v + "###); +} + +#[test] +fn module_resolution_decl_empty_path() { + let map = def_map_with_crate_graph( + r###" + //- /main.rs + #[path = ""] + mod foo; + + //- /foo.rs + pub struct Baz; + "###, + crate_graph! { + "main": ("/main.rs", []), + }, + ); + + assert_snapshot_matches!(map, @r###" + ⋮crate + ⋮foo: t + ⋮ + ⋮crate::foo + ⋮Baz: t v + "###); +} + +// FIXME: issue #1510. not support out-of-line modules inside inline. +#[test] +#[ignore] +fn module_resolution_decl_inside_inline_module_relative_path() { + let map = def_map_with_crate_graph( + r###" + //- /main.rs + #[path = "./models"] + mod foo { + mod bar; + } + + //- /models/bar.rs + pub struct Baz; + "###, + crate_graph! { + "main": ("/main.rs", []), + }, + ); + + assert_snapshot_matches!(map, @r###" + ⋮crate + ⋮foo: t + ⋮ + ⋮crate::foo + ⋮bar: t + ⋮ + ⋮crate::foo::bar + ⋮Baz: t v + "###); +} + +// FIXME: issue #1510. not support out-of-line modules inside inline. +#[test] +#[ignore] +fn module_resolution_decl_inside_inline_module_in_crate_root() { + let map = def_map_with_crate_graph( + r###" + //- /main.rs + mod foo { + #[path = "baz.rs"] + mod bar; + } + use self::foo::bar::Baz; + + //- /foo/baz.rs + pub struct Baz; + "###, + crate_graph! { + "main": ("/main.rs", []), + }, + ); + + assert_snapshot_matches!(map, @r###" + ⋮crate + ⋮Baz: t v + ⋮foo: t + ⋮ + ⋮crate::foo + ⋮bar: t + ⋮ + ⋮crate::foo::bar + ⋮Baz: t v + "###); +} + +// FIXME: issue #1510. not support out-of-line modules inside inline. +#[test] +#[ignore] +fn module_resolution_decl_inside_inline_module_in_mod_rs() { + let map = def_map_with_crate_graph( + r###" + //- /main.rs + mod foo; + + //- /foo/mod.rs + mod bar { + #[path = "qwe.rs"] + pub mod baz; + } + use self::bar::baz::Baz; + + //- /foo/bar/qwe.rs + pub struct Baz; + "###, + crate_graph! { + "main": ("/main.rs", []), + }, + ); + + assert_snapshot_matches!(map, @r###" + ⋮crate + ⋮foo: t + ⋮ + ⋮crate::foo + ⋮Baz: t v + ⋮bar: t + ⋮ + ⋮crate::foo::bar + ⋮baz: t + ⋮ + ⋮crate::foo::bar::baz + ⋮Baz: t v + "###); +} + +// FIXME: issue #1510. not support out-of-line modules inside inline. +#[test] +#[ignore] +fn module_resolution_decl_inside_inline_module_in_non_crate_root() { + let map = def_map_with_crate_graph( + r###" + //- /main.rs + mod foo; + + //- /foo.rs + mod bar { + #[path = "qwe.rs"] + pub mod baz; + } + use self::bar::baz::Baz; + + //- /foo/bar/qwe.rs + pub struct Baz; + "###, + crate_graph! { + "main": ("/main.rs", []), + }, + ); + + assert_snapshot_matches!(map, @r###" + ⋮crate + ⋮foo: t + ⋮ + ⋮crate::foo + ⋮Baz: t v + ⋮bar: t + ⋮ + ⋮crate::foo::bar + ⋮baz: t + ⋮ + ⋮crate::foo::bar::baz + ⋮Baz: t v + "###); +} + +// FIXME: issue #1510. not support out-of-line modules inside inline. +#[test] +#[ignore] +fn module_resolution_decl_inside_inline_module_in_non_crate_root_2() { + let map = def_map_with_crate_graph( + r###" + //- /main.rs + mod foo; + + //- /foo.rs + #[path = "bar"] + mod bar { + pub mod baz; + } + use self::bar::baz::Baz; + + //- /bar/baz.rs + pub struct Baz; + "###, + crate_graph! { + "main": ("/main.rs", []), + }, + ); + + assert_snapshot_matches!(map, @r###" + ⋮crate + ⋮foo: t + ⋮ + ⋮crate::foo + ⋮Baz: t v + ⋮bar: t + ⋮ + ⋮crate::foo::bar + ⋮baz: t + ⋮ + ⋮crate::foo::bar::baz + ⋮Baz: t v + "###); +} + #[test] fn unresolved_module_diagnostics() { let diagnostics = MockDatabase::with_files(