Warn when an escaped newline skips multiple lines

This commit is contained in:
Anton Golov 2021-07-31 20:35:37 +02:00
parent d488de82f3
commit a03fbfe2ff
3 changed files with 19 additions and 0 deletions

View file

@ -60,6 +60,9 @@ pub enum EscapeError {
/// After a line ending with '\', the next line contains whitespace /// After a line ending with '\', the next line contains whitespace
/// characters that are not skipped. /// characters that are not skipped.
UnskippedWhitespaceWarning, UnskippedWhitespaceWarning,
/// After a line ending with '\', multiple lines are skipped.
MultipleSkippedLinesWarning,
} }
impl EscapeError { impl EscapeError {
@ -67,6 +70,7 @@ impl EscapeError {
pub fn is_fatal(&self) -> bool { pub fn is_fatal(&self) -> bool {
match self { match self {
EscapeError::UnskippedWhitespaceWarning => false, EscapeError::UnskippedWhitespaceWarning => false,
EscapeError::MultipleSkippedLinesWarning => false,
_ => true, _ => true,
} }
} }
@ -320,6 +324,11 @@ where
.bytes() .bytes()
.position(|b| b != b' ' && b != b'\t' && b != b'\n' && b != b'\r') .position(|b| b != b' ' && b != b'\t' && b != b'\n' && b != b'\r')
.unwrap_or(str.len()); .unwrap_or(str.len());
if str[1..first_non_space].contains('\n') {
// The +1 accounts for the escaping slash.
let end = start + first_non_space + 1;
callback(start..end, Err(EscapeError::MultipleSkippedLinesWarning));
}
let tail = &str[first_non_space..]; let tail = &str[first_non_space..];
if let Some(c) = tail.chars().nth(0) { if let Some(c) = tail.chars().nth(0) {
// For error reporting, we would like the span to contain the character that was not // For error reporting, we would like the span to contain the character that was not

View file

@ -106,6 +106,10 @@ fn test_unescape_str_warn() {
assert_eq!(unescaped, expected); assert_eq!(unescaped, expected);
} }
// Check we can handle escaped newlines at the end of a file.
check("\\\n", &[]);
check("\\\n ", &[]);
check( check(
"\\\n \u{a0} x", "\\\n \u{a0} x",
&[ &[
@ -115,6 +119,7 @@ fn test_unescape_str_warn() {
(6..7, Ok('x')), (6..7, Ok('x')),
], ],
); );
check("\\\n \n x", &[(0..7, Err(EscapeError::MultipleSkippedLinesWarning)), (7..8, Ok('x'))]);
} }
#[test] #[test]

View file

@ -280,6 +280,11 @@ pub(crate) fn emit_unescape_error(
format!("non-ASCII whitespace symbol '{}' is not skipped", c.escape_unicode()); format!("non-ASCII whitespace symbol '{}' is not skipped", c.escape_unicode());
handler.struct_span_warn(span, &msg).span_label(char_span, &msg).emit(); handler.struct_span_warn(span, &msg).span_label(char_span, &msg).emit();
} }
EscapeError::MultipleSkippedLinesWarning => {
let msg = "multiple lines skipped by escaped newline";
let bottom_msg = "skipping everything up to and including this point";
handler.struct_span_warn(span, msg).span_label(span, bottom_msg).emit();
}
} }
} }