Repository: rust-analyzer/rust-analyzer (rust)

Issue:
Using path attribute causes false "unresolved module" error for submodules
main.rs
```
#[path="module/module.rs"]
mod module;

fn main() {
    let _ = module::submod::SubModStruct{};
}
```

module/module.rs
`pub mod submod;`

modules/submod.rs
`pub struct SubModStruct {}`

```
{
	"resource": "/home/hegemon/programming/rust/rapath/src/module/module.rs",
	"owner": "_generated_diagnostic_collection_name_#0",
	"severity": 8,
	"message": "unresolved module",
	"source": "rust-analyzer",
	"startLineNumber": 1,
	"startColumn": 1,
	"endLineNumber": 1,
	"endColumn": 16
}
```


Pull request:
Fix path attribute causing false "unresolved module" error for submodules
fixed #1880

Patch:
diff --git a/crates/ra_hir/src/nameres/collector.rs b/crates/ra_hir/src/nameres/collector.rs
index a6b9b41d02..6b253ac409 100644
--- a/crates/ra_hir/src/nameres/collector.rs
+++ b/crates/ra_hir/src/nameres/collector.rs
@@ -1,5 +1,5 @@
 use ra_db::FileId;
-use ra_syntax::ast;
+use ra_syntax::{ast, SmolStr};
 use rustc_hash::FxHashMap;
 use test_utils::tested_by;
 
@@ -98,6 +98,7 @@ where
         self.def_map.modules[module_id].definition = Some(file_id);
         ModCollector {
             def_collector: &mut *self,
+            attr_path: None,
             module_id,
             file_id: file_id.into(),
             raw_items: &raw_items,
@@ -474,6 +475,7 @@ where
             ModCollector {
                 def_collector: &mut *self,
                 file_id,
+                attr_path: None,
                 module_id,
                 raw_items: &raw_items,
                 parent_module: None,
@@ -497,6 +499,7 @@ struct ModCollector<'a, D> {
     def_collector: D,
     module_id: CrateModuleId,
     file_id: HirFileId,
+    attr_path: Option<&'a SmolStr>,
     raw_items: &'a raw::RawItems,
     parent_module: Option<ParentModule<'a>>,
 }
@@ -551,6 +554,7 @@ where
                 ModCollector {
                     def_collector: &mut *self.def_collector,
                     module_id,
+                    attr_path: attr_path.as_ref(),
                     file_id: self.file_id,
                     raw_items: self.raw_items,
                     parent_module: Some(parent_module),
@@ -567,6 +571,7 @@ where
                 match resolve_submodule(
                     self.def_collector.db,
                     self.file_id,
+                    self.attr_path,
                     name,
                     is_root,
                     attr_path.as_ref(),
@@ -578,6 +583,7 @@ where
                         ModCollector {
                             def_collector: &mut *self.def_collector,
                             module_id,
+                            attr_path: attr_path.as_ref(),
                             file_id: file_id.into(),
                             raw_items: &raw_items,
                             parent_module: None,
diff --git a/crates/ra_hir/src/nameres/mod_resolution.rs b/crates/ra_hir/src/nameres/mod_resolution.rs
index a9e9eb9e65..3aa32bd66c 100644
--- a/crates/ra_hir/src/nameres/mod_resolution.rs
+++ b/crates/ra_hir/src/nameres/mod_resolution.rs
@@ -23,6 +23,7 @@ impl<'a> ParentModule<'a> {
 pub(super) fn resolve_submodule(
     db: &impl DefDatabase,
     file_id: HirFileId,
+    mod_attr_path: Option<&SmolStr>,
     name: &Name,
     is_root: bool,
     attr_path: Option<&SmolStr>,
@@ -80,7 +81,7 @@ pub(super) fn resolve_submodule(
             ResolutionMode::OutOfLine(OutOfLineMode::WithAttributePath(path))
         }
         (None, None) => {
-            let is_dir_owner = is_root || mod_name == "mod";
+            let is_dir_owner = is_root || mod_name == "mod" || mod_attr_path.is_some();
             if is_dir_owner {
                 let file_mod = dir_path.join(format!("{}.rs", name));
                 let dir_mod = dir_path.join(format!("{}/mod.rs", name));
diff --git a/crates/ra_parser/src/grammar/items/use_item.rs b/crates/ra_parser/src/grammar/items/use_item.rs
index 63ac37e9e1..2af2ad3157 100644
--- a/crates/ra_parser/src/grammar/items/use_item.rs
+++ b/crates/ra_parser/src/grammar/items/use_item.rs
@@ -3,7 +3,7 @@ use super::*;
 pub(super) fn use_item(p: &mut Parser, m: Marker) {
     assert!(p.at(T![use]));
     p.bump(T![use]);
-    use_tree(p, true);
+    use_tree(p);
     p.expect(T![;]);
     m.complete(p, USE_ITEM);
 }
@@ -12,7 +12,7 @@ pub(super) fn use_item(p: &mut Parser, m: Marker) {
 /// Note that this is called both by `use_item` and `use_tree_list`,
 /// so handles both `some::path::{inner::path}` and `inner::path` in
 /// `use some::path::{inner::path};`
-fn use_tree(p: &mut Parser, top_level: bool) {
+fn use_tree(p: &mut Parser) {
     let m = p.start();
     match p.current() {
         // Finish the use_tree for cases of e.g.
@@ -101,14 +101,10 @@ fn use_tree(p: &mut Parser, top_level: bool) {
         }
         _ => {
             m.abandon(p);
-            let msg = "expected one of `*`, `::`, `{`, `self`, `super` or an identifier";
-            if top_level {
-                p.err_recover(msg, ITEM_RECOVERY_SET);
-            } else {
-                // if we are parsing a nested tree, we have to eat a token to
-                // main balanced `{}`
-                p.err_and_bump(msg);
-            }
+            p.err_recover(
+                "expected one of `*`, `::`, `{`, `self`, `super` or an identifier",
+                ITEM_RECOVERY_SET,
+            );
             return;
         }
     }
@@ -120,7 +116,7 @@ pub(crate) fn use_tree_list(p: &mut Parser) {
     let m = p.start();
     p.bump(T!['{']);
     while !p.at(EOF) && !p.at(T!['}']) {
-        use_tree(p, false);
+        use_tree(p);
         if !p.at(T!['}']) {
             p.expect(T![,]);
         }
diff --git a/crates/ra_parser/src/grammar/types.rs b/crates/ra_parser/src/grammar/types.rs
index 4e3522d487..bd3829f418 100644
--- a/crates/ra_parser/src/grammar/types.rs
+++ b/crates/ra_parser/src/grammar/types.rs
@@ -256,7 +256,7 @@ fn path_or_macro_type_(p: &mut Parser, allow_bounds: bool) {
     let m = p.start();
     paths::type_path(p);
 
-    let kind = if p.at(T![!]) && !p.at(T![!=]) {
+    let kind = if p.at(T![!]) {
         items::macro_call_after_excl(p);
         MACRO_CALL
     } else {


Test patch:
diff --git a/crates/ra_hir/src/nameres/tests/mod_resolution.rs b/crates/ra_hir/src/nameres/tests/mod_resolution.rs
index 4f8398460d..e3e6f1e959 100644
--- a/crates/ra_hir/src/nameres/tests/mod_resolution.rs
+++ b/crates/ra_hir/src/nameres/tests/mod_resolution.rs
@@ -706,3 +706,34 @@ fn unresolved_module_diagnostics() {
     "###
     );
 }
+
+#[test]
+fn module_resolution_decl_inside_module_in_non_crate_root_2() {
+    let map = def_map_with_crate_graph(
+        r###"
+        //- /main.rs
+        #[path="module/m2.rs"]
+        mod module;
+
+        //- /module/m2.rs
+        pub mod submod;
+
+        //- /module/submod.rs
+        pub struct Baz;
+        "###,
+        crate_graph! {
+            "main": ("/main.rs", []),
+        },
+    );
+
+    assert_snapshot!(map, @r###"
+        ⋮crate
+        ⋮module: t
+        ⋮
+        ⋮crate::module
+        ⋮submod: t
+        ⋮
+        ⋮crate::module::submod
+        ⋮Baz: t v
+    "###);
+}
diff --git a/crates/ra_syntax/test_data/parser/err/0036_partial_use.rs b/crates/ra_syntax/test_data/parser/err/0036_partial_use.rs
deleted file mode 100644
index d521a5bb2d..0000000000
--- a/crates/ra_syntax/test_data/parser/err/0036_partial_use.rs
+++ /dev/null
@@ -1,2 +0,0 @@
-use std::{error::Error;
-use std::io;
diff --git a/crates/ra_syntax/test_data/parser/err/0036_partial_use.txt b/crates/ra_syntax/test_data/parser/err/0036_partial_use.txt
deleted file mode 100644
index 181f408c87..0000000000
--- a/crates/ra_syntax/test_data/parser/err/0036_partial_use.txt
+++ /dev/null
@@ -1,51 +0,0 @@
-SOURCE_FILE@[0; 37)
-  USE_ITEM@[0; 36)
-    USE_KW@[0; 3) "use"
-    WHITESPACE@[3; 4) " "
-    USE_TREE@[4; 36)
-      PATH@[4; 7)
-        PATH_SEGMENT@[4; 7)
-          NAME_REF@[4; 7)
-            IDENT@[4; 7) "std"
-      COLONCOLON@[7; 9) "::"
-      USE_TREE_LIST@[9; 36)
-        L_CURLY@[9; 10) "{"
-        USE_TREE@[10; 22)
-          PATH@[10; 22)
-            PATH@[10; 15)
-              PATH_SEGMENT@[10; 15)
-                NAME_REF@[10; 15)
-                  IDENT@[10; 15) "error"
-            COLONCOLON@[15; 17) "::"
-            PATH_SEGMENT@[17; 22)
-              NAME_REF@[17; 22)
-                IDENT@[17; 22) "Error"
-        ERROR@[22; 23)
-          SEMI@[22; 23) ";"
-        WHITESPACE@[23; 24) "\n"
-        ERROR@[24; 27)
-          USE_KW@[24; 27) "use"
-        WHITESPACE@[27; 28) " "
-        USE_TREE@[28; 35)
-          PATH@[28; 35)
-            PATH@[28; 31)
-              PATH_SEGMENT@[28; 31)
-                NAME_REF@[28; 31)
-                  IDENT@[28; 31) "std"
-            COLONCOLON@[31; 33) "::"
-            PATH_SEGMENT@[33; 35)
-              NAME_REF@[33; 35)
-                IDENT@[33; 35) "io"
-        ERROR@[35; 36)
-          SEMI@[35; 36) ";"
-  WHITESPACE@[36; 37) "\n"
-error 22: expected COMMA
-error 22: expected one of `*`, `::`, `{`, `self`, `super` or an identifier
-error 23: expected COMMA
-error 24: expected one of `*`, `::`, `{`, `self`, `super` or an identifier
-error 27: expected COMMA
-error 35: expected COMMA
-error 35: expected one of `*`, `::`, `{`, `self`, `super` or an identifier
-error 36: expected COMMA
-error 36: expected R_CURLY
-error 36: expected SEMI
diff --git a/crates/ra_syntax/test_data/parser/ok/0056_neq_in_type.rs b/crates/ra_syntax/test_data/parser/ok/0056_neq_in_type.rs
deleted file mode 100644
index 6210683cea..0000000000
--- a/crates/ra_syntax/test_data/parser/ok/0056_neq_in_type.rs
+++ /dev/null
@@ -1,3 +0,0 @@
-fn main() {
-    if 1.0f32.floor() as i64 != 1.0f32.floor() as i64 {}
-}
diff --git a/crates/ra_syntax/test_data/parser/ok/0056_neq_in_type.txt b/crates/ra_syntax/test_data/parser/ok/0056_neq_in_type.txt
deleted file mode 100644
index 4a4ad84cab..0000000000
--- a/crates/ra_syntax/test_data/parser/ok/0056_neq_in_type.txt
+++ /dev/null
@@ -1,66 +0,0 @@
-SOURCE_FILE@[0; 71)
-  FN_DEF@[0; 70)
-    FN_KW@[0; 2) "fn"
-    WHITESPACE@[2; 3) " "
-    NAME@[3; 7)
-      IDENT@[3; 7) "main"
-    PARAM_LIST@[7; 9)
-      L_PAREN@[7; 8) "("
-      R_PAREN@[8; 9) ")"
-    WHITESPACE@[9; 10) " "
-    BLOCK_EXPR@[10; 70)
-      BLOCK@[10; 70)
-        L_CURLY@[10; 11) "{"
-        WHITESPACE@[11; 16) "\n    "
-        IF_EXPR@[16; 68)
-          IF_KW@[16; 18) "if"
-          WHITESPACE@[18; 19) " "
-          CONDITION@[19; 65)
-            BIN_EXPR@[19; 65)
-              CAST_EXPR@[19; 40)
-                METHOD_CALL_EXPR@[19; 33)
-                  LITERAL@[19; 25)
-                    FLOAT_NUMBER@[19; 25) "1.0f32"
-                  DOT@[25; 26) "."
-                  NAME_REF@[26; 31)
-                    IDENT@[26; 31) "floor"
-                  ARG_LIST@[31; 33)
-                    L_PAREN@[31; 32) "("
-                    R_PAREN@[32; 33) ")"
-                WHITESPACE@[33; 34) " "
-                AS_KW@[34; 36) "as"
-                WHITESPACE@[36; 37) " "
-                PATH_TYPE@[37; 40)
-                  PATH@[37; 40)
-                    PATH_SEGMENT@[37; 40)
-                      NAME_REF@[37; 40)
-                        IDENT@[37; 40) "i64"
-              WHITESPACE@[40; 41) " "
-              NEQ@[41; 43) "!="
-              WHITESPACE@[43; 44) " "
-              CAST_EXPR@[44; 65)
-                METHOD_CALL_EXPR@[44; 58)
-                  LITERAL@[44; 50)
-                    FLOAT_NUMBER@[44; 50) "1.0f32"
-                  DOT@[50; 51) "."
-                  NAME_REF@[51; 56)
-                    IDENT@[51; 56) "floor"
-                  ARG_LIST@[56; 58)
-                    L_PAREN@[56; 57) "("
-                    R_PAREN@[57; 58) ")"
-                WHITESPACE@[58; 59) " "
-                AS_KW@[59; 61) "as"
-                WHITESPACE@[61; 62) " "
-                PATH_TYPE@[62; 65)
-                  PATH@[62; 65)
-                    PATH_SEGMENT@[62; 65)
-                      NAME_REF@[62; 65)
-                        IDENT@[62; 65) "i64"
-          WHITESPACE@[65; 66) " "
-          BLOCK_EXPR@[66; 68)
-            BLOCK@[66; 68)
-              L_CURLY@[66; 67) "{"
-              R_CURLY@[67; 68) "}"
-        WHITESPACE@[68; 69) "\n"
-        R_CURLY@[69; 70) "}"
-  WHITESPACE@[70; 71) "\n"