about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2023-06-24 18:59:58 +0000
committerbors <bors@rust-lang.org>2023-06-24 18:59:58 +0000
commit1b4c423f305e839c29a3355fc8cd5c092d80bd78 (patch)
tree116d0b7f18c15626041d1d06df568b519ecc1430
parent3cee98d1a32e634b71b02fe4f3de875171ecaff4 (diff)
parentfe856d383f75a9c8341a451033fa03992cfb0b3c (diff)
downloadrust-1b4c423f305e839c29a3355fc8cd5c092d80bd78.tar.gz
rust-1b4c423f305e839c29a3355fc8cd5c092d80bd78.zip
Auto merge of #11021 - y21:issue9493, r=llogiq
[`format_push_string`]: look through `match` and `if` expressions

Closes #9493.

changelog: [`format_push_string`]: look through `match` and `if` expressions
-rw-r--r--clippy_lints/src/format_push_string.rs23
-rw-r--r--tests/ui/format_push_string.rs29
-rw-r--r--tests/ui/format_push_string.stderr37
3 files changed, 83 insertions, 6 deletions
diff --git a/clippy_lints/src/format_push_string.rs b/clippy_lints/src/format_push_string.rs
index 68c5c3673fe..45f67020c2d 100644
--- a/clippy_lints/src/format_push_string.rs
+++ b/clippy_lints/src/format_push_string.rs
@@ -1,7 +1,7 @@
 use clippy_utils::diagnostics::span_lint_and_help;
 use clippy_utils::ty::is_type_lang_item;
-use clippy_utils::{match_def_path, paths, peel_hir_expr_refs};
-use rustc_hir::{BinOpKind, Expr, ExprKind, LangItem};
+use clippy_utils::{higher, match_def_path, paths};
+use rustc_hir::{BinOpKind, Expr, ExprKind, LangItem, MatchSource};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_session::{declare_lint_pass, declare_tool_lint};
 use rustc_span::sym;
@@ -44,10 +44,24 @@ fn is_string(cx: &LateContext<'_>, e: &Expr<'_>) -> bool {
     is_type_lang_item(cx, cx.typeck_results().expr_ty(e).peel_refs(), LangItem::String)
 }
 fn is_format(cx: &LateContext<'_>, e: &Expr<'_>) -> bool {
-    if let Some(macro_def_id) = e.span.ctxt().outer_expn_data().macro_def_id {
+    let e = e.peel_blocks().peel_borrows();
+
+    if e.span.from_expansion()
+        && let Some(macro_def_id) = e.span.ctxt().outer_expn_data().macro_def_id
+    {
         cx.tcx.get_diagnostic_name(macro_def_id) == Some(sym::format_macro)
+    } else if let Some(higher::If { then, r#else, .. }) = higher::If::hir(e) {
+        is_format(cx, then) || r#else.is_some_and(|e| is_format(cx, e))
     } else {
-        false
+        match higher::IfLetOrMatch::parse(cx, e) {
+            Some(higher::IfLetOrMatch::Match(_, arms, MatchSource::Normal)) => {
+                arms.iter().any(|arm| is_format(cx, arm.body))
+            },
+            Some(higher::IfLetOrMatch::IfLet(_, _, then, r#else)) => {
+                is_format(cx, then) ||r#else.is_some_and(|e| is_format(cx, e))
+            },
+            _ => false,
+        }
     }
 }
 
@@ -68,7 +82,6 @@ impl<'tcx> LateLintPass<'tcx> for FormatPushString {
             },
             _ => return,
         };
-        let (arg, _) = peel_hir_expr_refs(arg);
         if is_format(cx, arg) {
             span_lint_and_help(
                 cx,
diff --git a/tests/ui/format_push_string.rs b/tests/ui/format_push_string.rs
index 4db13d650eb..89423ffe1cf 100644
--- a/tests/ui/format_push_string.rs
+++ b/tests/ui/format_push_string.rs
@@ -5,3 +5,32 @@ fn main() {
     string += &format!("{:?}", 1234);
     string.push_str(&format!("{:?}", 5678));
 }
+
+mod issue9493 {
+    pub fn u8vec_to_hex(vector: &Vec<u8>, upper: bool) -> String {
+        let mut hex = String::with_capacity(vector.len() * 2);
+        for byte in vector {
+            hex += &(if upper {
+                format!("{byte:02X}")
+            } else {
+                format!("{byte:02x}")
+            });
+        }
+        hex
+    }
+
+    pub fn other_cases() {
+        let mut s = String::new();
+        // if let
+        s += &(if let Some(_a) = Some(1234) {
+            format!("{}", 1234)
+        } else {
+            format!("{}", 1234)
+        });
+        // match
+        s += &(match Some(1234) {
+            Some(_) => format!("{}", 1234),
+            None => format!("{}", 1234),
+        });
+    }
+}
diff --git a/tests/ui/format_push_string.stderr b/tests/ui/format_push_string.stderr
index d7be9a5f206..76762c4a1d1 100644
--- a/tests/ui/format_push_string.stderr
+++ b/tests/ui/format_push_string.stderr
@@ -15,5 +15,40 @@ LL |     string.push_str(&format!("{:?}", 5678));
    |
    = help: consider using `write!` to avoid the extra allocation
 
-error: aborting due to 2 previous errors
+error: `format!(..)` appended to existing `String`
+  --> $DIR/format_push_string.rs:13:13
+   |
+LL | /             hex += &(if upper {
+LL | |                 format!("{byte:02X}")
+LL | |             } else {
+LL | |                 format!("{byte:02x}")
+LL | |             });
+   | |______________^
+   |
+   = help: consider using `write!` to avoid the extra allocation
+
+error: `format!(..)` appended to existing `String`
+  --> $DIR/format_push_string.rs:25:9
+   |
+LL | /         s += &(if let Some(_a) = Some(1234) {
+LL | |             format!("{}", 1234)
+LL | |         } else {
+LL | |             format!("{}", 1234)
+LL | |         });
+   | |__________^
+   |
+   = help: consider using `write!` to avoid the extra allocation
+
+error: `format!(..)` appended to existing `String`
+  --> $DIR/format_push_string.rs:31:9
+   |
+LL | /         s += &(match Some(1234) {
+LL | |             Some(_) => format!("{}", 1234),
+LL | |             None => format!("{}", 1234),
+LL | |         });
+   | |__________^
+   |
+   = help: consider using `write!` to avoid the extra allocation
+
+error: aborting due to 5 previous errors