|
3 | 3 | use clippy_utils::diagnostics::{span_lint, span_lint_and_help}; |
4 | 4 | use clippy_utils::source::is_present_in_source; |
5 | 5 | use clippy_utils::str_utils::{self, count_match_end, count_match_start}; |
6 | | -use rustc_hir::{EnumDef, Item, ItemKind}; |
| 6 | +use rustc_hir::{EnumDef, Item, ItemKind, Variant}; |
7 | 7 | use rustc_lint::{LateContext, LateLintPass}; |
8 | 8 | use rustc_session::{declare_tool_lint, impl_lint_pass}; |
9 | 9 | use rustc_span::source_map::Span; |
@@ -115,50 +115,54 @@ impl EnumVariantNames { |
115 | 115 | } |
116 | 116 |
|
117 | 117 | impl_lint_pass!(EnumVariantNames => [ |
118 | | - ENUM_VARIANT_NAMES, |
119 | | - MODULE_NAME_REPETITIONS, |
120 | | - MODULE_INCEPTION |
| 118 | + ENUM_VARIANT_NAMES, |
| 119 | + MODULE_NAME_REPETITIONS, |
| 120 | + MODULE_INCEPTION |
121 | 121 | ]); |
122 | 122 |
|
123 | | -fn check_variant( |
124 | | - cx: &LateContext<'_>, |
125 | | - threshold: u64, |
126 | | - def: &EnumDef<'_>, |
127 | | - item_name: &str, |
128 | | - item_name_chars: usize, |
129 | | - span: Span, |
130 | | -) { |
| 123 | +fn check_enum_start(cx: &LateContext<'_>, item_name: &str, variant: &Variant<'_>) { |
| 124 | + let name = variant.ident.name.as_str(); |
| 125 | + let item_name_chars = item_name.chars().count(); |
| 126 | + |
| 127 | + if count_match_start(item_name, &name).char_count == item_name_chars |
| 128 | + && name.chars().nth(item_name_chars).map_or(false, |c| !c.is_lowercase()) |
| 129 | + && name.chars().nth(item_name_chars + 1).map_or(false, |c| !c.is_numeric()) |
| 130 | + { |
| 131 | + span_lint( |
| 132 | + cx, |
| 133 | + ENUM_VARIANT_NAMES, |
| 134 | + variant.span, |
| 135 | + "variant name starts with the enum's name", |
| 136 | + ); |
| 137 | + } |
| 138 | +} |
| 139 | + |
| 140 | +fn check_enum_end(cx: &LateContext<'_>, item_name: &str, variant: &Variant<'_>) { |
| 141 | + let name = variant.ident.name.as_str(); |
| 142 | + let item_name_chars = item_name.chars().count(); |
| 143 | + |
| 144 | + if count_match_end(item_name, &name).char_count == item_name_chars { |
| 145 | + span_lint( |
| 146 | + cx, |
| 147 | + ENUM_VARIANT_NAMES, |
| 148 | + variant.span, |
| 149 | + "variant name ends with the enum's name", |
| 150 | + ); |
| 151 | + } |
| 152 | +} |
| 153 | + |
| 154 | +fn check_variant(cx: &LateContext<'_>, threshold: u64, def: &EnumDef<'_>, item_name: &str, span: Span) { |
131 | 155 | if (def.variants.len() as u64) < threshold { |
132 | 156 | return; |
133 | 157 | } |
134 | | - for var in def.variants { |
135 | | - let name = var.ident.name.as_str(); |
136 | | - if count_match_start(item_name, &name).char_count == item_name_chars |
137 | | - && name.chars().nth(item_name_chars).map_or(false, |c| !c.is_lowercase()) |
138 | | - && name.chars().nth(item_name_chars + 1).map_or(false, |c| !c.is_numeric()) |
139 | | - { |
140 | | - span_lint( |
141 | | - cx, |
142 | | - ENUM_VARIANT_NAMES, |
143 | | - var.span, |
144 | | - "variant name starts with the enum's name", |
145 | | - ); |
146 | | - } |
147 | | - if count_match_end(item_name, &name).char_count == item_name_chars { |
148 | | - span_lint( |
149 | | - cx, |
150 | | - ENUM_VARIANT_NAMES, |
151 | | - var.span, |
152 | | - "variant name ends with the enum's name", |
153 | | - ); |
154 | | - } |
155 | | - } |
| 158 | + |
156 | 159 | let first = &def.variants[0].ident.name.as_str(); |
157 | 160 | let mut pre = &first[..str_utils::camel_case_until(&*first).byte_index]; |
158 | 161 | let mut post = &first[str_utils::camel_case_start(&*first).byte_index..]; |
159 | 162 | for var in def.variants { |
| 163 | + check_enum_start(cx, item_name, var); |
| 164 | + check_enum_end(cx, item_name, var); |
160 | 165 | let name = var.ident.name.as_str(); |
161 | | - |
162 | 166 | let pre_match = count_match_start(pre, &name).byte_count; |
163 | 167 | pre = &pre[..pre_match]; |
164 | 168 | let pre_camel = str_utils::camel_case_until(pre).byte_index; |
@@ -233,7 +237,6 @@ impl LateLintPass<'_> for EnumVariantNames { |
233 | 237 | #[allow(clippy::similar_names)] |
234 | 238 | fn check_item(&mut self, cx: &LateContext<'_>, item: &Item<'_>) { |
235 | 239 | let item_name = item.ident.name.as_str(); |
236 | | - let item_name_chars = item_name.chars().count(); |
237 | 240 | let item_camel = to_camel_case(&item_name); |
238 | 241 | if !item.span.from_expansion() && is_present_in_source(cx, item.span) { |
239 | 242 | if let Some(&(ref mod_name, ref mod_camel)) = self.modules.last() { |
@@ -283,7 +286,7 @@ impl LateLintPass<'_> for EnumVariantNames { |
283 | 286 | } |
284 | 287 | if let ItemKind::Enum(ref def, _) = item.kind { |
285 | 288 | if !(self.avoid_breaking_exported_api && cx.access_levels.is_exported(item.def_id)) { |
286 | | - check_variant(cx, self.threshold, def, &item_name, item_name_chars, item.span); |
| 289 | + check_variant(cx, self.threshold, def, &item_name, item.span); |
287 | 290 | } |
288 | 291 | } |
289 | 292 | self.modules.push((item.ident.name, item_camel)); |
|
0 commit comments