Auto 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.
This commit is contained in:
commit
180f87065f
@ -29,6 +29,8 @@ extern crate rustc_errors;
|
|||||||
#[allow(unused_extern_crates)]
|
#[allow(unused_extern_crates)]
|
||||||
extern crate rustc_index;
|
extern crate rustc_index;
|
||||||
#[allow(unused_extern_crates)]
|
#[allow(unused_extern_crates)]
|
||||||
|
extern crate rustc_lexer;
|
||||||
|
#[allow(unused_extern_crates)]
|
||||||
extern crate rustc_mir;
|
extern crate rustc_mir;
|
||||||
#[allow(unused_extern_crates)]
|
#[allow(unused_extern_crates)]
|
||||||
extern crate rustc_parse;
|
extern crate rustc_parse;
|
||||||
|
@ -1,9 +1,12 @@
|
|||||||
|
use std::borrow::Cow;
|
||||||
|
use std::ops::Range;
|
||||||
|
|
||||||
use crate::utils::{snippet_with_applicability, span_lint, span_lint_and_sugg, span_lint_and_then};
|
use crate::utils::{snippet_with_applicability, span_lint, span_lint_and_sugg, span_lint_and_then};
|
||||||
use rustc::lint::{EarlyContext, EarlyLintPass, LintArray, LintPass};
|
use rustc::lint::{EarlyContext, EarlyLintPass, LintArray, LintPass};
|
||||||
use rustc::{declare_lint_pass, declare_tool_lint};
|
use rustc::{declare_lint_pass, declare_tool_lint};
|
||||||
use rustc_errors::Applicability;
|
use rustc_errors::Applicability;
|
||||||
|
use rustc_lexer::unescape::{self, EscapeError};
|
||||||
use rustc_parse::parser;
|
use rustc_parse::parser;
|
||||||
use std::borrow::Cow;
|
|
||||||
use syntax::ast::*;
|
use syntax::ast::*;
|
||||||
use syntax::token;
|
use syntax::token;
|
||||||
use syntax::tokenstream::TokenStream;
|
use syntax::tokenstream::TokenStream;
|
||||||
@ -202,7 +205,7 @@ impl EarlyLintPass for Write {
|
|||||||
} else if mac.path == sym!(print) {
|
} else if mac.path == sym!(print) {
|
||||||
span_lint(cx, PRINT_STDOUT, mac.span, "use of `print!`");
|
span_lint(cx, PRINT_STDOUT, mac.span, "use of `print!`");
|
||||||
if let (Some(fmt_str), _) = check_tts(cx, &mac.tts, false) {
|
if let (Some(fmt_str), _) = check_tts(cx, &mac.tts, false) {
|
||||||
if check_newlines(&fmt_str) {
|
if check_newlines(&fmt_str.contents, fmt_str.style) {
|
||||||
span_lint_and_then(
|
span_lint_and_then(
|
||||||
cx,
|
cx,
|
||||||
PRINT_WITH_NEWLINE,
|
PRINT_WITH_NEWLINE,
|
||||||
@ -223,7 +226,7 @@ impl EarlyLintPass for Write {
|
|||||||
}
|
}
|
||||||
} else if mac.path == sym!(write) {
|
} else if mac.path == sym!(write) {
|
||||||
if let (Some(fmt_str), _) = check_tts(cx, &mac.tts, true) {
|
if let (Some(fmt_str), _) = check_tts(cx, &mac.tts, true) {
|
||||||
if check_newlines(&fmt_str) {
|
if check_newlines(&fmt_str.contents, fmt_str.style) {
|
||||||
span_lint_and_then(
|
span_lint_and_then(
|
||||||
cx,
|
cx,
|
||||||
WRITE_WITH_NEWLINE,
|
WRITE_WITH_NEWLINE,
|
||||||
@ -442,38 +445,31 @@ fn check_tts<'a>(cx: &EarlyContext<'a>, tts: &TokenStream, is_write: bool) -> (O
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Checks if the format string constains a single newline that terminates it.
|
/// Checks if the format string contains a single newline that terminates it.
|
||||||
///
|
///
|
||||||
/// Literal and escaped newlines are both checked (only literal for raw strings).
|
/// Literal and escaped newlines are both checked (only literal for raw strings).
|
||||||
fn check_newlines(fmt_str: &FmtStr) -> bool {
|
fn check_newlines(contents: &str, style: StrStyle) -> bool {
|
||||||
let s = &fmt_str.contents;
|
let mut has_internal_newline = false;
|
||||||
|
let mut last_was_cr = false;
|
||||||
|
let mut should_lint = false;
|
||||||
|
|
||||||
if s.ends_with('\n') {
|
let mut cb = |r: Range<usize>, c: Result<char, EscapeError>| {
|
||||||
return true;
|
let c = c.unwrap();
|
||||||
} else if let StrStyle::Raw(_) = fmt_str.style {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if s.len() < 2 {
|
if r.end == contents.len() && c == '\n' && !last_was_cr && !has_internal_newline {
|
||||||
return false;
|
should_lint = true;
|
||||||
}
|
} else {
|
||||||
|
last_was_cr = c == '\r';
|
||||||
let bytes = s.as_bytes();
|
if c == '\n' {
|
||||||
if bytes[bytes.len() - 2] != b'\\' || bytes[bytes.len() - 1] != b'n' {
|
has_internal_newline = true;
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut escaping = false;
|
|
||||||
for (index, &byte) in bytes.iter().enumerate() {
|
|
||||||
if escaping {
|
|
||||||
if byte == b'n' {
|
|
||||||
return index == bytes.len() - 1;
|
|
||||||
}
|
}
|
||||||
escaping = false;
|
|
||||||
} else if byte == b'\\' {
|
|
||||||
escaping = true;
|
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
match style {
|
||||||
|
StrStyle::Cooked => unescape::unescape_str(contents, &mut cb),
|
||||||
|
StrStyle::Raw(_) => unescape::unescape_raw_str(contents, &mut cb),
|
||||||
}
|
}
|
||||||
|
|
||||||
false
|
should_lint
|
||||||
}
|
}
|
||||||
|
@ -42,4 +42,10 @@ fn main() {
|
|||||||
r"
|
r"
|
||||||
"
|
"
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// Don't warn on CRLF (#4208)
|
||||||
|
print!("\r\n");
|
||||||
|
print!("foo\r\n");
|
||||||
|
print!("\\r\n"); //~ ERROR
|
||||||
|
print!("foo\rbar\n") // ~ ERROR
|
||||||
}
|
}
|
||||||
|
@ -84,5 +84,27 @@ LL | println!(
|
|||||||
LL | r""
|
LL | r""
|
||||||
|
|
|
|
||||||
|
|
||||||
error: aborting due to 7 previous errors
|
error: using `print!()` with a format string that ends in a single newline
|
||||||
|
--> $DIR/print_with_newline.rs:49:5
|
||||||
|
|
|
||||||
|
LL | print!("/r/n"); //~ ERROR
|
||||||
|
| ^^^^^^^^^^^^^^^
|
||||||
|
|
|
||||||
|
help: use `println!` instead
|
||||||
|
|
|
||||||
|
LL | println!("/r"); //~ ERROR
|
||||||
|
| ^^^^^^^ --
|
||||||
|
|
||||||
|
error: using `print!()` with a format string that ends in a single newline
|
||||||
|
--> $DIR/print_with_newline.rs:50:5
|
||||||
|
|
|
||||||
|
LL | print!("foo/rbar/n") // ~ ERROR
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
|
||||||
|
help: use `println!` instead
|
||||||
|
|
|
||||||
|
LL | println!("foo/rbar") // ~ ERROR
|
||||||
|
| ^^^^^^^ --
|
||||||
|
|
||||||
|
error: aborting due to 9 previous errors
|
||||||
|
|
||||||
|
@ -49,4 +49,10 @@ fn main() {
|
|||||||
r"
|
r"
|
||||||
"
|
"
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// Don't warn on CRLF (#4208)
|
||||||
|
write!(&mut v, "\r\n");
|
||||||
|
write!(&mut v, "foo\r\n");
|
||||||
|
write!(&mut v, "\\r\n"); //~ ERROR
|
||||||
|
write!(&mut v, "foo\rbar\n");
|
||||||
}
|
}
|
||||||
|
@ -88,5 +88,27 @@ LL | &mut v,
|
|||||||
LL | r""
|
LL | r""
|
||||||
|
|
|
|
||||||
|
|
||||||
error: aborting due to 7 previous errors
|
error: using `write!()` with a format string that ends in a single newline
|
||||||
|
--> $DIR/write_with_newline.rs:56:5
|
||||||
|
|
|
||||||
|
LL | write!(&mut v, "/r/n"); //~ ERROR
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
|
||||||
|
help: use `writeln!()` instead
|
||||||
|
|
|
||||||
|
LL | writeln!(&mut v, "/r"); //~ ERROR
|
||||||
|
| ^^^^^^^ --
|
||||||
|
|
||||||
|
error: using `write!()` with a format string that ends in a single newline
|
||||||
|
--> $DIR/write_with_newline.rs:57:5
|
||||||
|
|
|
||||||
|
LL | write!(&mut v, "foo/rbar/n");
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
|
||||||
|
help: use `writeln!()` instead
|
||||||
|
|
|
||||||
|
LL | writeln!(&mut v, "foo/rbar");
|
||||||
|
| ^^^^^^^ --
|
||||||
|
|
||||||
|
error: aborting due to 9 previous errors
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user