aboutsummaryrefslogtreecommitdiff
path: root/crates
diff options
context:
space:
mode:
Diffstat (limited to 'crates')
-rw-r--r--crates/hir_ty/src/diagnostics/decl_check/str_helpers.rs129
1 files changed, 97 insertions, 32 deletions
diff --git a/crates/hir_ty/src/diagnostics/decl_check/str_helpers.rs b/crates/hir_ty/src/diagnostics/decl_check/str_helpers.rs
index 953d0276f..e3826909b 100644
--- a/crates/hir_ty/src/diagnostics/decl_check/str_helpers.rs
+++ b/crates/hir_ty/src/diagnostics/decl_check/str_helpers.rs
@@ -1,10 +1,74 @@
1#[derive(Debug)]
2enum DetectedCase {
3 LowerCamelCase,
4 UpperCamelCase,
5 LowerSnakeCase,
6 UpperSnakeCase,
7 Unknown,
8}
9
10fn detect_case(ident: &str) -> DetectedCase {
11 let trimmed_ident = ident.trim_matches('_');
12 let first_lowercase =
13 trimmed_ident.chars().next().map(|chr| chr.is_ascii_lowercase()).unwrap_or(false);
14 let mut has_lowercase = first_lowercase;
15 let mut has_uppercase = false;
16 let mut has_underscore = false;
17
18 for chr in trimmed_ident.chars() {
19 if chr == '_' {
20 has_underscore = true;
21 } else if chr.is_ascii_uppercase() {
22 has_uppercase = true;
23 } else if chr.is_ascii_lowercase() {
24 has_lowercase = true;
25 }
26 }
27
28 if has_uppercase {
29 if !has_lowercase {
30 DetectedCase::UpperSnakeCase
31 } else if !has_underscore {
32 if first_lowercase {
33 DetectedCase::LowerCamelCase
34 } else {
35 DetectedCase::UpperCamelCase
36 }
37 } else {
38 // It has uppercase, it has lowercase, it has underscore.
39 // No assumptions here
40 DetectedCase::Unknown
41 }
42 } else {
43 DetectedCase::LowerSnakeCase
44 }
45}
46
1pub fn to_camel_case(ident: &str) -> Option<String> { 47pub fn to_camel_case(ident: &str) -> Option<String> {
2 let mut output = String::new(); 48 let detected_case = detect_case(ident);
3 49
4 if is_camel_case(ident) { 50 match detected_case {
5 return None; 51 DetectedCase::UpperCamelCase => return None,
52 DetectedCase::LowerCamelCase => {
53 let mut first_capitalized = false;
54 let output = ident
55 .chars()
56 .map(|chr| {
57 if !first_capitalized && chr.is_ascii_lowercase() {
58 first_capitalized = true;
59 chr.to_ascii_uppercase()
60 } else {
61 chr
62 }
63 })
64 .collect();
65 return Some(output);
66 }
67 _ => {}
6 } 68 }
7 69
70 let mut output = String::with_capacity(ident.len());
71
8 let mut capital_added = false; 72 let mut capital_added = false;
9 for chr in ident.chars() { 73 for chr in ident.chars() {
10 if chr.is_alphabetic() { 74 if chr.is_alphabetic() {
@@ -23,47 +87,37 @@ pub fn to_camel_case(ident: &str) -> Option<String> {
23 } 87 }
24 } 88 }
25 89
26 if output == ident { 90 Some(output)
27 None
28 } else {
29 Some(output)
30 }
31} 91}
32 92
33pub fn to_lower_snake_case(ident: &str) -> Option<String> { 93pub fn to_lower_snake_case(ident: &str) -> Option<String> {
34 // First, assume that it's UPPER_SNAKE_CASE. 94 // First, assume that it's UPPER_SNAKE_CASE.
35 if let Some(normalized) = to_lower_snake_case_from_upper_snake_case(ident) { 95 match detect_case(ident) {
36 return Some(normalized); 96 DetectedCase::LowerSnakeCase => return None,
97 DetectedCase::UpperSnakeCase => {
98 return Some(ident.chars().map(|chr| chr.to_ascii_lowercase()).collect())
99 }
100 _ => {}
37 } 101 }
38 102
39 // Otherwise, assume that it's CamelCase. 103 // Otherwise, assume that it's CamelCase.
40 let lower_snake_case = stdx::to_lower_snake_case(ident); 104 let lower_snake_case = stdx::to_lower_snake_case(ident);
41 105 Some(lower_snake_case)
42 if lower_snake_case == ident {
43 None
44 } else {
45 Some(lower_snake_case)
46 }
47} 106}
48 107
49fn to_lower_snake_case_from_upper_snake_case(ident: &str) -> Option<String> { 108pub fn to_upper_snake_case(ident: &str) -> Option<String> {
50 if is_upper_snake_case(ident) { 109 match detect_case(ident) {
51 let string = ident.chars().map(|c| c.to_ascii_lowercase()).collect(); 110 DetectedCase::UpperSnakeCase => return None,
52 Some(string) 111 DetectedCase::LowerSnakeCase => {
53 } else { 112 return Some(ident.chars().map(|chr| chr.to_ascii_uppercase()).collect())
54 None 113 }
114 _ => {}
55 } 115 }
56}
57
58fn is_upper_snake_case(ident: &str) -> bool {
59 ident.chars().all(|c| c.is_ascii_uppercase() || c == '_')
60}
61 116
62fn is_camel_case(ident: &str) -> bool { 117 // Normalize the string from whatever form it's in currently, and then just make it uppercase.
63 // We assume that the string is either snake case or camel case. 118 let upper_snake_case =
64 // `_` is allowed only at the beginning or in the end of identifier, not between characters. 119 stdx::to_lower_snake_case(ident).chars().map(|c| c.to_ascii_uppercase()).collect();
65 ident.trim_matches('_').chars().all(|c| c != '_') 120 Some(upper_snake_case)
66 && ident.chars().find(|c| c.is_alphabetic()).map(|c| c.is_ascii_uppercase()).unwrap_or(true)
67} 121}
68 122
69#[cfg(test)] 123#[cfg(test)]
@@ -84,6 +138,7 @@ mod tests {
84 check(to_lower_snake_case, "UPPER_SNAKE_CASE", expect![["upper_snake_case"]]); 138 check(to_lower_snake_case, "UPPER_SNAKE_CASE", expect![["upper_snake_case"]]);
85 check(to_lower_snake_case, "Weird_Case", expect![["weird_case"]]); 139 check(to_lower_snake_case, "Weird_Case", expect![["weird_case"]]);
86 check(to_lower_snake_case, "CamelCase", expect![["camel_case"]]); 140 check(to_lower_snake_case, "CamelCase", expect![["camel_case"]]);
141 check(to_lower_snake_case, "lowerCamelCase", expect![["lower_camel_case"]]);
87 } 142 }
88 143
89 #[test] 144 #[test]
@@ -91,9 +146,19 @@ mod tests {
91 check(to_camel_case, "CamelCase", expect![[""]]); 146 check(to_camel_case, "CamelCase", expect![[""]]);
92 check(to_camel_case, "CamelCase_", expect![[""]]); 147 check(to_camel_case, "CamelCase_", expect![[""]]);
93 check(to_camel_case, "_CamelCase", expect![[""]]); 148 check(to_camel_case, "_CamelCase", expect![[""]]);
149 check(to_camel_case, "lowerCamelCase", expect![["LowerCamelCase"]]);
94 check(to_camel_case, "lower_snake_case", expect![["LowerSnakeCase"]]); 150 check(to_camel_case, "lower_snake_case", expect![["LowerSnakeCase"]]);
95 check(to_camel_case, "UPPER_SNAKE_CASE", expect![["UpperSnakeCase"]]); 151 check(to_camel_case, "UPPER_SNAKE_CASE", expect![["UpperSnakeCase"]]);
96 check(to_camel_case, "Weird_Case", expect![["WeirdCase"]]); 152 check(to_camel_case, "Weird_Case", expect![["WeirdCase"]]);
97 check(to_camel_case, "name", expect![["Name"]]); 153 check(to_camel_case, "name", expect![["Name"]]);
98 } 154 }
155
156 #[test]
157 fn test_to_upper_snake_case() {
158 check(to_upper_snake_case, "UPPER_SNAKE_CASE", expect![[""]]);
159 check(to_upper_snake_case, "lower_snake_case", expect![["LOWER_SNAKE_CASE"]]);
160 check(to_upper_snake_case, "Weird_Case", expect![["WEIRD_CASE"]]);
161 check(to_upper_snake_case, "CamelCase", expect![["CAMEL_CASE"]]);
162 check(to_upper_snake_case, "lowerCamelCase", expect![["LOWER_CAMEL_CASE"]]);
163 }
99} 164}