Check {print,write}_with_newline for literal newline

Both regular strings and raw strings can contain literal newlines. This commit
extends the lint to also warn about terminating strings with these.

Behaviour handling for raw strings is also moved into `check_newlines` by
passing in the `is_raw` boolean from `check_tts` as
[suggested](https://github.com/rust-lang/rust-clippy/pull/3781#pullrequestreview-204663732)
This commit is contained in:
phil 2019-02-18 11:39:23 -05:00
parent 3fa3bd8e94
commit ef72b2cac0
5 changed files with 72 additions and 5 deletions

View File

@ -201,7 +201,7 @@ fn check_mac(&mut self, cx: &EarlyContext<'_>, mac: &Mac) {
} else if mac.node.path == "print" {
span_lint(cx, PRINT_STDOUT, mac.span, "use of `print!`");
if let (Some(fmtstr), _, is_raw) = check_tts(cx, &mac.node.tts, false) {
if !is_raw && check_newlines(&fmtstr) {
if check_newlines(&fmtstr, is_raw) {
span_lint(
cx,
PRINT_WITH_NEWLINE,
@ -213,7 +213,7 @@ fn check_mac(&mut self, cx: &EarlyContext<'_>, mac: &Mac) {
}
} else if mac.node.path == "write" {
if let (Some(fmtstr), _, is_raw) = check_tts(cx, &mac.node.tts, true) {
if !is_raw && check_newlines(&fmtstr) {
if check_newlines(&fmtstr, is_raw) {
span_lint(
cx,
WRITE_WITH_NEWLINE,
@ -382,7 +382,14 @@ fn check_tts<'a>(cx: &EarlyContext<'a>, tts: &TokenStream, is_write: bool) -> (O
}
// Checks if `s` constains a single newline that terminates it
fn check_newlines(s: &str) -> bool {
// Literal and escaped newlines are both checked (only literal for raw strings)
fn check_newlines(s: &str, is_raw: bool) -> bool {
if s.ends_with('\n') {
return true;
} else if is_raw {
return false;
}
if s.len() < 2 {
return false;
}

View File

@ -29,4 +29,14 @@ fn main() {
// Raw strings
print!(r"\n"); // #3778
// Literal newlines should also fail
print!(
"
"
);
print!(
r"
"
);
}

View File

@ -30,5 +30,23 @@ error: using `print!()` with a format string that ends in a single newline, cons
LL | print!("//n"); // should fail
| ^^^^^^^^^^^^^^
error: aborting due to 5 previous errors
error: using `print!()` with a format string that ends in a single newline, consider using `println!()` instead
--> $DIR/print_with_newline.rs:34:5
|
LL | / print!(
LL | | "
LL | | "
LL | | );
| |_____^
error: using `print!()` with a format string that ends in a single newline, consider using `println!()` instead
--> $DIR/print_with_newline.rs:38:5
|
LL | / print!(
LL | | r"
LL | | "
LL | | );
| |_____^
error: aborting due to 7 previous errors

View File

@ -34,4 +34,16 @@ fn main() {
// Raw strings
write!(&mut v, r"\n"); // #3778
// Literal newlines should also fail
write!(
&mut v,
"
"
);
write!(
&mut v,
r"
"
);
}

View File

@ -30,5 +30,25 @@ error: using `write!()` with a format string that ends in a single newline, cons
LL | write!(&mut v, "//n"); // should fail
| ^^^^^^^^^^^^^^^^^^^^^^
error: aborting due to 5 previous errors
error: using `write!()` with a format string that ends in a single newline, consider using `writeln!()` instead
--> $DIR/write_with_newline.rs:39:5
|
LL | / write!(
LL | | &mut v,
LL | | "
LL | | "
LL | | );
| |_____^
error: using `write!()` with a format string that ends in a single newline, consider using `writeln!()` instead
--> $DIR/write_with_newline.rs:44:5
|
LL | / write!(
LL | | &mut v,
LL | | r"
LL | | "
LL | | );
| |_____^
error: aborting due to 7 previous errors