Skip to content

Commit 0660451

Browse files
committed
fix self_named_module_files (#14697, #10271, #11916)
tracks each sub folder by its relative path from crate's working directory instead of individual path segments changelog: none Signed-off-by: Zihan <[email protected]>
1 parent e6b63d1 commit 0660451

File tree

13 files changed

+65
-25
lines changed

13 files changed

+65
-25
lines changed

clippy_lints/src/module_style.rs

Lines changed: 17 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,7 @@ use rustc_lint::{EarlyContext, EarlyLintPass, Level, LintContext};
55
use rustc_session::impl_lint_pass;
66
use rustc_span::def_id::LOCAL_CRATE;
77
use rustc_span::{FileName, SourceFile, Span, SyntaxContext};
8-
use std::ffi::OsStr;
9-
use std::path::{Component, Path};
8+
use std::path::Path;
109

1110
declare_clippy_lint! {
1211
/// ### What it does
@@ -85,13 +84,12 @@ impl EarlyLintPass for ModStyle {
8584
return;
8685
};
8786

88-
// `folder_segments` is all unique folder path segments `path/to/foo.rs` gives
89-
// `[path, to]` but not foo
90-
let mut folder_segments = FxIndexSet::default();
87+
// `sub_folders` is all the sub folders under `src` directory including `src`
88+
let mut sub_folders = FxIndexSet::default();
9189
// `mod_folders` is all the unique folder names that contain a mod.rs file
9290
let mut mod_folders = FxHashSet::default();
93-
// `file_map` maps file names to the full path including the file name
94-
// `{ foo => path/to/foo.rs, .. }
91+
// `file_map` maps file names with `.rs` extension excluded to file path and
92+
// `rustc_span::SourceFile`.
9593
let mut file_map = FxHashMap::default();
9694
for file in files.iter() {
9795
if let FileName::Real(name) = &file.name
@@ -109,16 +107,13 @@ impl EarlyLintPass for ModStyle {
109107
} else {
110108
continue;
111109
};
112-
113-
if let Some(stem) = path.file_stem() {
114-
file_map.insert(stem, (file, path));
115-
}
116-
process_paths_for_mod_files(path, &mut folder_segments, &mut mod_folders);
110+
file_map.insert(path.with_extension(""), (file, path));
111+
process_paths_for_mod_files(path, &mut sub_folders, &mut mod_folders);
117112
check_self_named_mod_exists(cx, path, file);
118113
}
119114
}
120115

121-
for folder in &folder_segments {
116+
for folder in sub_folders {
122117
if !mod_folders.contains(folder)
123118
&& let Some((file, path)) = file_map.get(folder)
124119
{
@@ -128,9 +123,7 @@ impl EarlyLintPass for ModStyle {
128123
Span::new(file.start_pos, file.start_pos, SyntaxContext::root(), None),
129124
format!("`mod.rs` files are required, found `{}`", path.display()),
130125
|diag| {
131-
let mut correct = path.to_path_buf();
132-
correct.pop();
133-
correct.push(folder);
126+
let mut correct = folder.to_path_buf();
134127
correct.push("mod.rs");
135128
diag.help(format!("move `{}` to `{}`", path.display(), correct.display(),));
136129
},
@@ -140,20 +133,19 @@ impl EarlyLintPass for ModStyle {
140133
}
141134
}
142135

143-
/// For each `path` we add each folder component to `folder_segments` and if the file name
144-
/// is `mod.rs` we add it's parent folder to `mod_folders`.
136+
/// Adds sub folder path relative to crate's working folder to `folders`.
137+
/// If `path` is a `mod.rs`, its parent folder is added to `mod_folders`.
145138
fn process_paths_for_mod_files<'a>(
146139
path: &'a Path,
147-
folder_segments: &mut FxIndexSet<&'a OsStr>,
148-
mod_folders: &mut FxHashSet<&'a OsStr>,
140+
folders: &mut FxIndexSet<&'a Path>,
141+
mod_folders: &mut FxHashSet<&'a Path>,
149142
) {
150-
let mut comp = path.components().rev().peekable();
151-
let _: Option<_> = comp.next();
143+
let mut comp = path.components();
144+
let _: Option<_> = comp.next_back();
152145
if path.ends_with("mod.rs") {
153-
mod_folders.insert(comp.peek().map(|c| c.as_os_str()).unwrap_or_default());
146+
mod_folders.insert(comp.as_path());
154147
}
155-
let folders = comp.filter_map(|c| if let Component::Normal(s) = c { Some(s) } else { None });
156-
folder_segments.extend(folders);
148+
folders.insert(comp.as_path());
157149
}
158150

159151
/// Checks every path for the presence of `mod.rs` files and emits the lint if found.
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
error: `mod.rs` files are required, found `src/foo.rs`
2+
--> src/foo.rs:1:1
3+
|
4+
1 | pub mod bar;
5+
| ^
6+
|
7+
= help: move `src/foo.rs` to `src/foo/mod.rs`
8+
= note: `-D clippy::self-named-module-files` implied by `-D warnings`
9+
= help: to override `-D warnings` add `#[allow(clippy::self_named_module_files)]`
10+
11+
error: could not compile `duplicated-mod-names-14697` (lib) due to 1 previous error
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
# Should trigger when multiple mods with the same name exist and not all of them follow self-named convention.
2+
# See issue #14697.
3+
[package]
4+
name = "duplicated-mod-names-14697"
5+
version = "0.1.0"
6+
edition = "2024"
7+
publish = false
8+
9+
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
10+
11+
[dependencies]
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
pub mod bar;
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
#![warn(clippy::self_named_module_files)]
2+
3+
pub mod foo;
4+
pub mod other;
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
pub mod foo;
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
# Should not produce FP when irrelavant path segment shares the same name with module.
2+
# See issue #10271 and #11916.
3+
[package]
4+
name = "segment-with-mod-name-10271-11916"
5+
version = "0.1.0"
6+
edition = "2024"
7+
publish = false
8+
9+
[workspace]
10+
members = ["foo/bar"]
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
[package]
2+
name = "bar"
3+
version = "0.1.0"
4+
edition = "2024"
5+
publish = false

0 commit comments

Comments
 (0)