11//! lint on enum variants that are prefixed or suffixed by the same characters
22
3- use clippy_utils:: camel_case;
43use clippy_utils:: diagnostics:: { span_lint, span_lint_and_help} ;
54use clippy_utils:: source:: is_present_in_source;
5+ use clippy_utils:: str_utils:: { self , count_match_end, count_match_start} ;
66use rustc_hir:: { EnumDef , Item , ItemKind } ;
77use rustc_lint:: { LateContext , LateLintPass } ;
88use rustc_session:: { declare_tool_lint, impl_lint_pass} ;
@@ -117,26 +117,6 @@ impl_lint_pass!(EnumVariantNames => [
117117 MODULE_INCEPTION
118118] ) ;
119119
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-
140120fn check_variant (
141121 cx : & LateContext < ' _ > ,
142122 threshold : u64 ,
@@ -150,7 +130,7 @@ fn check_variant(
150130 }
151131 for var in def. variants {
152132 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
154134 && name. chars ( ) . nth ( item_name_chars) . map_or ( false , |c| !c. is_lowercase ( ) )
155135 && name. chars ( ) . nth ( item_name_chars + 1 ) . map_or ( false , |c| !c. is_numeric ( ) )
156136 {
@@ -161,7 +141,7 @@ fn check_variant(
161141 "variant name starts with the enum's name" ,
162142 ) ;
163143 }
164- if partial_rmatch ( item_name, & name) == item_name_chars {
144+ if count_match_end ( item_name, & name) . char_count == item_name_chars {
165145 span_lint (
166146 cx,
167147 ENUM_VARIANT_NAMES ,
@@ -171,33 +151,33 @@ fn check_variant(
171151 }
172152 }
173153 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 ..] ;
176156 for var in def. variants {
177157 let name = var. ident . name . as_str ( ) ;
178158
179- let pre_match = partial_match ( pre, & name) ;
159+ let pre_match = count_match_start ( pre, & name) . byte_count ;
180160 pre = & pre[ ..pre_match] ;
181- let pre_camel = camel_case :: until ( pre) ;
161+ let pre_camel = str_utils :: camel_case_until ( pre) . byte_index ;
182162 pre = & pre[ ..pre_camel] ;
183163 while let Some ( ( next, last) ) = name[ pre. len ( ) ..] . chars ( ) . zip ( pre. chars ( ) . rev ( ) ) . next ( ) {
184164 if next. is_numeric ( ) {
185165 return ;
186166 }
187167 if next. is_lowercase ( ) {
188168 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 ] ;
191171 } else {
192172 break ;
193173 }
194174 }
195175
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 ;
198178 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 . .] ;
201181 }
202182 let ( what, value) = match ( pre. is_empty ( ) , post. is_empty ( ) ) {
203183 ( true , true ) => return ,
@@ -266,14 +246,16 @@ impl LateLintPass<'_> for EnumVariantNames {
266246 ) ;
267247 }
268248 }
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) ;
272254 let nchars = mod_camel. chars ( ) . count ( ) ;
273255
274256 let is_word_beginning = |c : char | c == '_' || c. is_uppercase ( ) || c. is_numeric ( ) ;
275257
276- if matching == nchars {
258+ if matching. char_count == nchars {
277259 match item_camel. chars ( ) . nth ( nchars) {
278260 Some ( c) if is_word_beginning ( c) => span_lint (
279261 cx,
@@ -284,7 +266,7 @@ impl LateLintPass<'_> for EnumVariantNames {
284266 _ => ( ) ,
285267 }
286268 }
287- if rmatching == nchars {
269+ if rmatching. char_count == nchars {
288270 span_lint (
289271 cx,
290272 MODULE_NAME_REPETITIONS ,
0 commit comments