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,21 +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 && ( d == 'f ' || d == 'e ' || d == 'E' ) ||
177
- !float && ( d == 'i' || d == 'u' || is_possible_suffix_index ( & sans_prefix , suffix_start , len ) ) {
178
- let ( digits, suffix) = sans_prefix. split_at ( suffix_start) ;
179
- return Self {
180
- digits,
181
- radix,
182
- prefix,
183
- suffix : Some ( suffix) ,
184
- float,
185
- } ;
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
+ } ;
186
185
}
187
186
last_d = d
188
187
}
@@ -224,18 +223,44 @@ impl<'a> DigitInfo<'a> {
224
223
. map ( |chunk| chunk. iter ( ) . collect ( ) )
225
224
. collect :: < Vec < String > > ( )
226
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. 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. 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
+ } ;
227
254
format ! (
228
- "{}.{}{}" ,
229
- int_part_hint,
230
- frac_part_hint,
231
- self . suffix. unwrap_or( "" )
255
+ "{}{}{}{}{}" ,
256
+ self . prefix. unwrap_or( "" ) ,
257
+ before_e_hint,
258
+ which_e,
259
+ after_e_hint,
260
+ suffix_hint
232
261
)
233
262
} else {
234
- let filtered_digits_vec = self . digits
235
- . chars ( )
236
- . filter ( |& c| c != '_' )
237
- . rev ( )
238
- . collect :: < Vec < _ > > ( ) ;
263
+ let filtered_digits_vec = self . digits . chars ( ) . filter ( |& c| c != '_' ) . rev ( ) . collect :: < Vec < _ > > ( ) ;
239
264
let mut hint = filtered_digits_vec
240
265
. chunks ( group_size)
241
266
. map ( |chunk| chunk. iter ( ) . rev ( ) . collect ( ) )
@@ -248,18 +273,11 @@ impl<'a> DigitInfo<'a> {
248
273
hint = format ! ( "{:0>4}{}" , & hint[ ..nb_digits_to_fill] , & hint[ nb_digits_to_fill..] ) ;
249
274
}
250
275
let suffix_hint = match self . suffix {
251
- Some ( suffix) if is_mistyped_suffix ( suffix) => {
252
- format ! ( "_i{}" , & suffix[ 1 ..] )
253
- } ,
276
+ Some ( suffix) if is_mistyped_suffix ( suffix) => format ! ( "_i{}" , & suffix[ 1 ..] ) ,
254
277
Some ( suffix) => suffix. to_string ( ) ,
255
- None => String :: new ( )
278
+ None => String :: new ( ) ,
256
279
} ;
257
- format ! (
258
- "{}{}{}" ,
259
- self . prefix. unwrap_or( "" ) ,
260
- hint,
261
- suffix_hint
262
- )
280
+ format ! ( "{}{}{}" , self . prefix. unwrap_or( "" ) , hint, suffix_hint)
263
281
}
264
282
}
265
283
}
@@ -269,22 +287,20 @@ enum WarningType {
269
287
InconsistentDigitGrouping ,
270
288
LargeDigitGroups ,
271
289
DecimalRepresentation ,
272
- MistypedLiteralSuffix
290
+ MistypedLiteralSuffix ,
273
291
}
274
292
275
293
impl WarningType {
276
294
crate fn display ( & self , grouping_hint : & str , cx : & EarlyContext < ' _ > , span : syntax_pos:: Span ) {
277
295
match self {
278
- WarningType :: MistypedLiteralSuffix => {
279
- span_lint_and_sugg (
280
- cx,
281
- MISTYPED_LITERAL_SUFFIXES ,
282
- span,
283
- "mistyped literal suffix" ,
284
- "did you mean to write" ,
285
- grouping_hint. to_string ( )
286
- )
287
- } ,
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
+ ) ,
288
304
WarningType :: UnreadableLiteral => span_lint_and_sugg (
289
305
cx,
290
306
UNREADABLE_LITERAL ,
@@ -380,7 +396,7 @@ impl LiteralDigitGrouping {
380
396
381
397
// Lint integral and fractional parts separately, and then check consistency of digit
382
398
// groups if both pass.
383
- let _ = Self :: do_lint( parts[ 0 ] , None )
399
+ let _ = Self :: do_lint( parts[ 0 ] , digit_info . suffix )
384
400
. map( |integral_group_size| {
385
401
if parts. len( ) > 1 {
386
402
// Lint the fractional part of literal just like integral part, but reversed.
@@ -391,11 +407,11 @@ impl LiteralDigitGrouping {
391
407
fractional_group_size,
392
408
parts[ 0 ] . len( ) ,
393
409
parts[ 1 ] . len( ) ) ;
394
- if !consistent {
395
- WarningType :: InconsistentDigitGrouping . display( & digit_info. grouping_hint( ) ,
396
- cx,
397
- lit. span) ;
398
- }
410
+ if !consistent {
411
+ WarningType :: InconsistentDigitGrouping . display( & digit_info. grouping_hint( ) ,
412
+ cx,
413
+ lit. span) ;
414
+ }
399
415
} )
400
416
. map_err( |warning_type| warning_type. display( & digit_info. grouping_hint( ) ,
401
417
cx,
@@ -494,9 +510,7 @@ impl EarlyLintPass for LiteralRepresentation {
494
510
495
511
impl LiteralRepresentation {
496
512
pub fn new ( threshold : u64 ) -> Self {
497
- Self {
498
- threshold,
499
- }
513
+ Self { threshold }
500
514
}
501
515
fn check_lit ( self , cx : & EarlyContext < ' _ > , lit : & Lit ) {
502
516
// Lint integral literals.
@@ -529,7 +543,12 @@ impl LiteralRepresentation {
529
543
fn do_lint ( digits : & str ) -> Result < ( ) , WarningType > {
530
544
if digits. len ( ) == 1 {
531
545
// Lint for 1 digit literals, if someone really sets the threshold that low
532
- if digits == "1" || digits == "2" || digits == "4" || digits == "8" || digits == "3" || digits == "7"
546
+ if digits == "1"
547
+ || digits == "2"
548
+ || digits == "4"
549
+ || digits == "8"
550
+ || digits == "3"
551
+ || digits == "7"
533
552
|| digits == "F"
534
553
{
535
554
return Err ( WarningType :: DecimalRepresentation ) ;
@@ -538,6 +557,7 @@ impl LiteralRepresentation {
538
557
// Lint for Literals with a hex-representation of 2 or 3 digits
539
558
let f = & digits[ 0 ..1 ] ; // first digit
540
559
let s = & digits[ 1 ..] ; // suffix
560
+
541
561
// Powers of 2
542
562
if ( ( f. eq ( "1" ) || f. eq ( "2" ) || f. eq ( "4" ) || f. eq ( "8" ) ) && s. chars ( ) . all ( |c| c == '0' ) )
543
563
// Powers of 2 minus 1
@@ -550,6 +570,7 @@ impl LiteralRepresentation {
550
570
let f = & digits[ 0 ..1 ] ; // first digit
551
571
let m = & digits[ 1 ..digits. len ( ) - 1 ] ; // middle digits, except last
552
572
let s = & digits[ 1 ..] ; // suffix
573
+
553
574
// Powers of 2 with a margin of +15/-16
554
575
if ( ( f. eq ( "1" ) || f. eq ( "2" ) || f. eq ( "4" ) || f. eq ( "8" ) ) && m. chars ( ) . all ( |c| c == '0' ) )
555
576
|| ( ( f. eq ( "1" ) || f. eq ( "3" ) || f. eq ( "7" ) || f. eq ( "F" ) ) && m. chars ( ) . all ( |c| c == 'F' ) )
@@ -570,6 +591,17 @@ fn is_mistyped_suffix(suffix: &str) -> bool {
570
591
}
571
592
572
593
fn is_possible_suffix_index ( lit : & str , idx : usize , len : usize ) -> bool {
573
- ( ( len > 3 && idx == len - 3 ) || ( len > 2 && idx == len - 2 ) ) &&
574
- is_mistyped_suffix ( lit. split_at ( idx) . 1 )
594
+ ( ( len > 3 && idx == len - 3 ) || ( len > 2 && idx == len - 2 ) ) && is_mistyped_suffix ( lit. split_at ( idx) . 1 )
595
+ }
596
+
597
+ fn is_mistyped_float_suffix ( suffix : & str ) -> bool {
598
+ [ "_32" , "_64" ] . contains ( & suffix)
599
+ }
600
+
601
+ fn is_possible_float_suffix_index ( lit : & str , idx : usize , len : usize ) -> bool {
602
+ ( len > 3 && idx == len - 3 ) && is_mistyped_float_suffix ( lit. split_at ( idx) . 1 )
603
+ }
604
+
605
+ fn has_possible_float_suffix ( lit : & str ) -> bool {
606
+ lit. ends_with ( "_32" ) || lit. ends_with ( "_64" )
575
607
}
0 commit comments