Skip to content

Commit 850e7f5

Browse files
committed
octal_escapes: updates from review, fix byte string prefix
1 parent 982124a commit 850e7f5

File tree

3 files changed

+131
-39
lines changed

3 files changed

+131
-39
lines changed

clippy_lints/src/octal_escapes.rs

+16-28
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,8 @@ use rustc_span::Span;
99

1010
declare_clippy_lint! {
1111
/// ### What it does
12-
/// Checks for `\0` escapes in string and byte literals that look like octal character
13-
/// escapes in C
12+
/// Checks for `\0` escapes in string and byte literals that look like octal
13+
/// character escapes in C.
1414
///
1515
/// ### Why is this bad?
1616
/// Rust does not support octal notation for character escapes. `\0` is always a
@@ -57,20 +57,18 @@ impl EarlyLintPass for OctalEscapes {
5757

5858
fn check_lit(cx: &EarlyContext<'tcx>, lit: &Lit, span: Span, is_string: bool) {
5959
let contents = lit.symbol.as_str();
60-
let mut iter = contents.char_indices();
60+
let mut iter = contents.char_indices().peekable();
6161

6262
// go through the string, looking for \0[0-7]
6363
while let Some((from, ch)) = iter.next() {
6464
if ch == '\\' {
65-
if let Some((mut to, '0')) = iter.next() {
66-
// collect all further potentially octal digits
67-
while let Some((j, '0'..='7')) = iter.next() {
68-
to = j + 1;
69-
}
70-
// if it's more than just `\0` we have a match
71-
if to > from + 2 {
72-
emit(cx, &contents, from, to, span, is_string);
73-
return;
65+
if let Some((_, '0')) = iter.next() {
66+
// collect up to two further octal digits
67+
if let Some((mut to, '0'..='7')) = iter.next() {
68+
if let Some((_, '0'..='7')) = iter.peek() {
69+
to += 1;
70+
}
71+
emit(cx, &contents, from, to + 1, span, is_string);
7472
}
7573
}
7674
}
@@ -80,19 +78,9 @@ fn check_lit(cx: &EarlyContext<'tcx>, lit: &Lit, span: Span, is_string: bool) {
8078
fn emit(cx: &EarlyContext<'tcx>, contents: &str, from: usize, to: usize, span: Span, is_string: bool) {
8179
// construct a replacement escape for that case that octal was intended
8280
let escape = &contents[from + 1..to];
83-
let literal_suggestion = if is_string {
84-
u32::from_str_radix(escape, 8).ok().and_then(|n| {
85-
if n < 256 {
86-
Some(format!("\\x{:02x}", n))
87-
} else if n <= std::char::MAX as u32 {
88-
Some(format!("\\u{{{:x}}}", n))
89-
} else {
90-
None
91-
}
92-
})
93-
} else {
94-
u8::from_str_radix(escape, 8).ok().map(|n| format!("\\x{:02x}", n))
95-
};
81+
// the maximum value is \077, or \x3f
82+
let literal_suggestion = u8::from_str_radix(escape, 8).ok().map(|n| format!("\\x{:02x}", n));
83+
let prefix = if is_string { "" } else { "b" };
9684

9785
span_lint_and_then(
9886
cx,
@@ -111,8 +99,8 @@ fn emit(cx: &EarlyContext<'tcx>, contents: &str, from: usize, to: usize, span: S
11199
if let Some(sugg) = literal_suggestion {
112100
diag.span_suggestion(
113101
span,
114-
"if an octal escape is intended, use",
115-
format!("\"{}{}{}\"", &contents[..from], sugg, &contents[to..]),
102+
"if an octal escape was intended, use the hexadecimal representation instead",
103+
format!("{}\"{}{}{}\"", prefix, &contents[..from], sugg, &contents[to..]),
116104
Applicability::MaybeIncorrect,
117105
);
118106
}
@@ -123,7 +111,7 @@ fn emit(cx: &EarlyContext<'tcx>, contents: &str, from: usize, to: usize, span: S
123111
"if the null {} is intended, disambiguate using",
124112
if is_string { "character" } else { "byte" }
125113
),
126-
format!("\"{}\\x00{}\"", &contents[..from], &contents[from + 2..]),
114+
format!("{}\"{}\\x00{}\"", prefix, &contents[..from], &contents[from + 2..]),
127115
Applicability::MaybeIncorrect,
128116
);
129117
},

tests/ui/octal_escapes.rs

+8
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,17 @@ fn main() {
44
let _bad1 = "\033[0m";
55
let _bad2 = b"\033[0m";
66
let _bad3 = "\\\033[0m";
7+
// maximum 3 digits (\012 is the escape)
78
let _bad4 = "\01234567";
89
let _bad5 = "\0\03";
10+
let _bad6 = "Text-\055\077-MoreText";
11+
let _bad7 = "EvenMoreText-\01\02-ShortEscapes";
12+
let _bad8 = "锈\01锈";
13+
let _bad9 = "锈\011锈";
914

1015
let _good1 = "\\033[0m";
1116
let _good2 = "\0\\0";
17+
let _good3 = "\0\0";
18+
let _good4 = "X\0\0X";
19+
let _good5 = "锈\0锈";
1220
}

tests/ui/octal_escapes.stderr

+107-11
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ LL | let _bad1 = "/033[0m";
66
|
77
= note: `-D clippy::octal-escapes` implied by `-D warnings`
88
= help: octal escapes are not supported, `/0` is always a null character
9-
help: if an octal escape is intended, use
9+
help: if an octal escape was intended, use the hexadecimal representation instead
1010
|
1111
LL | let _bad1 = "/x1b[0m";
1212
| ~~~~~~~~~
@@ -22,14 +22,14 @@ LL | let _bad2 = b"/033[0m";
2222
| ^^^^^^^^^^
2323
|
2424
= help: octal escapes are not supported, `/0` is always a null byte
25-
help: if an octal escape is intended, use
25+
help: if an octal escape was intended, use the hexadecimal representation instead
2626
|
27-
LL | let _bad2 = "/x1b[0m";
28-
| ~~~~~~~~~
27+
LL | let _bad2 = b"/x1b[0m";
28+
| ~~~~~~~~~~
2929
help: if the null byte is intended, disambiguate using
3030
|
31-
LL | let _bad2 = "/x0033[0m";
32-
| ~~~~~~~~~~~
31+
LL | let _bad2 = b"/x0033[0m";
32+
| ~~~~~~~~~~~~
3333

3434
error: octal-looking escape in string literal
3535
--> $DIR/octal_escapes.rs:6:17
@@ -38,7 +38,7 @@ LL | let _bad3 = "//033[0m";
3838
| ^^^^^^^^^^^
3939
|
4040
= help: octal escapes are not supported, `/0` is always a null character
41-
help: if an octal escape is intended, use
41+
help: if an octal escape was intended, use the hexadecimal representation instead
4242
|
4343
LL | let _bad3 = "//x1b[0m";
4444
| ~~~~~~~~~~~
@@ -48,20 +48,116 @@ LL | let _bad3 = "//x0033[0m";
4848
| ~~~~~~~~~~~~~
4949

5050
error: octal-looking escape in string literal
51-
--> $DIR/octal_escapes.rs:7:17
51+
--> $DIR/octal_escapes.rs:8:17
5252
|
5353
LL | let _bad4 = "/01234567";
5454
| ^^^^^^^^^^^
5555
|
5656
= help: octal escapes are not supported, `/0` is always a null character
57-
help: if an octal escape is intended, use
57+
help: if an octal escape was intended, use the hexadecimal representation instead
5858
|
59-
LL | let _bad4 = "/u{53977}";
59+
LL | let _bad4 = "/x0a34567";
6060
| ~~~~~~~~~~~
6161
help: if the null character is intended, disambiguate using
6262
|
6363
LL | let _bad4 = "/x001234567";
6464
| ~~~~~~~~~~~~~
6565

66-
error: aborting due to 4 previous errors
66+
error: octal-looking escape in string literal
67+
--> $DIR/octal_escapes.rs:10:17
68+
|
69+
LL | let _bad6 = "Text-/055/077-MoreText";
70+
| ^^^^^^^^^^^^^^^^^^^^^^^^
71+
|
72+
= help: octal escapes are not supported, `/0` is always a null character
73+
help: if an octal escape was intended, use the hexadecimal representation instead
74+
|
75+
LL | let _bad6 = "Text-/x2d/077-MoreText";
76+
| ~~~~~~~~~~~~~~~~~~~~~~~~
77+
help: if the null character is intended, disambiguate using
78+
|
79+
LL | let _bad6 = "Text-/x0055/077-MoreText";
80+
| ~~~~~~~~~~~~~~~~~~~~~~~~~~
81+
82+
error: octal-looking escape in string literal
83+
--> $DIR/octal_escapes.rs:10:17
84+
|
85+
LL | let _bad6 = "Text-/055/077-MoreText";
86+
| ^^^^^^^^^^^^^^^^^^^^^^^^
87+
|
88+
= help: octal escapes are not supported, `/0` is always a null character
89+
help: if an octal escape was intended, use the hexadecimal representation instead
90+
|
91+
LL | let _bad6 = "Text-/055/x3f-MoreText";
92+
| ~~~~~~~~~~~~~~~~~~~~~~~~
93+
help: if the null character is intended, disambiguate using
94+
|
95+
LL | let _bad6 = "Text-/055/x0077-MoreText";
96+
| ~~~~~~~~~~~~~~~~~~~~~~~~~~
97+
98+
error: octal-looking escape in string literal
99+
--> $DIR/octal_escapes.rs:11:17
100+
|
101+
LL | let _bad7 = "EvenMoreText-/01/02-ShortEscapes";
102+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
103+
|
104+
= help: octal escapes are not supported, `/0` is always a null character
105+
help: if an octal escape was intended, use the hexadecimal representation instead
106+
|
107+
LL | let _bad7 = "EvenMoreText-/x01/02-ShortEscapes";
108+
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
109+
help: if the null character is intended, disambiguate using
110+
|
111+
LL | let _bad7 = "EvenMoreText-/x001/02-ShortEscapes";
112+
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
113+
114+
error: octal-looking escape in string literal
115+
--> $DIR/octal_escapes.rs:11:17
116+
|
117+
LL | let _bad7 = "EvenMoreText-/01/02-ShortEscapes";
118+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
119+
|
120+
= help: octal escapes are not supported, `/0` is always a null character
121+
help: if an octal escape was intended, use the hexadecimal representation instead
122+
|
123+
LL | let _bad7 = "EvenMoreText-/01/x02-ShortEscapes";
124+
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
125+
help: if the null character is intended, disambiguate using
126+
|
127+
LL | let _bad7 = "EvenMoreText-/01/x002-ShortEscapes";
128+
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
129+
130+
error: octal-looking escape in string literal
131+
--> $DIR/octal_escapes.rs:12:17
132+
|
133+
LL | let _bad8 = "锈/01锈";
134+
| ^^^^^^^^^
135+
|
136+
= help: octal escapes are not supported, `/0` is always a null character
137+
help: if an octal escape was intended, use the hexadecimal representation instead
138+
|
139+
LL | let _bad8 = "锈/x01锈";
140+
| ~~~~~~~~~~
141+
help: if the null character is intended, disambiguate using
142+
|
143+
LL | let _bad8 = "锈/x001锈";
144+
| ~~~~~~~~~~~
145+
146+
error: octal-looking escape in string literal
147+
--> $DIR/octal_escapes.rs:13:17
148+
|
149+
LL | let _bad9 = "锈/011锈";
150+
| ^^^^^^^^^^
151+
|
152+
= help: octal escapes are not supported, `/0` is always a null character
153+
help: if an octal escape was intended, use the hexadecimal representation instead
154+
|
155+
LL | let _bad9 = "锈/x09锈";
156+
| ~~~~~~~~~~
157+
help: if the null character is intended, disambiguate using
158+
|
159+
LL | let _bad9 = "锈/x0011锈";
160+
| ~~~~~~~~~~~~
161+
162+
error: aborting due to 10 previous errors
67163

0 commit comments

Comments
 (0)