aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--crates/hir_ty/src/diagnostics/decl_check.rs49
-rw-r--r--crates/hir_ty/src/diagnostics/decl_check/str_helpers.rs92
2 files changed, 112 insertions, 29 deletions
diff --git a/crates/hir_ty/src/diagnostics/decl_check.rs b/crates/hir_ty/src/diagnostics/decl_check.rs
index 083df3772..1a0906492 100644
--- a/crates/hir_ty/src/diagnostics/decl_check.rs
+++ b/crates/hir_ty/src/diagnostics/decl_check.rs
@@ -9,6 +9,8 @@
9// If you see these lines in the pull request, feel free to call me stupid :P. 9// If you see these lines in the pull request, feel free to call me stupid :P.
10#![allow(dead_code, unused_imports, unused_variables)] 10#![allow(dead_code, unused_imports, unused_variables)]
11 11
12mod str_helpers;
13
12use std::sync::Arc; 14use std::sync::Arc;
13 15
14use hir_def::{ 16use hir_def::{
@@ -18,7 +20,7 @@ use hir_def::{
18 item_tree::ItemTreeNode, 20 item_tree::ItemTreeNode,
19 resolver::{resolver_for_expr, ResolveValueResult, ValueNs}, 21 resolver::{resolver_for_expr, ResolveValueResult, ValueNs},
20 src::HasSource, 22 src::HasSource,
21 AdtId, FunctionId, Lookup, ModuleDefId, 23 AdtId, EnumId, FunctionId, Lookup, ModuleDefId, StructId,
22}; 24};
23use hir_expand::{diagnostics::DiagnosticSink, name::Name}; 25use hir_expand::{diagnostics::DiagnosticSink, name::Name};
24use syntax::{ 26use syntax::{
@@ -28,7 +30,7 @@ use syntax::{
28 30
29use crate::{ 31use crate::{
30 db::HirDatabase, 32 db::HirDatabase,
31 diagnostics::{CaseType, IncorrectCase}, 33 diagnostics::{decl_check::str_helpers::*, CaseType, IncorrectCase},
32 lower::CallableDefId, 34 lower::CallableDefId,
33 ApplicationTy, InferenceResult, Ty, TypeCtor, 35 ApplicationTy, InferenceResult, Ty, TypeCtor,
34}; 36};
@@ -191,41 +193,30 @@ impl<'a, 'b> DeclValidator<'a, 'b> {
191 } 193 }
192 } 194 }
193 195
194 fn validate_adt(&mut self, db: &dyn HirDatabase, adt: AdtId) {} 196 fn validate_adt(&mut self, db: &dyn HirDatabase, adt: AdtId) {
195} 197 match adt {
196 198 AdtId::StructId(struct_id) => self.validate_struct(db, struct_id),
197fn pat_equals_to_name(pat: Option<ast::Pat>, name: &Name) -> bool { 199 AdtId::EnumId(enum_id) => self.validate_enum(db, enum_id),
198 if let Some(ast::Pat::IdentPat(ident)) = pat { 200 AdtId::UnionId(_) => {
199 ident.to_string() == name.to_string() 201 // Unions aren't yet supported by this validator.
200 } else { 202 }
201 false 203 }
202 } 204 }
203}
204 205
205fn to_lower_snake_case(ident: &str) -> Option<String> { 206 fn validate_struct(&mut self, db: &dyn HirDatabase, struct_id: StructId) {
206 // First, assume that it's UPPER_SNAKE_CASE. 207 let data = db.struct_data(struct_id);
207 if let Some(normalized) = to_lower_snake_case_from_upper_snake_case(ident) {
208 return Some(normalized);
209 } 208 }
210 209
211 // Otherwise, assume that it's CamelCase. 210 fn validate_enum(&mut self, db: &dyn HirDatabase, enum_id: EnumId) {
212 let lower_snake_case = stdx::to_lower_snake_case(ident); 211 let data = db.enum_data(enum_id);
213
214 if lower_snake_case == ident {
215 None
216 } else {
217 Some(lower_snake_case)
218 } 212 }
219} 213}
220 214
221fn to_lower_snake_case_from_upper_snake_case(ident: &str) -> Option<String> { 215fn pat_equals_to_name(pat: Option<ast::Pat>, name: &Name) -> bool {
222 let is_upper_snake_case = ident.chars().all(|c| c.is_ascii_uppercase() || c == '_'); 216 if let Some(ast::Pat::IdentPat(ident)) = pat {
223 217 ident.to_string() == name.to_string()
224 if is_upper_snake_case {
225 let string = ident.chars().map(|c| c.to_ascii_lowercase()).collect();
226 Some(string)
227 } else { 218 } else {
228 None 219 false
229 } 220 }
230} 221}
231 222
diff --git a/crates/hir_ty/src/diagnostics/decl_check/str_helpers.rs b/crates/hir_ty/src/diagnostics/decl_check/str_helpers.rs
new file mode 100644
index 000000000..3d8f1b5f2
--- /dev/null
+++ b/crates/hir_ty/src/diagnostics/decl_check/str_helpers.rs
@@ -0,0 +1,92 @@
1pub fn to_camel_case(ident: &str) -> Option<String> {
2 let mut output = String::new();
3
4 if is_camel_case(ident) {
5 return None;
6 }
7
8 let mut capital_added = false;
9 for chr in ident.chars() {
10 if chr.is_alphabetic() {
11 if !capital_added {
12 output.push(chr.to_ascii_uppercase());
13 capital_added = true;
14 } else {
15 output.push(chr.to_ascii_lowercase());
16 }
17 } else if chr == '_' {
18 // Skip this character and make the next one capital.
19 capital_added = false;
20 } else {
21 // Put the characted as-is.
22 output.push(chr);
23 }
24 }
25
26 if output == ident {
27 None
28 } else {
29 Some(output)
30 }
31}
32
33pub fn to_lower_snake_case(ident: &str) -> Option<String> {
34 // First, assume that it's UPPER_SNAKE_CASE.
35 if let Some(normalized) = to_lower_snake_case_from_upper_snake_case(ident) {
36 return Some(normalized);
37 }
38
39 // Otherwise, assume that it's CamelCase.
40 let lower_snake_case = stdx::to_lower_snake_case(ident);
41
42 if lower_snake_case == ident {
43 None
44 } else {
45 Some(lower_snake_case)
46 }
47}
48
49fn to_lower_snake_case_from_upper_snake_case(ident: &str) -> Option<String> {
50 if is_upper_snake_case(ident) {
51 let string = ident.chars().map(|c| c.to_ascii_lowercase()).collect();
52 Some(string)
53 } else {
54 None
55 }
56}
57
58fn is_upper_snake_case(ident: &str) -> bool {
59 ident.chars().all(|c| c.is_ascii_uppercase() || c == '_')
60}
61
62fn is_camel_case(ident: &str) -> bool {
63 // We assume that the string is either snake case or camel case.
64 ident.chars().all(|c| c != '_')
65}
66
67#[cfg(test)]
68mod tests {
69 use super::*;
70 use expect_test::{expect, Expect};
71
72 fn check<F: Fn(&str) -> Option<String>>(fun: F, input: &str, expect: Expect) {
73 // `None` is translated to empty string, meaning that there is nothing to fix.
74 let output = fun(input).unwrap_or_default();
75
76 expect.assert_eq(&output);
77 }
78
79 #[test]
80 fn test_to_lower_snake_case() {
81 check(to_lower_snake_case, "lower_snake_case", expect![[""]]);
82 check(to_lower_snake_case, "UPPER_SNAKE_CASE", expect![["upper_snake_case"]]);
83 check(to_lower_snake_case, "CamelCase", expect![["camel_case"]]);
84 }
85
86 #[test]
87 fn test_to_camel_case() {
88 check(to_camel_case, "CamelCase", expect![[""]]);
89 check(to_camel_case, "lower_snake_case", expect![["LowerSnakeCase"]]);
90 check(to_camel_case, "UPPER_SNAKE_CASE", expect![["UpperSnakeCase"]]);
91 }
92}