@@ -21,13 +21,6 @@ use syntax_pos::Span;
2121use rustc:: hir:: { self , PatKind } ;
2222use rustc:: hir:: intravisit:: FnKind ;
2323
24- use regex:: Regex ;
25-
26- lazy_static ! {
27- static ref ALPHABETIC_UNDERSCORE : Regex =
28- Regex :: new( "([[:alpha:]])_+|_+([[:alpha:]])" ) . unwrap( ) ;
29- }
30-
3124#[ derive( PartialEq ) ]
3225pub enum MethodLateContext {
3326 TraitAutoImpl ,
@@ -60,6 +53,10 @@ pub struct NonCamelCaseTypes;
6053
6154impl NonCamelCaseTypes {
6255 fn check_case ( & self , cx : & LateContext , sort : & str , name : ast:: Name , span : Span ) {
56+ fn char_has_case ( c : char ) -> bool {
57+ c. is_lowercase ( ) || c. is_uppercase ( )
58+ }
59+
6360 fn is_camel_case ( name : ast:: Name ) -> bool {
6461 let name = name. as_str ( ) ;
6562 if name. is_empty ( ) {
@@ -70,25 +67,37 @@ impl NonCamelCaseTypes {
7067 // start with a non-lowercase letter rather than non-uppercase
7168 // ones (some scripts don't have a concept of upper/lowercase)
7269 !name. is_empty ( ) && !name. chars ( ) . next ( ) . unwrap ( ) . is_lowercase ( ) &&
73- !name. contains ( "__" ) && !ALPHABETIC_UNDERSCORE . is_match ( name)
70+ !name. contains ( "__" ) && !name. chars ( ) . collect :: < Vec < _ > > ( ) . windows ( 2 ) . any ( |pair| {
71+ // contains a capitalisable character followed by, or preceded by, an underscore
72+ char_has_case ( pair[ 0 ] ) && pair[ 1 ] == '_' ||
73+ char_has_case ( pair[ 1 ] ) && pair[ 0 ] == '_'
74+ } )
7475 }
7576
7677 fn to_camel_case ( s : & str ) -> String {
77- let s = s. trim_matches ( '_' )
78- . split ( '_' )
79- . map ( |word| {
80- word. chars ( ) . enumerate ( ) . map ( |( i, c) | if i == 0 {
81- c. to_uppercase ( ) . collect :: < String > ( )
82- } else {
83- c. to_lowercase ( ) . collect ( )
84- } )
85- . collect :: < Vec < _ > > ( )
86- . concat ( )
87- } )
88- . filter ( |x| !x. is_empty ( ) )
89- . collect :: < Vec < _ > > ( )
90- . join ( "_" ) ;
91- ALPHABETIC_UNDERSCORE . replace_all ( s. as_str ( ) , "$1$2" ) . to_string ( )
78+ s. trim_matches ( '_' )
79+ . split ( '_' )
80+ . map ( |word| {
81+ word. chars ( ) . enumerate ( ) . map ( |( i, c) | if i == 0 {
82+ c. to_uppercase ( ) . collect :: < String > ( )
83+ } else {
84+ c. to_lowercase ( ) . collect ( )
85+ } )
86+ . collect :: < Vec < _ > > ( )
87+ . concat ( )
88+ } )
89+ . filter ( |x| !x. is_empty ( ) )
90+ . collect :: < Vec < _ > > ( )
91+ . iter ( ) . fold ( ( String :: new ( ) , None ) , |( acc, prev) : ( String , Option < & String > ) , next| {
92+ // separate two components with an underscore if their boundary cannot
93+ // be distinguished using a uppercase/lowercase case distinction
94+ let join = if let Some ( prev) = prev {
95+ let l = prev. chars ( ) . last ( ) . unwrap ( ) ;
96+ let f = next. chars ( ) . next ( ) . unwrap ( ) ;
97+ !char_has_case ( l) && !char_has_case ( f)
98+ } else { false } ;
99+ ( acc + if join { "_" } else { "" } + next, Some ( next) )
100+ } ) . 0
92101 }
93102
94103 if !is_camel_case ( name) {
0 commit comments