@@ -196,80 +196,100 @@ fn have_no_extra_prefix(prefixes: &[&str]) -> bool {
196
196
prefixes. iter ( ) . all ( |p| p == & "" || p == & "_" )
197
197
}
198
198
199
- fn check_fields ( cx : & LateContext < ' _ > , threshold : u64 , item : & Item < ' _ > , fields : & [ FieldDef < ' _ > ] ) {
200
- if ( fields. len ( ) as u64 ) < threshold {
201
- return ;
202
- }
203
-
204
- check_struct_name_repetition ( cx , item , fields ) ;
199
+ impl ItemNameRepetitions {
200
+ /// Lint the names of struct fields against the name of the struct.
201
+ fn check_fields ( & self , cx : & LateContext < ' _ > , item : & Item < ' _ > , fields : & [ FieldDef < ' _ > ] ) {
202
+ if ( fields . len ( ) as u64 ) < self . struct_threshold {
203
+ return ;
204
+ }
205
205
206
- // if the SyntaxContext of the identifiers of the fields and struct differ dont lint them.
207
- // this prevents linting in macros in which the location of the field identifier names differ
208
- if !fields. iter ( ) . all ( |field| item. ident . span . eq_ctxt ( field. ident . span ) ) {
209
- return ;
206
+ self . check_struct_name_repetition ( cx, item, fields) ;
207
+ self . check_common_affix ( cx, item, fields) ;
210
208
}
211
209
212
- let mut pre: Vec < & str > = match fields. first ( ) {
213
- Some ( first_field) => first_field. ident . name . as_str ( ) . split ( '_' ) . collect ( ) ,
214
- None => return ,
215
- } ;
216
- let mut post = pre. clone ( ) ;
217
- post. reverse ( ) ;
218
- for field in fields {
219
- let field_split: Vec < & str > = field. ident . name . as_str ( ) . split ( '_' ) . collect ( ) ;
220
- if field_split. len ( ) == 1 {
210
+ fn check_common_affix ( & self , cx : & LateContext < ' _ > , item : & Item < ' _ > , fields : & [ FieldDef < ' _ > ] ) {
211
+ // if the SyntaxContext of the identifiers of the fields and struct differ dont lint them.
212
+ // this prevents linting in macros in which the location of the field identifier names differ
213
+ if !fields. iter ( ) . all ( |field| item. ident . span . eq_ctxt ( field. ident . span ) ) {
221
214
return ;
222
215
}
223
216
224
- pre = pre
225
- . into_iter ( )
226
- . zip ( field_split. iter ( ) )
227
- . take_while ( |( a, b) | & a == b)
228
- . map ( |e| e. 0 )
229
- . collect ( ) ;
230
- post = post
231
- . into_iter ( )
232
- . zip ( field_split. iter ( ) . rev ( ) )
233
- . take_while ( |( a, b) | & a == b)
234
- . map ( |e| e. 0 )
235
- . collect ( ) ;
236
- }
237
- let prefix = pre. join ( "_" ) ;
238
- post. reverse ( ) ;
239
- let postfix = match post. last ( ) {
240
- Some ( & "" ) => post. join ( "_" ) + "_" ,
241
- Some ( _) | None => post. join ( "_" ) ,
242
- } ;
243
- if fields. len ( ) > 1 {
244
- let ( what, value) = match (
245
- prefix. is_empty ( ) || prefix. chars ( ) . all ( |c| c == '_' ) ,
246
- postfix. is_empty ( ) ,
247
- ) {
248
- ( true , true ) => return ,
249
- ( false , _) => ( "pre" , prefix) ,
250
- ( true , false ) => ( "post" , postfix) ,
251
- } ;
252
- if fields. iter ( ) . all ( |field| is_bool ( field. ty ) ) {
253
- // If all fields are booleans, we don't want to emit this lint.
217
+ if self . avoid_breaking_exported_api
218
+ && fields
219
+ . iter ( )
220
+ . any ( |field| cx. effective_visibilities . is_exported ( field. def_id ) )
221
+ {
254
222
return ;
255
223
}
256
- span_lint_and_help (
257
- cx,
258
- STRUCT_FIELD_NAMES ,
259
- item. span ,
260
- format ! ( "all fields have the same {what}fix: `{value}`" ) ,
261
- None ,
262
- format ! ( "remove the {what}fixes" ) ,
263
- ) ;
224
+
225
+ let mut pre: Vec < & str > = match fields. first ( ) {
226
+ Some ( first_field) => first_field. ident . name . as_str ( ) . split ( '_' ) . collect ( ) ,
227
+ None => return ,
228
+ } ;
229
+ let mut post = pre. clone ( ) ;
230
+ post. reverse ( ) ;
231
+ for field in fields {
232
+ let field_split: Vec < & str > = field. ident . name . as_str ( ) . split ( '_' ) . collect ( ) ;
233
+ if field_split. len ( ) == 1 {
234
+ return ;
235
+ }
236
+
237
+ pre = pre
238
+ . into_iter ( )
239
+ . zip ( field_split. iter ( ) )
240
+ . take_while ( |( a, b) | & a == b)
241
+ . map ( |e| e. 0 )
242
+ . collect ( ) ;
243
+ post = post
244
+ . into_iter ( )
245
+ . zip ( field_split. iter ( ) . rev ( ) )
246
+ . take_while ( |( a, b) | & a == b)
247
+ . map ( |e| e. 0 )
248
+ . collect ( ) ;
249
+ }
250
+ let prefix = pre. join ( "_" ) ;
251
+ post. reverse ( ) ;
252
+ let postfix = match post. last ( ) {
253
+ Some ( & "" ) => post. join ( "_" ) + "_" ,
254
+ Some ( _) | None => post. join ( "_" ) ,
255
+ } ;
256
+ if fields. len ( ) > 1 {
257
+ let ( what, value) = match (
258
+ prefix. is_empty ( ) || prefix. chars ( ) . all ( |c| c == '_' ) ,
259
+ postfix. is_empty ( ) ,
260
+ ) {
261
+ ( true , true ) => return ,
262
+ ( false , _) => ( "pre" , prefix) ,
263
+ ( true , false ) => ( "post" , postfix) ,
264
+ } ;
265
+ if fields. iter ( ) . all ( |field| is_bool ( field. ty ) ) {
266
+ // If all fields are booleans, we don't want to emit this lint.
267
+ return ;
268
+ }
269
+ span_lint_and_help (
270
+ cx,
271
+ STRUCT_FIELD_NAMES ,
272
+ item. span ,
273
+ format ! ( "all fields have the same {what}fix: `{value}`" ) ,
274
+ None ,
275
+ format ! ( "remove the {what}fixes" ) ,
276
+ ) ;
277
+ }
264
278
}
265
- }
266
279
267
- fn check_struct_name_repetition ( cx : & LateContext < ' _ > , item : & Item < ' _ > , fields : & [ FieldDef < ' _ > ] ) {
268
- let snake_name = to_snake_case ( item. ident . name . as_str ( ) ) ;
269
- let item_name_words: Vec < & str > = snake_name. split ( '_' ) . collect ( ) ;
270
- for field in fields {
271
- if field. ident . span . eq_ctxt ( item. ident . span ) {
272
- //consider linting only if the field identifier has the same SyntaxContext as the item(struct)
280
+ fn check_struct_name_repetition ( & self , cx : & LateContext < ' _ > , item : & Item < ' _ > , fields : & [ FieldDef < ' _ > ] ) {
281
+ let snake_name = to_snake_case ( item. ident . name . as_str ( ) ) ;
282
+ let item_name_words: Vec < & str > = snake_name. split ( '_' ) . collect ( ) ;
283
+ for field in fields {
284
+ if self . avoid_breaking_exported_api && cx. effective_visibilities . is_exported ( field. def_id ) {
285
+ continue ;
286
+ }
287
+
288
+ if !field. ident . span . eq_ctxt ( item. ident . span ) {
289
+ // consider linting only if the field identifier has the same SyntaxContext as the item(struct)
290
+ continue ;
291
+ }
292
+
273
293
let field_words: Vec < & str > = field. ident . name . as_str ( ) . split ( '_' ) . collect ( ) ;
274
294
if field_words. len ( ) >= item_name_words. len ( ) {
275
295
// if the field name is shorter than the struct name it cannot contain it
@@ -458,17 +478,23 @@ impl LateLintPass<'_> for ItemNameRepetitions {
458
478
}
459
479
}
460
480
}
461
- if !( self . avoid_breaking_exported_api && cx. effective_visibilities . is_exported ( item. owner_id . def_id ) )
462
- && span_is_local ( item. span )
463
- {
481
+
482
+ if span_is_local ( item. span ) {
464
483
match item. kind {
465
- ItemKind :: Enum ( def, _) => check_variant ( cx, self . enum_threshold , & def, item_name, item. span ) ,
484
+ ItemKind :: Enum ( def, _) => {
485
+ if !( self . avoid_breaking_exported_api
486
+ && cx. effective_visibilities . is_exported ( item. owner_id . def_id ) )
487
+ {
488
+ check_variant ( cx, self . enum_threshold , & def, item_name, item. span ) ;
489
+ }
490
+ } ,
466
491
ItemKind :: Struct ( VariantData :: Struct { fields, .. } , _) => {
467
- check_fields ( cx, self . struct_threshold , item, fields) ;
492
+ self . check_fields ( cx, item, fields) ;
468
493
} ,
469
494
_ => ( ) ,
470
495
}
471
496
}
497
+
472
498
self . modules . push ( ( item. ident . name , item_camel, item. owner_id ) ) ;
473
499
}
474
500
}
0 commit comments