Merge pull request #10603 from robertbastian/octal

Fix false positives and false negatives in `octal_escapes`
This commit is contained in:
Manish Goregaokar 2023-04-13 15:50:00 -07:00 committed by GitHub
commit b2edd42b24
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 67 additions and 46 deletions

View file

@ -76,8 +76,8 @@ fn check_lit(cx: &EarlyContext<'_>, lit: &Lit, span: Span, is_string: bool) {
if ch == '\\' {
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() {
if let Some((mut to, _)) = iter.next_if(|(_, ch)| matches!(ch, '0'..='7')) {
if iter.next_if(|(_, ch)| matches!(ch, '0'..='7')).is_some() {
to += 1;
}
found.push((from, to + 1));
@ -90,32 +90,6 @@ fn check_lit(cx: &EarlyContext<'_>, lit: &Lit, span: Span, is_string: bool) {
return;
}
// construct two suggestion strings, one with \x escapes with octal meaning
// as in C, and one with \x00 for null bytes.
let mut suggest_1 = if is_string { "\"" } else { "b\"" }.to_string();
let mut suggest_2 = suggest_1.clone();
let mut index = 0;
for (from, to) in found {
suggest_1.push_str(&contents[index..from]);
suggest_2.push_str(&contents[index..from]);
// construct a replacement escape
// the maximum value is \077, or \x3f, so u8 is sufficient here
if let Ok(n) = u8::from_str_radix(&contents[from + 1..to], 8) {
write!(suggest_1, "\\x{n:02x}").unwrap();
}
// append the null byte as \x00 and the following digits literally
suggest_2.push_str("\\x00");
suggest_2.push_str(&contents[from + 2..to]);
index = to;
}
suggest_1.push_str(&contents[index..]);
suggest_1.push('"');
suggest_2.push_str(&contents[index..]);
suggest_2.push('"');
span_lint_and_then(
cx,
OCTAL_ESCAPES,
@ -129,23 +103,53 @@ fn check_lit(cx: &EarlyContext<'_>, lit: &Lit, span: Span, is_string: bool) {
"octal escapes are not supported, `\\0` is always a null {}",
if is_string { "character" } else { "byte" }
));
// suggestion 1: equivalent hex escape
diag.span_suggestion(
span,
"if an octal escape was intended, use the hexadecimal representation instead",
suggest_1,
Applicability::MaybeIncorrect,
);
// suggestion 2: unambiguous null byte
diag.span_suggestion(
span,
format!(
"if the null {} is intended, disambiguate using",
if is_string { "character" } else { "byte" }
),
suggest_2,
Applicability::MaybeIncorrect,
);
// Generate suggestions if the string is not too long (~ 5 lines)
if contents.len() < 400 {
// construct two suggestion strings, one with \x escapes with octal meaning
// as in C, and one with \x00 for null bytes.
let mut suggest_1 = if is_string { "\"" } else { "b\"" }.to_string();
let mut suggest_2 = suggest_1.clone();
let mut index = 0;
for (from, to) in found {
suggest_1.push_str(&contents[index..from]);
suggest_2.push_str(&contents[index..from]);
// construct a replacement escape
// the maximum value is \077, or \x3f, so u8 is sufficient here
if let Ok(n) = u8::from_str_radix(&contents[from + 1..to], 8) {
write!(suggest_1, "\\x{n:02x}").unwrap();
}
// append the null byte as \x00 and the following digits literally
suggest_2.push_str("\\x00");
suggest_2.push_str(&contents[from + 2..to]);
index = to;
}
suggest_1.push_str(&contents[index..]);
suggest_2.push_str(&contents[index..]);
suggest_1.push('"');
suggest_2.push('"');
// suggestion 1: equivalent hex escape
diag.span_suggestion(
span,
"if an octal escape was intended, use the hexadecimal representation instead",
suggest_1,
Applicability::MaybeIncorrect,
);
// suggestion 2: unambiguous null byte
diag.span_suggestion(
span,
format!(
"if the null {} is intended, disambiguate using",
if is_string { "character" } else { "byte" }
),
suggest_2,
Applicability::MaybeIncorrect,
);
}
},
);
}

View file

@ -17,4 +17,5 @@ fn main() {
let _good3 = "\0\0";
let _good4 = "X\0\0X";
let _good5 = "\0";
let _good6 = "\0\\01";
}

View file

@ -63,6 +63,22 @@ help: if the null character is intended, disambiguate using
LL | let _bad4 = "/x001234567";
| ~~~~~~~~~~~~~
error: octal-looking escape in string literal
--> $DIR/octal_escapes.rs:9:17
|
LL | let _bad5 = "/0/03";
| ^^^^^^^
|
= 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 _bad5 = "/0/x03";
| ~~~~~~~~
help: if the null character is intended, disambiguate using
|
LL | let _bad5 = "/0/x003";
| ~~~~~~~~~
error: octal-looking escape in string literal
--> $DIR/octal_escapes.rs:10:17
|
@ -127,5 +143,5 @@ help: if the null character is intended, disambiguate using
LL | let _bad9 = "锈/x0011锈";
| ~~~~~~~~~~~~
error: aborting due to 8 previous errors
error: aborting due to 9 previous errors