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:
commit
79e818267b
5 changed files with 150 additions and 113 deletions
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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");
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue