Skip to content

Commit a115fea

Browse files
authored
Rollup merge of #58407 - euclio:upper-camel-case, r=estebank
specify "upper camel case" in style lint Also, fix an issue where internal upper case letters were converted to lower case. Fixes #57319.
2 parents 2a539a1 + 2f95299 commit a115fea

8 files changed

+139
-126
lines changed

src/librustc_lint/Cargo.toml

-1
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@ edition = "2018"
88
name = "rustc_lint"
99
path = "lib.rs"
1010
crate-type = ["dylib"]
11-
test = false
1211

1312
[dependencies]
1413
log = "0.4"

src/librustc_lint/nonstandard_style.rs

+95-53
Original file line numberDiff line numberDiff line change
@@ -38,66 +38,87 @@ declare_lint! {
3838
"types, variants, traits and type parameters should have camel case names"
3939
}
4040

41-
#[derive(Copy, Clone)]
42-
pub struct NonCamelCaseTypes;
41+
fn char_has_case(c: char) -> bool {
42+
c.is_lowercase() || c.is_uppercase()
43+
}
4344

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+
}
4950

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;
5486
}
5587

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+
}
65107

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;
89110

111+
impl NonCamelCaseTypes {
112+
fn check_case(&self, cx: &EarlyContext<'_>, sort: &str, ident: &Ident) {
90113
let name = &ident.name.as_str();
91114

92115
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);
96117
cx.struct_span_lint(NON_CAMEL_CASE_TYPES, ident.span, &msg)
97118
.span_suggestion(
98119
ident.span,
99-
"convert the identifier to camel case",
100-
c,
120+
"convert the identifier to upper camel case",
121+
to_camel_case(name),
101122
Applicability::MaybeIncorrect,
102123
)
103124
.emit();
@@ -119,11 +140,7 @@ impl EarlyLintPass for NonCamelCaseTypes {
119140
fn check_item(&mut self, cx: &EarlyContext<'_>, it: &ast::Item) {
120141
let has_repr_c = it.attrs
121142
.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));
127144

128145
if has_repr_c {
129146
return;
@@ -439,3 +456,28 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for NonUpperCaseGlobals {
439456
}
440457
}
441458
}
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+
}

src/test/ui/lint/lint-group-nonstandard-style.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ mod test {
1919

2020
fn CamelCase() {} //~ WARN should have a snake
2121

22-
struct snake_case; //~ WARN should have a camel
22+
struct snake_case; //~ WARN should have an upper camel
2323
}
2424
}
2525

src/test/ui/lint/lint-group-nonstandard-style.stderr

+3-3
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
1-
warning: type `snake_case` should have a camel case name
1+
warning: type `snake_case` should have an upper camel case name
22
--> $DIR/lint-group-nonstandard-style.rs:22:16
33
|
4-
LL | struct snake_case; //~ WARN should have a camel
5-
| ^^^^^^^^^^ help: convert the identifier to camel case: `SnakeCase`
4+
LL | struct snake_case; //~ WARN should have an upper camel
5+
| ^^^^^^^^^^ help: convert the identifier to upper camel case: `SnakeCase`
66
|
77
note: lint level defined here
88
--> $DIR/lint-group-nonstandard-style.rs:18:17

src/test/ui/lint/lint-non-camel-case-types.rs

+8-16
Original file line numberDiff line numberDiff line change
@@ -2,43 +2,35 @@
22
#![allow(dead_code)]
33

44
struct ONE_TWO_THREE;
5-
//~^ ERROR type `ONE_TWO_THREE` should have a camel case name
5+
//~^ ERROR type `ONE_TWO_THREE` should have an upper camel case name
66

7-
struct foo { //~ ERROR type `foo` should have a camel case name
7+
struct foo { //~ ERROR type `foo` should have an upper camel case name
88
bar: isize,
99
}
1010

11-
enum foo2 { //~ ERROR type `foo2` should have a camel case name
11+
enum foo2 { //~ ERROR type `foo2` should have an upper camel case name
1212
Bar
1313
}
1414

15-
struct foo3 { //~ ERROR type `foo3` should have a camel case name
15+
struct foo3 { //~ ERROR type `foo3` should have an upper camel case name
1616
bar: isize
1717
}
1818

19-
type foo4 = isize; //~ ERROR type `foo4` should have a camel case name
19+
type foo4 = isize; //~ ERROR type `foo4` should have an upper camel case name
2020

2121
enum Foo5 {
22-
bar //~ ERROR variant `bar` should have a camel case name
22+
bar //~ ERROR variant `bar` should have an upper camel case name
2323
}
2424

25-
trait foo6 { //~ ERROR trait `foo6` should have a camel case name
25+
trait foo6 { //~ ERROR trait `foo6` should have an upper camel case name
2626
fn dummy(&self) { }
2727
}
2828

29-
fn f<ty>(_: ty) {} //~ ERROR type parameter `ty` should have a camel case name
29+
fn f<ty>(_: ty) {} //~ ERROR type parameter `ty` should have an upper camel case name
3030

3131
#[repr(C)]
3232
struct foo7 {
3333
bar: isize,
3434
}
3535

36-
struct X86_64;
37-
38-
struct X86__64; //~ ERROR type `X86__64` should have a camel case name
39-
40-
struct Abc_123; //~ ERROR type `Abc_123` should have a camel case name
41-
42-
struct A1_b2_c3; //~ ERROR type `A1_b2_c3` should have a camel case name
43-
4436
fn main() { }
Original file line numberDiff line numberDiff line change
@@ -1,74 +1,56 @@
1-
error: type `ONE_TWO_THREE` should have a camel case name
1+
error: type `ONE_TWO_THREE` should have an upper camel case name
22
--> $DIR/lint-non-camel-case-types.rs:4:8
33
|
44
LL | struct ONE_TWO_THREE;
5-
| ^^^^^^^^^^^^^ help: convert the identifier to camel case: `OneTwoThree`
5+
| ^^^^^^^^^^^^^ help: convert the identifier to upper camel case: `OneTwoThree`
66
|
77
note: lint level defined here
88
--> $DIR/lint-non-camel-case-types.rs:1:11
99
|
1010
LL | #![forbid(non_camel_case_types)]
1111
| ^^^^^^^^^^^^^^^^^^^^
1212

13-
error: type `foo` should have a camel case name
13+
error: type `foo` should have an upper camel case name
1414
--> $DIR/lint-non-camel-case-types.rs:7:8
1515
|
16-
LL | struct foo { //~ ERROR type `foo` should have a camel case name
17-
| ^^^ help: convert the identifier to camel case: `Foo`
16+
LL | struct foo { //~ ERROR type `foo` should have an upper camel case name
17+
| ^^^ help: convert the identifier to upper camel case: `Foo`
1818

19-
error: type `foo2` should have a camel case name
19+
error: type `foo2` should have an upper camel case name
2020
--> $DIR/lint-non-camel-case-types.rs:11:6
2121
|
22-
LL | enum foo2 { //~ ERROR type `foo2` should have a camel case name
23-
| ^^^^ help: convert the identifier to camel case: `Foo2`
22+
LL | enum foo2 { //~ ERROR type `foo2` should have an upper camel case name
23+
| ^^^^ help: convert the identifier to upper camel case: `Foo2`
2424

25-
error: type `foo3` should have a camel case name
25+
error: type `foo3` should have an upper camel case name
2626
--> $DIR/lint-non-camel-case-types.rs:15:8
2727
|
28-
LL | struct foo3 { //~ ERROR type `foo3` should have a camel case name
29-
| ^^^^ help: convert the identifier to camel case: `Foo3`
28+
LL | struct foo3 { //~ ERROR type `foo3` should have an upper camel case name
29+
| ^^^^ help: convert the identifier to upper camel case: `Foo3`
3030

31-
error: type `foo4` should have a camel case name
31+
error: type `foo4` should have an upper camel case name
3232
--> $DIR/lint-non-camel-case-types.rs:19:6
3333
|
34-
LL | type foo4 = isize; //~ ERROR type `foo4` should have a camel case name
35-
| ^^^^ help: convert the identifier to camel case: `Foo4`
34+
LL | type foo4 = isize; //~ ERROR type `foo4` should have an upper camel case name
35+
| ^^^^ help: convert the identifier to upper camel case: `Foo4`
3636

37-
error: variant `bar` should have a camel case name
37+
error: variant `bar` should have an upper camel case name
3838
--> $DIR/lint-non-camel-case-types.rs:22:5
3939
|
40-
LL | bar //~ ERROR variant `bar` should have a camel case name
41-
| ^^^ help: convert the identifier to camel case: `Bar`
40+
LL | bar //~ ERROR variant `bar` should have an upper camel case name
41+
| ^^^ help: convert the identifier to upper camel case: `Bar`
4242

43-
error: trait `foo6` should have a camel case name
43+
error: trait `foo6` should have an upper camel case name
4444
--> $DIR/lint-non-camel-case-types.rs:25:7
4545
|
46-
LL | trait foo6 { //~ ERROR trait `foo6` should have a camel case name
47-
| ^^^^ help: convert the identifier to camel case: `Foo6`
46+
LL | trait foo6 { //~ ERROR trait `foo6` should have an upper camel case name
47+
| ^^^^ help: convert the identifier to upper camel case: `Foo6`
4848

49-
error: type parameter `ty` should have a camel case name
49+
error: type parameter `ty` should have an upper camel case name
5050
--> $DIR/lint-non-camel-case-types.rs:29:6
5151
|
52-
LL | fn f<ty>(_: ty) {} //~ ERROR type parameter `ty` should have a camel case name
53-
| ^^ help: convert the identifier to camel case: `Ty`
52+
LL | fn f<ty>(_: ty) {} //~ ERROR type parameter `ty` should have an upper camel case name
53+
| ^^ help: convert the identifier to upper camel case: `Ty`
5454

55-
error: type `X86__64` should have a camel case name
56-
--> $DIR/lint-non-camel-case-types.rs:38:8
57-
|
58-
LL | struct X86__64; //~ ERROR type `X86__64` should have a camel case name
59-
| ^^^^^^^ help: convert the identifier to camel case: `X86_64`
60-
61-
error: type `Abc_123` should have a camel case name
62-
--> $DIR/lint-non-camel-case-types.rs:40:8
63-
|
64-
LL | struct Abc_123; //~ ERROR type `Abc_123` should have a camel case name
65-
| ^^^^^^^ help: convert the identifier to camel case: `Abc123`
66-
67-
error: type `A1_b2_c3` should have a camel case name
68-
--> $DIR/lint-non-camel-case-types.rs:42:8
69-
|
70-
LL | struct A1_b2_c3; //~ ERROR type `A1_b2_c3` should have a camel case name
71-
| ^^^^^^^^ help: convert the identifier to camel case: `A1B2C3`
72-
73-
error: aborting due to 11 previous errors
55+
error: aborting due to 8 previous errors
7456

src/test/ui/utf8_idents.rs

+1-3
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,7 @@
1-
//
2-
31
fn foo<
42
'β, //~ ERROR non-ascii idents are not fully supported
53
γ //~ ERROR non-ascii idents are not fully supported
6-
//~^ WARN type parameter `γ` should have a camel case name
4+
//~^ WARN type parameter `γ` should have an upper camel case name
75
>() {}
86

97
struct X {

0 commit comments

Comments
 (0)