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 } ,
@@ -62,6 +64,7 @@ impl EarlyLintPass for RawStrings {
62
64
&& let ExprKind :: Lit ( lit) = expr. kind
63
65
&& let LitKind :: StrRaw ( max) | LitKind :: ByteStrRaw ( max) | LitKind :: CStrRaw ( max) = lit. kind
64
66
{
67
+ let str = lit. symbol . as_str ( ) ;
65
68
let prefix = match lit. kind {
66
69
LitKind :: StrRaw ( ..) => "r" ,
67
70
LitKind :: ByteStrRaw ( ..) => "br" ,
@@ -72,7 +75,7 @@ impl EarlyLintPass for RawStrings {
72
75
return ;
73
76
}
74
77
75
- if !lit . symbol . as_str ( ) . contains ( [ '\\' , '"' ] ) {
78
+ if !str . contains ( [ '\\' , '"' ] ) {
76
79
span_lint_and_sugg (
77
80
cx,
78
81
NEEDLESS_RAW_STRING ,
@@ -86,25 +89,41 @@ impl EarlyLintPass for RawStrings {
86
89
return ;
87
90
}
88
91
89
- #[ expect( clippy:: cast_possible_truncation) ]
90
- let req = lit
91
- . symbol
92
- . as_str ( )
93
- . as_bytes ( )
94
- . split ( |& b| b == b'"' )
95
- . skip ( 1 )
96
- . map_while ( |bs| {
97
- let num = bs. iter ( ) . take_while ( |& & b| b == b'#' ) . count ( ) as u8 ;
98
- if num. saturating_sub ( 1 ) == max {
99
- // Since `num - 1` is the max number of hashes it can have, we can
100
- // short-circuit with full confidence this is correct
101
- return None ;
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
+ } ,
102
118
}
103
119
104
- Some ( num + 1 )
105
- } )
106
- . max ( )
107
- . unwrap_or ( 0 ) ;
120
+ ControlFlow :: Continue ( acc)
121
+ } ) ;
122
+
123
+ match num {
124
+ ControlFlow :: Continue ( num) | ControlFlow :: Break ( num) => num,
125
+ }
126
+ } ;
108
127
109
128
if req < max {
110
129
let hashes = "#" . repeat ( req as usize ) ;
0 commit comments