11mod borrowed_box;
22mod box_collection;
33mod linked_list;
4+ mod null_pointer_optimization;
45mod option_option;
56mod rc_buffer;
67mod rc_mutex;
@@ -303,13 +304,50 @@ declare_clippy_lint! {
303304 "usage of `Rc<Mutex<T>>`"
304305}
305306
307+ declare_clippy_lint ! {
308+ /// ### What it does
309+ /// Checks for `C<Option<T>>` where `C` is a type that has
310+ /// [null pointer optimization](https://doc.rust-lang.org/core/option/#representation).
311+ ///
312+ /// Note: There are some cases where `C<Option<T>>` is necessary, like getting a
313+ /// `&mut Option<T>` from a `Box<Option<T>>`. This requires ownership of the `Box`, so
314+ /// if you have a reference this is not possible to do.
315+ ///
316+ /// ### Why is this bad?
317+ /// It's slower, as `Option` can use `null` as `None`, instead of adding another layer of
318+ /// indirection.
319+ ///
320+ /// ### Example
321+ /// ```rust
322+ /// struct MyWrapperType<T>(Box<Option<T>>);
323+ /// ```
324+ /// Use instead:
325+ /// ```rust
326+ /// struct MyWrapperType<T>(Option<Box<T>>);
327+ /// ```
328+ #[ clippy:: version = "1.73.0" ]
329+ pub NULL_POINTER_OPTIMIZATION ,
330+ perf,
331+ "checks for `C<Option<T>>` where `C` is a type that has null pointer optimization"
332+ }
306333pub struct Types {
307334 vec_box_size_threshold : u64 ,
308335 type_complexity_threshold : u64 ,
309336 avoid_breaking_exported_api : bool ,
310337}
311338
312- impl_lint_pass ! ( Types => [ BOX_COLLECTION , VEC_BOX , OPTION_OPTION , LINKEDLIST , BORROWED_BOX , REDUNDANT_ALLOCATION , RC_BUFFER , RC_MUTEX , TYPE_COMPLEXITY ] ) ;
339+ impl_lint_pass ! ( Types => [
340+ BOX_COLLECTION ,
341+ VEC_BOX ,
342+ OPTION_OPTION ,
343+ LINKEDLIST ,
344+ BORROWED_BOX ,
345+ REDUNDANT_ALLOCATION ,
346+ RC_BUFFER ,
347+ RC_MUTEX ,
348+ TYPE_COMPLEXITY ,
349+ NULL_POINTER_OPTIMIZATION ,
350+ ] ) ;
313351
314352impl < ' tcx > LateLintPass < ' tcx > for Types {
315353 fn check_fn (
@@ -349,10 +387,11 @@ impl<'tcx> LateLintPass<'tcx> for Types {
349387 let is_exported = cx. effective_visibilities . is_exported ( item. owner_id . def_id ) ;
350388
351389 match item. kind {
352- ItemKind :: Static ( ty, _, _) | ItemKind :: Const ( ty, _) => self . check_ty (
390+ ItemKind :: Static ( ty, _, _) | ItemKind :: Const ( ty, _) | ItemKind :: TyAlias ( ty , _ ) => self . check_ty (
353391 cx,
354392 ty,
355393 CheckTyContext {
394+ is_in_ty_alias : matches ! ( item. kind, ItemKind :: TyAlias ( ..) ) ,
356395 is_exported,
357396 ..CheckTyContext :: default ( )
358397 } ,
@@ -476,7 +515,10 @@ impl Types {
476515 return ;
477516 }
478517
479- if !context. is_nested_call && type_complexity:: check ( cx, hir_ty, self . type_complexity_threshold ) {
518+ if !context. is_nested_call
519+ && !context. is_in_ty_alias
520+ && type_complexity:: check ( cx, hir_ty, self . type_complexity_threshold )
521+ {
480522 return ;
481523 }
482524
@@ -492,13 +534,16 @@ impl Types {
492534 // in `clippy_lints::utils::conf.rs`
493535
494536 let mut triggered = false ;
495- triggered |= box_collection:: check ( cx, hir_ty, qpath, def_id) ;
496- triggered |= redundant_allocation:: check ( cx, hir_ty, qpath, def_id) ;
497- triggered |= rc_buffer:: check ( cx, hir_ty, qpath, def_id) ;
498- triggered |= vec_box:: check ( cx, hir_ty, qpath, def_id, self . vec_box_size_threshold ) ;
499- triggered |= option_option:: check ( cx, hir_ty, qpath, def_id) ;
500- triggered |= linked_list:: check ( cx, hir_ty, def_id) ;
501- triggered |= rc_mutex:: check ( cx, hir_ty, qpath, def_id) ;
537+ if !context. is_in_ty_alias {
538+ triggered |= box_collection:: check ( cx, hir_ty, qpath, def_id) ;
539+ triggered |= redundant_allocation:: check ( cx, hir_ty, qpath, def_id) ;
540+ triggered |= rc_buffer:: check ( cx, hir_ty, qpath, def_id) ;
541+ triggered |= vec_box:: check ( cx, hir_ty, qpath, def_id, self . vec_box_size_threshold ) ;
542+ triggered |= option_option:: check ( cx, hir_ty, qpath, def_id) ;
543+ triggered |= linked_list:: check ( cx, hir_ty, def_id) ;
544+ triggered |= rc_mutex:: check ( cx, hir_ty, qpath, def_id) ;
545+ }
546+ triggered |= null_pointer_optimization:: check ( cx, hir_ty, qpath, res) ;
502547
503548 if triggered {
504549 return ;
@@ -580,6 +625,7 @@ impl Types {
580625#[ allow( clippy:: struct_excessive_bools) ]
581626#[ derive( Clone , Copy , Default ) ]
582627struct CheckTyContext {
628+ is_in_ty_alias : bool ,
583629 is_in_trait_impl : bool ,
584630 /// `true` for types on local variables.
585631 is_local : bool ,
0 commit comments