Skip to content

Commit 088a429

Browse files
committed
item_name_repetitions: exclude enum variants with identical path components
1 parent d3267e9 commit 088a429

File tree

2 files changed

+52
-3
lines changed

2 files changed

+52
-3
lines changed

clippy_lints/src/item_name_repetitions.rs

Lines changed: 36 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ use clippy_utils::macros::span_is_local;
55
use clippy_utils::source::is_present_in_source;
66
use clippy_utils::str_utils::{camel_case_split, count_match_end, count_match_start, to_camel_case, to_snake_case};
77
use rustc_data_structures::fx::FxHashSet;
8-
use rustc_hir::{EnumDef, FieldDef, Item, ItemKind, OwnerId, Variant, VariantData};
8+
use rustc_hir::{EnumDef, FieldDef, Item, ItemKind, OwnerId, QPath, TyKind, Variant, VariantData};
99
use rustc_lint::{LateContext, LateLintPass};
1010
use rustc_session::impl_lint_pass;
1111
use rustc_span::symbol::Symbol;
@@ -202,22 +202,55 @@ impl ItemNameRepetitions {
202202
return;
203203
}
204204

205-
if (def.variants.len() as u64) < self.enum_threshold {
205+
let variants = Self::filter_matching_enum_data(def);
206+
if (variants.len() as u64) < self.enum_threshold {
206207
return;
207208
}
208209

209210
let Some(ident) = item.kind.ident() else {
210211
return;
211212
};
212213
let item_name = ident.name.as_str();
213-
for var in def.variants {
214+
for var in variants {
214215
check_enum_start(cx, item_name, var);
215216
check_enum_end(cx, item_name, var);
216217
}
217218

218219
Self::check_enum_common_affix(cx, item, def);
219220
}
220221

222+
// Exclude enum variants that contain a single item where any component
223+
// of the contained item's path is identical to the variant's name.
224+
fn filter_matching_enum_data<'a>(def: &'a EnumDef<'a>) -> Vec<&'a Variant<'a>> {
225+
def.variants
226+
.iter()
227+
.filter(|var| {
228+
let variant_name = var.ident.name.as_str();
229+
if let VariantData::Tuple(fields, ..) = var.data
230+
&& fields.len() == 1
231+
{
232+
let field_ty = &fields[0].ty;
233+
if let TyKind::Path(qpath) = field_ty.kind {
234+
let path = match qpath {
235+
QPath::Resolved(_, path) => path,
236+
QPath::TypeRelative(_, segment) => {
237+
return segment.ident.name.as_str() != variant_name;
238+
},
239+
QPath::LangItem(..) => return true,
240+
};
241+
// Check if any path segment matches the variant name
242+
for segment in path.segments {
243+
if segment.ident.name.as_str() == variant_name {
244+
return false;
245+
}
246+
}
247+
}
248+
}
249+
true
250+
})
251+
.collect()
252+
}
253+
221254
/// Lint the names of struct fields against the name of the struct.
222255
fn check_fields(&self, cx: &LateContext<'_>, item: &Item<'_>, fields: &[FieldDef<'_>]) {
223256
if (fields.len() as u64) < self.struct_threshold {

tests/ui/enum_variants.rs

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -220,4 +220,20 @@ mod issue11494 {
220220
}
221221
}
222222

223+
mod encapsulated {
224+
mod local_types {
225+
pub struct FooError;
226+
pub struct BarError;
227+
pub struct BazError;
228+
pub struct QuxError;
229+
}
230+
231+
enum Error {
232+
FooError(local_types::FooError),
233+
BarError(local_types::BarError),
234+
BazError(local_types::BazError),
235+
NoMatch(local_types::QuxError),
236+
}
237+
}
238+
223239
fn main() {}

0 commit comments

Comments
 (0)