[CFE] Spell checker improvements
- Spell checker in interactive mode shows the 'close words' (if any)
when asking if wanting to add a word to the directory. Hopefully this
will make it less likely adding wrong words to the dictionary.
- When finding 'close' words it now also tries to insert a letter at the
end which it erroneously didn't before. The close words method is also
tested better.
Change-Id: Ic2628fc261ecb4d9c9322a0ab8c462b174707051
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/403863
Commit-Queue: Jens Johansen <jensj@google.com>
Reviewed-by: Johnni Winther <johnniwinther@google.com>
diff --git a/pkg/front_end/test/messages_suite.dart b/pkg/front_end/test/messages_suite.dart
index c4d5a75..b476ccd 100644
--- a/pkg/front_end/test/messages_suite.dart
+++ b/pkg/front_end/test/messages_suite.dart
@@ -89,7 +89,7 @@
final bool fastOnly;
final bool interactive;
- final Set<String> reportedWords = {};
+ final Map<String, List<String>?> reportedWordsAndAlternatives = {};
final Set<String> reportedWordsDenylisted = {};
@override
@@ -103,7 +103,7 @@
}
String suitePath = suiteFile.path;
spell.spellSummarizeAndInteractiveMode(
- reportedWords,
+ reportedWordsAndAlternatives,
reportedWordsDenylisted,
[spell.Dictionaries.cfeMessages],
interactive,
@@ -182,7 +182,8 @@
messageToUse = messageForDenyListed;
reportedWordsDenylisted.add(spellResult.misspelledWords![i]);
} else {
- reportedWords.add(spellResult.misspelledWords![i]);
+ reportedWordsAndAlternatives[spellResult.misspelledWords![i]] =
+ spellResult.misspelledWordsAlternatives![i];
}
result.add(command_line_reporting.formatErrorMessage(
source!.getTextLine(location.line),
diff --git a/pkg/front_end/test/spell_checking_utils.dart b/pkg/front_end/test/spell_checking_utils.dart
index 2f3c928..508d229 100644
--- a/pkg/front_end/test/spell_checking_utils.dart
+++ b/pkg/front_end/test/spell_checking_utils.dart
@@ -82,28 +82,36 @@
(result ??= <String>[]).add(w);
}
+ void checkInsert(String before, String afterIncluding) {
+ for (int j = 0; j < 25; j++) {
+ String c = new String.fromCharCode(97 + j);
+ String insertedLetter = "${before}${c}${afterIncluding}";
+ if (check(insertedLetter)) ok(insertedLetter);
+ }
+ }
+
// Delete a letter, insert a letter or change a letter and lookup.
for (int i = 0; i < word.length; i++) {
String before = word.substring(0, i);
- String after = word.substring(i + 1);
- String afterIncluding = word.substring(i);
+ String afterExcluding = word.substring(i + 1);
{
- String deletedLetter = before + after;
+ String deletedLetter = "${before}${afterExcluding}";
if (check(deletedLetter)) ok(deletedLetter);
}
+
+ checkInsert(before, word.substring(i));
+
for (int j = 0; j < 25; j++) {
String c = new String.fromCharCode(97 + j);
- String insertedLetter = before + c + afterIncluding;
- if (check(insertedLetter)) ok(insertedLetter);
- }
- for (int j = 0; j < 25; j++) {
- String c = new String.fromCharCode(97 + j);
- String replacedLetter = before + c + after;
+ String replacedLetter = "${before}${c}${afterExcluding}";
if (check(replacedLetter)) ok(replacedLetter);
}
}
+ // Check insert at end.
+ checkInsert(word, "");
+
return result;
}
@@ -347,7 +355,7 @@
}
void spellSummarizeAndInteractiveMode(
- Set<String> reportedWords,
+ Map<String, List<String>?> reportedWordsAndAlternatives,
Set<String> reportedWordsDenylisted,
List<Dictionaries> dictionaries,
bool interactive,
@@ -365,8 +373,8 @@
}
print("================");
}
- if (reportedWords.isNotEmpty) {
- bool isSingular = reportedWords.length == 1;
+ if (reportedWordsAndAlternatives.isNotEmpty) {
+ bool isSingular = reportedWordsAndAlternatives.length == 1;
String suffix = isSingular ? "" : "s";
String were = isSingular ? "was" : "were";
String are = isSingular ? "is" : "are";
@@ -394,8 +402,15 @@
if (interactive && dictionaryToUse != null) {
List<String> addedWords = <String>[];
- for (String s in reportedWords) {
- print("- $s");
+ for (MapEntry<String, List<String>?> wordAndAlternative
+ in reportedWordsAndAlternatives.entries) {
+ String s = wordAndAlternative.key;
+ List<String>? alternative = wordAndAlternative.value;
+ if (alternative != null) {
+ print(" - $s (notice close word(s)): ${alternative.join(", ")})");
+ } else {
+ print(" - $s");
+ }
String answer;
bool? add;
while (true) {
@@ -451,7 +466,7 @@
dictionaryFile.writeAsStringSync(lines.join("\n"));
}
} else {
- for (String s in reportedWords) {
+ for (String s in reportedWordsAndAlternatives.keys) {
print("$s");
}
if (dictionaries.isNotEmpty) {
diff --git a/pkg/front_end/test/spell_checking_utils_test.dart b/pkg/front_end/test/spell_checking_utils_test.dart
index c4aa4dc..797caf4 100644
--- a/pkg/front_end/test/spell_checking_utils_test.dart
+++ b/pkg/front_end/test/spell_checking_utils_test.dart
@@ -90,6 +90,33 @@
"explicitley", ["explicitly"], {"foo", "explicitly", "bar"});
expectAlternative("explicitlqqqqy", null, {"foo", "explicitly", "bar"});
+ // Insert first letter.
+ expectAlternative("ar", ["bar"], {"foo", "explicitly", "bar"});
+
+ // Insert middle letter.
+ expectAlternative("br", ["bar"], {"foo", "explicitly", "bar"});
+
+ // Insert last letter.
+ expectAlternative("ba", ["bar"], {"foo", "explicitly", "bar"});
+
+ // Delete first letter.
+ expectAlternative("xbar", ["bar"], {"foo", "explicitly", "bar"});
+
+ // Delete middle letter.
+ expectAlternative("bxar", ["bar"], {"foo", "explicitly", "bar"});
+
+ // Delete last letter.
+ expectAlternative("barx", ["bar"], {"foo", "explicitly", "bar"});
+
+ // Replace first letter.
+ expectAlternative("car", ["bar"], {"foo", "explicitly", "bar"});
+
+ // Replace middle letter.
+ expectAlternative("bcr", ["bar"], {"foo", "explicitly", "bar"});
+
+ // Replace last letter.
+ expectAlternative("bac", ["bar"], {"foo", "explicitly", "bar"});
+
print("OK");
}
diff --git a/pkg/front_end/test/spelling_test_base.dart b/pkg/front_end/test/spelling_test_base.dart
index b60c5b6..ffef67f 100644
--- a/pkg/front_end/test/spelling_test_base.dart
+++ b/pkg/front_end/test/spelling_test_base.dart
@@ -36,7 +36,7 @@
String get repoRelativeSuitePath;
- Set<String> reportedWords = {};
+ Map<String, List<String>?> reportedWordsAndAlternatives = {};
Set<String> reportedWordsDenylisted = {};
@override
@@ -54,7 +54,7 @@
}
String suitePath = suiteFile.path;
spell.spellSummarizeAndInteractiveMode(
- reportedWords,
+ reportedWordsAndAlternatives,
reportedWordsDenylisted,
dictionaries,
interactive,
@@ -92,7 +92,7 @@
context.reportedWordsDenylisted.add(word);
} else {
message = "The word '$word' is not in our dictionary.";
- context.reportedWords.add(word);
+ context.reportedWordsAndAlternatives[word] = alternatives;
}
if (alternatives != null && alternatives.isNotEmpty) {
message += "\n\nThe following word(s) was 'close' "