Repository: rust-lang/rustfmt (Rust)

Issue:
fmt does not find modules inside inline modules inside non-inline modules
**Problem**
`cargo fmt` does not processes modules that are referenced in an inline mod in a non-inline mod.

This is slightly more complex case than https://github.com/rust-lang/rustfmt/issues/4874, so it seems that bug was not fully fixed.

**Steps**

crate tree:
```
.
├── Cargo.toml
└── src
    ├── foo
    │   └── bar
    │       └── baz.rs
    ├── foo.rs
    └── main.rs
```

`src/main.rs`:
```rust
fn main() {
    println!("Hello, world!");
}

mod foo;
```

`src/foo.rs`:
```rust
mod bar {
    mod baz;
}
```

`src/foo/bar/baz.rs`: empty

1.52.0 is fine:
```
> cargo +1.52.0 fmt -- -v
Formatting /home/jan/x/src/foo/bar/baz.rs
Formatting /home/jan/x/src/foo.rs
Formatting /home/jan/x/src/main.rs
```

1.53.0, stable and nightly are broken:
```
> cargo +1.53.0 fmt -- -v
Formatting /home/jan/x/src/foo.rs
Formatting /home/jan/x/src/main.rs

> cargo +stable fmt -- -v
Formatting /home/jan/x/src/foo.rs
Formatting /home/jan/x/src/main.rs

> cargo +nightly fmt -- -v
Formatting /home/jan/x/src/foo.rs
Formatting /home/jan/x/src/main.rs
```

**Notes**

Output of `rustfmt --version`:
- 1.52.0: `rustfmt 1.4.36-stable (7de6968 2021-02-07)`
- 1.53.0: `rustfmt 1.4.37-stable (2a3635d 2021-05-04)`
- stable: `rustfmt 1.4.37-stable (59eed8a 2021-11-01)`
- nightly: `rustfmt 1.4.38-nightly (baba668 2021-11-03)`

Rust via rustup 1.24.3, Arch Linux.


Discussion:
Thanks for the report @heftig and the repro case! Believe I know what the issue is so I'll take a look later today after work.

I still suspect we could handle our mod/file resolution process a bit more simply, but can never seem to find the time for investigating a more holistic refactor. Will make sure the fix for this gets pulled into the next sync though
 



Patch:
diff --git a/src/modules.rs b/src/modules.rs
index 9e75f41ae36..b1f229d9daa 100644
--- a/src/modules.rs
+++ b/src/modules.rs
@@ -321,7 +321,9 @@ impl<'ast, 'sess, 'c> ModResolver<'ast, 'sess> {
             (Some(Cow::Borrowed(ast::ModKind::Loaded(items, _, _))), _) => {
                 self.visit_mod_from_ast(items)
             }
-            (Some(Cow::Owned(..)), Cow::Owned(items)) => self.visit_mod_outside_ast(items),
+            (Some(Cow::Owned(ast::ModKind::Loaded(items, _, _))), _) | (_, Cow::Owned(items)) => {
+                self.visit_mod_outside_ast(items)
+            }
             (_, _) => Ok(()),
         }
     }


Test patch:
diff --git a/src/test/mod_resolver.rs b/src/test/mod_resolver.rs
index e0b55e3efb2..ae4a0d0fccb 100644
--- a/src/test/mod_resolver.rs
+++ b/src/test/mod_resolver.rs
@@ -5,21 +5,39 @@ use super::read_config;
 
 use crate::{FileName, Input, Session};
 
-#[test]
-fn nested_out_of_line_mods_loaded() {
-    // See also https://github.com/rust-lang/rustfmt/issues/4874
-    let filename = "tests/mod-resolver/issue-4874/main.rs";
-    let input_file = PathBuf::from(filename);
+fn verify_mod_resolution(input_file_name: &str, exp_misformatted_files: &[&str]) {
+    let input_file = PathBuf::from(input_file_name);
     let config = read_config(&input_file);
     let mut session = Session::<io::Stdout>::new(config, None);
     let report = session
-        .format(Input::File(filename.into()))
+        .format(Input::File(input_file_name.into()))
         .expect("Should not have had any execution errors");
     let errors_by_file = &report.internal.borrow().0;
-    assert!(errors_by_file.contains_key(&FileName::Real(PathBuf::from(
-        "tests/mod-resolver/issue-4874/bar/baz.rs",
-    ))));
-    assert!(errors_by_file.contains_key(&FileName::Real(PathBuf::from(
-        "tests/mod-resolver/issue-4874/foo/qux.rs",
-    ))));
+    for exp_file in exp_misformatted_files {
+        assert!(errors_by_file.contains_key(&FileName::Real(PathBuf::from(exp_file))));
+    }
+}
+
+#[test]
+fn nested_out_of_line_mods_loaded() {
+    // See also https://github.com/rust-lang/rustfmt/issues/4874
+    verify_mod_resolution(
+        "tests/mod-resolver/issue-4874/main.rs",
+        &[
+            "tests/mod-resolver/issue-4874/bar/baz.rs",
+            "tests/mod-resolver/issue-4874/foo/qux.rs",
+        ],
+    );
+}
+
+#[test]
+fn out_of_line_nested_inline_within_out_of_line() {
+    // See also https://github.com/rust-lang/rustfmt/issues/5063
+    verify_mod_resolution(
+        "tests/mod-resolver/issue-5063/main.rs",
+        &[
+            "tests/mod-resolver/issue-5063/foo/bar/baz.rs",
+            "tests/mod-resolver/issue-5063/foo.rs",
+        ],
+    );
 }
diff --git a/tests/mod-resolver/issue-5063/foo.rs b/tests/mod-resolver/issue-5063/foo.rs
new file mode 100644
index 00000000000..d56974773fb
--- /dev/null
+++ b/tests/mod-resolver/issue-5063/foo.rs
@@ -0,0 +1,2 @@
+mod bar {
+        mod baz;}
\ No newline at end of file
diff --git a/tests/mod-resolver/issue-5063/foo/bar/baz.rs b/tests/mod-resolver/issue-5063/foo/bar/baz.rs
new file mode 100644
index 00000000000..3519b0ee59c
--- /dev/null
+++ b/tests/mod-resolver/issue-5063/foo/bar/baz.rs
@@ -0,0 +1,1 @@
+fn    baz()    {       }
\ No newline at end of file
diff --git a/tests/mod-resolver/issue-5063/main.rs b/tests/mod-resolver/issue-5063/main.rs
new file mode 100644
index 00000000000..41c81c7bb43
--- /dev/null
+++ b/tests/mod-resolver/issue-5063/main.rs
@@ -0,0 +1,5 @@
+fn main() {
+    println!("Hello, world!");
+}
+
+mod foo;
\ No newline at end of file