Merge pull request #2690 from mrecachinas/feature/print-string-literal

Fix alignment/precision/width false positives for print/write_literal
This commit is contained in:
Oliver Schneider 2018-04-23 10:36:48 +02:00 committed by GitHub
commit 79e818267b
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 150 additions and 113 deletions

View file

@ -7,7 +7,7 @@ use syntax::ptr;
use syntax::symbol::InternedString;
use syntax_pos::Span;
use utils::{is_expn_of, match_def_path, match_path, resolve_node, span_lint, span_lint_and_sugg};
use utils::{opt_def_id, paths};
use utils::{opt_def_id, paths, last_path_segment};
/// **What it does:** This lint warns when you use `println!("")` to
/// print a newline.
@ -266,7 +266,6 @@ fn check_print_variants<'a, 'tcx>(
};
span_lint(cx, PRINT_STDOUT, span, &format!("use of `{}!`", name));
if_chain! {
// ensure we're calling Arguments::new_v1
if args.len() == 1;
@ -339,7 +338,9 @@ where
F: Fn(Span),
{
if_chain! {
if args.len() > 1;
if args.len() >= 2;
// the match statement
if let ExprAddrOf(_, ref match_expr) = args[1].node;
if let ExprMatch(ref matchee, ref arms, _) = match_expr.node;
if let ExprTup(ref tup) = matchee.node;
@ -355,15 +356,31 @@ where
if let ExprLit(_) = tup_val.node;
// next, check the corresponding match arm body to ensure
// this is "{}", or DISPLAY_FMT_METHOD
// this is DISPLAY_FMT_METHOD
if let ExprCall(_, ref body_args) = arm_body_exprs[idx].node;
if body_args.len() == 2;
if let ExprPath(ref body_qpath) = body_args[1].node;
if let Some(fun_def_id) = opt_def_id(resolve_node(cx, body_qpath, body_args[1].hir_id));
if match_def_path(cx.tcx, fun_def_id, &paths::DISPLAY_FMT_METHOD) ||
match_def_path(cx.tcx, fun_def_id, &paths::DEBUG_FMT_METHOD);
if match_def_path(cx.tcx, fun_def_id, &paths::DISPLAY_FMT_METHOD);
then {
lint_fn(tup_val.span);
if args.len() == 2 {
lint_fn(tup_val.span);
}
// ensure the format str has no options (e.g., width, precision, alignment, etc.)
// and is just "{}"
if_chain! {
if args.len() == 3;
if let ExprAddrOf(_, ref format_expr) = args[2].node;
if let ExprArray(ref format_exprs) = format_expr.node;
if format_exprs.len() >= 1;
if let ExprStruct(_, ref fields, _) = format_exprs[idx].node;
if let Some(format_field) = fields.iter().find(|f| f.name.node == "format");
if check_unformatted(&format_field.expr);
then {
lint_fn(tup_val.span);
}
}
}
}
}
@ -438,3 +455,33 @@ fn is_in_debug_impl(cx: &LateContext, expr: &Expr) -> bool {
}
false
}
/// Checks if the expression matches
/// ```rust,ignore
/// &[_ {
/// format: _ {
/// width: _::Implied,
/// ...
/// },
/// ...,
/// }]
/// ```
pub fn check_unformatted(format_field: &Expr) -> bool {
if_chain! {
if let ExprStruct(_, ref fields, _) = format_field.node;
if let Some(width_field) = fields.iter().find(|f| f.name.node == "width");
if let ExprPath(ref qpath) = width_field.expr.node;
if last_path_segment(qpath).name == "Implied";
if let Some(align_field) = fields.iter().find(|f| f.name.node == "align");
if let ExprPath(ref qpath) = align_field.expr.node;
if last_path_segment(qpath).name == "Unknown";
if let Some(precision_field) = fields.iter().find(|f| f.name.node == "precision");
if let ExprPath(ref qpath_precision) = precision_field.expr.node;
if last_path_segment(qpath_precision).name == "Implied";
then {
return true;
}
}
false
}

View file

@ -9,16 +9,23 @@ fn main() {
let world = "world";
println!("Hello {}", world);
println!("3 in hex is {:X}", 3);
println!("2 + 1 = {:.4}", 3);
println!("2 + 1 = {:5.4}", 3);
println!("Debug test {:?}", "hello, world");
println!("{0:8} {1:>8}", "hello", "world");
println!("{1:8} {0:>8}", "hello", "world");
println!("{foo:8} {bar:>8}", foo="hello", bar="world");
println!("{bar:8} {foo:>8}", foo="hello", bar="world");
println!("{number:>width$}", number=1, width=6);
println!("{number:>0width$}", number=1, width=6);
// these should throw warnings
println!("{} of {:b} people know binary, the other half doesn't", 1, 2);
print!("Hello {}", "world");
println!("Hello {} {}", world, "world");
println!("Hello {}", "world");
println!("10 / 4 is {}", 2.5);
println!("2 + 1 = {}", 3);
println!("2 + 1 = {:.4}", 3);
println!("2 + 1 = {:5.4}", 3);
println!("Debug test {:?}", "hello, world");
// positional args don't change the fact
// that we're using a literal -- this should

View file

@ -1,100 +1,88 @@
error: printing a literal with an empty format string
--> $DIR/print_literal.rs:14:24
--> $DIR/print_literal.rs:23:71
|
14 | print!("Hello {}", "world");
| ^^^^^^^
23 | println!("{} of {:b} people know binary, the other half doesn't", 1, 2);
| ^
|
= note: `-D print-literal` implied by `-D warnings`
error: printing a literal with an empty format string
--> $DIR/print_literal.rs:15:36
--> $DIR/print_literal.rs:24:24
|
15 | println!("Hello {} {}", world, "world");
24 | print!("Hello {}", "world");
| ^^^^^^^
error: printing a literal with an empty format string
--> $DIR/print_literal.rs:25:36
|
25 | println!("Hello {} {}", world, "world");
| ^^^^^^^
error: printing a literal with an empty format string
--> $DIR/print_literal.rs:16:26
--> $DIR/print_literal.rs:26:26
|
16 | println!("Hello {}", "world");
26 | println!("Hello {}", "world");
| ^^^^^^^
error: printing a literal with an empty format string
--> $DIR/print_literal.rs:17:30
--> $DIR/print_literal.rs:27:30
|
17 | println!("10 / 4 is {}", 2.5);
27 | println!("10 / 4 is {}", 2.5);
| ^^^
error: printing a literal with an empty format string
--> $DIR/print_literal.rs:18:28
--> $DIR/print_literal.rs:28:28
|
18 | println!("2 + 1 = {}", 3);
28 | println!("2 + 1 = {}", 3);
| ^
error: printing a literal with an empty format string
--> $DIR/print_literal.rs:19:31
--> $DIR/print_literal.rs:33:25
|
19 | println!("2 + 1 = {:.4}", 3);
| ^
error: printing a literal with an empty format string
--> $DIR/print_literal.rs:20:32
|
20 | println!("2 + 1 = {:5.4}", 3);
| ^
error: printing a literal with an empty format string
--> $DIR/print_literal.rs:21:33
|
21 | println!("Debug test {:?}", "hello, world");
| ^^^^^^^^^^^^^^
error: printing a literal with an empty format string
--> $DIR/print_literal.rs:26:25
|
26 | println!("{0} {1}", "hello", "world");
33 | println!("{0} {1}", "hello", "world");
| ^^^^^^^
error: printing a literal with an empty format string
--> $DIR/print_literal.rs:26:34
--> $DIR/print_literal.rs:33:34
|
26 | println!("{0} {1}", "hello", "world");
33 | println!("{0} {1}", "hello", "world");
| ^^^^^^^
error: printing a literal with an empty format string
--> $DIR/print_literal.rs:27:25
--> $DIR/print_literal.rs:34:25
|
27 | println!("{1} {0}", "hello", "world");
34 | println!("{1} {0}", "hello", "world");
| ^^^^^^^
error: printing a literal with an empty format string
--> $DIR/print_literal.rs:27:34
--> $DIR/print_literal.rs:34:34
|
27 | println!("{1} {0}", "hello", "world");
34 | println!("{1} {0}", "hello", "world");
| ^^^^^^^
error: printing a literal with an empty format string
--> $DIR/print_literal.rs:30:33
--> $DIR/print_literal.rs:37:33
|
30 | println!("{foo} {bar}", foo="hello", bar="world");
37 | println!("{foo} {bar}", foo="hello", bar="world");
| ^^^^^^^
error: printing a literal with an empty format string
--> $DIR/print_literal.rs:30:46
--> $DIR/print_literal.rs:37:46
|
30 | println!("{foo} {bar}", foo="hello", bar="world");
37 | println!("{foo} {bar}", foo="hello", bar="world");
| ^^^^^^^
error: printing a literal with an empty format string
--> $DIR/print_literal.rs:31:33
--> $DIR/print_literal.rs:38:33
|
31 | println!("{bar} {foo}", foo="hello", bar="world");
38 | println!("{bar} {foo}", foo="hello", bar="world");
| ^^^^^^^
error: printing a literal with an empty format string
--> $DIR/print_literal.rs:31:46
--> $DIR/print_literal.rs:38:46
|
31 | println!("{bar} {foo}", foo="hello", bar="world");
38 | println!("{bar} {foo}", foo="hello", bar="world");
| ^^^^^^^
error: aborting due to 16 previous errors
error: aborting due to 14 previous errors

View file

@ -6,22 +6,29 @@ use std::io::Write;
fn main() {
let mut v = Vec::new();
// These should be fine
// these should be fine
write!(&mut v, "Hello");
writeln!(&mut v, "Hello");
let world = "world";
writeln!(&mut v, "Hello {}", world);
writeln!(&mut v, "3 in hex is {:X}", 3);
writeln!(&mut v, "2 + 1 = {:.4}", 3);
writeln!(&mut v, "2 + 1 = {:5.4}", 3);
writeln!(&mut v, "Debug test {:?}", "hello, world");
writeln!(&mut v, "{0:8} {1:>8}", "hello", "world");
writeln!(&mut v, "{1:8} {0:>8}", "hello", "world");
writeln!(&mut v, "{foo:8} {bar:>8}", foo="hello", bar="world");
writeln!(&mut v, "{bar:8} {foo:>8}", foo="hello", bar="world");
writeln!(&mut v, "{number:>width$}", number=1, width=6);
writeln!(&mut v, "{number:>0width$}", number=1, width=6);
// These should throw warnings
// these should throw warnings
writeln!(&mut v, "{} of {:b} people know binary, the other half doesn't", 1, 2);
write!(&mut v, "Hello {}", "world");
writeln!(&mut v, "Hello {} {}", world, "world");
writeln!(&mut v, "Hello {}", "world");
writeln!(&mut v, "10 / 4 is {}", 2.5);
writeln!(&mut v, "2 + 1 = {}", 3);
writeln!(&mut v, "2 + 1 = {:.4}", 3);
writeln!(&mut v, "2 + 1 = {:5.4}", 3);
writeln!(&mut v, "Debug test {:?}", "hello, world");
// positional args don't change the fact
// that we're using a literal -- this should
@ -30,6 +37,6 @@ fn main() {
writeln!(&mut v, "{1} {0}", "hello", "world");
// named args shouldn't change anything either
writeln!(&mut v, "{foo} {bar}", foo = "hello", bar = "world");
writeln!(&mut v, "{bar} {foo}", foo = "hello", bar = "world");
writeln!(&mut v, "{foo} {bar}", foo="hello", bar="world");
writeln!(&mut v, "{bar} {foo}", foo="hello", bar="world");
}

View file

@ -1,100 +1,88 @@
error: writing a literal with an empty format string
--> $DIR/write_literal.rs:17:32
--> $DIR/write_literal.rs:26:79
|
17 | write!(&mut v, "Hello {}", "world");
| ^^^^^^^
26 | writeln!(&mut v, "{} of {:b} people know binary, the other half doesn't", 1, 2);
| ^
|
= note: `-D write-literal` implied by `-D warnings`
error: writing a literal with an empty format string
--> $DIR/write_literal.rs:18:44
--> $DIR/write_literal.rs:27:32
|
18 | writeln!(&mut v, "Hello {} {}", world, "world");
27 | write!(&mut v, "Hello {}", "world");
| ^^^^^^^
error: writing a literal with an empty format string
--> $DIR/write_literal.rs:28:44
|
28 | writeln!(&mut v, "Hello {} {}", world, "world");
| ^^^^^^^
error: writing a literal with an empty format string
--> $DIR/write_literal.rs:19:34
--> $DIR/write_literal.rs:29:34
|
19 | writeln!(&mut v, "Hello {}", "world");
29 | writeln!(&mut v, "Hello {}", "world");
| ^^^^^^^
error: writing a literal with an empty format string
--> $DIR/write_literal.rs:20:38
--> $DIR/write_literal.rs:30:38
|
20 | writeln!(&mut v, "10 / 4 is {}", 2.5);
30 | writeln!(&mut v, "10 / 4 is {}", 2.5);
| ^^^
error: writing a literal with an empty format string
--> $DIR/write_literal.rs:21:36
--> $DIR/write_literal.rs:31:36
|
21 | writeln!(&mut v, "2 + 1 = {}", 3);
31 | writeln!(&mut v, "2 + 1 = {}", 3);
| ^
error: writing a literal with an empty format string
--> $DIR/write_literal.rs:22:39
--> $DIR/write_literal.rs:36:33
|
22 | writeln!(&mut v, "2 + 1 = {:.4}", 3);
| ^
error: writing a literal with an empty format string
--> $DIR/write_literal.rs:23:40
|
23 | writeln!(&mut v, "2 + 1 = {:5.4}", 3);
| ^
error: writing a literal with an empty format string
--> $DIR/write_literal.rs:24:41
|
24 | writeln!(&mut v, "Debug test {:?}", "hello, world");
| ^^^^^^^^^^^^^^
error: writing a literal with an empty format string
--> $DIR/write_literal.rs:29:33
|
29 | writeln!(&mut v, "{0} {1}", "hello", "world");
36 | writeln!(&mut v, "{0} {1}", "hello", "world");
| ^^^^^^^
error: writing a literal with an empty format string
--> $DIR/write_literal.rs:29:42
--> $DIR/write_literal.rs:36:42
|
29 | writeln!(&mut v, "{0} {1}", "hello", "world");
36 | writeln!(&mut v, "{0} {1}", "hello", "world");
| ^^^^^^^
error: writing a literal with an empty format string
--> $DIR/write_literal.rs:30:33
--> $DIR/write_literal.rs:37:33
|
30 | writeln!(&mut v, "{1} {0}", "hello", "world");
37 | writeln!(&mut v, "{1} {0}", "hello", "world");
| ^^^^^^^
error: writing a literal with an empty format string
--> $DIR/write_literal.rs:30:42
--> $DIR/write_literal.rs:37:42
|
30 | writeln!(&mut v, "{1} {0}", "hello", "world");
37 | writeln!(&mut v, "{1} {0}", "hello", "world");
| ^^^^^^^
error: writing a literal with an empty format string
--> $DIR/write_literal.rs:33:43
--> $DIR/write_literal.rs:40:41
|
33 | writeln!(&mut v, "{foo} {bar}", foo = "hello", bar = "world");
| ^^^^^^^
40 | writeln!(&mut v, "{foo} {bar}", foo="hello", bar="world");
| ^^^^^^^
error: writing a literal with an empty format string
--> $DIR/write_literal.rs:33:58
--> $DIR/write_literal.rs:40:54
|
33 | writeln!(&mut v, "{foo} {bar}", foo = "hello", bar = "world");
| ^^^^^^^
40 | writeln!(&mut v, "{foo} {bar}", foo="hello", bar="world");
| ^^^^^^^
error: writing a literal with an empty format string
--> $DIR/write_literal.rs:34:43
--> $DIR/write_literal.rs:41:41
|
34 | writeln!(&mut v, "{bar} {foo}", foo = "hello", bar = "world");
| ^^^^^^^
41 | writeln!(&mut v, "{bar} {foo}", foo="hello", bar="world");
| ^^^^^^^
error: writing a literal with an empty format string
--> $DIR/write_literal.rs:34:58
--> $DIR/write_literal.rs:41:54
|
34 | writeln!(&mut v, "{bar} {foo}", foo = "hello", bar = "world");
| ^^^^^^^
41 | writeln!(&mut v, "{bar} {foo}", foo="hello", bar="world");
| ^^^^^^^
error: aborting due to 16 previous errors
error: aborting due to 14 previous errors