@@ -295,6 +295,7 @@ declare_clippy_lint! {
295
295
pub struct Types {
296
296
vec_box_size_threshold : u64 ,
297
297
type_complexity_threshold : u64 ,
298
+ avoid_breaking_exported_api : bool ,
298
299
}
299
300
300
301
impl_lint_pass ! ( Types => [ BOX_VEC , VEC_BOX , OPTION_OPTION , LINKEDLIST , BORROWED_BOX , REDUNDANT_ALLOCATION , RC_BUFFER , RC_MUTEX , TYPE_COMPLEXITY ] ) ;
@@ -308,19 +309,31 @@ impl<'tcx> LateLintPass<'tcx> for Types {
308
309
false
309
310
} ;
310
311
312
+ let is_exported = cx. access_levels . is_exported ( cx. tcx . hir ( ) . local_def_id ( id) ) ;
313
+
311
314
self . check_fn_decl (
312
315
cx,
313
316
decl,
314
317
CheckTyContext {
315
318
is_in_trait_impl,
319
+ is_exported,
316
320
..CheckTyContext :: default ( )
317
321
} ,
318
322
) ;
319
323
}
320
324
321
325
fn check_item ( & mut self , cx : & LateContext < ' tcx > , item : & ' tcx Item < ' _ > ) {
326
+ let is_exported = cx. access_levels . is_exported ( item. def_id ) ;
327
+
322
328
match item. kind {
323
- ItemKind :: Static ( ty, _, _) | ItemKind :: Const ( ty, _) => self . check_ty ( cx, ty, CheckTyContext :: default ( ) ) ,
329
+ ItemKind :: Static ( ty, _, _) | ItemKind :: Const ( ty, _) => self . check_ty (
330
+ cx,
331
+ ty,
332
+ CheckTyContext {
333
+ is_exported,
334
+ ..CheckTyContext :: default ( )
335
+ } ,
336
+ ) ,
324
337
// functions, enums, structs, impls and traits are covered
325
338
_ => ( ) ,
326
339
}
@@ -342,15 +355,31 @@ impl<'tcx> LateLintPass<'tcx> for Types {
342
355
}
343
356
344
357
fn check_field_def ( & mut self , cx : & LateContext < ' _ > , field : & hir:: FieldDef < ' _ > ) {
345
- self . check_ty ( cx, field. ty , CheckTyContext :: default ( ) ) ;
358
+ let is_exported = cx. access_levels . is_exported ( cx. tcx . hir ( ) . local_def_id ( field. hir_id ) ) ;
359
+
360
+ self . check_ty (
361
+ cx,
362
+ field. ty ,
363
+ CheckTyContext {
364
+ is_exported,
365
+ ..CheckTyContext :: default ( )
366
+ } ,
367
+ ) ;
346
368
}
347
369
348
- fn check_trait_item ( & mut self , cx : & LateContext < ' _ > , item : & TraitItem < ' _ > ) {
370
+ fn check_trait_item ( & mut self , cx : & LateContext < ' tcx > , item : & TraitItem < ' _ > ) {
371
+ let is_exported = cx. access_levels . is_exported ( item. def_id ) ;
372
+
373
+ let context = CheckTyContext {
374
+ is_exported,
375
+ ..CheckTyContext :: default ( )
376
+ } ;
377
+
349
378
match item. kind {
350
379
TraitItemKind :: Const ( ty, _) | TraitItemKind :: Type ( _, Some ( ty) ) => {
351
- self . check_ty ( cx, ty, CheckTyContext :: default ( ) ) ;
380
+ self . check_ty ( cx, ty, context ) ;
352
381
} ,
353
- TraitItemKind :: Fn ( ref sig, _) => self . check_fn_decl ( cx, sig. decl , CheckTyContext :: default ( ) ) ,
382
+ TraitItemKind :: Fn ( ref sig, _) => self . check_fn_decl ( cx, sig. decl , context ) ,
354
383
TraitItemKind :: Type ( ..) => ( ) ,
355
384
}
356
385
}
@@ -370,10 +399,11 @@ impl<'tcx> LateLintPass<'tcx> for Types {
370
399
}
371
400
372
401
impl Types {
373
- pub fn new ( vec_box_size_threshold : u64 , type_complexity_threshold : u64 ) -> Self {
402
+ pub fn new ( vec_box_size_threshold : u64 , type_complexity_threshold : u64 , avoid_breaking_exported_api : bool ) -> Self {
374
403
Self {
375
404
vec_box_size_threshold,
376
405
type_complexity_threshold,
406
+ avoid_breaking_exported_api,
377
407
}
378
408
}
379
409
@@ -410,17 +440,24 @@ impl Types {
410
440
let hir_id = hir_ty. hir_id ;
411
441
let res = cx. qpath_res ( qpath, hir_id) ;
412
442
if let Some ( def_id) = res. opt_def_id ( ) {
413
- let mut triggered = false ;
414
- triggered |= box_vec:: check ( cx, hir_ty, qpath, def_id) ;
415
- triggered |= redundant_allocation:: check ( cx, hir_ty, qpath, def_id) ;
416
- triggered |= rc_buffer:: check ( cx, hir_ty, qpath, def_id) ;
417
- triggered |= vec_box:: check ( cx, hir_ty, qpath, def_id, self . vec_box_size_threshold ) ;
418
- triggered |= option_option:: check ( cx, hir_ty, qpath, def_id) ;
419
- triggered |= linked_list:: check ( cx, hir_ty, def_id) ;
420
- triggered |= rc_mutex:: check ( cx, hir_ty, qpath, def_id) ;
421
-
422
- if triggered {
423
- return ;
443
+ if self . is_type_change_allowed ( context) {
444
+ // All lints that are being checked in this block are guarded by
445
+ // the `avoid_breaking_exported_api` configuration. When adding a
446
+ // new lint, please also add the name to the configuration documentation
447
+ // in `clippy_lints::utils::conf.rs`
448
+
449
+ let mut triggered = false ;
450
+ triggered |= box_vec:: check ( cx, hir_ty, qpath, def_id) ;
451
+ triggered |= redundant_allocation:: check ( cx, hir_ty, qpath, def_id) ;
452
+ triggered |= rc_buffer:: check ( cx, hir_ty, qpath, def_id) ;
453
+ triggered |= vec_box:: check ( cx, hir_ty, qpath, def_id, self . vec_box_size_threshold ) ;
454
+ triggered |= option_option:: check ( cx, hir_ty, qpath, def_id) ;
455
+ triggered |= linked_list:: check ( cx, hir_ty, def_id) ;
456
+ triggered |= rc_mutex:: check ( cx, hir_ty, qpath, def_id) ;
457
+
458
+ if triggered {
459
+ return ;
460
+ }
424
461
}
425
462
}
426
463
match * qpath {
@@ -487,11 +524,21 @@ impl Types {
487
524
_ => { } ,
488
525
}
489
526
}
527
+
528
+ /// This function checks if the type is allowed to change in the current context
529
+ /// based on the `avoid_breaking_exported_api` configuration
530
+ fn is_type_change_allowed ( & self , context : CheckTyContext ) -> bool {
531
+ !( context. is_exported && self . avoid_breaking_exported_api )
532
+ }
490
533
}
491
534
535
+ #[ allow( clippy:: struct_excessive_bools) ]
492
536
#[ derive( Clone , Copy , Default ) ]
493
537
struct CheckTyContext {
494
538
is_in_trait_impl : bool ,
539
+ /// `true` for types on local variables.
495
540
is_local : bool ,
541
+ /// `true` for types that are part of the public API.
542
+ is_exported : bool ,
496
543
is_nested_call : bool ,
497
544
}
0 commit comments