about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2020-10-09 23:14:58 +0000
committerbors <bors@rust-lang.org>2020-10-09 23:14:58 +0000
commit2bdadd8e7dc54651df06e0adff1c1b1e7dcf6480 (patch)
treeb3471fef1070d8876826263fbb632602d8a76d5e
parent0b86340999c207647b797bccbb1d49f824a277df (diff)
parent7b7ddfa55da889b41e90243ac59a04eed832a71e (diff)
downloadrust-2bdadd8e7dc54651df06e0adff1c1b1e7dcf6480.tar.gz
rust-2bdadd8e7dc54651df06e0adff1c1b1e7dcf6480.zip
Auto merge of #6151 - bofh69:master, r=ebroto
Preserve raw strs for: format!(s) to s.to_string() lint

fixes #6142

clippy::useless_format will keep the source's string (after converting {{ and }} to { and }) when suggesting a change from format!() to .to_string() usage. Ie:
|     let s = format!(r#""hello {{}}""#);
|             ^^^^^^^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `r#""hello {}""#.to_string()`

changelog: [`useless_format`]: preserve raw string literals when no arguments to `format!()` are provided.
-rw-r--r--clippy_lints/src/format.rs8
-rw-r--r--tests/ui/format.fixed3
-rw-r--r--tests/ui/format.stderr8
3 files changed, 15 insertions, 4 deletions
diff --git a/clippy_lints/src/format.rs b/clippy_lints/src/format.rs
index d6541010bca..26da058598e 100644
--- a/clippy_lints/src/format.rs
+++ b/clippy_lints/src/format.rs
@@ -1,6 +1,6 @@
 use crate::utils::paths;
 use crate::utils::{
-    is_expn_of, is_type_diagnostic_item, last_path_segment, match_def_path, match_function_call, snippet,
+    is_expn_of, is_type_diagnostic_item, last_path_segment, match_def_path, match_function_call, snippet, snippet_opt,
     span_lint_and_then,
 };
 use if_chain::if_chain;
@@ -132,7 +132,11 @@ fn on_new_v1<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> Option<Strin
         then {
             // `format!("foo")` expansion contains `match () { () => [], }`
             if tup.is_empty() {
-                return Some(format!("{:?}.to_string()", s.as_str()));
+                if let Some(s_src) = snippet_opt(cx, lit.span) {
+                    // Simulate macro expansion, converting {{ and }} to { and }.
+                    let s_expand = s_src.replace("{{", "{").replace("}}", "}");
+                    return Some(format!("{}.to_string()", s_expand))
+                }
             } else if s.as_str().is_empty() {
                 return on_argumentv1_new(cx, &tup[0], arms);
             }
diff --git a/tests/ui/format.fixed b/tests/ui/format.fixed
index 30651476999..740a22a07d7 100644
--- a/tests/ui/format.fixed
+++ b/tests/ui/format.fixed
@@ -13,7 +13,8 @@ fn main() {
     "foo".to_string();
     "{}".to_string();
     "{} abc {}".to_string();
-    "foo {}\n\" bar".to_string();
+    r##"foo {}
+" bar"##.to_string();
 
     "foo".to_string();
     format!("{:?}", "foo"); // Don't warn about `Debug`.
diff --git a/tests/ui/format.stderr b/tests/ui/format.stderr
index 9734492154e..96df7f37f77 100644
--- a/tests/ui/format.stderr
+++ b/tests/ui/format.stderr
@@ -25,7 +25,13 @@ LL | /     format!(
 LL | |         r##"foo {{}}
 LL | | " bar"##
 LL | |     );
-   | |______^ help: consider using `.to_string()`: `"foo {}/n/" bar".to_string();`
+   | |______^
+   |
+help: consider using `.to_string()`
+   |
+LL |     r##"foo {}
+LL | " bar"##.to_string();
+   |
 
 error: useless use of `format!`
   --> $DIR/format.rs:21:5