Skip to content

Commit c3e3be3

Browse files
authored
Merge pull request #3256 from rust-lang-nursery/fix-2796
Fix 2796 and 3020
2 parents c47b948 + 5173ed0 commit c3e3be3

File tree

3 files changed

+63
-21
lines changed

3 files changed

+63
-21
lines changed

clippy_lints/src/format.rs

Lines changed: 24 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,6 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass {
4747
return;
4848
}
4949
match expr.node {
50-
5150
// `format!("{}", foo)` expansion
5251
ExprKind::Call(ref fun, ref args) => {
5352
if_chain! {
@@ -58,12 +57,24 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass {
5857
if check_single_piece(&args[0]);
5958
if let Some(format_arg) = get_single_string_arg(cx, &args[1]);
6059
if check_unformatted(&args[2]);
60+
if let ExprKind::AddrOf(_, ref format_arg) = format_arg.node;
6161
then {
62-
let sugg = format!("{}.to_string()", snippet(cx, format_arg, "<arg>").into_owned());
62+
let (message, sugg) = if_chain! {
63+
if let ExprKind::MethodCall(ref path, ref span, ref expr) = format_arg.node;
64+
if path.ident.as_interned_str() == "to_string";
65+
then {
66+
("`to_string()` is enough",
67+
snippet(cx, format_arg.span, "<arg>").to_string())
68+
} else {
69+
("consider using .to_string()",
70+
format!("{}.to_string()", snippet(cx, format_arg.span, "<arg>")))
71+
}
72+
};
73+
6374
span_lint_and_then(cx, USELESS_FORMAT, span, "useless use of `format!`", |db| {
6475
db.span_suggestion_with_applicability(
6576
expr.span,
66-
"consider using .to_string()",
77+
message,
6778
sugg,
6879
Applicability::MachineApplicable,
6980
);
@@ -114,9 +125,9 @@ fn check_single_piece(expr: &Expr) -> bool {
114125
/// ::std::fmt::Display::fmt)],
115126
/// }
116127
/// ```
117-
/// and that type of `__arg0` is `&str` or `String`
118-
/// then returns the span of first element of the matched tuple
119-
fn get_single_string_arg(cx: &LateContext<'_, '_>, expr: &Expr) -> Option<Span> {
128+
/// and that the type of `__arg0` is `&str` or `String`,
129+
/// then returns the span of first element of the matched tuple.
130+
fn get_single_string_arg<'a>(cx: &LateContext<'_, '_>, expr: &'a Expr) -> Option<&'a Expr> {
120131
if_chain! {
121132
if let ExprKind::AddrOf(_, ref expr) = expr.node;
122133
if let ExprKind::Match(ref match_expr, ref arms, _) = expr.node;
@@ -135,7 +146,7 @@ fn get_single_string_arg(cx: &LateContext<'_, '_>, expr: &Expr) -> Option<Span>
135146
let ty = walk_ptrs_ty(cx.tables.pat_ty(&pat[0]));
136147
if ty.sty == ty::Str || match_type(cx, ty, &paths::STRING) {
137148
if let ExprKind::Tup(ref values) = match_expr.node {
138-
return Some(values[0].span);
149+
return Some(&values[0]);
139150
}
140151
}
141152
}
@@ -162,9 +173,12 @@ fn check_unformatted(expr: &Expr) -> bool {
162173
if let ExprKind::Struct(_, ref fields, _) = exprs[0].node;
163174
if let Some(format_field) = fields.iter().find(|f| f.ident.name == "format");
164175
if let ExprKind::Struct(_, ref fields, _) = format_field.expr.node;
165-
if let Some(align_field) = fields.iter().find(|f| f.ident.name == "width");
166-
if let ExprKind::Path(ref qpath) = align_field.expr.node;
167-
if last_path_segment(qpath).ident.name == "Implied";
176+
if let Some(width_field) = fields.iter().find(|f| f.ident.name == "width");
177+
if let ExprKind::Path(ref width_qpath) = width_field.expr.node;
178+
if last_path_segment(width_qpath).ident.name == "Implied";
179+
if let Some(precision_field) = fields.iter().find(|f| f.ident.name == "precision");
180+
if let ExprKind::Path(ref precision_path) = precision_field.expr.node;
181+
if last_path_segment(precision_path).ident.name == "Implied";
168182
then {
169183
return true;
170184
}

tests/ui/format.rs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ fn main() {
1414
format!("{}", "foo");
1515
format!("{:?}", "foo"); // don't warn about debug
1616
format!("{:8}", "foo");
17+
format!("{:width$}", "foo", width = 8);
1718
format!("{:+}", "foo"); // warn when the format makes no difference
1819
format!("{:<}", "foo"); // warn when the format makes no difference
1920
format!("foo {}", "bar");
@@ -23,6 +24,7 @@ fn main() {
2324
format!("{}", arg);
2425
format!("{:?}", arg); // don't warn about debug
2526
format!("{:8}", arg);
27+
format!("{:width$}", arg, width = 8);
2628
format!("{:+}", arg); // warn when the format makes no difference
2729
format!("{:<}", arg); // warn when the format makes no difference
2830
format!("foo {}", arg);
@@ -44,4 +46,14 @@ fn main() {
4446

4547
// A format! inside a macro should not trigger a warning
4648
foo!("should not warn");
49+
50+
// precision on string means slicing without panicking on size:
51+
format!("{:.1}", "foo"); // could be "foo"[..1]
52+
format!("{:.10}", "foo"); // could not be "foo"[..10]
53+
format!("{:.prec$}", "foo", prec = 1);
54+
format!("{:.prec$}", "foo", prec = 10);
55+
56+
format!("{}", 42.to_string());
57+
let x = std::path::PathBuf::from("/bar/foo/qux");
58+
format!("{}", x.display().to_string());
4759
}

tests/ui/format.stderr

Lines changed: 27 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -15,44 +15,60 @@ error: useless use of `format!`
1515
= note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info)
1616

1717
error: useless use of `format!`
18-
--> $DIR/format.rs:17:5
18+
--> $DIR/format.rs:18:5
1919
|
20-
17 | format!("{:+}", "foo"); // warn when the format makes no difference
20+
18 | format!("{:+}", "foo"); // warn when the format makes no difference
2121
| ^^^^^^^^^^^^^^^^^^^^^^^ help: consider using .to_string(): `"foo".to_string()`
2222
|
2323
= note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info)
2424

2525
error: useless use of `format!`
26-
--> $DIR/format.rs:18:5
26+
--> $DIR/format.rs:19:5
2727
|
28-
18 | format!("{:<}", "foo"); // warn when the format makes no difference
28+
19 | format!("{:<}", "foo"); // warn when the format makes no difference
2929
| ^^^^^^^^^^^^^^^^^^^^^^^ help: consider using .to_string(): `"foo".to_string()`
3030
|
3131
= note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info)
3232

3333
error: useless use of `format!`
34-
--> $DIR/format.rs:23:5
34+
--> $DIR/format.rs:24:5
3535
|
36-
23 | format!("{}", arg);
36+
24 | format!("{}", arg);
3737
| ^^^^^^^^^^^^^^^^^^^ help: consider using .to_string(): `arg.to_string()`
3838
|
3939
= note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info)
4040

4141
error: useless use of `format!`
42-
--> $DIR/format.rs:26:5
42+
--> $DIR/format.rs:28:5
4343
|
44-
26 | format!("{:+}", arg); // warn when the format makes no difference
44+
28 | format!("{:+}", arg); // warn when the format makes no difference
4545
| ^^^^^^^^^^^^^^^^^^^^^ help: consider using .to_string(): `arg.to_string()`
4646
|
4747
= note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info)
4848

4949
error: useless use of `format!`
50-
--> $DIR/format.rs:27:5
50+
--> $DIR/format.rs:29:5
5151
|
52-
27 | format!("{:<}", arg); // warn when the format makes no difference
52+
29 | format!("{:<}", arg); // warn when the format makes no difference
5353
| ^^^^^^^^^^^^^^^^^^^^^ help: consider using .to_string(): `arg.to_string()`
5454
|
5555
= note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info)
5656

57-
error: aborting due to 7 previous errors
57+
error: useless use of `format!`
58+
--> $DIR/format.rs:56:5
59+
|
60+
56 | format!("{}", 42.to_string());
61+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: `to_string()` is enough: `42.to_string()`
62+
|
63+
= note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info)
64+
65+
error: useless use of `format!`
66+
--> $DIR/format.rs:58:5
67+
|
68+
58 | format!("{}", x.display().to_string());
69+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: `to_string()` is enough: `x.display().to_string()`
70+
|
71+
= note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info)
72+
73+
error: aborting due to 9 previous errors
5874

0 commit comments

Comments
 (0)