diff --git a/clippy_lints/src/octal_escapes.rs b/clippy_lints/src/octal_escapes.rs index 7376ab0c846..6d3865080a6 100644 --- a/clippy_lints/src/octal_escapes.rs +++ b/clippy_lints/src/octal_escapes.rs @@ -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, + ); + } }, ); } diff --git a/tests/ui/octal_escapes.rs b/tests/ui/octal_escapes.rs index 53145ef0fd2..61ea9660457 100644 --- a/tests/ui/octal_escapes.rs +++ b/tests/ui/octal_escapes.rs @@ -17,4 +17,5 @@ fn main() { let _good3 = "\0\0"; let _good4 = "X\0\0X"; let _good5 = "锈\0锈"; + let _good6 = "\0\\01"; } diff --git a/tests/ui/octal_escapes.stderr b/tests/ui/octal_escapes.stderr index 295dc1798e3..aa362e96321 100644 --- a/tests/ui/octal_escapes.stderr +++ b/tests/ui/octal_escapes.stderr @@ -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