11// Characters and their corresponding confusables were collected from
22// http://www.unicode.org/Public/security/10.0.0/confusables.txt
33
4- use syntax_pos:: { Span , Pos , NO_EXPANSION } ;
5- use errors:: { Applicability , DiagnosticBuilder } ;
64use super :: StringReader ;
5+ use errors:: { Applicability , DiagnosticBuilder } ;
6+ use syntax_pos:: { Pos , Span , NO_EXPANSION } ;
77
8+ #[ rustfmt:: skip] // for line breaks
89const UNICODE_ARRAY : & [ ( char , & str , char ) ] = & [
910 ( '
' , "Line Separator" , ' ' ) ,
1011 ( '
' , "Paragraph Separator" , ' ' ) ,
@@ -293,8 +294,8 @@ const UNICODE_ARRAY: &[(char, &str, char)] = &[
293294 ( '〉' , "Right-Pointing Angle Bracket" , '>' ) ,
294295 ( '〉' , "Right Angle Bracket" , '>' ) ,
295296 ( '》' , "Right Double Angle Bracket" , '>' ) ,
296- ( '>' , "Fullwidth Greater-Than Sign" , '>' ) , ] ;
297-
297+ ( '>' , "Fullwidth Greater-Than Sign" , '>' ) ,
298+ ] ;
298299
299300const ASCII_ARRAY : & [ ( char , & str ) ] = & [
300301 ( ' ' , "Space" ) ,
@@ -321,46 +322,72 @@ const ASCII_ARRAY: &[(char, &str)] = &[
321322 ( '+' , "Plus Sign" ) ,
322323 ( '<' , "Less-Than Sign" ) ,
323324 ( '=' , "Equals Sign" ) ,
324- ( '>' , "Greater-Than Sign" ) , ] ;
325-
326- crate fn check_for_substitution < ' a > ( reader : & StringReader < ' a > ,
327- ch : char ,
328- err : & mut DiagnosticBuilder < ' a > ) -> bool {
329- UNICODE_ARRAY
330- . iter ( )
331- . find ( |& & ( c, _, _) | c == ch)
332- . map ( |& ( _, u_name, ascii_char) | {
333- let span = Span :: new ( reader. pos , reader. next_pos , NO_EXPANSION ) ;
334- match ASCII_ARRAY . iter ( ) . find ( |& & ( c, _) | c == ascii_char) {
335- Some ( & ( ascii_char, ascii_name) ) => {
336- // special help suggestion for "directed" double quotes
337- if let Some ( s) = reader. peek_delimited ( '“' , '”' ) {
338- let msg = format ! ( "Unicode characters '“' (Left Double Quotation Mark) and \
339- '”' (Right Double Quotation Mark) look like '{}' ({}), but are not",
340- ascii_char, ascii_name) ;
341- err. span_suggestion (
342- Span :: new ( reader. pos , reader. next_pos + Pos :: from_usize ( s. len ( ) ) +
343- Pos :: from_usize ( '”' . len_utf8 ( ) ) , NO_EXPANSION ) ,
344- & msg,
345- format ! ( "\" {}\" " , s) ,
346- Applicability :: MaybeIncorrect ) ;
347- } else {
348- let msg =
349- format ! ( "Unicode character '{}' ({}) looks like '{}' ({}), but it is not" ,
350- ch, u_name, ascii_char, ascii_name) ;
351- err. span_suggestion (
352- span,
353- & msg,
354- ascii_char. to_string ( ) ,
355- Applicability :: MaybeIncorrect ) ;
356- }
357- true
358- } ,
359- None => {
360- let msg = format ! ( "substitution character not found for '{}'" , ch) ;
361- reader. sess . span_diagnostic . span_bug_no_panic ( span, & msg) ;
362- false
363- }
325+ ( '>' , "Greater-Than Sign" ) ,
326+ ] ;
327+
328+ crate fn check_for_substitution < ' a > (
329+ reader : & StringReader < ' a > ,
330+ ch : char ,
331+ err : & mut DiagnosticBuilder < ' a > ,
332+ ) -> bool {
333+ let ( u_name, ascii_char) = match UNICODE_ARRAY . iter ( ) . find ( |& & ( c, _, _) | c == ch) {
334+ Some ( & ( _u_char, u_name, ascii_char) ) => ( u_name, ascii_char) ,
335+ None => return false ,
336+ } ;
337+
338+ let span = Span :: new ( reader. pos , reader. next_pos , NO_EXPANSION ) ;
339+
340+ let ascii_name = match ASCII_ARRAY . iter ( ) . find ( |& & ( c, _) | c == ascii_char) {
341+ Some ( ( _ascii_char, ascii_name) ) => ascii_name,
342+ None => {
343+ let msg = format ! ( "substitution character not found for '{}'" , ch) ;
344+ reader. sess . span_diagnostic . span_bug_no_panic ( span, & msg) ;
345+ return false
346+ } ,
347+ } ;
348+
349+ // special help suggestion for "directed" double quotes
350+ if let Some ( s) = reader. peek_delimited ( '“' , '”' ) {
351+ let msg = format ! (
352+ "Unicode characters '“' (Left Double Quotation Mark) and \
353+ '”' (Right Double Quotation Mark) look like '{}' ({}), but are not",
354+ ascii_char, ascii_name
355+ ) ;
356+ err. span_suggestion (
357+ Span :: new (
358+ reader. pos ,
359+ reader. next_pos + Pos :: from_usize ( s. len ( ) ) + Pos :: from_usize ( '”' . len_utf8 ( ) ) ,
360+ NO_EXPANSION ,
361+ ) ,
362+ & msg,
363+ format ! ( "\" {}\" " , s) ,
364+ Applicability :: MaybeIncorrect ,
365+ ) ;
366+ } else {
367+ let msg = format ! (
368+ "Unicode character '{}' ({}) looks like '{}' ({}), but it is not" ,
369+ ch, u_name, ascii_char, ascii_name
370+ ) ;
371+ err. span_suggestion (
372+ span,
373+ & msg,
374+ ascii_char. to_string ( ) ,
375+ Applicability :: MaybeIncorrect ,
376+ ) ;
377+ }
378+ true
379+ }
380+
381+ impl StringReader < ' _ > {
382+ /// Immutably extract string if found at current position with given delimiters
383+ fn peek_delimited ( & self , from_ch : char , to_ch : char ) -> Option < & str > {
384+ let tail = & self . src [ self . src_index ( self . pos ) ..] ;
385+ let mut chars = tail. chars ( ) ;
386+ let first_char = chars. next ( ) ?;
387+ if first_char != from_ch {
388+ return None ;
364389 }
365- } ) . unwrap_or ( false )
390+ let last_char_idx = chars. as_str ( ) . find ( to_ch) ?;
391+ Some ( & chars. as_str ( ) [ ..last_char_idx] )
392+ }
366393}
0 commit comments