about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--clippy_lints/src/octal_escapes.rs44
-rw-r--r--tests/ui/octal_escapes.rs8
-rw-r--r--tests/ui/octal_escapes.stderr118
3 files changed, 131 insertions, 39 deletions
diff --git a/clippy_lints/src/octal_escapes.rs b/clippy_lints/src/octal_escapes.rs
index 9ae269bc7d9..b3a4ab121e1 100644
--- a/clippy_lints/src/octal_escapes.rs
+++ b/clippy_lints/src/octal_escapes.rs
@@ -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,
             );
         },
diff --git a/tests/ui/octal_escapes.rs b/tests/ui/octal_escapes.rs
index 5ddee73c020..53145ef0fd2 100644
--- a/tests/ui/octal_escapes.rs
+++ b/tests/ui/octal_escapes.rs
@@ -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锈";
 }
diff --git a/tests/ui/octal_escapes.stderr b/tests/ui/octal_escapes.stderr
index 8a93e781bed..8c27dc0cf05 100644
--- a/tests/ui/octal_escapes.stderr
+++ b/tests/ui/octal_escapes.stderr
@@ -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