@@ -138,13 +138,21 @@ pub(super) struct DigitInfo<'a> {
138
138
139
139
/// The type suffix, including preceding underscore if present.
140
140
crate suffix : Option < & ' a str > ,
141
- /// True for floating-point literals.
142
- crate float : bool ,
143
141
}
144
142
145
143
impl < ' a > DigitInfo < ' a > {
144
+ fn from_lit ( src : & ' a str , lit : & Lit ) -> Option < DigitInfo < ' a > > {
145
+ if lit. kind . is_numeric ( ) && src. chars ( ) . next ( ) . map_or ( false , |c| c. is_digit ( 10 ) ) {
146
+ let ( unsuffixed, suffix) = split_suffix ( & src, & lit. kind ) ;
147
+ let float = if let LitKind :: Float ( ..) = lit. kind { true } else { false } ;
148
+ Some ( DigitInfo :: new ( unsuffixed, suffix, float) )
149
+ } else {
150
+ None
151
+ }
152
+ }
153
+
146
154
#[ must_use]
147
- crate fn new ( lit : & ' a str , float : bool ) -> Self {
155
+ crate fn new ( lit : & ' a str , suffix : Option < & ' a str > , float : bool ) -> Self {
148
156
// Determine delimiter for radix prefix, if present, and radix.
149
157
let radix = if lit. starts_with ( "0x" ) {
150
158
Radix :: Hexadecimal
@@ -157,35 +165,19 @@ impl<'a> DigitInfo<'a> {
157
165
} ;
158
166
159
167
// Grab part of the literal after prefix, if present.
160
- let ( prefix, sans_prefix) = if let Radix :: Decimal = radix {
168
+ let ( prefix, mut sans_prefix) = if let Radix :: Decimal = radix {
161
169
( None , lit)
162
170
} else {
163
171
let ( p, s) = lit. split_at ( 2 ) ;
164
172
( Some ( p) , s)
165
173
} ;
166
174
167
- let mut digits = sans_prefix;
168
- let mut suffix = None ;
169
-
170
- let len = sans_prefix. len ( ) ;
171
- let mut last_d = '\0' ;
172
- for ( d_idx, d) in sans_prefix. char_indices ( ) {
173
- let suffix_start = if last_d == '_' { d_idx - 1 } else { d_idx } ;
174
- if float
175
- && ( d == 'f'
176
- || is_possible_float_suffix_index ( & sans_prefix, suffix_start, len)
177
- || ( ( d == 'E' || d == 'e' ) && !has_possible_float_suffix ( & sans_prefix) ) )
178
- || !float && ( d == 'i' || d == 'u' || is_possible_suffix_index ( & sans_prefix, suffix_start, len) )
179
- {
180
- let ( d, s) = sans_prefix. split_at ( suffix_start) ;
181
- digits = d;
182
- suffix = Some ( s) ;
183
- break ;
184
- }
185
- last_d = d
175
+ if suffix. is_some ( ) && sans_prefix. ends_with ( '_' ) {
176
+ // The '_' before the suffix isn't part of the digits
177
+ sans_prefix = & sans_prefix[ ..sans_prefix. len ( ) - 1 ] ;
186
178
}
187
179
188
- let ( integer, fraction, exponent) = Self :: split_digit_parts ( digits , float) ;
180
+ let ( integer, fraction, exponent) = Self :: split_digit_parts ( sans_prefix , float) ;
189
181
190
182
Self {
191
183
radix,
@@ -194,7 +186,6 @@ impl<'a> DigitInfo<'a> {
194
186
fraction,
195
187
exponent,
196
188
suffix,
197
- float,
198
189
}
199
190
}
200
191
@@ -256,15 +247,8 @@ impl<'a> DigitInfo<'a> {
256
247
}
257
248
258
249
if let Some ( suffix) = self . suffix {
259
- if self . float && is_mistyped_float_suffix ( suffix) {
260
- output. push_str ( "_f" ) ;
261
- output. push_str ( & suffix[ 1 ..] ) ;
262
- } else if is_mistyped_suffix ( suffix) {
263
- output. push_str ( "_i" ) ;
264
- output. push_str ( & suffix[ 1 ..] ) ;
265
- } else {
266
- output. push_str ( suffix) ;
267
- }
250
+ output. push ( '_' ) ;
251
+ output. push_str ( suffix) ;
268
252
}
269
253
270
254
output
@@ -303,6 +287,34 @@ impl<'a> DigitInfo<'a> {
303
287
}
304
288
}
305
289
290
+ fn split_suffix < ' a > ( src : & ' a str , lit_kind : & LitKind ) -> ( & ' a str , Option < & ' a str > ) {
291
+ debug_assert ! ( lit_kind. is_numeric( ) ) ;
292
+ if let Some ( suffix_length) = lit_suffix_length ( lit_kind) {
293
+ let ( unsuffixed, suffix) = src. split_at ( src. len ( ) - suffix_length) ;
294
+ ( unsuffixed, Some ( suffix) )
295
+ } else {
296
+ ( src, None )
297
+ }
298
+ }
299
+
300
+ fn lit_suffix_length ( lit_kind : & LitKind ) -> Option < usize > {
301
+ debug_assert ! ( lit_kind. is_numeric( ) ) ;
302
+ let suffix = match lit_kind {
303
+ LitKind :: Int ( _, int_lit_kind) => match int_lit_kind {
304
+ LitIntType :: Signed ( int_ty) => Some ( int_ty. name_str ( ) ) ,
305
+ LitIntType :: Unsigned ( uint_ty) => Some ( uint_ty. name_str ( ) ) ,
306
+ LitIntType :: Unsuffixed => None ,
307
+ } ,
308
+ LitKind :: Float ( _, float_lit_kind) => match float_lit_kind {
309
+ LitFloatType :: Suffixed ( float_ty) => Some ( float_ty. name_str ( ) ) ,
310
+ LitFloatType :: Unsuffixed => None ,
311
+ } ,
312
+ _ => None ,
313
+ } ;
314
+
315
+ suffix. map ( str:: len)
316
+ }
317
+
306
318
enum WarningType {
307
319
UnreadableLiteral ,
308
320
InconsistentDigitGrouping ,
@@ -388,22 +400,13 @@ impl LiteralDigitGrouping {
388
400
389
401
if_chain ! {
390
402
if let Some ( src) = snippet_opt( cx, lit. span) ;
391
- if let Some ( firstch) = src. chars( ) . next( ) ;
392
- if char :: is_digit( firstch, 10 ) ;
403
+ if let Some ( mut digit_info) = DigitInfo :: from_lit( & src, & lit) ;
393
404
then {
394
-
395
- let digit_info = match lit. kind {
396
- LitKind :: Int ( ..) => DigitInfo :: new( & src, false ) ,
397
- LitKind :: Float ( ..) => DigitInfo :: new( & src, true ) ,
398
- _ => return ,
399
- } ;
405
+ if !Self :: check_for_mistyped_suffix( cx, lit. span, & mut digit_info) {
406
+ return ;
407
+ }
400
408
401
409
let result = ( || {
402
- if let Some ( suffix) = digit_info. suffix {
403
- if is_mistyped_suffix( suffix) {
404
- return Err ( WarningType :: MistypedLiteralSuffix ) ;
405
- }
406
- }
407
410
408
411
let integral_group_size = Self :: get_group_size( digit_info. integer. split( '_' ) , in_macro) ?;
409
412
if let Some ( fraction) = digit_info. fraction {
@@ -428,6 +431,39 @@ impl LiteralDigitGrouping {
428
431
}
429
432
}
430
433
434
+ // Returns `false` if the check fails
435
+ fn check_for_mistyped_suffix (
436
+ cx : & EarlyContext < ' _ > ,
437
+ span : syntax_pos:: Span ,
438
+ digit_info : & mut DigitInfo < ' _ > ,
439
+ ) -> bool {
440
+ if digit_info. suffix . is_some ( ) {
441
+ return true ;
442
+ }
443
+
444
+ let ( part, mistyped_suffixes, missing_char) = if let Some ( ( _, exponent) ) = & mut digit_info. exponent {
445
+ ( exponent, & [ "32" , "64" ] [ ..] , 'f' )
446
+ } else if let Some ( fraction) = & mut digit_info. fraction {
447
+ ( fraction, & [ "32" , "64" ] [ ..] , 'f' )
448
+ } else {
449
+ ( & mut digit_info. integer , & [ "8" , "16" , "32" , "64" ] [ ..] , 'i' )
450
+ } ;
451
+
452
+ let mut split = part. rsplit ( '_' ) ;
453
+ let last_group = split. next ( ) . expect ( "At least one group" ) ;
454
+ if split. next ( ) . is_some ( ) && mistyped_suffixes. contains ( & last_group) {
455
+ * part = & part[ ..part. len ( ) - last_group. len ( ) ] ;
456
+ let mut hint = digit_info. grouping_hint ( ) ;
457
+ hint. push ( '_' ) ;
458
+ hint. push ( missing_char) ;
459
+ hint. push_str ( last_group) ;
460
+ WarningType :: MistypedLiteralSuffix . display ( & hint, cx, span) ;
461
+ false
462
+ } else {
463
+ true
464
+ }
465
+ }
466
+
431
467
/// Given the sizes of the digit groups of both integral and fractional
432
468
/// parts, and the length
433
469
/// of both parts, determine if the digits have been grouped consistently.
@@ -503,14 +539,12 @@ impl DecimalLiteralRepresentation {
503
539
if_chain ! {
504
540
if let LitKind :: Int ( val, _) = lit. kind;
505
541
if let Some ( src) = snippet_opt( cx, lit. span) ;
506
- if let Some ( firstch) = src. chars( ) . next( ) ;
507
- if char :: is_digit( firstch, 10 ) ;
508
- let digit_info = DigitInfo :: new( & src, false ) ;
542
+ if let Some ( digit_info) = DigitInfo :: from_lit( & src, & lit) ;
509
543
if digit_info. radix == Radix :: Decimal ;
510
544
if val >= u128 :: from( self . threshold) ;
511
545
then {
512
546
let hex = format!( "{:#X}" , val) ;
513
- let digit_info = DigitInfo :: new( & hex, false ) ;
547
+ let digit_info = DigitInfo :: new( & hex, None , false ) ;
514
548
let _ = Self :: do_lint( digit_info. integer) . map_err( |warning_type| {
515
549
warning_type. display( & digit_info. grouping_hint( ) , cx, lit. span)
516
550
} ) ;
@@ -563,28 +597,3 @@ impl DecimalLiteralRepresentation {
563
597
Ok ( ( ) )
564
598
}
565
599
}
566
-
567
- #[ must_use]
568
- fn is_mistyped_suffix ( suffix : & str ) -> bool {
569
- [ "_8" , "_16" , "_32" , "_64" ] . contains ( & suffix)
570
- }
571
-
572
- #[ must_use]
573
- fn is_possible_suffix_index ( lit : & str , idx : usize , len : usize ) -> bool {
574
- ( ( len > 3 && idx == len - 3 ) || ( len > 2 && idx == len - 2 ) ) && is_mistyped_suffix ( lit. split_at ( idx) . 1 )
575
- }
576
-
577
- #[ must_use]
578
- fn is_mistyped_float_suffix ( suffix : & str ) -> bool {
579
- [ "_32" , "_64" ] . contains ( & suffix)
580
- }
581
-
582
- #[ must_use]
583
- fn is_possible_float_suffix_index ( lit : & str , idx : usize , len : usize ) -> bool {
584
- ( len > 3 && idx == len - 3 ) && is_mistyped_float_suffix ( lit. split_at ( idx) . 1 )
585
- }
586
-
587
- #[ must_use]
588
- fn has_possible_float_suffix ( lit : & str ) -> bool {
589
- lit. ends_with ( "_32" ) || lit. ends_with ( "_64" )
590
- }
0 commit comments