Repository: rust-analyzer/rust-analyzer
Pull request #1528 (2019-07-13 18:27:00)

More resolution modules with attribute path
#1211


Patch:
diff --git a/crates/ra_hir/src/nameres/collector.rs b/crates/ra_hir/src/nameres/collector.rs
index 552a1b6d9e..7f765caf36 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<DB> {
     global_macro_scope: FxHashMap<Name, MacroDefId>,
 
     /// 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<str> {
+    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;


Test patch:
diff --git a/crates/ra_hir/src/nameres/tests/mods.rs b/crates/ra_hir/src/nameres/tests/mods.rs
index 7c8c832fc1..d714a3276a 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(