7
7
// option. This file may not be copied, modified, or distributed
8
8
// except according to those terms.
9
9
10
-
11
10
//! Lints concerned with the grouping of digits with underscores in integral or
12
11
//! floating-point literal expressions.
13
12
14
- use crate :: rustc:: lint:: { EarlyContext , EarlyLintPass , LintArray , LintPass , in_external_macro , LintContext } ;
13
+ use crate :: rustc:: lint:: { in_external_macro , EarlyContext , EarlyLintPass , LintArray , LintContext , LintPass } ;
15
14
use crate :: rustc:: { declare_tool_lint, lint_array} ;
16
- use if_chain:: if_chain;
17
15
use crate :: syntax:: ast:: * ;
18
16
use crate :: syntax_pos;
19
17
use crate :: utils:: { snippet_opt, span_lint_and_sugg} ;
18
+ use if_chain:: if_chain;
20
19
21
20
/// **What it does:** Warns if a long integral or floating-point constant does
22
21
/// not contain underscores.
@@ -41,9 +40,9 @@ declare_clippy_lint! {
41
40
/// **Why is this bad?** This is most probably a typo
42
41
///
43
42
/// **Known problems:**
44
- /// - Recommends a signed suffix, even though the number might be too big and an unsigned
43
+ /// - Recommends a signed suffix, even though the number might be too big and an unsigned
45
44
/// suffix is required
46
- /// - Does not match on `_128` since that is a valid grouping for decimal and octal numbers
45
+ /// - Does not match on `_128` since that is a valid grouping for decimal and octal numbers
47
46
///
48
47
/// **Example:**
49
48
///
@@ -168,23 +167,21 @@ impl<'a> DigitInfo<'a> {
168
167
let len = sans_prefix. len ( ) ;
169
168
let mut last_d = '\0' ;
170
169
for ( d_idx, d) in sans_prefix. char_indices ( ) {
171
- let suffix_start = if last_d == '_' {
172
- d_idx - 1
173
- } else {
174
- d_idx
175
- } ;
176
- if float && ( ( is_possible_float_suffix_index ( & sans_prefix, suffix_start, len) ) ||
177
- ( d == 'f' || d == 'e' || d == 'E' ) ) ||
178
- !float && ( d == 'i' || d == 'u' ||
179
- is_possible_suffix_index ( & sans_prefix, suffix_start, len) ) {
180
- let ( digits, suffix) = sans_prefix. split_at ( suffix_start) ;
181
- return Self {
182
- digits,
183
- radix,
184
- prefix,
185
- suffix : Some ( suffix) ,
186
- float,
187
- } ;
170
+ let suffix_start = if last_d == '_' { d_idx - 1 } else { d_idx } ;
171
+ if float
172
+ && ( d == 'f'
173
+ || is_possible_float_suffix_index ( & sans_prefix, suffix_start, len)
174
+ || ( ( d == 'E' || d == 'e' ) && !has_possible_float_suffix ( & sans_prefix) ) )
175
+ || !float && ( d == 'i' || d == 'u' || is_possible_suffix_index ( & sans_prefix, suffix_start, len) )
176
+ {
177
+ let ( digits, suffix) = sans_prefix. split_at ( suffix_start) ;
178
+ return Self {
179
+ digits,
180
+ radix,
181
+ prefix,
182
+ suffix : Some ( suffix) ,
183
+ float,
184
+ } ;
188
185
}
189
186
last_d = d
190
187
}
@@ -226,18 +223,44 @@ impl<'a> DigitInfo<'a> {
226
223
. map ( |chunk| chunk. into_iter ( ) . collect ( ) )
227
224
. collect :: < Vec < String > > ( )
228
225
. join ( "_" ) ;
226
+ let suffix_hint = match self . suffix {
227
+ Some ( suffix) if is_mistyped_float_suffix ( suffix) => format ! ( "_f{}" , & suffix[ 1 ..] ) ,
228
+ Some ( suffix) => suffix. to_string ( ) ,
229
+ None => String :: new ( ) ,
230
+ } ;
231
+ format ! ( "{}.{}{}" , int_part_hint, frac_part_hint, suffix_hint)
232
+ } else if self . float && ( self . digits . contains ( "E" ) || self . digits . contains ( "E" ) ) {
233
+ let which_e = if self . digits . contains ( "E" ) { "E" } else { "e" } ;
234
+ let parts: Vec < & str > = self . digits . split ( which_e) . collect ( ) ;
235
+ let filtered_digits_vec_0 = parts[ 0 ] . chars ( ) . filter ( |& c| c != '_' ) . rev ( ) . collect :: < Vec < _ > > ( ) ;
236
+ let filtered_digits_vec_1 = parts[ 1 ] . chars ( ) . filter ( |& c| c != '_' ) . rev ( ) . collect :: < Vec < _ > > ( ) ;
237
+ let before_e_hint = filtered_digits_vec_0
238
+ . chunks ( group_size)
239
+ . map ( |chunk| chunk. into_iter ( ) . rev ( ) . collect ( ) )
240
+ . rev ( )
241
+ . collect :: < Vec < String > > ( )
242
+ . join ( "_" ) ;
243
+ let after_e_hint = filtered_digits_vec_1
244
+ . chunks ( group_size)
245
+ . map ( |chunk| chunk. into_iter ( ) . rev ( ) . collect ( ) )
246
+ . rev ( )
247
+ . collect :: < Vec < String > > ( )
248
+ . join ( "_" ) ;
249
+ let suffix_hint = match self . suffix {
250
+ Some ( suffix) if is_mistyped_float_suffix ( suffix) => format ! ( "_f{}" , & suffix[ 1 ..] ) ,
251
+ Some ( suffix) => suffix. to_string ( ) ,
252
+ None => String :: new ( ) ,
253
+ } ;
229
254
format ! (
230
- "{}.{}{}" ,
231
- int_part_hint,
232
- frac_part_hint,
233
- self . suffix. unwrap_or( "" )
255
+ "{}{}{}{}{}" ,
256
+ self . prefix. unwrap_or( "" ) ,
257
+ before_e_hint,
258
+ which_e,
259
+ after_e_hint,
260
+ suffix_hint
234
261
)
235
262
} else {
236
- let filtered_digits_vec = self . digits
237
- . chars ( )
238
- . filter ( |& c| c != '_' )
239
- . rev ( )
240
- . collect :: < Vec < _ > > ( ) ;
263
+ let filtered_digits_vec = self . digits . chars ( ) . filter ( |& c| c != '_' ) . rev ( ) . collect :: < Vec < _ > > ( ) ;
241
264
let mut hint = filtered_digits_vec
242
265
. chunks ( group_size)
243
266
. map ( |chunk| chunk. into_iter ( ) . rev ( ) . collect ( ) )
@@ -250,21 +273,11 @@ impl<'a> DigitInfo<'a> {
250
273
hint = format ! ( "{:0>4}{}" , & hint[ ..nb_digits_to_fill] , & hint[ nb_digits_to_fill..] ) ;
251
274
}
252
275
let suffix_hint = match self . suffix {
253
- Some ( suffix) if is_mistyped_float_suffix ( suffix) && self . digits . contains ( "." ) => {
254
- format ! ( "_f{}" , & suffix[ 1 ..] )
255
- } ,
256
- Some ( suffix) if is_mistyped_suffix ( suffix) => {
257
- format ! ( "_i{}" , & suffix[ 1 ..] )
258
- } ,
276
+ Some ( suffix) if is_mistyped_suffix ( suffix) => format ! ( "_i{}" , & suffix[ 1 ..] ) ,
259
277
Some ( suffix) => suffix. to_string ( ) ,
260
- None => String :: new ( )
278
+ None => String :: new ( ) ,
261
279
} ;
262
- format ! (
263
- "{}{}{}" ,
264
- self . prefix. unwrap_or( "" ) ,
265
- hint,
266
- suffix_hint
267
- )
280
+ format ! ( "{}{}{}" , self . prefix. unwrap_or( "" ) , hint, suffix_hint)
268
281
}
269
282
}
270
283
}
@@ -274,22 +287,20 @@ enum WarningType {
274
287
InconsistentDigitGrouping ,
275
288
LargeDigitGroups ,
276
289
DecimalRepresentation ,
277
- MistypedLiteralSuffix
290
+ MistypedLiteralSuffix ,
278
291
}
279
292
280
293
impl WarningType {
281
294
crate fn display ( & self , grouping_hint : & str , cx : & EarlyContext < ' _ > , span : syntax_pos:: Span ) {
282
295
match self {
283
- WarningType :: MistypedLiteralSuffix => {
284
- span_lint_and_sugg (
285
- cx,
286
- MISTYPED_LITERAL_SUFFIXES ,
287
- span,
288
- "mistyped literal suffix" ,
289
- "did you mean to write" ,
290
- grouping_hint. to_string ( )
291
- )
292
- } ,
296
+ WarningType :: MistypedLiteralSuffix => span_lint_and_sugg (
297
+ cx,
298
+ MISTYPED_LITERAL_SUFFIXES ,
299
+ span,
300
+ "mistyped literal suffix" ,
301
+ "did you mean to write" ,
302
+ grouping_hint. to_string ( ) ,
303
+ ) ,
293
304
WarningType :: UnreadableLiteral => span_lint_and_sugg (
294
305
cx,
295
306
UNREADABLE_LITERAL ,
@@ -331,11 +342,7 @@ pub struct LiteralDigitGrouping;
331
342
332
343
impl LintPass for LiteralDigitGrouping {
333
344
fn get_lints ( & self ) -> LintArray {
334
- lint_array ! (
335
- UNREADABLE_LITERAL ,
336
- INCONSISTENT_DIGIT_GROUPING ,
337
- LARGE_DIGIT_GROUPS
338
- )
345
+ lint_array ! ( UNREADABLE_LITERAL , INCONSISTENT_DIGIT_GROUPING , LARGE_DIGIT_GROUPS )
339
346
}
340
347
}
341
348
@@ -384,7 +391,7 @@ impl LiteralDigitGrouping {
384
391
385
392
// Lint integral and fractional parts separately, and then check consistency of digit
386
393
// groups if both pass.
387
- let _ = Self :: do_lint( parts[ 0 ] , None )
394
+ let _ = Self :: do_lint( parts[ 0 ] , digit_info . suffix )
388
395
. map( |integral_group_size| {
389
396
if parts. len( ) > 1 {
390
397
// Lint the fractional part of literal just like integral part, but reversed.
@@ -395,11 +402,11 @@ impl LiteralDigitGrouping {
395
402
fractional_group_size,
396
403
parts[ 0 ] . len( ) ,
397
404
parts[ 1 ] . len( ) ) ;
398
- if !consistent {
399
- WarningType :: InconsistentDigitGrouping . display( & digit_info. grouping_hint( ) ,
400
- cx,
401
- lit. span) ;
402
- }
405
+ if !consistent {
406
+ WarningType :: InconsistentDigitGrouping . display( & digit_info. grouping_hint( ) ,
407
+ cx,
408
+ lit. span) ;
409
+ }
403
410
} )
404
411
. map_err( |warning_type| warning_type. display( & digit_info. grouping_hint( ) ,
405
412
cx,
@@ -498,9 +505,7 @@ impl EarlyLintPass for LiteralRepresentation {
498
505
499
506
impl LiteralRepresentation {
500
507
pub fn new ( threshold : u64 ) -> Self {
501
- Self {
502
- threshold,
503
- }
508
+ Self { threshold }
504
509
}
505
510
fn check_lit ( self , cx : & EarlyContext < ' _ > , lit : & Lit ) {
506
511
// Lint integral literals.
@@ -533,7 +538,12 @@ impl LiteralRepresentation {
533
538
fn do_lint ( digits : & str ) -> Result < ( ) , WarningType > {
534
539
if digits. len ( ) == 1 {
535
540
// Lint for 1 digit literals, if someone really sets the threshold that low
536
- if digits == "1" || digits == "2" || digits == "4" || digits == "8" || digits == "3" || digits == "7"
541
+ if digits == "1"
542
+ || digits == "2"
543
+ || digits == "4"
544
+ || digits == "8"
545
+ || digits == "3"
546
+ || digits == "7"
537
547
|| digits == "F"
538
548
{
539
549
return Err ( WarningType :: DecimalRepresentation ) ;
@@ -542,7 +552,7 @@ impl LiteralRepresentation {
542
552
// Lint for Literals with a hex-representation of 2 or 3 digits
543
553
let f = & digits[ 0 ..1 ] ; // first digit
544
554
let s = & digits[ 1 ..] ; // suffix
545
- // Powers of 2
555
+ // Powers of 2
546
556
if ( ( f. eq ( "1" ) || f. eq ( "2" ) || f. eq ( "4" ) || f. eq ( "8" ) ) && s. chars ( ) . all ( |c| c == '0' ) )
547
557
// Powers of 2 minus 1
548
558
|| ( ( f. eq ( "1" ) || f. eq ( "3" ) || f. eq ( "7" ) || f. eq ( "F" ) ) && s. chars ( ) . all ( |c| c == 'F' ) )
@@ -554,7 +564,7 @@ impl LiteralRepresentation {
554
564
let f = & digits[ 0 ..1 ] ; // first digit
555
565
let m = & digits[ 1 ..digits. len ( ) - 1 ] ; // middle digits, except last
556
566
let s = & digits[ 1 ..] ; // suffix
557
- // Powers of 2 with a margin of +15/-16
567
+ // Powers of 2 with a margin of +15/-16
558
568
if ( ( f. eq ( "1" ) || f. eq ( "2" ) || f. eq ( "4" ) || f. eq ( "8" ) ) && m. chars ( ) . all ( |c| c == '0' ) )
559
569
|| ( ( f. eq ( "1" ) || f. eq ( "3" ) || f. eq ( "7" ) || f. eq ( "F" ) ) && m. chars ( ) . all ( |c| c == 'F' ) )
560
570
// Lint for representations with only 0s and Fs, while allowing 7 as the first
@@ -574,15 +584,17 @@ fn is_mistyped_suffix(suffix: &str) -> bool {
574
584
}
575
585
576
586
fn is_possible_suffix_index ( lit : & str , idx : usize , len : usize ) -> bool {
577
- ( ( len > 3 && idx == len - 3 ) || ( len > 2 && idx == len - 2 ) ) &&
578
- is_mistyped_suffix ( lit. split_at ( idx) . 1 )
587
+ ( ( len > 3 && idx == len - 3 ) || ( len > 2 && idx == len - 2 ) ) && is_mistyped_suffix ( lit. split_at ( idx) . 1 )
579
588
}
580
589
581
590
fn is_mistyped_float_suffix ( suffix : & str ) -> bool {
582
591
[ "_32" , "_64" ] . contains ( & suffix)
583
592
}
584
593
585
594
fn is_possible_float_suffix_index ( lit : & str , idx : usize , len : usize ) -> bool {
586
- ( ( len > 3 && idx == len - 3 ) || ( len > 2 && idx == len - 2 ) ) &&
587
- is_mistyped_float_suffix ( lit. split_at ( idx) . 1 )
595
+ ( len > 3 && idx == len - 3 ) && is_mistyped_float_suffix ( lit. split_at ( idx) . 1 )
596
+ }
597
+
598
+ fn has_possible_float_suffix ( lit : & str ) -> bool {
599
+ lit. ends_with ( "_32" ) || lit. ends_with ( "_64" )
588
600
}
0 commit comments