Skip to content

Commit 06280e8

Browse files
authored
Merge pull request #2097 from rust-lang-nursery/fix-2041
Fix detection of format and print macros
2 parents bc76f39 + 7e956ac commit 06280e8

File tree

4 files changed

+72
-44
lines changed

4 files changed

+72
-44
lines changed

clippy_lints/src/format.rs

Lines changed: 11 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,7 @@
11
use rustc::hir::*;
2-
use rustc::hir::map::Node::NodeItem;
32
use rustc::lint::*;
43
use rustc::ty;
54
use syntax::ast::LitKind;
6-
use syntax::symbol::InternedString;
75
use utils::paths;
86
use utils::{is_expn_of, match_def_path, match_type, resolve_node, span_lint, walk_ptrs_ty, opt_def_id};
97

@@ -50,8 +48,9 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass {
5048
let Some(fun_def_id) = opt_def_id(resolve_node(cx, qpath, fun.hir_id)),
5149
match_def_path(cx.tcx, fun_def_id, &paths::FMT_ARGUMENTS_NEWV1),
5250
// ensure the format string is `"{..}"` with only one argument and no text
53-
check_static_str(cx, &args[0]),
51+
check_static_str(&args[0]),
5452
// ensure the format argument is `{}` ie. Display with no fancy option
53+
// and that the argument is a string
5554
check_arg_is_display(cx, &args[1])
5655
], {
5756
span_lint(cx, USELESS_FORMAT, span, "useless use of `format!`");
@@ -69,44 +68,19 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass {
6968
}
7069
}
7170

72-
/// Returns the slice of format string parts in an `Arguments::new_v1` call.
73-
/// Public because it's shared with a lint in print.rs.
74-
pub fn get_argument_fmtstr_parts<'a, 'b>(cx: &LateContext<'a, 'b>, expr: &'a Expr) -> Option<Vec<InternedString>> {
71+
/// Checks if the expressions matches `&[""]`
72+
fn check_static_str(expr: &Expr) -> bool {
7573
if_let_chain! {[
76-
let ExprBlock(ref block) = expr.node,
77-
block.stmts.len() == 1,
78-
let StmtDecl(ref decl, _) = block.stmts[0].node,
79-
let DeclItem(ref decl) = decl.node,
80-
let Some(NodeItem(decl)) = cx.tcx.hir.find(decl.id),
81-
decl.name == "__STATIC_FMTSTR",
82-
let ItemStatic(_, _, ref expr) = decl.node,
83-
let ExprAddrOf(_, ref expr) = cx.tcx.hir.body(*expr).value.node, // &["…", "…", …]
84-
let ExprArray(ref exprs) = expr.node,
74+
let ExprAddrOf(_, ref expr) = expr.node, // &[""]
75+
let ExprArray(ref exprs) = expr.node, // [""]
76+
exprs.len() == 1,
77+
let ExprLit(ref lit) = exprs[0].node,
78+
let LitKind::Str(ref lit, _) = lit.node,
8579
], {
86-
let mut result = Vec::new();
87-
for expr in exprs {
88-
if let ExprLit(ref lit) = expr.node {
89-
if let LitKind::Str(ref lit, _) = lit.node {
90-
result.push(lit.as_str());
91-
}
92-
}
93-
}
94-
return Some(result);
80+
return lit.as_str().is_empty();
9581
}}
96-
None
97-
}
9882

99-
/// Checks if the expressions matches
100-
/// ```rust, ignore
101-
/// { static __STATIC_FMTSTR: &'static[&'static str] = &["a", "b", c];
102-
/// __STATIC_FMTSTR }
103-
/// ```
104-
fn check_static_str(cx: &LateContext, expr: &Expr) -> bool {
105-
if let Some(expr) = get_argument_fmtstr_parts(cx, expr) {
106-
expr.len() == 1 && expr[0].is_empty()
107-
} else {
108-
false
109-
}
83+
false
11084
}
11185

11286
/// Checks if the expressions matches

clippy_lints/src/print.rs

Lines changed: 20 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
11
use rustc::hir::*;
22
use rustc::hir::map::Node::{NodeImplItem, NodeItem};
33
use rustc::lint::*;
4-
use utils::{paths, opt_def_id};
4+
use syntax::ast::LitKind;
5+
use syntax::symbol::InternedString;
56
use utils::{is_expn_of, match_def_path, match_path, resolve_node, span_lint};
6-
use format::get_argument_fmtstr_parts;
7+
use utils::{paths, opt_def_id};
78

89
/// **What it does:** This lint warns when you using `print!()` with a format
910
/// string that
@@ -103,15 +104,14 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass {
103104
let ExprTup(ref args) = args.node,
104105

105106
// collect the format string parts and check the last one
106-
let Some(fmtstrs) = get_argument_fmtstr_parts(cx, &args_args[0]),
107-
let Some(last_str) = fmtstrs.last(),
108-
let Some('\n') = last_str.chars().last(),
107+
let Some((fmtstr, fmtlen)) = get_argument_fmtstr_parts(&args_args[0]),
108+
let Some('\n') = fmtstr.chars().last(),
109109

110110
// "foo{}bar" is made into two strings + one argument,
111111
// if the format string starts with `{}` (eg. "{}foo"),
112112
// the string array is prepended an empty string "".
113113
// We only want to check the last string after any `{}`:
114-
args.len() < fmtstrs.len(),
114+
args.len() < fmtlen,
115115
], {
116116
span_lint(cx, PRINT_WITH_NEWLINE, span,
117117
"using `print!()` with a format string that ends in a \
@@ -150,3 +150,17 @@ fn is_in_debug_impl(cx: &LateContext, expr: &Expr) -> bool {
150150

151151
false
152152
}
153+
154+
/// Returns the slice of format string parts in an `Arguments::new_v1` call.
155+
fn get_argument_fmtstr_parts(expr: &Expr) -> Option<(InternedString, usize)> {
156+
if_let_chain! {[
157+
let ExprAddrOf(_, ref expr) = expr.node, // &["…", "…", …]
158+
let ExprArray(ref exprs) = expr.node,
159+
let Some(expr) = exprs.last(),
160+
let ExprLit(ref lit) = expr.node,
161+
let LitKind::Str(ref lit, _) = lit.node,
162+
], {
163+
return Some((lit.as_str(), exprs.len()));
164+
}}
165+
None
166+
}

tests/ui/format.stderr

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,5 +6,17 @@ error: useless use of `format!`
66
|
77
= note: `-D useless-format` implied by `-D warnings`
88

9-
error: aborting due to previous error
9+
error: useless use of `format!`
10+
--> $DIR/format.rs:8:5
11+
|
12+
8 | format!("{}", "foo");
13+
| ^^^^^^^^^^^^^^^^^^^^^
14+
15+
error: useless use of `format!`
16+
--> $DIR/format.rs:15:5
17+
|
18+
15 | format!("{}", arg);
19+
| ^^^^^^^^^^^^^^^^^^^
20+
21+
error: aborting due to 3 previous errors
1022

tests/ui/print_with_newline.stderr

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
error: using `print!()` with a format string that ends in a newline, consider using `println!()` instead
2+
--> $DIR/print_with_newline.rs:6:5
3+
|
4+
6 | print!("Hello/n");
5+
| ^^^^^^^^^^^^^^^^^^
6+
|
7+
= note: `-D print-with-newline` implied by `-D warnings`
8+
9+
error: using `print!()` with a format string that ends in a newline, consider using `println!()` instead
10+
--> $DIR/print_with_newline.rs:7:5
11+
|
12+
7 | print!("Hello {}/n", "world");
13+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
14+
15+
error: using `print!()` with a format string that ends in a newline, consider using `println!()` instead
16+
--> $DIR/print_with_newline.rs:8:5
17+
|
18+
8 | print!("Hello {} {}/n/n", "world", "#2");
19+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
20+
21+
error: using `print!()` with a format string that ends in a newline, consider using `println!()` instead
22+
--> $DIR/print_with_newline.rs:9:5
23+
|
24+
9 | print!("{}/n", 1265);
25+
| ^^^^^^^^^^^^^^^^^^^^^
26+
27+
error: aborting due to 4 previous errors
28+

0 commit comments

Comments
 (0)