octal_escapes: updates from review, fix byte string prefix

This commit is contained in:
Georg Brandl 2021-11-21 16:06:19 +01:00
parent 982124acfa
commit 850e7f533e
3 changed files with 131 additions and 39 deletions

View File

@ -9,8 +9,8 @@ use rustc_span::Span;
declare_clippy_lint! {
/// ### What it does
/// Checks for `\0` escapes in string and byte literals that look like octal character
/// escapes in C
/// Checks for `\0` escapes in string and byte literals that look like octal
/// character escapes in C.
///
/// ### Why is this bad?
/// Rust does not support octal notation for character escapes. `\0` is always a
@ -57,20 +57,18 @@ impl EarlyLintPass for OctalEscapes {
fn check_lit(cx: &EarlyContext<'tcx>, lit: &Lit, span: Span, is_string: bool) {
let contents = lit.symbol.as_str();
let mut iter = contents.char_indices();
let mut iter = contents.char_indices().peekable();
// go through the string, looking for \0[0-7]
while let Some((from, ch)) = iter.next() {
if ch == '\\' {
if let Some((mut to, '0')) = iter.next() {
// collect all further potentially octal digits
while let Some((j, '0'..='7')) = iter.next() {
to = j + 1;
}
// if it's more than just `\0` we have a match
if to > from + 2 {
emit(cx, &contents, from, to, span, is_string);
return;
if let Some((_, '0')) = iter.next() {
// collect up to two further octal digits
if let Some((mut to, '0'..='7')) = iter.next() {
if let Some((_, '0'..='7')) = iter.peek() {
to += 1;
}
emit(cx, &contents, from, to + 1, span, is_string);
}
}
}
@ -80,19 +78,9 @@ fn check_lit(cx: &EarlyContext<'tcx>, lit: &Lit, span: Span, is_string: bool) {
fn emit(cx: &EarlyContext<'tcx>, contents: &str, from: usize, to: usize, span: Span, is_string: bool) {
// construct a replacement escape for that case that octal was intended
let escape = &contents[from + 1..to];
let literal_suggestion = if is_string {
u32::from_str_radix(escape, 8).ok().and_then(|n| {
if n < 256 {
Some(format!("\\x{:02x}", n))
} else if n <= std::char::MAX as u32 {
Some(format!("\\u{{{:x}}}", n))
} else {
None
}
})
} else {
u8::from_str_radix(escape, 8).ok().map(|n| format!("\\x{:02x}", n))
};
// the maximum value is \077, or \x3f
let literal_suggestion = u8::from_str_radix(escape, 8).ok().map(|n| format!("\\x{:02x}", n));
let prefix = if is_string { "" } else { "b" };
span_lint_and_then(
cx,
@ -111,8 +99,8 @@ fn emit(cx: &EarlyContext<'tcx>, contents: &str, from: usize, to: usize, span: S
if let Some(sugg) = literal_suggestion {
diag.span_suggestion(
span,
"if an octal escape is intended, use",
format!("\"{}{}{}\"", &contents[..from], sugg, &contents[to..]),
"if an octal escape was intended, use the hexadecimal representation instead",
format!("{}\"{}{}{}\"", prefix, &contents[..from], sugg, &contents[to..]),
Applicability::MaybeIncorrect,
);
}
@ -123,7 +111,7 @@ fn emit(cx: &EarlyContext<'tcx>, contents: &str, from: usize, to: usize, span: S
"if the null {} is intended, disambiguate using",
if is_string { "character" } else { "byte" }
),
format!("\"{}\\x00{}\"", &contents[..from], &contents[from + 2..]),
format!("{}\"{}\\x00{}\"", prefix, &contents[..from], &contents[from + 2..]),
Applicability::MaybeIncorrect,
);
},

View File

@ -4,9 +4,17 @@ fn main() {
let _bad1 = "\033[0m";
let _bad2 = b"\033[0m";
let _bad3 = "\\\033[0m";
// maximum 3 digits (\012 is the escape)
let _bad4 = "\01234567";
let _bad5 = "\0\03";
let _bad6 = "Text-\055\077-MoreText";
let _bad7 = "EvenMoreText-\01\02-ShortEscapes";
let _bad8 = "\01锈";
let _bad9 = "\011锈";
let _good1 = "\\033[0m";
let _good2 = "\0\\0";
let _good3 = "\0\0";
let _good4 = "X\0\0X";
let _good5 = "\0";
}

View File

@ -6,7 +6,7 @@ LL | let _bad1 = "/033[0m";
|
= note: `-D clippy::octal-escapes` implied by `-D warnings`
= help: octal escapes are not supported, `/0` is always a null character
help: if an octal escape is intended, use
help: if an octal escape was intended, use the hexadecimal representation instead
|
LL | let _bad1 = "/x1b[0m";
| ~~~~~~~~~
@ -22,14 +22,14 @@ LL | let _bad2 = b"/033[0m";
| ^^^^^^^^^^
|
= help: octal escapes are not supported, `/0` is always a null byte
help: if an octal escape is intended, use
help: if an octal escape was intended, use the hexadecimal representation instead
|
LL | let _bad2 = "/x1b[0m";
| ~~~~~~~~~
LL | let _bad2 = b"/x1b[0m";
| ~~~~~~~~~~
help: if the null byte is intended, disambiguate using
|
LL | let _bad2 = "/x0033[0m";
| ~~~~~~~~~~~
LL | let _bad2 = b"/x0033[0m";
| ~~~~~~~~~~~~
error: octal-looking escape in string literal
--> $DIR/octal_escapes.rs:6:17
@ -38,7 +38,7 @@ LL | let _bad3 = "//033[0m";
| ^^^^^^^^^^^
|
= help: octal escapes are not supported, `/0` is always a null character
help: if an octal escape is intended, use
help: if an octal escape was intended, use the hexadecimal representation instead
|
LL | let _bad3 = "//x1b[0m";
| ~~~~~~~~~~~
@ -48,20 +48,116 @@ LL | let _bad3 = "//x0033[0m";
| ~~~~~~~~~~~~~
error: octal-looking escape in string literal
--> $DIR/octal_escapes.rs:7:17
--> $DIR/octal_escapes.rs:8:17
|
LL | let _bad4 = "/01234567";
| ^^^^^^^^^^^
|
= help: octal escapes are not supported, `/0` is always a null character
help: if an octal escape is intended, use
help: if an octal escape was intended, use the hexadecimal representation instead
|
LL | let _bad4 = "/u{53977}";
LL | let _bad4 = "/x0a34567";
| ~~~~~~~~~~~
help: if the null character is intended, disambiguate using
|
LL | let _bad4 = "/x001234567";
| ~~~~~~~~~~~~~
error: aborting due to 4 previous errors
error: octal-looking escape in string literal
--> $DIR/octal_escapes.rs:10:17
|
LL | let _bad6 = "Text-/055/077-MoreText";
| ^^^^^^^^^^^^^^^^^^^^^^^^
|
= help: octal escapes are not supported, `/0` is always a null character
help: if an octal escape was intended, use the hexadecimal representation instead
|
LL | let _bad6 = "Text-/x2d/077-MoreText";
| ~~~~~~~~~~~~~~~~~~~~~~~~
help: if the null character is intended, disambiguate using
|
LL | let _bad6 = "Text-/x0055/077-MoreText";
| ~~~~~~~~~~~~~~~~~~~~~~~~~~
error: octal-looking escape in string literal
--> $DIR/octal_escapes.rs:10:17
|
LL | let _bad6 = "Text-/055/077-MoreText";
| ^^^^^^^^^^^^^^^^^^^^^^^^
|
= help: octal escapes are not supported, `/0` is always a null character
help: if an octal escape was intended, use the hexadecimal representation instead
|
LL | let _bad6 = "Text-/055/x3f-MoreText";
| ~~~~~~~~~~~~~~~~~~~~~~~~
help: if the null character is intended, disambiguate using
|
LL | let _bad6 = "Text-/055/x0077-MoreText";
| ~~~~~~~~~~~~~~~~~~~~~~~~~~
error: octal-looking escape in string literal
--> $DIR/octal_escapes.rs:11:17
|
LL | let _bad7 = "EvenMoreText-/01/02-ShortEscapes";
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= help: octal escapes are not supported, `/0` is always a null character
help: if an octal escape was intended, use the hexadecimal representation instead
|
LL | let _bad7 = "EvenMoreText-/x01/02-ShortEscapes";
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
help: if the null character is intended, disambiguate using
|
LL | let _bad7 = "EvenMoreText-/x001/02-ShortEscapes";
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
error: octal-looking escape in string literal
--> $DIR/octal_escapes.rs:11:17
|
LL | let _bad7 = "EvenMoreText-/01/02-ShortEscapes";
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= help: octal escapes are not supported, `/0` is always a null character
help: if an octal escape was intended, use the hexadecimal representation instead
|
LL | let _bad7 = "EvenMoreText-/01/x02-ShortEscapes";
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
help: if the null character is intended, disambiguate using
|
LL | let _bad7 = "EvenMoreText-/01/x002-ShortEscapes";
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
error: octal-looking escape in string literal
--> $DIR/octal_escapes.rs:12:17
|
LL | let _bad8 = "锈/01锈";
| ^^^^^^^^^
|
= help: octal escapes are not supported, `/0` is always a null character
help: if an octal escape was intended, use the hexadecimal representation instead
|
LL | let _bad8 = "锈/x01锈";
| ~~~~~~~~~~
help: if the null character is intended, disambiguate using
|
LL | let _bad8 = "锈/x001锈";
| ~~~~~~~~~~~
error: octal-looking escape in string literal
--> $DIR/octal_escapes.rs:13:17
|
LL | let _bad9 = "锈/011锈";
| ^^^^^^^^^^
|
= help: octal escapes are not supported, `/0` is always a null character
help: if an octal escape was intended, use the hexadecimal representation instead
|
LL | let _bad9 = "锈/x09锈";
| ~~~~~~~~~~
help: if the null character is intended, disambiguate using
|
LL | let _bad9 = "锈/x0011锈";
| ~~~~~~~~~~~~
error: aborting due to 10 previous errors