Skip to content

Commit 2df272b

Browse files
authored
Rollup merge of #4769 - euclio:crlf, r=flip1995
don't warn on CRLF in `with_newline` lints changelog: don't warn on CRLF in `print_with_newline` and `write_with_newline` fixes #4208. This PR also transitions the unescaping logic to use the compiler's lexer.
2 parents 2980ccd + 1329dc2 commit 2df272b

File tree

6 files changed

+85
-31
lines changed

6 files changed

+85
-31
lines changed

clippy_lints/src/lib.rs

+2
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,8 @@ extern crate rustc_errors;
2929
#[allow(unused_extern_crates)]
3030
extern crate rustc_index;
3131
#[allow(unused_extern_crates)]
32+
extern crate rustc_lexer;
33+
#[allow(unused_extern_crates)]
3234
extern crate rustc_mir;
3335
#[allow(unused_extern_crates)]
3436
extern crate rustc_target;

clippy_lints/src/write.rs

+25-29
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,11 @@
1+
use std::borrow::Cow;
2+
use std::ops::Range;
3+
14
use crate::utils::{snippet_with_applicability, span_lint, span_lint_and_sugg, span_lint_and_then};
25
use rustc::lint::{EarlyContext, EarlyLintPass, LintArray, LintPass};
36
use rustc::{declare_lint_pass, declare_tool_lint};
47
use rustc_errors::Applicability;
5-
use std::borrow::Cow;
8+
use rustc_lexer::unescape::{self, EscapeError};
69
use syntax::ast::*;
710
use syntax::parse::{parser, token};
811
use syntax::tokenstream::TokenStream;
@@ -201,7 +204,7 @@ impl EarlyLintPass for Write {
201204
} else if mac.path == sym!(print) {
202205
span_lint(cx, PRINT_STDOUT, mac.span, "use of `print!`");
203206
if let (Some(fmt_str), _) = check_tts(cx, &mac.tts, false) {
204-
if check_newlines(&fmt_str) {
207+
if check_newlines(&fmt_str.contents, fmt_str.style) {
205208
span_lint_and_then(
206209
cx,
207210
PRINT_WITH_NEWLINE,
@@ -222,7 +225,7 @@ impl EarlyLintPass for Write {
222225
}
223226
} else if mac.path == sym!(write) {
224227
if let (Some(fmt_str), _) = check_tts(cx, &mac.tts, true) {
225-
if check_newlines(&fmt_str) {
228+
if check_newlines(&fmt_str.contents, fmt_str.style) {
226229
span_lint_and_then(
227230
cx,
228231
WRITE_WITH_NEWLINE,
@@ -440,38 +443,31 @@ fn check_tts<'a>(cx: &EarlyContext<'a>, tts: &TokenStream, is_write: bool) -> (O
440443
}
441444
}
442445

443-
/// Checks if the format string constains a single newline that terminates it.
446+
/// Checks if the format string contains a single newline that terminates it.
444447
///
445448
/// Literal and escaped newlines are both checked (only literal for raw strings).
446-
fn check_newlines(fmt_str: &FmtStr) -> bool {
447-
let s = &fmt_str.contents;
449+
fn check_newlines(contents: &str, style: StrStyle) -> bool {
450+
let mut has_internal_newline = false;
451+
let mut last_was_cr = false;
452+
let mut should_lint = false;
448453

449-
if s.ends_with('\n') {
450-
return true;
451-
} else if let StrStyle::Raw(_) = fmt_str.style {
452-
return false;
453-
}
454-
455-
if s.len() < 2 {
456-
return false;
457-
}
454+
let mut cb = |r: Range<usize>, c: Result<char, EscapeError>| {
455+
let c = c.unwrap();
458456

459-
let bytes = s.as_bytes();
460-
if bytes[bytes.len() - 2] != b'\\' || bytes[bytes.len() - 1] != b'n' {
461-
return false;
462-
}
463-
464-
let mut escaping = false;
465-
for (index, &byte) in bytes.iter().enumerate() {
466-
if escaping {
467-
if byte == b'n' {
468-
return index == bytes.len() - 1;
457+
if r.end == contents.len() && c == '\n' && !last_was_cr && !has_internal_newline {
458+
should_lint = true;
459+
} else {
460+
last_was_cr = c == '\r';
461+
if c == '\n' {
462+
has_internal_newline = true;
469463
}
470-
escaping = false;
471-
} else if byte == b'\\' {
472-
escaping = true;
473464
}
465+
};
466+
467+
match style {
468+
StrStyle::Cooked => unescape::unescape_str(contents, &mut cb),
469+
StrStyle::Raw(_) => unescape::unescape_raw_str(contents, &mut cb),
474470
}
475471

476-
false
472+
should_lint
477473
}

tests/ui/print_with_newline.rs

+6
Original file line numberDiff line numberDiff line change
@@ -42,4 +42,10 @@ fn main() {
4242
r"
4343
"
4444
);
45+
46+
// Don't warn on CRLF (#4208)
47+
print!("\r\n");
48+
print!("foo\r\n");
49+
print!("\\r\n"); //~ ERROR
50+
print!("foo\rbar\n") // ~ ERROR
4551
}

tests/ui/print_with_newline.stderr

+23-1
Original file line numberDiff line numberDiff line change
@@ -84,5 +84,27 @@ LL | println!(
8484
LL | r""
8585
|
8686

87-
error: aborting due to 7 previous errors
87+
error: using `print!()` with a format string that ends in a single newline
88+
--> $DIR/print_with_newline.rs:49:5
89+
|
90+
LL | print!("/r/n"); //~ ERROR
91+
| ^^^^^^^^^^^^^^^
92+
|
93+
help: use `println!` instead
94+
|
95+
LL | println!("/r"); //~ ERROR
96+
| ^^^^^^^ --
97+
98+
error: using `print!()` with a format string that ends in a single newline
99+
--> $DIR/print_with_newline.rs:50:5
100+
|
101+
LL | print!("foo/rbar/n") // ~ ERROR
102+
| ^^^^^^^^^^^^^^^^^^^^
103+
|
104+
help: use `println!` instead
105+
|
106+
LL | println!("foo/rbar") // ~ ERROR
107+
| ^^^^^^^ --
108+
109+
error: aborting due to 9 previous errors
88110

tests/ui/write_with_newline.rs

+6
Original file line numberDiff line numberDiff line change
@@ -49,4 +49,10 @@ fn main() {
4949
r"
5050
"
5151
);
52+
53+
// Don't warn on CRLF (#4208)
54+
write!(&mut v, "\r\n");
55+
write!(&mut v, "foo\r\n");
56+
write!(&mut v, "\\r\n"); //~ ERROR
57+
write!(&mut v, "foo\rbar\n"); //~ ERROR
5258
}

tests/ui/write_with_newline.stderr

+23-1
Original file line numberDiff line numberDiff line change
@@ -88,5 +88,27 @@ LL | &mut v,
8888
LL | r""
8989
|
9090

91-
error: aborting due to 7 previous errors
91+
error: using `write!()` with a format string that ends in a single newline
92+
--> $DIR/write_with_newline.rs:56:5
93+
|
94+
LL | write!(&mut v, "/r/n"); //~ ERROR
95+
| ^^^^^^^^^^^^^^^^^^^^^^^
96+
|
97+
help: use `writeln!()` instead
98+
|
99+
LL | writeln!(&mut v, "/r"); //~ ERROR
100+
| ^^^^^^^ --
101+
102+
error: using `write!()` with a format string that ends in a single newline
103+
--> $DIR/write_with_newline.rs:57:5
104+
|
105+
LL | write!(&mut v, "foo/rbar/n"); //~ ERROR
106+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
107+
|
108+
help: use `writeln!()` instead
109+
|
110+
LL | writeln!(&mut v, "foo/rbar"); //~ ERROR
111+
| ^^^^^^^ --
112+
113+
error: aborting due to 9 previous errors
92114

0 commit comments

Comments
 (0)