@@ -38,66 +38,87 @@ declare_lint! {
38
38
"types, variants, traits and type parameters should have camel case names"
39
39
}
40
40
41
- #[ derive( Copy , Clone ) ]
42
- pub struct NonCamelCaseTypes ;
41
+ fn char_has_case ( c : char ) -> bool {
42
+ c. is_lowercase ( ) || c. is_uppercase ( )
43
+ }
43
44
44
- impl NonCamelCaseTypes {
45
- fn check_case ( & self , cx : & EarlyContext < ' _ > , sort : & str , ident : & Ident ) {
46
- fn char_has_case ( c : char ) -> bool {
47
- c . is_lowercase ( ) || c . is_uppercase ( )
48
- }
45
+ fn is_camel_case ( name : & str ) -> bool {
46
+ let name = name . trim_matches ( '_' ) ;
47
+ if name . is_empty ( ) {
48
+ return true ;
49
+ }
49
50
50
- fn is_camel_case ( name : & str ) -> bool {
51
- let name = name. trim_matches ( '_' ) ;
52
- if name. is_empty ( ) {
53
- return true ;
51
+ // start with a non-lowercase letter rather than non-uppercase
52
+ // ones (some scripts don't have a concept of upper/lowercase)
53
+ !name. chars ( ) . next ( ) . unwrap ( ) . is_lowercase ( )
54
+ && !name. contains ( "__" )
55
+ && !name. chars ( ) . collect :: < Vec < _ > > ( ) . windows ( 2 ) . any ( |pair| {
56
+ // contains a capitalisable character followed by, or preceded by, an underscore
57
+ char_has_case ( pair[ 0 ] ) && pair[ 1 ] == '_' || char_has_case ( pair[ 1 ] ) && pair[ 0 ] == '_'
58
+ } )
59
+ }
60
+
61
+ fn to_camel_case ( s : & str ) -> String {
62
+ s. trim_matches ( '_' )
63
+ . split ( '_' )
64
+ . filter ( |component| !component. is_empty ( ) )
65
+ . map ( |component| {
66
+ let mut camel_cased_component = String :: new ( ) ;
67
+
68
+ let mut new_word = true ;
69
+ let mut prev_is_lower_case = true ;
70
+
71
+ for c in component. chars ( ) {
72
+ // Preserve the case if an uppercase letter follows a lowercase letter, so that
73
+ // `camelCase` is converted to `CamelCase`.
74
+ if prev_is_lower_case && c. is_uppercase ( ) {
75
+ new_word = true ;
76
+ }
77
+
78
+ if new_word {
79
+ camel_cased_component. push_str ( & c. to_uppercase ( ) . to_string ( ) ) ;
80
+ } else {
81
+ camel_cased_component. push_str ( & c. to_lowercase ( ) . to_string ( ) ) ;
82
+ }
83
+
84
+ prev_is_lower_case = c. is_lowercase ( ) ;
85
+ new_word = false ;
54
86
}
55
87
56
- // start with a non-lowercase letter rather than non-uppercase
57
- // ones (some scripts don't have a concept of upper/lowercase)
58
- !name. is_empty ( ) && !name. chars ( ) . next ( ) . unwrap ( ) . is_lowercase ( ) &&
59
- !name. contains ( "__" ) && !name. chars ( ) . collect :: < Vec < _ > > ( ) . windows ( 2 ) . any ( |pair| {
60
- // contains a capitalisable character followed by, or preceded by, an underscore
61
- char_has_case ( pair[ 0 ] ) && pair[ 1 ] == '_' ||
62
- char_has_case ( pair[ 1 ] ) && pair[ 0 ] == '_'
63
- } )
64
- }
88
+ camel_cased_component
89
+ } )
90
+ . fold (
91
+ ( String :: new ( ) , None ) ,
92
+ |( acc, prev) : ( String , Option < String > ) , next| {
93
+ // separate two components with an underscore if their boundary cannot
94
+ // be distinguished using a uppercase/lowercase case distinction
95
+ let join = if let Some ( prev) = prev {
96
+ let l = prev. chars ( ) . last ( ) . unwrap ( ) ;
97
+ let f = next. chars ( ) . next ( ) . unwrap ( ) ;
98
+ !char_has_case ( l) && !char_has_case ( f)
99
+ } else {
100
+ false
101
+ } ;
102
+ ( acc + if join { "_" } else { "" } + & next, Some ( next) )
103
+ } ,
104
+ )
105
+ . 0
106
+ }
65
107
66
- fn to_camel_case ( s : & str ) -> String {
67
- s. trim_matches ( '_' )
68
- . split ( '_' )
69
- . map ( |word| {
70
- word. chars ( ) . enumerate ( ) . map ( |( i, c) | if i == 0 {
71
- c. to_uppercase ( ) . collect :: < String > ( )
72
- } else {
73
- c. to_lowercase ( ) . collect ( )
74
- } )
75
- . collect :: < String > ( )
76
- } )
77
- . filter ( |x| !x. is_empty ( ) )
78
- . fold ( ( String :: new ( ) , None ) , |( acc, prev) : ( String , Option < String > ) , next| {
79
- // separate two components with an underscore if their boundary cannot
80
- // be distinguished using a uppercase/lowercase case distinction
81
- let join = if let Some ( prev) = prev {
82
- let l = prev. chars ( ) . last ( ) . unwrap ( ) ;
83
- let f = next. chars ( ) . next ( ) . unwrap ( ) ;
84
- !char_has_case ( l) && !char_has_case ( f)
85
- } else { false } ;
86
- ( acc + if join { "_" } else { "" } + & next, Some ( next) )
87
- } ) . 0
88
- }
108
+ #[ derive( Copy , Clone ) ]
109
+ pub struct NonCamelCaseTypes ;
89
110
111
+ impl NonCamelCaseTypes {
112
+ fn check_case ( & self , cx : & EarlyContext < ' _ > , sort : & str , ident : & Ident ) {
90
113
let name = & ident. name . as_str ( ) ;
91
114
92
115
if !is_camel_case ( name) {
93
- let c = to_camel_case ( name) ;
94
-
95
- let msg = format ! ( "{} `{}` should have a camel case name" , sort, name) ;
116
+ let msg = format ! ( "{} `{}` should have an upper camel case name" , sort, name) ;
96
117
cx. struct_span_lint ( NON_CAMEL_CASE_TYPES , ident. span , & msg)
97
118
. span_suggestion (
98
119
ident. span ,
99
- "convert the identifier to camel case" ,
100
- c ,
120
+ "convert the identifier to upper camel case" ,
121
+ to_camel_case ( name ) ,
101
122
Applicability :: MaybeIncorrect ,
102
123
)
103
124
. emit ( ) ;
@@ -119,11 +140,7 @@ impl EarlyLintPass for NonCamelCaseTypes {
119
140
fn check_item ( & mut self , cx : & EarlyContext < ' _ > , it : & ast:: Item ) {
120
141
let has_repr_c = it. attrs
121
142
. iter ( )
122
- . any ( |attr| {
123
- attr:: find_repr_attrs ( & cx. sess . parse_sess , attr)
124
- . iter ( )
125
- . any ( |r| r == & attr:: ReprC )
126
- } ) ;
143
+ . any ( |attr| attr:: find_repr_attrs ( & cx. sess . parse_sess , attr) . contains ( & attr:: ReprC ) ) ;
127
144
128
145
if has_repr_c {
129
146
return ;
@@ -439,3 +456,28 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for NonUpperCaseGlobals {
439
456
}
440
457
}
441
458
}
459
+
460
+ #[ cfg( test) ]
461
+ mod tests {
462
+ use super :: { is_camel_case, to_camel_case} ;
463
+
464
+ #[ test]
465
+ fn camel_case ( ) {
466
+ assert ! ( !is_camel_case( "userData" ) ) ;
467
+ assert_eq ! ( to_camel_case( "userData" ) , "UserData" ) ;
468
+
469
+ assert ! ( is_camel_case( "X86_64" ) ) ;
470
+
471
+ assert ! ( !is_camel_case( "X86__64" ) ) ;
472
+ assert_eq ! ( to_camel_case( "X86__64" ) , "X86_64" ) ;
473
+
474
+ assert ! ( !is_camel_case( "Abc_123" ) ) ;
475
+ assert_eq ! ( to_camel_case( "Abc_123" ) , "Abc123" ) ;
476
+
477
+ assert ! ( !is_camel_case( "A1_b2_c3" ) ) ;
478
+ assert_eq ! ( to_camel_case( "A1_b2_c3" ) , "A1B2C3" ) ;
479
+
480
+ assert ! ( !is_camel_case( "ONE_TWO_THREE" ) ) ;
481
+ assert_eq ! ( to_camel_case( "ONE_TWO_THREE" ) , "OneTwoThree" ) ;
482
+ }
483
+ }
0 commit comments