@@ -21,13 +21,6 @@ use syntax_pos::Span;
21
21
use rustc:: hir:: { self , PatKind } ;
22
22
use rustc:: hir:: intravisit:: FnKind ;
23
23
24
- use regex:: Regex ;
25
-
26
- lazy_static ! {
27
- static ref ALPHABETIC_UNDERSCORE : Regex =
28
- Regex :: new( "([[:alpha:]])_+|_+([[:alpha:]])" ) . unwrap( ) ;
29
- }
30
-
31
24
#[ derive( PartialEq ) ]
32
25
pub enum MethodLateContext {
33
26
TraitAutoImpl ,
@@ -60,6 +53,10 @@ pub struct NonCamelCaseTypes;
60
53
61
54
impl NonCamelCaseTypes {
62
55
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
+
63
60
fn is_camel_case ( name : ast:: Name ) -> bool {
64
61
let name = name. as_str ( ) ;
65
62
if name. is_empty ( ) {
@@ -70,25 +67,37 @@ impl NonCamelCaseTypes {
70
67
// start with a non-lowercase letter rather than non-uppercase
71
68
// ones (some scripts don't have a concept of upper/lowercase)
72
69
!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
+ } )
74
75
}
75
76
76
77
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
92
101
}
93
102
94
103
if !is_camel_case ( name) {
0 commit comments