@@ -6,7 +6,6 @@ use rustc::lint::{in_external_macro, EarlyContext, EarlyLintPass, LintArray, Lin
6
6
use rustc:: { declare_lint_pass, declare_tool_lint} ;
7
7
use rustc_data_structures:: fx:: FxHashMap ;
8
8
use rustc_errors:: Applicability ;
9
- use std:: char;
10
9
use syntax:: ast:: * ;
11
10
use syntax:: source_map:: Span ;
12
11
use syntax:: visit:: { walk_expr, FnKind , Visitor } ;
@@ -391,92 +390,93 @@ impl EarlyLintPass for MiscEarlyLints {
391
390
392
391
impl MiscEarlyLints {
393
392
fn check_lit ( self , cx : & EarlyContext < ' _ > , lit : & Lit ) {
394
- if_chain ! {
395
- if let LitKind :: Int ( value, ..) = lit. node;
396
- if let Some ( src) = snippet_opt( cx, lit. span) ;
397
- if let Some ( firstch) = src. chars( ) . next( ) ;
398
- if char :: to_digit( firstch, 10 ) . is_some( ) ;
399
- then {
400
- let mut prev = '\0' ;
401
- for ( idx, ch) in src. chars( ) . enumerate( ) {
402
- if ch == 'i' || ch == 'u' {
403
- if prev != '_' {
404
- span_lint_and_sugg(
405
- cx,
406
- UNSEPARATED_LITERAL_SUFFIX ,
407
- lit. span,
408
- "integer type suffix should be separated by an underscore" ,
409
- "add an underscore" ,
410
- format!( "{}_{}" , & src[ 0 ..idx] , & src[ idx..] ) ,
411
- Applicability :: MachineApplicable ,
412
- ) ;
413
- }
414
- break ;
415
- }
416
- prev = ch;
393
+ // The `line!()` macro is compiler built-in and a special case for these lints.
394
+ let lit_snip = match snippet_opt ( cx, lit. span ) {
395
+ Some ( snip) => {
396
+ if snip. contains ( '!' ) {
397
+ return ;
417
398
}
418
- if src. starts_with( "0x" ) {
419
- let mut seen = ( false , false ) ;
420
- for ch in src. chars( ) {
421
- match ch {
422
- 'a' ..= 'f' => seen. 0 = true ,
423
- 'A' ..= 'F' => seen. 1 = true ,
424
- 'i' | 'u' => break , // start of suffix already
425
- _ => ( )
426
- }
399
+ snip
400
+ } ,
401
+ _ => return ,
402
+ } ;
403
+
404
+ if let LitKind :: Int ( value, lit_int_type) = lit. node {
405
+ let suffix = match lit_int_type {
406
+ LitIntType :: Signed ( ty) => ty. ty_to_string ( ) ,
407
+ LitIntType :: Unsigned ( ty) => ty. ty_to_string ( ) ,
408
+ LitIntType :: Unsuffixed => "" ,
409
+ } ;
410
+
411
+ let maybe_last_sep_idx = lit_snip. len ( ) - suffix. len ( ) - 1 ;
412
+ // Do not lint when literal is unsuffixed.
413
+ if !suffix. is_empty ( ) && lit_snip. as_bytes ( ) [ maybe_last_sep_idx] != b'_' {
414
+ span_lint_and_sugg (
415
+ cx,
416
+ UNSEPARATED_LITERAL_SUFFIX ,
417
+ lit. span ,
418
+ "integer type suffix should be separated by an underscore" ,
419
+ "add an underscore" ,
420
+ format ! ( "{}_{}" , & lit_snip[ ..=maybe_last_sep_idx] , suffix) ,
421
+ Applicability :: MachineApplicable ,
422
+ ) ;
423
+ }
424
+
425
+ if lit_snip. starts_with ( "0x" ) {
426
+ let mut seen = ( false , false ) ;
427
+ for ch in lit_snip. as_bytes ( ) [ 2 ..=maybe_last_sep_idx] . iter ( ) {
428
+ match ch {
429
+ b'a' ..=b'f' => seen. 0 = true ,
430
+ b'A' ..=b'F' => seen. 1 = true ,
431
+ _ => { } ,
427
432
}
428
433
if seen. 0 && seen. 1 {
429
- span_lint( cx, MIXED_CASE_HEX_LITERALS , lit. span,
430
- "inconsistent casing in hexadecimal literal" ) ;
434
+ span_lint (
435
+ cx,
436
+ MIXED_CASE_HEX_LITERALS ,
437
+ lit. span ,
438
+ "inconsistent casing in hexadecimal literal" ,
439
+ ) ;
440
+ break ;
431
441
}
432
- } else if src. starts_with( "0b" ) || src. starts_with( "0o" ) {
433
- /* nothing to do */
434
- } else if value != 0 && src. starts_with( '0' ) {
435
- span_lint_and_then( cx,
436
- ZERO_PREFIXED_LITERAL ,
437
- lit. span,
438
- "this is a decimal constant" ,
439
- |db| {
442
+ }
443
+ } else if lit_snip. starts_with ( "0b" ) || lit_snip. starts_with ( "0o" ) {
444
+ /* nothing to do */
445
+ } else if value != 0 && lit_snip. starts_with ( '0' ) {
446
+ span_lint_and_then (
447
+ cx,
448
+ ZERO_PREFIXED_LITERAL ,
449
+ lit. span ,
450
+ "this is a decimal constant" ,
451
+ |db| {
440
452
db. span_suggestion (
441
453
lit. span ,
442
- "if you mean to use a decimal constant, remove the `0` to remove confusion" ,
443
- src . trim_start_matches( |c| c == '_' || c == '0' ) . to_string( ) ,
454
+ "if you mean to use a decimal constant, remove the `0` to avoid confusion" ,
455
+ lit_snip . trim_start_matches ( |c| c == '_' || c == '0' ) . to_string ( ) ,
444
456
Applicability :: MaybeIncorrect ,
445
457
) ;
446
458
db. span_suggestion (
447
459
lit. span ,
448
460
"if you mean to use an octal constant, use `0o`" ,
449
- format!( "0o{}" , src . trim_start_matches( |c| c == '_' || c == '0' ) ) ,
461
+ format ! ( "0o{}" , lit_snip . trim_start_matches( |c| c == '_' || c == '0' ) ) ,
450
462
Applicability :: MaybeIncorrect ,
451
463
) ;
452
- } ) ;
453
- }
464
+ } ,
465
+ ) ;
454
466
}
455
- }
456
- if_chain ! {
457
- if let LitKind :: Float ( ..) = lit. node;
458
- if let Some ( src) = snippet_opt( cx, lit. span) ;
459
- if let Some ( firstch) = src. chars( ) . next( ) ;
460
- if char :: to_digit( firstch, 10 ) . is_some( ) ;
461
- then {
462
- let mut prev = '\0' ;
463
- for ( idx, ch) in src. chars( ) . enumerate( ) {
464
- if ch == 'f' {
465
- if prev != '_' {
466
- span_lint_and_sugg(
467
- cx,
468
- UNSEPARATED_LITERAL_SUFFIX ,
469
- lit. span,
470
- "float type suffix should be separated by an underscore" ,
471
- "add an underscore" ,
472
- format!( "{}_{}" , & src[ 0 ..idx] , & src[ idx..] ) ,
473
- Applicability :: MachineApplicable ,
474
- ) ;
475
- }
476
- break ;
477
- }
478
- prev = ch;
479
- }
467
+ } else if let LitKind :: Float ( _, float_ty) = lit. node {
468
+ let suffix = float_ty. ty_to_string ( ) ;
469
+ let maybe_last_sep_idx = lit_snip. len ( ) - suffix. len ( ) - 1 ;
470
+ if lit_snip. as_bytes ( ) [ maybe_last_sep_idx] != b'_' {
471
+ span_lint_and_sugg (
472
+ cx,
473
+ UNSEPARATED_LITERAL_SUFFIX ,
474
+ lit. span ,
475
+ "float type suffix should be separated by an underscore" ,
476
+ "add an underscore" ,
477
+ format ! ( "{}_{}" , & lit_snip[ ..=maybe_last_sep_idx] , suffix) ,
478
+ Applicability :: MachineApplicable ,
479
+ ) ;
480
480
}
481
481
}
482
482
}
0 commit comments