about summary refs log tree commit diff
diff options
context:
space:
mode:
authorcjkenn <cam.j.kennedy@gmail.com>2020-01-03 15:53:03 -0800
committercjkenn <cam.j.kennedy@gmail.com>2020-01-03 15:53:03 -0800
commit91334e0a799c35d6adf0a226a2f0aee0d70896e3 (patch)
treea13789d8c1e7cbe885a83b4851ab1b65aaafa2fa
parent0ec370670220b712b042ee09aab067ec7e5878d5 (diff)
downloadrust-91334e0a799c35d6adf0a226a2f0aee0d70896e3.tar.gz
rust-91334e0a799c35d6adf0a226a2f0aee0d70896e3.zip
add a check for variable names that might match by word
-rw-r--r--src/libsyntax/util/lev_distance.rs33
-rw-r--r--src/libsyntax/util/lev_distance/tests.rs6
2 files changed, 34 insertions, 5 deletions
diff --git a/src/libsyntax/util/lev_distance.rs b/src/libsyntax/util/lev_distance.rs
index f55b58d7d13..8ddda1720b8 100644
--- a/src/libsyntax/util/lev_distance.rs
+++ b/src/libsyntax/util/lev_distance.rs
@@ -52,14 +52,15 @@ where
     T: Iterator<Item = &'a Symbol>,
 {
     let max_dist = dist.map_or_else(|| cmp::max(lookup.len(), 3) / 3, |d| d);
+    let name_vec: Vec<&Symbol> = iter_names.collect();
 
-    let (case_insensitive_match, levenstein_match) = iter_names
+    let (case_insensitive_match, levenshtein_match) = name_vec.iter()
         .filter_map(|&name| {
             let dist = lev_distance(lookup, &name.as_str());
             if dist <= max_dist { Some((name, dist)) } else { None }
         })
         // Here we are collecting the next structure:
-        // (case_insensitive_match, (levenstein_match, levenstein_distance))
+        // (case_insensitive_match, (levenshtein_match, levenshtein_distance))
         .fold((None, None), |result, (candidate, dist)| {
             (
                 if candidate.as_str().to_uppercase() == lookup.to_uppercase() {
@@ -73,10 +74,32 @@ where
                 },
             )
         });
-
+    
+    // Priority of matches:
+    // 1. Exact case insensitive match
+    // 2. Levenshtein distance match
+    // 3. Sorted word match
     if let Some(candidate) = case_insensitive_match {
-        Some(candidate) // exact case insensitive match has a higher priority
+        Some(*candidate)
+    } else if levenshtein_match.is_some() {
+        levenshtein_match.map(|(candidate, _)| *candidate)
     } else {
-        levenstein_match.map(|(candidate, _)| candidate)
+        find_match_by_sorted_words(name_vec, lookup)
     }
 }
+
+fn find_match_by_sorted_words<'a>(iter_names: Vec<&'a Symbol>, lookup: &str) -> Option<Symbol> {
+    iter_names.iter().fold(None, |result, candidate| {
+        if sort_by_words(&candidate.as_str()) == sort_by_words(lookup) {
+            Some(**candidate)
+        } else {
+            result
+        }
+    })
+}
+
+fn sort_by_words(name: &str) -> String {
+    let mut split_words: Vec<&str> = name.split('_').collect();
+    split_words.sort();
+    split_words.join("_")
+}
diff --git a/src/libsyntax/util/lev_distance/tests.rs b/src/libsyntax/util/lev_distance/tests.rs
index f65f9275d03..222661687c1 100644
--- a/src/libsyntax/util/lev_distance/tests.rs
+++ b/src/libsyntax/util/lev_distance/tests.rs
@@ -46,5 +46,11 @@ fn test_find_best_match_for_name() {
             find_best_match_for_name(input.iter(), "aaaa", Some(4)),
             Some(Symbol::intern("AAAA"))
         );
+
+        let input = vec![Symbol::intern("a_longer_variable_name")];
+        assert_eq!(
+            find_best_match_for_name(input.iter(), "a_variable_longer_name", None),
+            Some(Symbol::intern("a_longer_variable_name"))
+        );
     })
 }