@@ -3519,23 +3519,68 @@ pub fn is_different(sm: &SourceMap, suggested: &str, sp: Span) -> bool {
3519
3519
3520
3520
/// Whether the original and suggested code are visually similar enough to warrant extra wording.
3521
3521
pub fn is_case_difference ( sm : & SourceMap , suggested : & str , sp : Span ) -> bool {
3522
- // FIXME: this should probably be extended to also account for `FO0` → `FOO` and unicode.
3523
3522
let found = match sm. span_to_snippet ( sp) {
3524
3523
Ok ( snippet) => snippet,
3525
3524
Err ( e) => {
3526
3525
warn ! ( error = ?e, "Invalid span {:?}" , sp) ;
3527
3526
return false ;
3528
3527
}
3529
3528
} ;
3530
- let ascii_confusables = & [ 'c' , 'f' , 'i' , 'k' , 'o' , 's' , 'u' , 'v' , 'w' , 'x' , 'y' , 'z' ] ;
3531
- // All the chars that differ in capitalization are confusable (above):
3532
- let confusable = iter:: zip ( found. chars ( ) , suggested. chars ( ) )
3533
- . filter ( |( f, s) | f != s)
3534
- . all ( |( f, s) | ascii_confusables. contains ( & f) || ascii_confusables. contains ( & s) ) ;
3535
- confusable && found. to_lowercase ( ) == suggested. to_lowercase ( )
3536
- // FIXME: We sometimes suggest the same thing we already have, which is a
3537
- // bug, but be defensive against that here.
3538
- && found != suggested
3529
+
3530
+ // Check if the strings are identical after case normalization
3531
+ if found. to_lowercase ( ) == suggested. to_lowercase ( ) {
3532
+ // Check if they differ only in case
3533
+ let ascii_confusables = & [ 'c' , 'f' , 'i' , 'k' , 'o' , 's' , 'u' , 'v' , 'w' , 'x' , 'y' , 'z' ] ;
3534
+ let confusable = iter:: zip ( found. chars ( ) , suggested. chars ( ) )
3535
+ . filter ( |( f, s) | f != s)
3536
+ . all ( |( f, s) | ascii_confusables. contains ( & f) || ascii_confusables. contains ( & s) ) ;
3537
+
3538
+ if confusable
3539
+ // FIXME: We sometimes suggest the same thing we already have, which is a
3540
+ // bug, but be defensive against that here.
3541
+ && found != suggested
3542
+ {
3543
+ return true ;
3544
+ }
3545
+ }
3546
+
3547
+ // Check for digit-letter confusables (like 0 vs O, 1 vs l, etc.)
3548
+ if found. len ( ) == suggested. len ( ) {
3549
+ let digit_letter_confusables = [
3550
+ ( '0' , 'O' ) ,
3551
+ ( 'O' , '0' ) ,
3552
+ ( '1' , 'l' ) ,
3553
+ ( 'l' , '1' ) ,
3554
+ ( '5' , 'S' ) ,
3555
+ ( 'S' , '5' ) ,
3556
+ ( '8' , 'B' ) ,
3557
+ ( 'B' , '8' ) ,
3558
+ ( '9' , 'g' ) ,
3559
+ ( 'g' , '9' ) ,
3560
+ ] ;
3561
+
3562
+ let mut has_confusable = false ;
3563
+ // To ensure all the differences are confusables,
3564
+ // we need to check that all the differences
3565
+ let mut all_confusable = true ;
3566
+
3567
+ for ( f, s) in iter:: zip ( found. chars ( ) , suggested. chars ( ) ) {
3568
+ if f != s {
3569
+ if digit_letter_confusables. contains ( & ( f, s) ) {
3570
+ has_confusable = true ;
3571
+ } else {
3572
+ all_confusable = false ;
3573
+ break ;
3574
+ }
3575
+ }
3576
+ }
3577
+
3578
+ if has_confusable && all_confusable && found != suggested {
3579
+ return true ;
3580
+ }
3581
+ }
3582
+
3583
+ false
3539
3584
}
3540
3585
3541
3586
pub ( crate ) fn should_show_source_code (
0 commit comments