@@ -295,6 +295,7 @@ declare_clippy_lint! {
295295pub struct Types {
296296 vec_box_size_threshold : u64 ,
297297 type_complexity_threshold : u64 ,
298+ avoid_breaking_exported_api : bool ,
298299}
299300
300301impl_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 {
308309 false
309310 } ;
310311
312+ let is_exported = cx. access_levels . is_exported ( cx. tcx . hir ( ) . local_def_id ( id) ) ;
313+
311314 self . check_fn_decl (
312315 cx,
313316 decl,
314317 CheckTyContext {
315318 is_in_trait_impl,
319+ is_exported,
316320 ..CheckTyContext :: default ( )
317321 } ,
318322 ) ;
319323 }
320324
321325 fn check_item ( & mut self , cx : & LateContext < ' tcx > , item : & ' tcx Item < ' _ > ) {
326+ let is_exported = cx. access_levels . is_exported ( item. def_id ) ;
327+
322328 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+ ) ,
324337 // functions, enums, structs, impls and traits are covered
325338 _ => ( ) ,
326339 }
@@ -342,15 +355,31 @@ impl<'tcx> LateLintPass<'tcx> for Types {
342355 }
343356
344357 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+ ) ;
346368 }
347369
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+
349378 match item. kind {
350379 TraitItemKind :: Const ( ty, _) | TraitItemKind :: Type ( _, Some ( ty) ) => {
351- self . check_ty ( cx, ty, CheckTyContext :: default ( ) ) ;
380+ self . check_ty ( cx, ty, context ) ;
352381 } ,
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 ) ,
354383 TraitItemKind :: Type ( ..) => ( ) ,
355384 }
356385 }
@@ -370,10 +399,11 @@ impl<'tcx> LateLintPass<'tcx> for Types {
370399}
371400
372401impl 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 {
374403 Self {
375404 vec_box_size_threshold,
376405 type_complexity_threshold,
406+ avoid_breaking_exported_api,
377407 }
378408 }
379409
@@ -410,17 +440,24 @@ impl Types {
410440 let hir_id = hir_ty. hir_id ;
411441 let res = cx. qpath_res ( qpath, hir_id) ;
412442 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+ }
424461 }
425462 }
426463 match * qpath {
@@ -487,11 +524,21 @@ impl Types {
487524 _ => { } ,
488525 }
489526 }
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+ }
490533}
491534
535+ #[ allow( clippy:: struct_excessive_bools) ]
492536#[ derive( Clone , Copy , Default ) ]
493537struct CheckTyContext {
494538 is_in_trait_impl : bool ,
539+ /// `true` for types on local variables.
495540 is_local : bool ,
541+ /// `true` for types that are part of the public API.
542+ is_exported : bool ,
496543 is_nested_call : bool ,
497544}
0 commit comments