about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--crates/hir_ty/src/diagnostics/decl_check/case_conv.rs3
-rw-r--r--crates/ide_diagnostics/src/handlers/incorrect_case.rs4
-rw-r--r--crates/stdx/src/lib.rs47
3 files changed, 40 insertions, 14 deletions
diff --git a/crates/hir_ty/src/diagnostics/decl_check/case_conv.rs b/crates/hir_ty/src/diagnostics/decl_check/case_conv.rs
index 7c477d4945c..88d607194f7 100644
--- a/crates/hir_ty/src/diagnostics/decl_check/case_conv.rs
+++ b/crates/hir_ty/src/diagnostics/decl_check/case_conv.rs
@@ -161,6 +161,7 @@ mod tests {
         check(to_lower_snake_case, "lowerCamelCase", expect![["lower_camel_case"]]);
         check(to_lower_snake_case, "a", expect![[""]]);
         check(to_lower_snake_case, "abc", expect![[""]]);
+        check(to_lower_snake_case, "foo__bar", expect![["foo_bar"]]);
     }
 
     #[test]
@@ -192,5 +193,7 @@ mod tests {
         check(to_upper_snake_case, "A", expect![[""]]);
         check(to_upper_snake_case, "ABC", expect![[""]]);
         check(to_upper_snake_case, "X86_64", expect![[""]]);
+        check(to_upper_snake_case, "FOO_BAr", expect![["FOO_BAR"]]);
+        check(to_upper_snake_case, "FOO__BAR", expect![["FOO_BAR"]]);
     }
 }
diff --git a/crates/ide_diagnostics/src/handlers/incorrect_case.rs b/crates/ide_diagnostics/src/handlers/incorrect_case.rs
index e2bbabd53c8..6990b19cf3a 100644
--- a/crates/ide_diagnostics/src/handlers/incorrect_case.rs
+++ b/crates/ide_diagnostics/src/handlers/incorrect_case.rs
@@ -102,8 +102,8 @@ fn some_fn() {
 "#,
             r#"
 fn some_fn() {
-    let what_a_weird_formatting = 10;
-    another_func(what_a_weird_formatting);
+    let what_aweird_formatting = 10;
+    another_func(what_aweird_formatting);
 }
 "#,
         );
diff --git a/crates/stdx/src/lib.rs b/crates/stdx/src/lib.rs
index bfa6024679b..ee23f579345 100644
--- a/crates/stdx/src/lib.rs
+++ b/crates/stdx/src/lib.rs
@@ -1,4 +1,5 @@
 //! Missing batteries for standard libraries.
+use std::iter;
 use std::{cmp::Ordering, ops, time::Instant};
 
 mod macros;
@@ -37,22 +38,44 @@ pub fn to_lower_snake_case(s: &str) -> String {
 pub fn to_upper_snake_case(s: &str) -> String {
     to_snake_case(s, char::to_ascii_uppercase)
 }
-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() {
-        // `&& prev` is required to not insert `_` before the first symbol.
-        if c.is_ascii_uppercase() && prev {
-            // This check is required to not translate `Weird_Case` into `weird__case`.
-            if !buf.ends_with('_') {
-                buf.push('_');
+
+// Code partially taken from rust/compiler/rustc_lint/src/nonstandard_style.rs
+// commit: 9626f2b
+fn to_snake_case<F: Fn(&char) -> char>(mut s: &str, change_case: F) -> String {
+    let mut words = vec![];
+
+    // Preserve leading underscores
+    s = s.trim_start_matches(|c: char| {
+        if c == '_' {
+            words.push(String::new());
+            true
+        } else {
+            false
+        }
+    });
+
+    for s in s.split('_') {
+        let mut last_upper = false;
+        let mut buf = String::new();
+
+        if s.is_empty() {
+            continue;
+        }
+
+        for ch in s.chars() {
+            if !buf.is_empty() && buf != "'" && ch.is_uppercase() && !last_upper {
+                words.push(buf);
+                buf = String::new();
             }
+
+            last_upper = ch.is_uppercase();
+            buf.extend(iter::once(change_case(&ch)));
         }
-        prev = true;
 
-        buf.push(change_case(&c));
+        words.push(buf);
     }
-    buf
+
+    words.join("_")
 }
 
 pub fn replace(buf: &mut String, from: char, to: &str) {