Skip to content

Commit 832fdb6

Browse files
committed
Auto merge of rust-lang#12573 - modelflat:recognize-common-prepositions-in-module-name-repetitions, r=Jarcho
[`module_name_repetition`] Recognize common prepositions Fixes rust-lang#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`]
2 parents 0d84f00 + 3705073 commit 832fdb6

File tree

13 files changed

+139
-1
lines changed

13 files changed

+139
-1
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5894,6 +5894,7 @@ Released 2018-09-13
58945894
[`allowed-dotfiles`]: https://doc.rust-lang.org/clippy/lint_configuration.html#allowed-dotfiles
58955895
[`allowed-duplicate-crates`]: https://doc.rust-lang.org/clippy/lint_configuration.html#allowed-duplicate-crates
58965896
[`allowed-idents-below-min-chars`]: https://doc.rust-lang.org/clippy/lint_configuration.html#allowed-idents-below-min-chars
5897+
[`allowed-prefixes`]: https://doc.rust-lang.org/clippy/lint_configuration.html#allowed-prefixes
58975898
[`allowed-scripts`]: https://doc.rust-lang.org/clippy/lint_configuration.html#allowed-scripts
58985899
[`allowed-wildcard-imports`]: https://doc.rust-lang.org/clippy/lint_configuration.html#allowed-wildcard-imports
58995900
[`arithmetic-side-effects-allowed`]: https://doc.rust-lang.org/clippy/lint_configuration.html#arithmetic-side-effects-allowed

book/src/lint_configuration.md

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -164,6 +164,32 @@ configuration of Clippy. By default, any configuration will replace the default
164164
* [`min_ident_chars`](https://rust-lang.github.io/rust-clippy/master/index.html#min_ident_chars)
165165

166166

167+
## `allowed-prefixes`
168+
List of prefixes to allow when determining whether an item's name ends with the module's name.
169+
If the rest of an item's name is an allowed prefix (e.g. item `ToFoo` or `to_foo` in module `foo`),
170+
then don't emit a warning.
171+
172+
#### Example
173+
174+
```toml
175+
allowed-prefixes = [ "to", "from" ]
176+
```
177+
178+
#### Noteworthy
179+
180+
- By default, the following prefixes are allowed: `to`, `as`, `into`, `from`, `try_into` and `try_from`
181+
- PascalCase variant is included automatically for each snake_case variant (e.g. if `try_into` is included,
182+
`TryInto` will also be included)
183+
- Use `".."` as part of the list to indicate that the configured values should be appended to the
184+
default configuration of Clippy. By default, any configuration will replace the default value
185+
186+
**Default Value:** `["to", "as", "into", "from", "try_into", "try_from"]`
187+
188+
---
189+
**Affected lints:**
190+
* [`module_name_repetitions`](https://rust-lang.github.io/rust-clippy/master/index.html#module_name_repetitions)
191+
192+
167193
## `allowed-scripts`
168194
The list of unicode scripts allowed to be used in the scope.
169195

clippy_config/src/conf.rs

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ const DEFAULT_DOC_VALID_IDENTS: &[&str] = &[
3939
];
4040
const DEFAULT_DISALLOWED_NAMES: &[&str] = &["foo", "baz", "quux"];
4141
const DEFAULT_ALLOWED_IDENTS_BELOW_MIN_CHARS: &[&str] = &["i", "j", "x", "y", "z", "w", "n"];
42+
const DEFAULT_ALLOWED_PREFIXES: &[&str] = &["to", "as", "into", "from", "try_into", "try_from"];
4243

4344
/// Conf with parse errors
4445
#[derive(Default)]
@@ -589,6 +590,26 @@ define_Conf! {
589590
/// 2. Paths with any segment that containing the word 'prelude'
590591
/// are already allowed by default.
591592
(allowed_wildcard_imports: FxHashSet<String> = FxHashSet::default()),
593+
/// Lint: MODULE_NAME_REPETITIONS.
594+
///
595+
/// List of prefixes to allow when determining whether an item's name ends with the module's name.
596+
/// If the rest of an item's name is an allowed prefix (e.g. item `ToFoo` or `to_foo` in module `foo`),
597+
/// then don't emit a warning.
598+
///
599+
/// #### Example
600+
///
601+
/// ```toml
602+
/// allowed-prefixes = [ "to", "from" ]
603+
/// ```
604+
///
605+
/// #### Noteworthy
606+
///
607+
/// - By default, the following prefixes are allowed: `to`, `as`, `into`, `from`, `try_into` and `try_from`
608+
/// - PascalCase variant is included automatically for each snake_case variant (e.g. if `try_into` is included,
609+
/// `TryInto` will also be included)
610+
/// - Use `".."` as part of the list to indicate that the configured values should be appended to the
611+
/// default configuration of Clippy. By default, any configuration will replace the default value
612+
(allowed_prefixes: Vec<String> = DEFAULT_ALLOWED_PREFIXES.iter().map(ToString::to_string).collect()),
592613
}
593614

594615
/// Search for the configuration file.
@@ -649,6 +670,7 @@ fn deserialize(file: &SourceFile) -> TryConf {
649670
Ok(mut conf) => {
650671
extend_vec_if_indicator_present(&mut conf.conf.doc_valid_idents, DEFAULT_DOC_VALID_IDENTS);
651672
extend_vec_if_indicator_present(&mut conf.conf.disallowed_names, DEFAULT_DISALLOWED_NAMES);
673+
extend_vec_if_indicator_present(&mut conf.conf.allowed_prefixes, DEFAULT_ALLOWED_PREFIXES);
652674
// TODO: THIS SHOULD BE TESTED, this comment will be gone soon
653675
if conf.conf.allowed_idents_below_min_chars.contains("..") {
654676
conf.conf

clippy_lints/src/item_name_repetitions.rs

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ use clippy_utils::is_bool;
55
use clippy_utils::macros::span_is_local;
66
use clippy_utils::source::is_present_in_source;
77
use clippy_utils::str_utils::{camel_case_split, count_match_end, count_match_start, to_camel_case, to_snake_case};
8+
use rustc_data_structures::fx::FxHashSet;
89
use rustc_hir::{EnumDef, FieldDef, Item, ItemKind, OwnerId, Variant, VariantData};
910
use rustc_lint::{LateContext, LateLintPass};
1011
use rustc_session::impl_lint_pass;
@@ -147,6 +148,7 @@ pub struct ItemNameRepetitions {
147148
struct_threshold: u64,
148149
avoid_breaking_exported_api: bool,
149150
allow_private_module_inception: bool,
151+
allowed_prefixes: FxHashSet<String>,
150152
}
151153

152154
impl ItemNameRepetitions {
@@ -156,15 +158,21 @@ impl ItemNameRepetitions {
156158
struct_threshold: u64,
157159
avoid_breaking_exported_api: bool,
158160
allow_private_module_inception: bool,
161+
allowed_prefixes: &[String],
159162
) -> Self {
160163
Self {
161164
modules: Vec::new(),
162165
enum_threshold,
163166
struct_threshold,
164167
avoid_breaking_exported_api,
165168
allow_private_module_inception,
169+
allowed_prefixes: allowed_prefixes.iter().map(|s| to_camel_case(s)).collect(),
166170
}
167171
}
172+
173+
fn is_allowed_prefix(&self, prefix: &str) -> bool {
174+
self.allowed_prefixes.contains(prefix)
175+
}
168176
}
169177

170178
impl_lint_pass!(ItemNameRepetitions => [
@@ -423,7 +431,9 @@ impl LateLintPass<'_> for ItemNameRepetitions {
423431
_ => (),
424432
}
425433
}
426-
if rmatching.char_count == nchars {
434+
if rmatching.char_count == nchars
435+
&& !self.is_allowed_prefix(&item_camel[..item_camel.len() - rmatching.byte_count])
436+
{
427437
span_lint(
428438
cx,
429439
MODULE_NAME_REPETITIONS,

clippy_lints/src/lib.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -594,6 +594,7 @@ pub fn register_lints(store: &mut rustc_lint::LintStore, conf: &'static Conf) {
594594
pub_underscore_fields_behavior,
595595
ref allowed_duplicate_crates,
596596
allow_comparison_to_zero,
597+
ref allowed_prefixes,
597598

598599
blacklisted_names: _,
599600
cyclomatic_complexity_threshold: _,
@@ -864,6 +865,7 @@ pub fn register_lints(store: &mut rustc_lint::LintStore, conf: &'static Conf) {
864865
struct_field_name_threshold,
865866
avoid_breaking_exported_api,
866867
allow_private_module_inception,
868+
allowed_prefixes,
867869
))
868870
});
869871
store.register_early_pass(|| Box::new(tabs_in_doc_comments::TabsInDocComments));
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
allowed-prefixes = ["bar"]
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
#![warn(clippy::module_name_repetitions)]
2+
#![allow(dead_code)]
3+
4+
mod foo {
5+
// #12544 - shouldn't warn if item name consists only of an allowed prefix and a module name.
6+
// In this test, allowed prefixes are configured to be ["bar"].
7+
8+
// this line should produce a warning:
9+
pub fn to_foo() {}
10+
11+
// but this line shouldn't
12+
pub fn bar_foo() {}
13+
}
14+
15+
fn main() {}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
error: item name ends with its containing module's name
2+
--> tests/ui-toml/item_name_repetitions/allowed_prefixes/item_name_repetitions.rs:9:12
3+
|
4+
LL | pub fn to_foo() {}
5+
| ^^^^^^
6+
|
7+
= note: `-D clippy::module-name-repetitions` implied by `-D warnings`
8+
= help: to override `-D warnings` add `#[allow(clippy::module_name_repetitions)]`
9+
10+
error: aborting due to 1 previous error
11+
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
allowed-prefixes = ["..", "bar"]
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
#![warn(clippy::module_name_repetitions)]
2+
#![allow(dead_code)]
3+
4+
mod foo {
5+
// #12544 - shouldn't warn if item name consists only of an allowed prefix and a module name.
6+
// In this test, allowed prefixes are configured to be all of the default prefixes and ["bar"].
7+
8+
// this line should produce a warning:
9+
pub fn something_foo() {}
10+
11+
// but none of the following should:
12+
pub fn bar_foo() {}
13+
pub fn to_foo() {}
14+
pub fn as_foo() {}
15+
pub fn into_foo() {}
16+
pub fn from_foo() {}
17+
pub fn try_into_foo() {}
18+
pub fn try_from_foo() {}
19+
}
20+
21+
fn main() {}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
error: item name ends with its containing module's name
2+
--> tests/ui-toml/item_name_repetitions/allowed_prefixes_extend/item_name_repetitions.rs:9:12
3+
|
4+
LL | pub fn something_foo() {}
5+
| ^^^^^^^^^^^^^
6+
|
7+
= note: `-D clippy::module-name-repetitions` implied by `-D warnings`
8+
= help: to override `-D warnings` add `#[allow(clippy::module_name_repetitions)]`
9+
10+
error: aborting due to 1 previous error
11+

tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ error: error reading Clippy's configuration file: unknown field `foobar`, expect
1414
allowed-dotfiles
1515
allowed-duplicate-crates
1616
allowed-idents-below-min-chars
17+
allowed-prefixes
1718
allowed-scripts
1819
allowed-wildcard-imports
1920
arithmetic-side-effects-allowed
@@ -93,6 +94,7 @@ error: error reading Clippy's configuration file: unknown field `barfoo`, expect
9394
allowed-dotfiles
9495
allowed-duplicate-crates
9596
allowed-idents-below-min-chars
97+
allowed-prefixes
9698
allowed-scripts
9799
allowed-wildcard-imports
98100
arithmetic-side-effects-allowed
@@ -172,6 +174,7 @@ error: error reading Clippy's configuration file: unknown field `allow_mixed_uni
172174
allowed-dotfiles
173175
allowed-duplicate-crates
174176
allowed-idents-below-min-chars
177+
allowed-prefixes
175178
allowed-scripts
176179
allowed-wildcard-imports
177180
arithmetic-side-effects-allowed

tests/ui/module_name_repetitions.rs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,20 @@ mod foo {
1919

2020
// Should not warn
2121
pub struct Foobar;
22+
23+
// #12544 - shouldn't warn if item name consists only of an allowed prefix and a module name.
24+
pub fn to_foo() {}
25+
pub fn into_foo() {}
26+
pub fn as_foo() {}
27+
pub fn from_foo() {}
28+
pub fn try_into_foo() {}
29+
pub fn try_from_foo() {}
30+
pub trait IntoFoo {}
31+
pub trait ToFoo {}
32+
pub trait AsFoo {}
33+
pub trait FromFoo {}
34+
pub trait TryIntoFoo {}
35+
pub trait TryFromFoo {}
2236
}
2337

2438
fn main() {}

0 commit comments

Comments
 (0)