|
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