Description
Summary
The self_named_module_files
implementation operates on path components, not paths. This leads to both, false negatives and super-confusing false positives.
The logic, as far as I can tell, is approximately this: The lint triggers if a file named foo.rs
exists, a folder named foo
exists, and foo/mod.rs
doesn't exist. The prefixes of those paths, if any, are completely ignored.
(The lint also cannot be allow
ed for individual modules).
This could probably be fixed by tracking things by their full paths, not path components, though maybe a completely different implementation might be the better solution.
E.g. my first idea for how something like this could be implemented was along the lines of:
- For every module file
x.rs
that is not amod.rs
file and not the crate root:- If
x.rs
contains amod
that is neither inline nor has a#[path="..."]
attribute:- Trigger
self_named_module_files
forx.rs
.
- Trigger
- If
I think this should cover the desired semantics, with no manipulation of file paths being required.
Reproducer
False negative:
Consider this directory layout:
src
├── foo
│ └── bar.rs
├── foo.rs
├── lib.rs
└── other
├── foo
│ └── mod.rs
└── mod.rs
The lint should trigger for foo.rs
, but doesn't trigger because other/foo/mod.rs
exists.
If you remove other
, the lint triggers correctly.
False positive:
(There's probably a simpler repro possible, but I like the absurdity of --release
making the lint trigger / not trigger, and this is essentially the situation I ran into, just with build
instead release
).
build.rs
:
use std::{env, fs};
fn main() {
let mut out_file = env::var("OUT_DIR").unwrap();
out_file.push_str("/data.txt");
fs::write(&out_file, "").unwrap();
println!("cargo::rustc-env=DATA={out_file}");
println!("cargo::warning=DATA: {out_file}");
}
src/lib.rs
:
pub static DATA: &str = include_str!(env!("DATA"));
mod release;
src/release.rs
: empty file
cargo clippy -- -D clippy::self-named-module-files
will not trigger the lint.
cargo clippy --release -- -D clippy::self-named-module-files
will trigger the lint.
This is because for --release
, $OUT_DIR
contains a directory named /release/
and there's no release/mod.rs
file anywhere, so release.rs
triggers the lint.
Version
rustc 1.88.0-nightly (10fa3c449 2025-04-26)
binary: rustc
commit-hash: 10fa3c449f6b1613b352a6cbf78d3d91fd9a1d81
commit-date: 2025-04-26
host: aarch64-apple-darwin
release: 1.88.0-nightly
LLVM version: 20.1.2
Additional Labels
No response