1
+ use std:: { iter:: once, ops:: ControlFlow } ;
2
+
1
3
use clippy_utils:: { diagnostics:: span_lint_and_sugg, source:: snippet} ;
2
4
use rustc_ast:: {
3
5
ast:: { Expr , ExprKind } ,
@@ -13,7 +15,8 @@ declare_clippy_lint! {
13
15
/// Checks for raw string literals where a string literal can be used instead.
14
16
///
15
17
/// ### Why is this bad?
16
- /// It's just unnecessary.
18
+ /// It's just unnecessary, but there are many cases where using a raw string literal is more
19
+ /// idiomatic than a string literal, so it's opt-in.
17
20
///
18
21
/// ### Example
19
22
/// ```rust
@@ -24,8 +27,8 @@ declare_clippy_lint! {
24
27
/// let r = "Hello, world!";
25
28
/// ```
26
29
#[ clippy:: version = "1.72.0" ]
27
- pub NEEDLESS_RAW_STRING ,
28
- complexity ,
30
+ pub NEEDLESS_RAW_STRINGS ,
31
+ restriction ,
29
32
"suggests using a string literal when a raw string literal is unnecessary"
30
33
}
31
34
declare_clippy_lint ! {
@@ -46,10 +49,10 @@ declare_clippy_lint! {
46
49
/// ```
47
50
#[ clippy:: version = "1.72.0" ]
48
51
pub NEEDLESS_RAW_STRING_HASHES ,
49
- complexity ,
52
+ style ,
50
53
"suggests reducing the number of hashes around a raw string literal"
51
54
}
52
- impl_lint_pass ! ( RawStrings => [ NEEDLESS_RAW_STRING , NEEDLESS_RAW_STRING_HASHES ] ) ;
55
+ impl_lint_pass ! ( RawStrings => [ NEEDLESS_RAW_STRINGS , NEEDLESS_RAW_STRING_HASHES ] ) ;
53
56
54
57
pub struct RawStrings {
55
58
pub needless_raw_string_hashes_allow_one : bool ,
@@ -59,8 +62,9 @@ impl EarlyLintPass for RawStrings {
59
62
fn check_expr ( & mut self , cx : & EarlyContext < ' _ > , expr : & Expr ) {
60
63
if !in_external_macro ( cx. sess ( ) , expr. span )
61
64
&& let ExprKind :: Lit ( lit) = expr. kind
62
- && let LitKind :: StrRaw ( num ) | LitKind :: ByteStrRaw ( num ) | LitKind :: CStrRaw ( num ) = lit. kind
65
+ && let LitKind :: StrRaw ( max ) | LitKind :: ByteStrRaw ( max ) | LitKind :: CStrRaw ( max ) = lit. kind
63
66
{
67
+ let str = lit. symbol . as_str ( ) ;
64
68
let prefix = match lit. kind {
65
69
LitKind :: StrRaw ( ..) => "r" ,
66
70
LitKind :: ByteStrRaw ( ..) => "br" ,
@@ -71,10 +75,10 @@ impl EarlyLintPass for RawStrings {
71
75
return ;
72
76
}
73
77
74
- if !lit . symbol . as_str ( ) . contains ( [ '\\' , '"' ] ) {
78
+ if !str . contains ( [ '\\' , '"' ] ) {
75
79
span_lint_and_sugg (
76
80
cx,
77
- NEEDLESS_RAW_STRING ,
81
+ NEEDLESS_RAW_STRINGS ,
78
82
expr. span ,
79
83
"unnecessary raw string literal" ,
80
84
"try" ,
@@ -85,15 +89,43 @@ impl EarlyLintPass for RawStrings {
85
89
return ;
86
90
}
87
91
88
- #[ expect( clippy:: cast_possible_truncation) ]
89
- let req = lit. symbol . as_str ( ) . as_bytes ( )
90
- . split ( |& b| b == b'"' )
91
- . skip ( 1 )
92
- . map ( |bs| 1 + bs. iter ( ) . take_while ( |& & b| b == b'#' ) . count ( ) as u8 )
93
- . max ( )
94
- . unwrap_or ( 0 ) ;
92
+ let req = {
93
+ let mut following_quote = false ;
94
+ let mut req = 0 ;
95
+ // `once` so a raw string ending in hashes is still checked
96
+ let num = str. as_bytes ( ) . iter ( ) . chain ( once ( & 0 ) ) . try_fold ( 0u8 , |acc, & b| {
97
+ match b {
98
+ b'"' => ( following_quote, req) = ( true , 1 ) ,
99
+ // I'm a bit surprised the compiler didn't optimize this out, there's no
100
+ // branch but it still ends up doing an unnecessary comparison, it's:
101
+ // - cmp r9b,1h
102
+ // - sbb cl,-1h
103
+ // which will add 1 if it's true. With this change, it becomes:
104
+ // - add cl,r9b
105
+ // isn't that so much nicer?
106
+ b'#' => req += u8:: from ( following_quote) ,
107
+ _ => {
108
+ if following_quote {
109
+ following_quote = false ;
110
+
111
+ if req == max {
112
+ return ControlFlow :: Break ( req) ;
113
+ }
114
+
115
+ return ControlFlow :: Continue ( acc. max ( req) ) ;
116
+ }
117
+ } ,
118
+ }
119
+
120
+ ControlFlow :: Continue ( acc)
121
+ } ) ;
122
+
123
+ match num {
124
+ ControlFlow :: Continue ( num) | ControlFlow :: Break ( num) => num,
125
+ }
126
+ } ;
95
127
96
- if req < num {
128
+ if req < max {
97
129
let hashes = "#" . repeat ( req as usize ) ;
98
130
99
131
span_lint_and_sugg (
0 commit comments