diff --git a/clippy_lints/src/module_style.rs b/clippy_lints/src/module_style.rs index 98614baffcea..92cec98438f3 100644 --- a/clippy_lints/src/module_style.rs +++ b/clippy_lints/src/module_style.rs @@ -5,8 +5,7 @@ use rustc_lint::{EarlyContext, EarlyLintPass, Level, LintContext}; use rustc_session::impl_lint_pass; use rustc_span::def_id::LOCAL_CRATE; use rustc_span::{FileName, SourceFile, Span, SyntaxContext}; -use std::ffi::OsStr; -use std::path::{Component, Path}; +use std::path::Path; declare_clippy_lint! { /// ### What it does @@ -85,13 +84,12 @@ impl EarlyLintPass for ModStyle { return; }; - // `folder_segments` is all unique folder path segments `path/to/foo.rs` gives - // `[path, to]` but not foo - let mut folder_segments = FxIndexSet::default(); + // `sub_folders` is all the sub folders under `src` directory including `src` + let mut sub_folders = FxIndexSet::default(); // `mod_folders` is all the unique folder names that contain a mod.rs file let mut mod_folders = FxHashSet::default(); - // `file_map` maps file names to the full path including the file name - // `{ foo => path/to/foo.rs, .. } + // `file_map` maps file names with `.rs` extension excluded to file path and + // `rustc_span::SourceFile`. let mut file_map = FxHashMap::default(); for file in files.iter() { if let FileName::Real(name) = &file.name @@ -109,16 +107,13 @@ impl EarlyLintPass for ModStyle { } else { continue; }; - - if let Some(stem) = path.file_stem() { - file_map.insert(stem, (file, path)); - } - process_paths_for_mod_files(path, &mut folder_segments, &mut mod_folders); + file_map.insert(path.with_extension(""), (file, path)); + process_paths_for_mod_files(path, &mut sub_folders, &mut mod_folders); check_self_named_mod_exists(cx, path, file); } } - for folder in &folder_segments { + for folder in sub_folders { if !mod_folders.contains(folder) && let Some((file, path)) = file_map.get(folder) { @@ -128,9 +123,7 @@ impl EarlyLintPass for ModStyle { Span::new(file.start_pos, file.start_pos, SyntaxContext::root(), None), format!("`mod.rs` files are required, found `{}`", path.display()), |diag| { - let mut correct = path.to_path_buf(); - correct.pop(); - correct.push(folder); + let mut correct = folder.to_path_buf(); correct.push("mod.rs"); diag.help(format!("move `{}` to `{}`", path.display(), correct.display(),)); }, @@ -140,20 +133,19 @@ impl EarlyLintPass for ModStyle { } } -/// For each `path` we add each folder component to `folder_segments` and if the file name -/// is `mod.rs` we add it's parent folder to `mod_folders`. +/// Adds sub folder path relative to crate's working folder to `folders`. +/// If `path` is a `mod.rs`, its parent folder is added to `mod_folders`. fn process_paths_for_mod_files<'a>( path: &'a Path, - folder_segments: &mut FxIndexSet<&'a OsStr>, - mod_folders: &mut FxHashSet<&'a OsStr>, + folders: &mut FxIndexSet<&'a Path>, + mod_folders: &mut FxHashSet<&'a Path>, ) { - let mut comp = path.components().rev().peekable(); - let _: Option<_> = comp.next(); + let mut comp = path.components(); + let _: Option<_> = comp.next_back(); if path.ends_with("mod.rs") { - mod_folders.insert(comp.peek().map(|c| c.as_os_str()).unwrap_or_default()); + mod_folders.insert(comp.as_path()); } - let folders = comp.filter_map(|c| if let Component::Normal(s) = c { Some(s) } else { None }); - folder_segments.extend(folders); + folders.insert(comp.as_path()); } /// Checks every path for the presence of `mod.rs` files and emits the lint if found. diff --git a/tests/ui-cargo/module_style/duplicated_mod_names_14697/Cargo.stderr b/tests/ui-cargo/module_style/duplicated_mod_names_14697/Cargo.stderr new file mode 100644 index 000000000000..c7490c5da027 --- /dev/null +++ b/tests/ui-cargo/module_style/duplicated_mod_names_14697/Cargo.stderr @@ -0,0 +1,11 @@ +error: `mod.rs` files are required, found `src/foo.rs` + --> src/foo.rs:1:1 + | +1 | pub mod bar; + | ^ + | + = help: move `src/foo.rs` to `src/foo/mod.rs` + = note: `-D clippy::self-named-module-files` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::self_named_module_files)]` + +error: could not compile `duplicated-mod-names-14697` (lib) due to 1 previous error diff --git a/tests/ui-cargo/module_style/duplicated_mod_names_14697/Cargo.toml b/tests/ui-cargo/module_style/duplicated_mod_names_14697/Cargo.toml new file mode 100644 index 000000000000..569082f2f659 --- /dev/null +++ b/tests/ui-cargo/module_style/duplicated_mod_names_14697/Cargo.toml @@ -0,0 +1,11 @@ +# Should trigger when multiple mods with the same name exist and not all of them follow self-named convention. +# See issue #14697. +[package] +name = "duplicated-mod-names-14697" +version = "0.1.0" +edition = "2024" +publish = false + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] diff --git a/tests/ui-cargo/module_style/duplicated_mod_names_14697/src/foo.rs b/tests/ui-cargo/module_style/duplicated_mod_names_14697/src/foo.rs new file mode 100644 index 000000000000..46f285ca47d6 --- /dev/null +++ b/tests/ui-cargo/module_style/duplicated_mod_names_14697/src/foo.rs @@ -0,0 +1 @@ +pub mod bar; diff --git a/tests/ui-cargo/module_style/duplicated_mod_names_14697/src/foo/bar.rs b/tests/ui-cargo/module_style/duplicated_mod_names_14697/src/foo/bar.rs new file mode 100644 index 000000000000..8b137891791f --- /dev/null +++ b/tests/ui-cargo/module_style/duplicated_mod_names_14697/src/foo/bar.rs @@ -0,0 +1 @@ + diff --git a/tests/ui-cargo/module_style/duplicated_mod_names_14697/src/lib.rs b/tests/ui-cargo/module_style/duplicated_mod_names_14697/src/lib.rs new file mode 100644 index 000000000000..a85dae574816 --- /dev/null +++ b/tests/ui-cargo/module_style/duplicated_mod_names_14697/src/lib.rs @@ -0,0 +1,4 @@ +#![warn(clippy::self_named_module_files)] + +pub mod foo; +pub mod other; diff --git a/tests/ui-cargo/module_style/duplicated_mod_names_14697/src/other/foo/mod.rs b/tests/ui-cargo/module_style/duplicated_mod_names_14697/src/other/foo/mod.rs new file mode 100644 index 000000000000..8b137891791f --- /dev/null +++ b/tests/ui-cargo/module_style/duplicated_mod_names_14697/src/other/foo/mod.rs @@ -0,0 +1 @@ + diff --git a/tests/ui-cargo/module_style/duplicated_mod_names_14697/src/other/mod.rs b/tests/ui-cargo/module_style/duplicated_mod_names_14697/src/other/mod.rs new file mode 100644 index 000000000000..b52703b25740 --- /dev/null +++ b/tests/ui-cargo/module_style/duplicated_mod_names_14697/src/other/mod.rs @@ -0,0 +1 @@ +pub mod foo; diff --git a/tests/ui-cargo/module_style/segment_with_mod_name_10271_11916/Cargo.toml b/tests/ui-cargo/module_style/segment_with_mod_name_10271_11916/Cargo.toml new file mode 100644 index 000000000000..5c2fabd2283d --- /dev/null +++ b/tests/ui-cargo/module_style/segment_with_mod_name_10271_11916/Cargo.toml @@ -0,0 +1,10 @@ +# Should not produce FP when irrelavant path segment shares the same name with module. +# See issue #10271 and #11916. +[package] +name = "segment-with-mod-name-10271-11916" +version = "0.1.0" +edition = "2024" +publish = false + +[workspace] +members = ["foo/bar"] \ No newline at end of file diff --git a/tests/ui-cargo/module_style/segment_with_mod_name_10271_11916/foo/bar/Cargo.toml b/tests/ui-cargo/module_style/segment_with_mod_name_10271_11916/foo/bar/Cargo.toml new file mode 100644 index 000000000000..1f68c0dccac5 --- /dev/null +++ b/tests/ui-cargo/module_style/segment_with_mod_name_10271_11916/foo/bar/Cargo.toml @@ -0,0 +1,5 @@ +[package] +name = "bar" +version = "0.1.0" +edition = "2024" +publish = false diff --git a/tests/ui-cargo/module_style/segment_with_mod_name_10271_11916/foo/bar/src/foo.rs b/tests/ui-cargo/module_style/segment_with_mod_name_10271_11916/foo/bar/src/foo.rs new file mode 100644 index 000000000000..8b137891791f --- /dev/null +++ b/tests/ui-cargo/module_style/segment_with_mod_name_10271_11916/foo/bar/src/foo.rs @@ -0,0 +1 @@ + diff --git a/tests/ui-cargo/module_style/segment_with_mod_name_10271_11916/foo/bar/src/lib.rs b/tests/ui-cargo/module_style/segment_with_mod_name_10271_11916/foo/bar/src/lib.rs new file mode 100644 index 000000000000..b52703b25740 --- /dev/null +++ b/tests/ui-cargo/module_style/segment_with_mod_name_10271_11916/foo/bar/src/lib.rs @@ -0,0 +1 @@ +pub mod foo; diff --git a/tests/ui-cargo/module_style/segment_with_mod_name_10271_11916/src/lib.rs b/tests/ui-cargo/module_style/segment_with_mod_name_10271_11916/src/lib.rs new file mode 100644 index 000000000000..8b137891791f --- /dev/null +++ b/tests/ui-cargo/module_style/segment_with_mod_name_10271_11916/src/lib.rs @@ -0,0 +1 @@ +