From 91334e0a799c35d6adf0a226a2f0aee0d70896e3 Mon Sep 17 00:00:00 2001 From: cjkenn Date: Fri, 3 Jan 2020 15:53:03 -0800 Subject: [PATCH 1/3] add a check for variable names that might match by word --- src/libsyntax/util/lev_distance.rs | 33 ++++++++++++++++++++---- src/libsyntax/util/lev_distance/tests.rs | 6 +++++ 2 files changed, 34 insertions(+), 5 deletions(-) diff --git a/src/libsyntax/util/lev_distance.rs b/src/libsyntax/util/lev_distance.rs index f55b58d7d137a..8ddda1720b8d7 100644 --- a/src/libsyntax/util/lev_distance.rs +++ b/src/libsyntax/util/lev_distance.rs @@ -52,14 +52,15 @@ where T: Iterator, { 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 { + 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 f65f9275d0341..222661687c1c2 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")) + ); }) } From 27ea4c855e2adeeea9e5e58622715d45fd9c7801 Mon Sep 17 00:00:00 2001 From: cjkenn Date: Fri, 3 Jan 2020 17:01:16 -0800 Subject: [PATCH 2/3] missed tidy check --- src/libsyntax/util/lev_distance.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libsyntax/util/lev_distance.rs b/src/libsyntax/util/lev_distance.rs index 8ddda1720b8d7..afbf91c00554e 100644 --- a/src/libsyntax/util/lev_distance.rs +++ b/src/libsyntax/util/lev_distance.rs @@ -54,7 +54,8 @@ where 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, levenshtein_match) = name_vec.iter() + 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 } @@ -74,7 +75,6 @@ where }, ) }); - // Priority of matches: // 1. Exact case insensitive match // 2. Levenshtein distance match From e01e8b9256587a074968b440aa30d43b31642cb5 Mon Sep 17 00:00:00 2001 From: cjkenn Date: Sat, 4 Jan 2020 10:58:04 -0800 Subject: [PATCH 3/3] add ui test --- .../ui/suggestions/issue-66968-suggest-sorted-words.rs | 4 ++++ .../suggestions/issue-66968-suggest-sorted-words.stderr | 9 +++++++++ 2 files changed, 13 insertions(+) create mode 100644 src/test/ui/suggestions/issue-66968-suggest-sorted-words.rs create mode 100644 src/test/ui/suggestions/issue-66968-suggest-sorted-words.stderr diff --git a/src/test/ui/suggestions/issue-66968-suggest-sorted-words.rs b/src/test/ui/suggestions/issue-66968-suggest-sorted-words.rs new file mode 100644 index 0000000000000..440bb653a83c3 --- /dev/null +++ b/src/test/ui/suggestions/issue-66968-suggest-sorted-words.rs @@ -0,0 +1,4 @@ +fn main() { + let a_longer_variable_name = 1; + println!("{}", a_variable_longer_name); //~ ERROR E0425 +} diff --git a/src/test/ui/suggestions/issue-66968-suggest-sorted-words.stderr b/src/test/ui/suggestions/issue-66968-suggest-sorted-words.stderr new file mode 100644 index 0000000000000..d7b33ea41f79a --- /dev/null +++ b/src/test/ui/suggestions/issue-66968-suggest-sorted-words.stderr @@ -0,0 +1,9 @@ +error[E0425]: cannot find value `a_variable_longer_name` in this scope + --> $DIR/issue-66968-suggest-sorted-words.rs:3:20 + | +LL | println!("{}", a_variable_longer_name); + | ^^^^^^^^^^^^^^^^^^^^^^ help: a local variable with a similar name exists: `a_longer_variable_name` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0425`.