Skip to content

Commit c6505aa

Browse files
author
Michael Wright
committed
Fix write_with_newline escaping false positive
Fixes #3514
1 parent 0fd7fe9 commit c6505aa

File tree

3 files changed

+40
-9
lines changed

3 files changed

+40
-9
lines changed

clippy_lints/src/write.rs

Lines changed: 28 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -206,10 +206,7 @@ impl EarlyLintPass for Pass {
206206
} else if mac.node.path == "print" {
207207
span_lint(cx, PRINT_STDOUT, mac.span, "use of `print!`");
208208
if let Some(fmtstr) = check_tts(cx, &mac.node.tts, false).0 {
209-
if fmtstr.ends_with("\\n") &&
210-
// don't warn about strings with several `\n`s (#3126)
211-
fmtstr.matches("\\n").count() == 1
212-
{
209+
if check_newlines(&fmtstr) {
213210
span_lint(
214211
cx,
215212
PRINT_WITH_NEWLINE,
@@ -221,10 +218,7 @@ impl EarlyLintPass for Pass {
221218
}
222219
} else if mac.node.path == "write" {
223220
if let Some(fmtstr) = check_tts(cx, &mac.node.tts, true).0 {
224-
if fmtstr.ends_with("\\n") &&
225-
// don't warn about strings with several `\n`s (#3126)
226-
fmtstr.matches("\\n").count() == 1
227-
{
221+
if check_newlines(&fmtstr) {
228222
span_lint(
229223
cx,
230224
WRITE_WITH_NEWLINE,
@@ -375,3 +369,29 @@ fn check_tts<'a>(cx: &EarlyContext<'a>, tts: &ThinTokenStream, is_write: bool) -
375369
}
376370
}
377371
}
372+
373+
// Checks if `s` constains a single newline that terminates it
374+
fn check_newlines(s: &str) -> bool {
375+
if s.len() < 2 {
376+
return false;
377+
}
378+
379+
let bytes = s.as_bytes();
380+
if bytes[bytes.len() - 2] != b'\\' || bytes[bytes.len() - 1] != b'n' {
381+
return false;
382+
}
383+
384+
let mut escaping = false;
385+
for (index, &byte) in bytes.iter().enumerate() {
386+
if escaping {
387+
if byte == b'n' {
388+
return index == bytes.len() - 1;
389+
}
390+
escaping = false;
391+
} else if byte == b'\\' {
392+
escaping = true;
393+
}
394+
}
395+
396+
false
397+
}

tests/ui/write_with_newline.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,4 +38,9 @@ fn main() {
3838
write!(&mut v, "Hello {} {}\n\n", "world", "#2");
3939
writeln!(&mut v, "\ndon't\nwarn\nfor\nmultiple\nnewlines\n"); // #3126
4040
writeln!(&mut v, "\nbla\n\n"); // #3126
41+
42+
// Escaping
43+
write!(&mut v, "\\n"); // #3514
44+
write!(&mut v, "\\\n");
45+
write!(&mut v, "\\\\n");
4146
}

tests/ui/write_with_newline.stderr

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,5 +24,11 @@ error: using `write!()` with a format string that ends in a single newline, cons
2424
25 | write!(&mut v, "{}/n", 1265);
2525
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
2626

27-
error: aborting due to 4 previous errors
27+
error: using `write!()` with a format string that ends in a single newline, consider using `writeln!()` instead
28+
--> $DIR/write_with_newline.rs:44:5
29+
|
30+
44 | write!(&mut v, "//n");
31+
| ^^^^^^^^^^^^^^^^^^^^^^
32+
33+
error: aborting due to 5 previous errors
2834

0 commit comments

Comments
 (0)