@@ -2,6 +2,7 @@ mod borrowed_box;
22mod box_collection;
33mod linked_list;
44mod option_option;
5+ mod owned_cow;
56mod rc_buffer;
67mod rc_mutex;
78mod redundant_allocation;
@@ -355,13 +356,63 @@ declare_clippy_lint! {
355356 "usage of `Rc<Mutex<T>>`"
356357}
357358
359+ declare_clippy_lint ! {
360+ /// ### What it does
361+ /// Detects needlessly owned `Cow` types.
362+ ///
363+ /// ### Why is this bad?
364+ /// The borrowed types are usually more flexible, in that e.g. a
365+ /// `Cow<'_, str>` can accept both `&str` and `String` while
366+ /// `Cow<'_, String>` can only accept `&String` and `String`. In
367+ /// particular, `&str` is more general, because it allows for string
368+ /// literals while `&String` can only be borrowed from a heap-owned
369+ /// `String`).
370+ ///
371+ /// ### Known Problems
372+ /// The lint does not check for usage of the type. There may be external
373+ /// interfaces that require the use of an owned type.
374+ ///
375+ /// At least the `CString` type also has a different API than `CStr`: The
376+ /// former has an `as_bytes` method which the latter calls `to_bytes`.
377+ /// There is no guarantee that other types won't gain additional methods
378+ /// leading to a similar mismatch.
379+ ///
380+ /// In addition, the lint only checks for the known problematic types
381+ /// `String`, `Vec<_>`, `CString`, `OsString` and `PathBuf`. Custom types
382+ /// that implement `ToOwned` will not be detected.
383+ ///
384+ /// ### Example
385+ /// ```no_run
386+ /// let wrogn: std::borrow::Cow<'_, Vec<u8>>;
387+ /// ```
388+ /// Use instead:
389+ /// ```no_run
390+ /// let right: std::borrow::Cow<'_, [u8]>;
391+ /// ```
392+ #[ clippy:: version = "1.85.0" ]
393+ pub OWNED_COW ,
394+ style,
395+ "needlessly owned Cow type"
396+ }
397+
358398pub struct Types {
359399 vec_box_size_threshold : u64 ,
360400 type_complexity_threshold : u64 ,
361401 avoid_breaking_exported_api : bool ,
362402}
363403
364- impl_lint_pass ! ( Types => [ BOX_COLLECTION , VEC_BOX , OPTION_OPTION , LINKEDLIST , BORROWED_BOX , REDUNDANT_ALLOCATION , RC_BUFFER , RC_MUTEX , TYPE_COMPLEXITY ] ) ;
404+ impl_lint_pass ! ( Types => [
405+ BOX_COLLECTION ,
406+ VEC_BOX ,
407+ OPTION_OPTION ,
408+ LINKEDLIST ,
409+ BORROWED_BOX ,
410+ REDUNDANT_ALLOCATION ,
411+ RC_BUFFER ,
412+ RC_MUTEX ,
413+ TYPE_COMPLEXITY ,
414+ OWNED_COW
415+ ] ) ;
365416
366417impl < ' tcx > LateLintPass < ' tcx > for Types {
367418 fn check_fn (
@@ -561,6 +612,7 @@ impl Types {
561612 triggered |= option_option:: check ( cx, hir_ty, qpath, def_id) ;
562613 triggered |= linked_list:: check ( cx, hir_ty, def_id) ;
563614 triggered |= rc_mutex:: check ( cx, hir_ty, qpath, def_id) ;
615+ triggered |= owned_cow:: check ( cx, qpath, def_id) ;
564616
565617 if triggered {
566618 return ;
@@ -612,6 +664,14 @@ impl Types {
612664 QPath :: LangItem ( ..) => { } ,
613665 }
614666 } ,
667+ TyKind :: Path ( ref qpath) => {
668+ let res = cx. qpath_res ( qpath, hir_ty. hir_id ) ;
669+ if let Some ( def_id) = res. opt_def_id ( )
670+ && self . is_type_change_allowed ( context)
671+ {
672+ owned_cow:: check ( cx, qpath, def_id) ;
673+ }
674+ } ,
615675 TyKind :: Ref ( lt, ref mut_ty) => {
616676 context. is_nested_call = true ;
617677 if !borrowed_box:: check ( cx, hir_ty, lt, mut_ty) {
0 commit comments