@@ -6,7 +6,6 @@ use rustc::lint::{in_external_macro, EarlyContext, EarlyLintPass, LintArray, Lin
66use rustc:: { declare_lint_pass, declare_tool_lint} ;
77use rustc_data_structures:: fx:: FxHashMap ;
88use rustc_errors:: Applicability ;
9- use std:: char;
109use syntax:: ast:: * ;
1110use syntax:: source_map:: Span ;
1211use syntax:: visit:: { walk_expr, FnKind , Visitor } ;
@@ -391,92 +390,93 @@ impl EarlyLintPass for MiscEarlyLints {
391390
392391impl MiscEarlyLints {
393392 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 ;
417398 }
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+ _ => { } ,
427432 }
428433 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 ;
431441 }
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| {
440452 db. span_suggestion (
441453 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 ( ) ,
444456 Applicability :: MaybeIncorrect ,
445457 ) ;
446458 db. span_suggestion (
447459 lit. span ,
448460 "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' ) ) ,
450462 Applicability :: MaybeIncorrect ,
451463 ) ;
452- } ) ;
453- }
464+ } ,
465+ ) ;
454466 }
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+ ) ;
480480 }
481481 }
482482 }
0 commit comments