]> git.lizzy.rs Git - rust.git/commitdiff
Add to_upper_snake_case function to stdx
authorIgor Aleksanov <popzxc@yandex.ru>
Thu, 8 Oct 2020 05:33:35 +0000 (08:33 +0300)
committerIgor Aleksanov <popzxc@yandex.ru>
Mon, 12 Oct 2020 08:05:00 +0000 (11:05 +0300)
crates/hir_ty/src/diagnostics/decl_check.rs
crates/hir_ty/src/diagnostics/decl_check/case_conv.rs [new file with mode: 0644]
crates/hir_ty/src/diagnostics/decl_check/str_helpers.rs [deleted file]
crates/stdx/src/lib.rs

index 4c20921e5de5430e3f85e333426654e8f60b2a2e..901ccc94f65b97136fa37af00942fb44a2e930b7 100644 (file)
@@ -10,7 +10,7 @@
 //! - static items (e.g. `static FOO: u8 = 10;`)
 //! - match arm bindings (e.g. `foo @ Some(_)`)
 
-mod str_helpers;
+mod case_conv;
 
 use hir_def::{
     adt::VariantData,
@@ -29,7 +29,7 @@
 
 use crate::{
     db::HirDatabase,
-    diagnostics::{decl_check::str_helpers::*, CaseType, IncorrectCase},
+    diagnostics::{decl_check::case_conv::*, CaseType, IncorrectCase},
 };
 
 pub(super) struct DeclValidator<'a, 'b: 'a> {
diff --git a/crates/hir_ty/src/diagnostics/decl_check/case_conv.rs b/crates/hir_ty/src/diagnostics/decl_check/case_conv.rs
new file mode 100644 (file)
index 0000000..3800f2a
--- /dev/null
@@ -0,0 +1,194 @@
+//! Functions for string case manipulation, such as detecting the identifier case,
+//! and converting it into appropriate form.
+
+#[derive(Debug)]
+enum DetectedCase {
+    LowerCamelCase,
+    UpperCamelCase,
+    LowerSnakeCase,
+    UpperSnakeCase,
+    Unknown,
+}
+
+fn detect_case(ident: &str) -> DetectedCase {
+    let trimmed_ident = ident.trim_matches('_');
+    let first_lowercase = trimmed_ident.starts_with(|chr: char| chr.is_ascii_lowercase());
+    let mut has_lowercase = first_lowercase;
+    let mut has_uppercase = false;
+    let mut has_underscore = false;
+
+    for chr in trimmed_ident.chars() {
+        if chr == '_' {
+            has_underscore = true;
+        } else if chr.is_ascii_uppercase() {
+            has_uppercase = true;
+        } else if chr.is_ascii_lowercase() {
+            has_lowercase = true;
+        }
+    }
+
+    if has_uppercase {
+        if !has_lowercase {
+            DetectedCase::UpperSnakeCase
+        } else if !has_underscore {
+            if first_lowercase {
+                DetectedCase::LowerCamelCase
+            } else {
+                DetectedCase::UpperCamelCase
+            }
+        } else {
+            // It has uppercase, it has lowercase, it has underscore.
+            // No assumptions here
+            DetectedCase::Unknown
+        }
+    } else {
+        DetectedCase::LowerSnakeCase
+    }
+}
+
+/// Converts an identifier to an UpperCamelCase form.
+/// Returns `None` if the string is already is UpperCamelCase.
+pub fn to_camel_case(ident: &str) -> Option<String> {
+    let detected_case = detect_case(ident);
+
+    match detected_case {
+        DetectedCase::UpperCamelCase => return None,
+        DetectedCase::LowerCamelCase => {
+            let mut first_capitalized = false;
+            let output = ident
+                .chars()
+                .map(|chr| {
+                    if !first_capitalized && chr.is_ascii_lowercase() {
+                        first_capitalized = true;
+                        chr.to_ascii_uppercase()
+                    } else {
+                        chr
+                    }
+                })
+                .collect();
+            return Some(output);
+        }
+        _ => {}
+    }
+
+    let mut output = String::with_capacity(ident.len());
+
+    let mut capital_added = false;
+    for chr in ident.chars() {
+        if chr.is_alphabetic() {
+            if !capital_added {
+                output.push(chr.to_ascii_uppercase());
+                capital_added = true;
+            } else {
+                output.push(chr.to_ascii_lowercase());
+            }
+        } else if chr == '_' {
+            // Skip this character and make the next one capital.
+            capital_added = false;
+        } else {
+            // Put the characted as-is.
+            output.push(chr);
+        }
+    }
+
+    if output == ident {
+        // While we didn't detect the correct case at the beginning, there
+        // may be special cases: e.g. `A` is both valid CamelCase and UPPER_SNAKE_CASE.
+        None
+    } else {
+        Some(output)
+    }
+}
+
+/// Converts an identifier to a lower_snake_case form.
+/// Returns `None` if the string is already in lower_snake_case.
+pub fn to_lower_snake_case(ident: &str) -> Option<String> {
+    // First, assume that it's UPPER_SNAKE_CASE.
+    match detect_case(ident) {
+        DetectedCase::LowerSnakeCase => return None,
+        DetectedCase::UpperSnakeCase => {
+            return Some(ident.chars().map(|chr| chr.to_ascii_lowercase()).collect())
+        }
+        _ => {}
+    }
+
+    // Otherwise, assume that it's CamelCase.
+    let lower_snake_case = stdx::to_lower_snake_case(ident);
+
+    if lower_snake_case == ident {
+        // While we didn't detect the correct case at the beginning, there
+        // may be special cases: e.g. `a` is both valid camelCase and snake_case.
+        None
+    } else {
+        Some(lower_snake_case)
+    }
+}
+
+/// Converts an identifier to an UPPER_SNAKE_CASE form.
+/// Returns `None` if the string is already is UPPER_SNAKE_CASE.
+pub fn to_upper_snake_case(ident: &str) -> Option<String> {
+    match detect_case(ident) {
+        DetectedCase::UpperSnakeCase => return None,
+        DetectedCase::LowerSnakeCase => {
+            return Some(ident.chars().map(|chr| chr.to_ascii_uppercase()).collect())
+        }
+        _ => {}
+    }
+
+    // Normalize the string from whatever form it's in currently, and then just make it uppercase.
+    let upper_snake_case = stdx::to_upper_snake_case(ident);
+
+    if upper_snake_case == ident {
+        // While we didn't detect the correct case at the beginning, there
+        // may be special cases: e.g. `A` is both valid CamelCase and UPPER_SNAKE_CASE.
+        None
+    } else {
+        Some(upper_snake_case)
+    }
+}
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+    use expect_test::{expect, Expect};
+
+    fn check<F: Fn(&str) -> Option<String>>(fun: F, input: &str, expect: Expect) {
+        // `None` is translated to empty string, meaning that there is nothing to fix.
+        let output = fun(input).unwrap_or_default();
+
+        expect.assert_eq(&output);
+    }
+
+    #[test]
+    fn test_to_lower_snake_case() {
+        check(to_lower_snake_case, "lower_snake_case", expect![[""]]);
+        check(to_lower_snake_case, "UPPER_SNAKE_CASE", expect![["upper_snake_case"]]);
+        check(to_lower_snake_case, "Weird_Case", expect![["weird_case"]]);
+        check(to_lower_snake_case, "CamelCase", expect![["camel_case"]]);
+        check(to_lower_snake_case, "lowerCamelCase", expect![["lower_camel_case"]]);
+        check(to_lower_snake_case, "a", expect![[""]]);
+    }
+
+    #[test]
+    fn test_to_camel_case() {
+        check(to_camel_case, "CamelCase", expect![[""]]);
+        check(to_camel_case, "CamelCase_", expect![[""]]);
+        check(to_camel_case, "_CamelCase", expect![[""]]);
+        check(to_camel_case, "lowerCamelCase", expect![["LowerCamelCase"]]);
+        check(to_camel_case, "lower_snake_case", expect![["LowerSnakeCase"]]);
+        check(to_camel_case, "UPPER_SNAKE_CASE", expect![["UpperSnakeCase"]]);
+        check(to_camel_case, "Weird_Case", expect![["WeirdCase"]]);
+        check(to_camel_case, "name", expect![["Name"]]);
+        check(to_camel_case, "A", expect![[""]]);
+    }
+
+    #[test]
+    fn test_to_upper_snake_case() {
+        check(to_upper_snake_case, "UPPER_SNAKE_CASE", expect![[""]]);
+        check(to_upper_snake_case, "lower_snake_case", expect![["LOWER_SNAKE_CASE"]]);
+        check(to_upper_snake_case, "Weird_Case", expect![["WEIRD_CASE"]]);
+        check(to_upper_snake_case, "CamelCase", expect![["CAMEL_CASE"]]);
+        check(to_upper_snake_case, "lowerCamelCase", expect![["LOWER_CAMEL_CASE"]]);
+        check(to_upper_snake_case, "A", expect![[""]]);
+    }
+}
diff --git a/crates/hir_ty/src/diagnostics/decl_check/str_helpers.rs b/crates/hir_ty/src/diagnostics/decl_check/str_helpers.rs
deleted file mode 100644 (file)
index 2e1468c..0000000
+++ /dev/null
@@ -1,195 +0,0 @@
-//! Functions for string case manipulation, such as detecting the identifier case,
-//! and converting it into appropriate form.
-
-#[derive(Debug)]
-enum DetectedCase {
-    LowerCamelCase,
-    UpperCamelCase,
-    LowerSnakeCase,
-    UpperSnakeCase,
-    Unknown,
-}
-
-fn detect_case(ident: &str) -> DetectedCase {
-    let trimmed_ident = ident.trim_matches('_');
-    let first_lowercase = trimmed_ident.starts_with(|chr: char| chr.is_ascii_lowercase());
-    let mut has_lowercase = first_lowercase;
-    let mut has_uppercase = false;
-    let mut has_underscore = false;
-
-    for chr in trimmed_ident.chars() {
-        if chr == '_' {
-            has_underscore = true;
-        } else if chr.is_ascii_uppercase() {
-            has_uppercase = true;
-        } else if chr.is_ascii_lowercase() {
-            has_lowercase = true;
-        }
-    }
-
-    if has_uppercase {
-        if !has_lowercase {
-            DetectedCase::UpperSnakeCase
-        } else if !has_underscore {
-            if first_lowercase {
-                DetectedCase::LowerCamelCase
-            } else {
-                DetectedCase::UpperCamelCase
-            }
-        } else {
-            // It has uppercase, it has lowercase, it has underscore.
-            // No assumptions here
-            DetectedCase::Unknown
-        }
-    } else {
-        DetectedCase::LowerSnakeCase
-    }
-}
-
-/// Converts an identifier to an UpperCamelCase form.
-/// Returns `None` if the string is already is UpperCamelCase.
-pub fn to_camel_case(ident: &str) -> Option<String> {
-    let detected_case = detect_case(ident);
-
-    match detected_case {
-        DetectedCase::UpperCamelCase => return None,
-        DetectedCase::LowerCamelCase => {
-            let mut first_capitalized = false;
-            let output = ident
-                .chars()
-                .map(|chr| {
-                    if !first_capitalized && chr.is_ascii_lowercase() {
-                        first_capitalized = true;
-                        chr.to_ascii_uppercase()
-                    } else {
-                        chr
-                    }
-                })
-                .collect();
-            return Some(output);
-        }
-        _ => {}
-    }
-
-    let mut output = String::with_capacity(ident.len());
-
-    let mut capital_added = false;
-    for chr in ident.chars() {
-        if chr.is_alphabetic() {
-            if !capital_added {
-                output.push(chr.to_ascii_uppercase());
-                capital_added = true;
-            } else {
-                output.push(chr.to_ascii_lowercase());
-            }
-        } else if chr == '_' {
-            // Skip this character and make the next one capital.
-            capital_added = false;
-        } else {
-            // Put the characted as-is.
-            output.push(chr);
-        }
-    }
-
-    if output == ident {
-        // While we didn't detect the correct case at the beginning, there
-        // may be special cases: e.g. `A` is both valid CamelCase and UPPER_SNAKE_CASE.
-        None
-    } else {
-        Some(output)
-    }
-}
-
-/// Converts an identifier to a lower_snake_case form.
-/// Returns `None` if the string is already in lower_snake_case.
-pub fn to_lower_snake_case(ident: &str) -> Option<String> {
-    // First, assume that it's UPPER_SNAKE_CASE.
-    match detect_case(ident) {
-        DetectedCase::LowerSnakeCase => return None,
-        DetectedCase::UpperSnakeCase => {
-            return Some(ident.chars().map(|chr| chr.to_ascii_lowercase()).collect())
-        }
-        _ => {}
-    }
-
-    // Otherwise, assume that it's CamelCase.
-    let lower_snake_case = stdx::to_lower_snake_case(ident);
-
-    if lower_snake_case == ident {
-        // While we didn't detect the correct case at the beginning, there
-        // may be special cases: e.g. `a` is both valid camelCase and snake_case.
-        None
-    } else {
-        Some(lower_snake_case)
-    }
-}
-
-/// Converts an identifier to an UPPER_SNAKE_CASE form.
-/// Returns `None` if the string is already is UPPER_SNAKE_CASE.
-pub fn to_upper_snake_case(ident: &str) -> Option<String> {
-    match detect_case(ident) {
-        DetectedCase::UpperSnakeCase => return None,
-        DetectedCase::LowerSnakeCase => {
-            return Some(ident.chars().map(|chr| chr.to_ascii_uppercase()).collect())
-        }
-        _ => {}
-    }
-
-    // Normalize the string from whatever form it's in currently, and then just make it uppercase.
-    let upper_snake_case =
-        stdx::to_lower_snake_case(ident).chars().map(|c| c.to_ascii_uppercase()).collect();
-
-    if upper_snake_case == ident {
-        // While we didn't detect the correct case at the beginning, there
-        // may be special cases: e.g. `A` is both valid CamelCase and UPPER_SNAKE_CASE.
-        None
-    } else {
-        Some(upper_snake_case)
-    }
-}
-
-#[cfg(test)]
-mod tests {
-    use super::*;
-    use expect_test::{expect, Expect};
-
-    fn check<F: Fn(&str) -> Option<String>>(fun: F, input: &str, expect: Expect) {
-        // `None` is translated to empty string, meaning that there is nothing to fix.
-        let output = fun(input).unwrap_or_default();
-
-        expect.assert_eq(&output);
-    }
-
-    #[test]
-    fn test_to_lower_snake_case() {
-        check(to_lower_snake_case, "lower_snake_case", expect![[""]]);
-        check(to_lower_snake_case, "UPPER_SNAKE_CASE", expect![["upper_snake_case"]]);
-        check(to_lower_snake_case, "Weird_Case", expect![["weird_case"]]);
-        check(to_lower_snake_case, "CamelCase", expect![["camel_case"]]);
-        check(to_lower_snake_case, "lowerCamelCase", expect![["lower_camel_case"]]);
-        check(to_lower_snake_case, "a", expect![[""]]);
-    }
-
-    #[test]
-    fn test_to_camel_case() {
-        check(to_camel_case, "CamelCase", expect![[""]]);
-        check(to_camel_case, "CamelCase_", expect![[""]]);
-        check(to_camel_case, "_CamelCase", expect![[""]]);
-        check(to_camel_case, "lowerCamelCase", expect![["LowerCamelCase"]]);
-        check(to_camel_case, "lower_snake_case", expect![["LowerSnakeCase"]]);
-        check(to_camel_case, "UPPER_SNAKE_CASE", expect![["UpperSnakeCase"]]);
-        check(to_camel_case, "Weird_Case", expect![["WeirdCase"]]);
-        check(to_camel_case, "name", expect![["Name"]]);
-        check(to_camel_case, "A", expect![[""]]);
-    }
-
-    #[test]
-    fn test_to_upper_snake_case() {
-        check(to_upper_snake_case, "UPPER_SNAKE_CASE", expect![[""]]);
-        check(to_upper_snake_case, "lower_snake_case", expect![["LOWER_SNAKE_CASE"]]);
-        check(to_upper_snake_case, "Weird_Case", expect![["WEIRD_CASE"]]);
-        check(to_upper_snake_case, "CamelCase", expect![["CAMEL_CASE"]]);
-        check(to_upper_snake_case, "lowerCamelCase", expect![["LOWER_CAMEL_CASE"]]);
-        check(to_upper_snake_case, "A", expect![[""]]);
-    }
-}
index b55de813ec521e1a7be9b301db4355d5bb853e3a..59d89f47d1c2d9946f2bdd90030883be5e7934ab 100644 (file)
@@ -28,7 +28,7 @@ fn drop(&mut self) {
     Guard { label, start: Instant::now() }
 }
 
-pub fn to_lower_snake_case(s: &str) -> String {
+fn to_snake_case<F: Fn(&char) -> char>(s: &str, change_case: F) -> String {
     let mut buf = String::with_capacity(s.len());
     let mut prev = false;
     for c in s.chars() {
@@ -41,11 +41,19 @@ pub fn to_lower_snake_case(s: &str) -> String {
         }
         prev = true;
 
-        buf.push(c.to_ascii_lowercase());
+        buf.push(change_case(&c));
     }
     buf
 }
 
+pub fn to_lower_snake_case(s: &str) -> String {
+    to_snake_case(s, char::to_ascii_lowercase)
+}
+
+pub fn to_upper_snake_case(s: &str) -> String {
+    to_snake_case(s, char::to_ascii_uppercase)
+}
+
 pub fn replace(buf: &mut String, from: char, to: &str) {
     if !buf.contains(from) {
         return;