1
1
//! lint on enum variants that are prefixed or suffixed by the same characters
2
2
3
- use clippy_utils:: camel_case;
4
3
use clippy_utils:: diagnostics:: { span_lint, span_lint_and_help} ;
5
4
use clippy_utils:: source:: is_present_in_source;
5
+ use clippy_utils:: str_utils:: { self , count_match_end, count_match_start} ;
6
6
use rustc_hir:: { EnumDef , Item , ItemKind } ;
7
7
use rustc_lint:: { LateContext , LateLintPass } ;
8
8
use rustc_session:: { declare_tool_lint, impl_lint_pass} ;
@@ -117,26 +117,6 @@ impl_lint_pass!(EnumVariantNames => [
117
117
MODULE_INCEPTION
118
118
] ) ;
119
119
120
- /// Returns the number of chars that match from the start
121
- #[ must_use]
122
- fn partial_match ( pre : & str , name : & str ) -> usize {
123
- let mut name_iter = name. chars ( ) ;
124
- let _ = name_iter. next_back ( ) ; // make sure the name is never fully matched
125
- pre. chars ( ) . zip ( name_iter) . take_while ( |& ( l, r) | l == r) . count ( )
126
- }
127
-
128
- /// Returns the number of chars that match from the end
129
- #[ must_use]
130
- fn partial_rmatch ( post : & str , name : & str ) -> usize {
131
- let mut name_iter = name. chars ( ) ;
132
- let _ = name_iter. next ( ) ; // make sure the name is never fully matched
133
- post. chars ( )
134
- . rev ( )
135
- . zip ( name_iter. rev ( ) )
136
- . take_while ( |& ( l, r) | l == r)
137
- . count ( )
138
- }
139
-
140
120
fn check_variant (
141
121
cx : & LateContext < ' _ > ,
142
122
threshold : u64 ,
@@ -150,7 +130,7 @@ fn check_variant(
150
130
}
151
131
for var in def. variants {
152
132
let name = var. ident . name . as_str ( ) ;
153
- if partial_match ( item_name, & name) == item_name_chars
133
+ if count_match_start ( item_name, & name) . char_count == item_name_chars
154
134
&& name. chars ( ) . nth ( item_name_chars) . map_or ( false , |c| !c. is_lowercase ( ) )
155
135
&& name. chars ( ) . nth ( item_name_chars + 1 ) . map_or ( false , |c| !c. is_numeric ( ) )
156
136
{
@@ -161,7 +141,7 @@ fn check_variant(
161
141
"variant name starts with the enum's name" ,
162
142
) ;
163
143
}
164
- if partial_rmatch ( item_name, & name) == item_name_chars {
144
+ if count_match_end ( item_name, & name) . char_count == item_name_chars {
165
145
span_lint (
166
146
cx,
167
147
ENUM_VARIANT_NAMES ,
@@ -171,33 +151,33 @@ fn check_variant(
171
151
}
172
152
}
173
153
let first = & def. variants [ 0 ] . ident . name . as_str ( ) ;
174
- let mut pre = & first[ ..camel_case :: until ( & * first) ] ;
175
- let mut post = & first[ camel_case :: from ( & * first) ..] ;
154
+ let mut pre = & first[ ..str_utils :: camel_case_until ( & * first) . byte_index ] ;
155
+ let mut post = & first[ str_utils :: camel_case_start ( & * first) . byte_index ..] ;
176
156
for var in def. variants {
177
157
let name = var. ident . name . as_str ( ) ;
178
158
179
- let pre_match = partial_match ( pre, & name) ;
159
+ let pre_match = count_match_start ( pre, & name) . byte_count ;
180
160
pre = & pre[ ..pre_match] ;
181
- let pre_camel = camel_case :: until ( pre) ;
161
+ let pre_camel = str_utils :: camel_case_until ( pre) . byte_index ;
182
162
pre = & pre[ ..pre_camel] ;
183
163
while let Some ( ( next, last) ) = name[ pre. len ( ) ..] . chars ( ) . zip ( pre. chars ( ) . rev ( ) ) . next ( ) {
184
164
if next. is_numeric ( ) {
185
165
return ;
186
166
}
187
167
if next. is_lowercase ( ) {
188
168
let last = pre. len ( ) - last. len_utf8 ( ) ;
189
- let last_camel = camel_case :: until ( & pre[ ..last] ) ;
190
- pre = & pre[ ..last_camel] ;
169
+ let last_camel = str_utils :: camel_case_until ( & pre[ ..last] ) ;
170
+ pre = & pre[ ..last_camel. byte_index ] ;
191
171
} else {
192
172
break ;
193
173
}
194
174
}
195
175
196
- let post_match = partial_rmatch ( post, & name) ;
197
- let post_end = post. len ( ) - post_match;
176
+ let post_match = count_match_end ( post, & name) ;
177
+ let post_end = post. len ( ) - post_match. byte_count ;
198
178
post = & post[ post_end..] ;
199
- let post_camel = camel_case :: from ( post) ;
200
- post = & post[ post_camel..] ;
179
+ let post_camel = str_utils :: camel_case_start ( post) ;
180
+ post = & post[ post_camel. byte_index . .] ;
201
181
}
202
182
let ( what, value) = match ( pre. is_empty ( ) , post. is_empty ( ) ) {
203
183
( true , true ) => return ,
@@ -266,14 +246,16 @@ impl LateLintPass<'_> for EnumVariantNames {
266
246
) ;
267
247
}
268
248
}
269
- if item. vis . node . is_pub ( ) {
270
- let matching = partial_match ( mod_camel, & item_camel) ;
271
- let rmatching = partial_rmatch ( mod_camel, & item_camel) ;
249
+ // The `module_name_repetitions` lint should only trigger if the item has the module in its
250
+ // name. Having the same name is accepted.
251
+ if item. vis . node . is_pub ( ) && item_camel. len ( ) > mod_camel. len ( ) {
252
+ let matching = count_match_start ( mod_camel, & item_camel) ;
253
+ let rmatching = count_match_end ( mod_camel, & item_camel) ;
272
254
let nchars = mod_camel. chars ( ) . count ( ) ;
273
255
274
256
let is_word_beginning = |c : char | c == '_' || c. is_uppercase ( ) || c. is_numeric ( ) ;
275
257
276
- if matching == nchars {
258
+ if matching. char_count == nchars {
277
259
match item_camel. chars ( ) . nth ( nchars) {
278
260
Some ( c) if is_word_beginning ( c) => span_lint (
279
261
cx,
@@ -284,7 +266,7 @@ impl LateLintPass<'_> for EnumVariantNames {
284
266
_ => ( ) ,
285
267
}
286
268
}
287
- if rmatching == nchars {
269
+ if rmatching. char_count == nchars {
288
270
span_lint (
289
271
cx,
290
272
MODULE_NAME_REPETITIONS ,
0 commit comments