@@ -26,6 +26,7 @@ mod filter_map_next;
26
26
mod filter_next;
27
27
mod flat_map_identity;
28
28
mod flat_map_option;
29
+ mod format_collect;
29
30
mod from_iter_instead_of_collect;
30
31
mod get_first;
31
32
mod get_last_with_len;
@@ -3378,6 +3379,36 @@ declare_clippy_lint! {
3378
3379
"calling `Stdin::read_line`, then trying to parse it without first trimming"
3379
3380
}
3380
3381
3382
+ declare_clippy_lint ! {
3383
+ /// ### What it does
3384
+ /// Checks for usage of `.map(|_| format!(..)).collect::<String>()`.
3385
+ ///
3386
+ /// ### Why is this bad?
3387
+ /// This allocates a new string for every element in the iterator.
3388
+ /// This can be done more efficiently by creating the `String` once and appending to it using `Iterator::fold`.
3389
+ ///
3390
+ /// ### Example
3391
+ /// ```rust
3392
+ /// fn hex_encode(bytes: &[u8]) -> String {
3393
+ /// bytes.iter().map(|b| format!("{b:02X}")).collect()
3394
+ /// }
3395
+ /// ```
3396
+ /// Use instead:
3397
+ /// ```rust
3398
+ /// use std::fmt::Write;
3399
+ /// fn hex_encode(bytes: &[u8]) -> String {
3400
+ /// bytes.iter().fold(String::new(), |mut output, b| {
3401
+ /// let _ = write!(output, "{b:02X}");
3402
+ /// output
3403
+ /// })
3404
+ /// }
3405
+ /// ```
3406
+ #[ clippy:: version = "1.72.0" ]
3407
+ pub FORMAT_COLLECT ,
3408
+ perf,
3409
+ "`format!`ing every element in a collection, then collecting the strings into a new `String`"
3410
+ }
3411
+
3381
3412
pub struct Methods {
3382
3413
avoid_breaking_exported_api : bool ,
3383
3414
msrv : Msrv ,
@@ -3512,6 +3543,7 @@ impl_lint_pass!(Methods => [
3512
3543
UNNECESSARY_LITERAL_UNWRAP ,
3513
3544
DRAIN_COLLECT ,
3514
3545
MANUAL_TRY_FOLD ,
3546
+ FORMAT_COLLECT ,
3515
3547
] ) ;
3516
3548
3517
3549
/// Extracts a method call name, args, and `Span` of the method name.
@@ -3733,8 +3765,9 @@ impl Methods {
3733
3765
Some ( ( name @ ( "cloned" | "copied" ) , recv2, [ ] , _, _) ) => {
3734
3766
iter_cloned_collect:: check ( cx, name, expr, recv2) ;
3735
3767
} ,
3736
- Some ( ( "map" , m_recv, [ m_arg] , _ , _) ) => {
3768
+ Some ( ( "map" , m_recv, [ m_arg] , m_ident_span , _) ) => {
3737
3769
map_collect_result_unit:: check ( cx, expr, m_recv, m_arg) ;
3770
+ format_collect:: check ( cx, expr, m_arg, m_ident_span) ;
3738
3771
} ,
3739
3772
Some ( ( "take" , take_self_arg, [ take_arg] , _, _) ) => {
3740
3773
if self . msrv . meets ( msrvs:: STR_REPEAT ) {
0 commit comments