allow disabling module inception on private modules

allow disabling module inception on private modules
This commit is contained in:
Centri3 2023-06-09 14:27:34 -05:00
parent 4886937212
commit b303e2053c
10 changed files with 121 additions and 17 deletions

View file

@ -643,3 +643,13 @@ The byte size a `T` in `Box<T>` can have, below which it triggers the `clippy::u
* [`unnecessary_box_returns`](https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_box_returns) * [`unnecessary_box_returns`](https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_box_returns)
## `allow-private-module-inception`
Whether to allow module inception if it's not public.
**Default Value:** `false` (`bool`)
---
**Affected lints:**
* [`module_inception`](https://rust-lang.github.io/rust-clippy/master/index.html#module_inception)

View file

@ -3,7 +3,7 @@
use clippy_utils::diagnostics::{span_lint, span_lint_and_help, span_lint_hir}; use clippy_utils::diagnostics::{span_lint, span_lint_and_help, span_lint_hir};
use clippy_utils::source::is_present_in_source; use clippy_utils::source::is_present_in_source;
use clippy_utils::str_utils::{camel_case_split, count_match_end, count_match_start}; use clippy_utils::str_utils::{camel_case_split, count_match_end, count_match_start};
use rustc_hir::{EnumDef, Item, ItemKind, Variant}; use rustc_hir::{EnumDef, Item, ItemKind, OwnerId, Variant};
use rustc_lint::{LateContext, LateLintPass}; use rustc_lint::{LateContext, LateLintPass};
use rustc_session::{declare_tool_lint, impl_lint_pass}; use rustc_session::{declare_tool_lint, impl_lint_pass};
use rustc_span::source_map::Span; use rustc_span::source_map::Span;
@ -105,18 +105,20 @@ declare_clippy_lint! {
} }
pub struct EnumVariantNames { pub struct EnumVariantNames {
modules: Vec<(Symbol, String)>, modules: Vec<(Symbol, String, OwnerId)>,
threshold: u64, threshold: u64,
avoid_breaking_exported_api: bool, avoid_breaking_exported_api: bool,
allow_private_module_inception: bool,
} }
impl EnumVariantNames { impl EnumVariantNames {
#[must_use] #[must_use]
pub fn new(threshold: u64, avoid_breaking_exported_api: bool) -> Self { pub fn new(threshold: u64, avoid_breaking_exported_api: bool, allow_private_module_inception: bool) -> Self {
Self { Self {
modules: Vec::new(), modules: Vec::new(),
threshold, threshold,
avoid_breaking_exported_api, avoid_breaking_exported_api,
allow_private_module_inception,
} }
} }
} }
@ -252,18 +254,19 @@ impl LateLintPass<'_> for EnumVariantNames {
let item_name = item.ident.name.as_str(); let item_name = item.ident.name.as_str();
let item_camel = to_camel_case(item_name); let item_camel = to_camel_case(item_name);
if !item.span.from_expansion() && is_present_in_source(cx, item.span) { if !item.span.from_expansion() && is_present_in_source(cx, item.span) {
if let Some((mod_name, mod_camel)) = self.modules.last() { if let [.., (mod_name, mod_camel, owner_id)] = &*self.modules {
// constants don't have surrounding modules // constants don't have surrounding modules
if !mod_camel.is_empty() { if !mod_camel.is_empty() {
if mod_name == &item.ident.name { if mod_name == &item.ident.name
if let ItemKind::Mod(..) = item.kind { && let ItemKind::Mod(..) = item.kind
span_lint( && (!self.allow_private_module_inception || cx.tcx.visibility(owner_id.def_id).is_public())
cx, {
MODULE_INCEPTION, span_lint(
item.span, cx,
"module has the same name as its containing module", MODULE_INCEPTION,
); item.span,
} "module has the same name as its containing module",
);
} }
// The `module_name_repetitions` lint should only trigger if the item has the module in its // The `module_name_repetitions` lint should only trigger if the item has the module in its
// name. Having the same name is accepted. // name. Having the same name is accepted.
@ -302,6 +305,6 @@ impl LateLintPass<'_> for EnumVariantNames {
check_variant(cx, self.threshold, def, item_name, item.span); check_variant(cx, self.threshold, def, item_name, item.span);
} }
} }
self.modules.push((item.ident.name, item_camel)); self.modules.push((item.ident.name, item_camel, item.owner_id));
} }
} }

View file

@ -813,10 +813,12 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
)) ))
}); });
let enum_variant_name_threshold = conf.enum_variant_name_threshold; let enum_variant_name_threshold = conf.enum_variant_name_threshold;
let allow_private_module_inception = conf.allow_private_module_inception;
store.register_late_pass(move |_| { store.register_late_pass(move |_| {
Box::new(enum_variants::EnumVariantNames::new( Box::new(enum_variants::EnumVariantNames::new(
enum_variant_name_threshold, enum_variant_name_threshold,
avoid_breaking_exported_api, avoid_breaking_exported_api,
allow_private_module_inception,
)) ))
}); });
store.register_early_pass(|| Box::new(tabs_in_doc_comments::TabsInDocComments)); store.register_early_pass(|| Box::new(tabs_in_doc_comments::TabsInDocComments));

View file

@ -514,6 +514,10 @@ define_Conf! {
/// ///
/// The byte size a `T` in `Box<T>` can have, below which it triggers the `clippy::unnecessary_box` lint /// The byte size a `T` in `Box<T>` can have, below which it triggers the `clippy::unnecessary_box` lint
(unnecessary_box_size: u64 = 128), (unnecessary_box_size: u64 = 128),
/// Lint: MODULE_INCEPTION.
///
/// Whether to allow module inception if it's not public.
(allow_private_module_inception: bool = false),
} }
/// Search for the configuration file. /// Search for the configuration file.

View file

@ -0,0 +1 @@
allow-private-module-inception = true

View file

@ -0,0 +1,34 @@
#![warn(clippy::module_inception)]
// Lint
pub mod foo2 {
pub mod bar2 {
pub mod bar2 {
pub mod foo2 {}
}
pub mod foo2 {}
}
pub mod foo2 {
pub mod bar2 {}
}
}
// Don't lint
mod foo {
pub mod bar {
pub mod foo {
pub mod bar {}
}
}
pub mod foo {
pub mod bar {}
}
}
// No warning. See <https://github.com/rust-lang/rust-clippy/issues/1220>.
pub mod bar {
#[allow(clippy::module_inception)]
pub mod bar {}
}
fn main() {}

View file

@ -0,0 +1,20 @@
error: module has the same name as its containing module
--> $DIR/module_inception.rs:6:9
|
LL | / pub mod bar2 {
LL | | pub mod foo2 {}
LL | | }
| |_________^
|
= note: `-D clippy::module-inception` implied by `-D warnings`
error: module has the same name as its containing module
--> $DIR/module_inception.rs:11:5
|
LL | / pub mod foo2 {
LL | | pub mod bar2 {}
LL | | }
| |_____^
error: aborting due to 2 previous errors

View file

@ -3,6 +3,7 @@ error: error reading Clippy's configuration file: unknown field `foobar`, expect
allow-expect-in-tests allow-expect-in-tests
allow-mixed-uninlined-format-args allow-mixed-uninlined-format-args
allow-print-in-tests allow-print-in-tests
allow-private-module-inception
allow-unwrap-in-tests allow-unwrap-in-tests
allowed-scripts allowed-scripts
arithmetic-side-effects-allowed arithmetic-side-effects-allowed
@ -64,6 +65,7 @@ error: error reading Clippy's configuration file: unknown field `barfoo`, expect
allow-expect-in-tests allow-expect-in-tests
allow-mixed-uninlined-format-args allow-mixed-uninlined-format-args
allow-print-in-tests allow-print-in-tests
allow-private-module-inception
allow-unwrap-in-tests allow-unwrap-in-tests
allowed-scripts allowed-scripts
arithmetic-side-effects-allowed arithmetic-side-effects-allowed

View file

@ -1,5 +1,17 @@
#![warn(clippy::module_inception)] #![warn(clippy::module_inception)]
pub mod foo2 {
pub mod bar2 {
pub mod bar2 {
pub mod foo2 {}
}
pub mod foo2 {}
}
pub mod foo2 {
pub mod bar2 {}
}
}
mod foo { mod foo {
mod bar { mod bar {
mod bar { mod bar {

View file

@ -1,8 +1,8 @@
error: module has the same name as its containing module error: module has the same name as its containing module
--> $DIR/module_inception.rs:5:9 --> $DIR/module_inception.rs:5:9
| |
LL | / mod bar { LL | / pub mod bar2 {
LL | | mod foo {} LL | | pub mod foo2 {}
LL | | } LL | | }
| |_________^ | |_________^
| |
@ -11,10 +11,26 @@ LL | | }
error: module has the same name as its containing module error: module has the same name as its containing module
--> $DIR/module_inception.rs:10:5 --> $DIR/module_inception.rs:10:5
| |
LL | / pub mod foo2 {
LL | | pub mod bar2 {}
LL | | }
| |_____^
error: module has the same name as its containing module
--> $DIR/module_inception.rs:17:9
|
LL | / mod bar {
LL | | mod foo {}
LL | | }
| |_________^
error: module has the same name as its containing module
--> $DIR/module_inception.rs:22:5
|
LL | / mod foo { LL | / mod foo {
LL | | mod bar {} LL | | mod bar {}
LL | | } LL | | }
| |_____^ | |_____^
error: aborting due to 2 previous errors error: aborting due to 4 previous errors