diff --git a/clippy_lints/src/format.rs b/clippy_lints/src/format.rs index 2d40150bc8e..30ad022f476 100644 --- a/clippy_lints/src/format.rs +++ b/clippy_lints/src/format.rs @@ -57,12 +57,24 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass { if check_single_piece(&args[0]); if let Some(format_arg) = get_single_string_arg(cx, &args[1]); if check_unformatted(&args[2]); + if let ExprKind::AddrOf(_, ref format_arg) = format_arg.node; then { - let sugg = format!("{}.to_string()", snippet(cx, format_arg, "").into_owned()); + let (message, sugg) = if_chain! { + if let ExprKind::MethodCall(ref path, ref span, ref expr) = format_arg.node; + if path.ident.as_interned_str() == "to_string"; + then { + ("`to_string()` is enough", + snippet(cx, format_arg.span, "").to_string()) + } else { + ("consider using .to_string()", + format!("{}.to_string()", snippet(cx, format_arg.span, ""))) + } + }; + span_lint_and_then(cx, USELESS_FORMAT, span, "useless use of `format!`", |db| { db.span_suggestion_with_applicability( expr.span, - "consider using .to_string()", + message, sugg, Applicability::MachineApplicable, ); @@ -113,9 +125,9 @@ fn check_single_piece(expr: &Expr) -> bool { /// ::std::fmt::Display::fmt)], /// } /// ``` -/// and that type of `__arg0` is `&str` or `String` -/// then returns the span of first element of the matched tuple -fn get_single_string_arg(cx: &LateContext<'_, '_>, expr: &Expr) -> Option { +/// and that the type of `__arg0` is `&str` or `String`, +/// then returns the span of first element of the matched tuple. +fn get_single_string_arg<'a>(cx: &LateContext<'_, '_>, expr: &'a Expr) -> Option<&'a Expr> { if_chain! { if let ExprKind::AddrOf(_, ref expr) = expr.node; if let ExprKind::Match(ref match_expr, ref arms, _) = expr.node; @@ -134,7 +146,7 @@ fn get_single_string_arg(cx: &LateContext<'_, '_>, expr: &Expr) -> Option let ty = walk_ptrs_ty(cx.tables.pat_ty(&pat[0])); if ty.sty == ty::Str || match_type(cx, ty, &paths::STRING) { if let ExprKind::Tup(ref values) = match_expr.node { - return Some(values[0].span); + return Some(&values[0]); } } } diff --git a/tests/ui/format.rs b/tests/ui/format.rs index 0162f34c085..858c9fc8de5 100644 --- a/tests/ui/format.rs +++ b/tests/ui/format.rs @@ -52,4 +52,8 @@ fn main() { format!("{:.10}", "foo"); // could not be "foo"[..10] format!("{:.prec$}", "foo", prec = 1); format!("{:.prec$}", "foo", prec = 10); + + format!("{}", 42.to_string()); + let x = std::path::PathBuf::from("/bar/foo/qux"); + format!("{}", x.display().to_string()); } diff --git a/tests/ui/format.stderr b/tests/ui/format.stderr index d77c99d90b8..520c1b79433 100644 --- a/tests/ui/format.stderr +++ b/tests/ui/format.stderr @@ -54,5 +54,21 @@ error: useless use of `format!` | = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info) -error: aborting due to 7 previous errors +error: useless use of `format!` + --> $DIR/format.rs:56:5 + | +56 | format!("{}", 42.to_string()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: `to_string()` is enough: `42.to_string()` + | + = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info) + +error: useless use of `format!` + --> $DIR/format.rs:58:5 + | +58 | format!("{}", x.display().to_string()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: `to_string()` is enough: `x.display().to_string()` + | + = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info) + +error: aborting due to 9 previous errors