about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2024-04-12 18:53:03 +0000
committerbors <bors@rust-lang.org>2024-04-12 18:53:03 +0000
commit832fdb6d30632d275b5a82c4e99f29267e8fac32 (patch)
treeb0ef3e398879b6b0532aff12c6758ed755ea2227
parent0d84f0015633809b8dcff9fe1a22318fe0c6d257 (diff)
parent3705073a71648cff81bdb3eadeeacacc8d65123c (diff)
downloadrust-832fdb6d30632d275b5a82c4e99f29267e8fac32.tar.gz
rust-832fdb6d30632d275b5a82c4e99f29267e8fac32.zip
Auto merge of #12573 - modelflat:recognize-common-prepositions-in-module-name-repetitions, r=Jarcho
[`module_name_repetition`] Recognize common prepositions

Fixes #12544

changelog: [`module_name_repetition`]: don't report an item name if it consists only of a prefix from `allowed-prefixes` list and a module name (e.g. `AsFoo` in module `foo`). Prefixes allowed by default: [`to`, `from`, `into`, `as`, `try_into`, `try_from`]
-rw-r--r--CHANGELOG.md1
-rw-r--r--book/src/lint_configuration.md26
-rw-r--r--clippy_config/src/conf.rs22
-rw-r--r--clippy_lints/src/item_name_repetitions.rs12
-rw-r--r--clippy_lints/src/lib.rs2
-rw-r--r--tests/ui-toml/item_name_repetitions/allowed_prefixes/clippy.toml1
-rw-r--r--tests/ui-toml/item_name_repetitions/allowed_prefixes/item_name_repetitions.rs15
-rw-r--r--tests/ui-toml/item_name_repetitions/allowed_prefixes/item_name_repetitions.stderr11
-rw-r--r--tests/ui-toml/item_name_repetitions/allowed_prefixes_extend/clippy.toml1
-rw-r--r--tests/ui-toml/item_name_repetitions/allowed_prefixes_extend/item_name_repetitions.rs21
-rw-r--r--tests/ui-toml/item_name_repetitions/allowed_prefixes_extend/item_name_repetitions.stderr11
-rw-r--r--tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr3
-rw-r--r--tests/ui/module_name_repetitions.rs14
13 files changed, 139 insertions, 1 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md
index f7e7ed86eed..bd3a04e34ae 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -5894,6 +5894,7 @@ Released 2018-09-13
 [`allowed-dotfiles`]: https://doc.rust-lang.org/clippy/lint_configuration.html#allowed-dotfiles
 [`allowed-duplicate-crates`]: https://doc.rust-lang.org/clippy/lint_configuration.html#allowed-duplicate-crates
 [`allowed-idents-below-min-chars`]: https://doc.rust-lang.org/clippy/lint_configuration.html#allowed-idents-below-min-chars
+[`allowed-prefixes`]: https://doc.rust-lang.org/clippy/lint_configuration.html#allowed-prefixes
 [`allowed-scripts`]: https://doc.rust-lang.org/clippy/lint_configuration.html#allowed-scripts
 [`allowed-wildcard-imports`]: https://doc.rust-lang.org/clippy/lint_configuration.html#allowed-wildcard-imports
 [`arithmetic-side-effects-allowed`]: https://doc.rust-lang.org/clippy/lint_configuration.html#arithmetic-side-effects-allowed
diff --git a/book/src/lint_configuration.md b/book/src/lint_configuration.md
index 4a2727c5197..7cefa685264 100644
--- a/book/src/lint_configuration.md
+++ b/book/src/lint_configuration.md
@@ -164,6 +164,32 @@ configuration of Clippy. By default, any configuration will replace the default
 * [`min_ident_chars`](https://rust-lang.github.io/rust-clippy/master/index.html#min_ident_chars)
 
 
+## `allowed-prefixes`
+List of prefixes to allow when determining whether an item's name ends with the module's name.
+If the rest of an item's name is an allowed prefix (e.g. item `ToFoo` or `to_foo` in module `foo`),
+then don't emit a warning.
+
+#### Example
+
+```toml
+allowed-prefixes = [ "to", "from" ]
+```
+
+#### Noteworthy
+
+- By default, the following prefixes are allowed: `to`, `as`, `into`, `from`, `try_into` and `try_from`
+- PascalCase variant is included automatically for each snake_case variant (e.g. if `try_into` is included,
+  `TryInto` will also be included)
+- Use `".."` as part of the list to indicate that the configured values should be appended to the
+default configuration of Clippy. By default, any configuration will replace the default value
+
+**Default Value:** `["to", "as", "into", "from", "try_into", "try_from"]`
+
+---
+**Affected lints:**
+* [`module_name_repetitions`](https://rust-lang.github.io/rust-clippy/master/index.html#module_name_repetitions)
+
+
 ## `allowed-scripts`
 The list of unicode scripts allowed to be used in the scope.
 
diff --git a/clippy_config/src/conf.rs b/clippy_config/src/conf.rs
index 53c10f7cee8..781282213cc 100644
--- a/clippy_config/src/conf.rs
+++ b/clippy_config/src/conf.rs
@@ -39,6 +39,7 @@ const DEFAULT_DOC_VALID_IDENTS: &[&str] = &[
 ];
 const DEFAULT_DISALLOWED_NAMES: &[&str] = &["foo", "baz", "quux"];
 const DEFAULT_ALLOWED_IDENTS_BELOW_MIN_CHARS: &[&str] = &["i", "j", "x", "y", "z", "w", "n"];
+const DEFAULT_ALLOWED_PREFIXES: &[&str] = &["to", "as", "into", "from", "try_into", "try_from"];
 
 /// Conf with parse errors
 #[derive(Default)]
@@ -589,6 +590,26 @@ define_Conf! {
     /// 2. Paths with any segment that containing the word 'prelude'
     /// are already allowed by default.
     (allowed_wildcard_imports: FxHashSet<String> = FxHashSet::default()),
+    /// Lint: MODULE_NAME_REPETITIONS.
+    ///
+    /// List of prefixes to allow when determining whether an item's name ends with the module's name.
+    /// If the rest of an item's name is an allowed prefix (e.g. item `ToFoo` or `to_foo` in module `foo`),
+    /// then don't emit a warning.
+    ///
+    /// #### Example
+    ///
+    /// ```toml
+    /// allowed-prefixes = [ "to", "from" ]
+    /// ```
+    ///
+    /// #### Noteworthy
+    ///
+    /// - By default, the following prefixes are allowed: `to`, `as`, `into`, `from`, `try_into` and `try_from`
+    /// - PascalCase variant is included automatically for each snake_case variant (e.g. if `try_into` is included,
+    ///   `TryInto` will also be included)
+    /// - Use `".."` as part of the list to indicate that the configured values should be appended to the
+    /// default configuration of Clippy. By default, any configuration will replace the default value
+    (allowed_prefixes: Vec<String> = DEFAULT_ALLOWED_PREFIXES.iter().map(ToString::to_string).collect()),
 }
 
 /// Search for the configuration file.
@@ -649,6 +670,7 @@ fn deserialize(file: &SourceFile) -> TryConf {
         Ok(mut conf) => {
             extend_vec_if_indicator_present(&mut conf.conf.doc_valid_idents, DEFAULT_DOC_VALID_IDENTS);
             extend_vec_if_indicator_present(&mut conf.conf.disallowed_names, DEFAULT_DISALLOWED_NAMES);
+            extend_vec_if_indicator_present(&mut conf.conf.allowed_prefixes, DEFAULT_ALLOWED_PREFIXES);
             // TODO: THIS SHOULD BE TESTED, this comment will be gone soon
             if conf.conf.allowed_idents_below_min_chars.contains("..") {
                 conf.conf
diff --git a/clippy_lints/src/item_name_repetitions.rs b/clippy_lints/src/item_name_repetitions.rs
index 6615122567d..33764d3eb09 100644
--- a/clippy_lints/src/item_name_repetitions.rs
+++ b/clippy_lints/src/item_name_repetitions.rs
@@ -5,6 +5,7 @@ use clippy_utils::is_bool;
 use clippy_utils::macros::span_is_local;
 use clippy_utils::source::is_present_in_source;
 use clippy_utils::str_utils::{camel_case_split, count_match_end, count_match_start, to_camel_case, to_snake_case};
+use rustc_data_structures::fx::FxHashSet;
 use rustc_hir::{EnumDef, FieldDef, Item, ItemKind, OwnerId, Variant, VariantData};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_session::impl_lint_pass;
@@ -147,6 +148,7 @@ pub struct ItemNameRepetitions {
     struct_threshold: u64,
     avoid_breaking_exported_api: bool,
     allow_private_module_inception: bool,
+    allowed_prefixes: FxHashSet<String>,
 }
 
 impl ItemNameRepetitions {
@@ -156,6 +158,7 @@ impl ItemNameRepetitions {
         struct_threshold: u64,
         avoid_breaking_exported_api: bool,
         allow_private_module_inception: bool,
+        allowed_prefixes: &[String],
     ) -> Self {
         Self {
             modules: Vec::new(),
@@ -163,8 +166,13 @@ impl ItemNameRepetitions {
             struct_threshold,
             avoid_breaking_exported_api,
             allow_private_module_inception,
+            allowed_prefixes: allowed_prefixes.iter().map(|s| to_camel_case(s)).collect(),
         }
     }
+
+    fn is_allowed_prefix(&self, prefix: &str) -> bool {
+        self.allowed_prefixes.contains(prefix)
+    }
 }
 
 impl_lint_pass!(ItemNameRepetitions => [
@@ -423,7 +431,9 @@ impl LateLintPass<'_> for ItemNameRepetitions {
                                 _ => (),
                             }
                         }
-                        if rmatching.char_count == nchars {
+                        if rmatching.char_count == nchars
+                            && !self.is_allowed_prefix(&item_camel[..item_camel.len() - rmatching.byte_count])
+                        {
                             span_lint(
                                 cx,
                                 MODULE_NAME_REPETITIONS,
diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs
index b92364a9d14..e2aac58bf97 100644
--- a/clippy_lints/src/lib.rs
+++ b/clippy_lints/src/lib.rs
@@ -594,6 +594,7 @@ pub fn register_lints(store: &mut rustc_lint::LintStore, conf: &'static Conf) {
         pub_underscore_fields_behavior,
         ref allowed_duplicate_crates,
         allow_comparison_to_zero,
+        ref allowed_prefixes,
 
         blacklisted_names: _,
         cyclomatic_complexity_threshold: _,
@@ -864,6 +865,7 @@ pub fn register_lints(store: &mut rustc_lint::LintStore, conf: &'static Conf) {
             struct_field_name_threshold,
             avoid_breaking_exported_api,
             allow_private_module_inception,
+            allowed_prefixes,
         ))
     });
     store.register_early_pass(|| Box::new(tabs_in_doc_comments::TabsInDocComments));
diff --git a/tests/ui-toml/item_name_repetitions/allowed_prefixes/clippy.toml b/tests/ui-toml/item_name_repetitions/allowed_prefixes/clippy.toml
new file mode 100644
index 00000000000..35145551b60
--- /dev/null
+++ b/tests/ui-toml/item_name_repetitions/allowed_prefixes/clippy.toml
@@ -0,0 +1 @@
+allowed-prefixes = ["bar"]
diff --git a/tests/ui-toml/item_name_repetitions/allowed_prefixes/item_name_repetitions.rs b/tests/ui-toml/item_name_repetitions/allowed_prefixes/item_name_repetitions.rs
new file mode 100644
index 00000000000..4142ced5f6b
--- /dev/null
+++ b/tests/ui-toml/item_name_repetitions/allowed_prefixes/item_name_repetitions.rs
@@ -0,0 +1,15 @@
+#![warn(clippy::module_name_repetitions)]
+#![allow(dead_code)]
+
+mod foo {
+    // #12544 - shouldn't warn if item name consists only of an allowed prefix and a module name.
+    // In this test, allowed prefixes are configured to be ["bar"].
+
+    // this line should produce a warning:
+    pub fn to_foo() {}
+
+    // but this line shouldn't
+    pub fn bar_foo() {}
+}
+
+fn main() {}
diff --git a/tests/ui-toml/item_name_repetitions/allowed_prefixes/item_name_repetitions.stderr b/tests/ui-toml/item_name_repetitions/allowed_prefixes/item_name_repetitions.stderr
new file mode 100644
index 00000000000..6cfe0eab479
--- /dev/null
+++ b/tests/ui-toml/item_name_repetitions/allowed_prefixes/item_name_repetitions.stderr
@@ -0,0 +1,11 @@
+error: item name ends with its containing module's name
+  --> tests/ui-toml/item_name_repetitions/allowed_prefixes/item_name_repetitions.rs:9:12
+   |
+LL |     pub fn to_foo() {}
+   |            ^^^^^^
+   |
+   = note: `-D clippy::module-name-repetitions` implied by `-D warnings`
+   = help: to override `-D warnings` add `#[allow(clippy::module_name_repetitions)]`
+
+error: aborting due to 1 previous error
+
diff --git a/tests/ui-toml/item_name_repetitions/allowed_prefixes_extend/clippy.toml b/tests/ui-toml/item_name_repetitions/allowed_prefixes_extend/clippy.toml
new file mode 100644
index 00000000000..31ef524671d
--- /dev/null
+++ b/tests/ui-toml/item_name_repetitions/allowed_prefixes_extend/clippy.toml
@@ -0,0 +1 @@
+allowed-prefixes = ["..", "bar"]
diff --git a/tests/ui-toml/item_name_repetitions/allowed_prefixes_extend/item_name_repetitions.rs b/tests/ui-toml/item_name_repetitions/allowed_prefixes_extend/item_name_repetitions.rs
new file mode 100644
index 00000000000..b132305d01c
--- /dev/null
+++ b/tests/ui-toml/item_name_repetitions/allowed_prefixes_extend/item_name_repetitions.rs
@@ -0,0 +1,21 @@
+#![warn(clippy::module_name_repetitions)]
+#![allow(dead_code)]
+
+mod foo {
+    // #12544 - shouldn't warn if item name consists only of an allowed prefix and a module name.
+    // In this test, allowed prefixes are configured to be all of the default prefixes and ["bar"].
+
+    // this line should produce a warning:
+    pub fn something_foo() {}
+
+    // but none of the following should:
+    pub fn bar_foo() {}
+    pub fn to_foo() {}
+    pub fn as_foo() {}
+    pub fn into_foo() {}
+    pub fn from_foo() {}
+    pub fn try_into_foo() {}
+    pub fn try_from_foo() {}
+}
+
+fn main() {}
diff --git a/tests/ui-toml/item_name_repetitions/allowed_prefixes_extend/item_name_repetitions.stderr b/tests/ui-toml/item_name_repetitions/allowed_prefixes_extend/item_name_repetitions.stderr
new file mode 100644
index 00000000000..f495ec42184
--- /dev/null
+++ b/tests/ui-toml/item_name_repetitions/allowed_prefixes_extend/item_name_repetitions.stderr
@@ -0,0 +1,11 @@
+error: item name ends with its containing module's name
+  --> tests/ui-toml/item_name_repetitions/allowed_prefixes_extend/item_name_repetitions.rs:9:12
+   |
+LL |     pub fn something_foo() {}
+   |            ^^^^^^^^^^^^^
+   |
+   = note: `-D clippy::module-name-repetitions` implied by `-D warnings`
+   = help: to override `-D warnings` add `#[allow(clippy::module_name_repetitions)]`
+
+error: aborting due to 1 previous error
+
diff --git a/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr b/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr
index 737c062ea56..24645b61fdb 100644
--- a/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr
+++ b/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr
@@ -14,6 +14,7 @@ error: error reading Clippy's configuration file: unknown field `foobar`, expect
            allowed-dotfiles
            allowed-duplicate-crates
            allowed-idents-below-min-chars
+           allowed-prefixes
            allowed-scripts
            allowed-wildcard-imports
            arithmetic-side-effects-allowed
@@ -93,6 +94,7 @@ error: error reading Clippy's configuration file: unknown field `barfoo`, expect
            allowed-dotfiles
            allowed-duplicate-crates
            allowed-idents-below-min-chars
+           allowed-prefixes
            allowed-scripts
            allowed-wildcard-imports
            arithmetic-side-effects-allowed
@@ -172,6 +174,7 @@ error: error reading Clippy's configuration file: unknown field `allow_mixed_uni
            allowed-dotfiles
            allowed-duplicate-crates
            allowed-idents-below-min-chars
+           allowed-prefixes
            allowed-scripts
            allowed-wildcard-imports
            arithmetic-side-effects-allowed
diff --git a/tests/ui/module_name_repetitions.rs b/tests/ui/module_name_repetitions.rs
index a6cf0389098..b75ef87ab36 100644
--- a/tests/ui/module_name_repetitions.rs
+++ b/tests/ui/module_name_repetitions.rs
@@ -19,6 +19,20 @@ mod foo {
 
     // Should not warn
     pub struct Foobar;
+
+    // #12544 - shouldn't warn if item name consists only of an allowed prefix and a module name.
+    pub fn to_foo() {}
+    pub fn into_foo() {}
+    pub fn as_foo() {}
+    pub fn from_foo() {}
+    pub fn try_into_foo() {}
+    pub fn try_from_foo() {}
+    pub trait IntoFoo {}
+    pub trait ToFoo {}
+    pub trait AsFoo {}
+    pub trait FromFoo {}
+    pub trait TryIntoFoo {}
+    pub trait TryFromFoo {}
 }
 
 fn main() {}