Merge pull request #10603 from robertbastian/octal
Fix false positives and false negatives in `octal_escapes`
This commit is contained in:
commit
b2edd42b24
@ -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,
|
||||
);
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
|
@ -17,4 +17,5 @@ fn main() {
|
||||
let _good3 = "\0\0";
|
||||
let _good4 = "X\0\0X";
|
||||
let _good5 = "锈\0锈";
|
||||
let _good6 = "\0\\01";
|
||||
}
|
||||
|
@ -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
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user