Sort lint_groups in no_lint_suggestion

The no_lint_suggestion routine passes a vector of lint group names
to find_best_match_for_name.  That routine depends on the sort
order of its input vector, which matters in case multiple inputs
are at the same Levenshtein distance to the target name.

However, no_lint_suggestion currently just passes lint_groups.keys()
as input vector - this is sorted in hash value order, which is not
guaranteed to be stable, and in fact differs between big- and
little-endian host platforms, causing test failures on s390x.

To fix this, always sort the lint groups before using their names
as input to find_best_match_for_name.  In addition, deprecated
lint groups should never be suggested, so filter those out.

Fixes https://github.com/rust-lang/rust/issues/105379
This commit is contained in:
Ulrich Weigand 2022-12-21 17:27:45 +01:00
parent 4653c93e44
commit 30fbfd5f05

View File

@ -483,7 +483,16 @@ fn no_lint_suggestion(&self, lint_name: &str) -> CheckLintNameResult<'_> {
return CheckLintNameResult::NoLint(Some(Symbol::intern(&name_lower)));
}
// ...if not, search for lints with a similar name
let groups = self.lint_groups.keys().copied().map(Symbol::intern);
// Note: find_best_match_for_name depends on the sort order of its input vector.
// To ensure deterministic output, sort elements of the lint_groups hash map.
// Also, never suggest deprecated lint groups.
let mut groups: Vec<_> = self
.lint_groups
.iter()
.filter_map(|(k, LintGroup { depr, .. })| if depr.is_none() { Some(k) } else { None })
.collect();
groups.sort();
let groups = groups.iter().map(|k| Symbol::intern(k));
let lints = self.lints.iter().map(|l| Symbol::intern(&l.name_lower()));
let names: Vec<Symbol> = groups.chain(lints).collect();
let suggestion = find_best_match_for_name(&names, Symbol::intern(&name_lower), None);