Skip to content

Commit 83a0f4a

Browse files
committed
Lintcheck: Limit output to 200 warnings per lint
1 parent e017f96 commit 83a0f4a

File tree

1 file changed

+74
-5
lines changed

1 file changed

+74
-5
lines changed

lintcheck/src/json.rs

+74-5
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
use std::fmt::Write;
12
use std::fs;
23
use std::path::Path;
34

@@ -52,11 +53,13 @@ fn load_warnings(path: &Path) -> Vec<LintJson> {
5253
serde_json::from_slice(&file).unwrap_or_else(|e| panic!("failed to deserialize {}: {e}", path.display()))
5354
}
5455

55-
fn print_warnings(title: &str, warnings: &[LintJson]) {
56+
fn print_warnings(title: &str, mut warnings: Vec<LintJson>) {
5657
if warnings.is_empty() {
5758
return;
5859
}
5960

61+
let redacted_msg = limit_by_lint(&mut warnings, |lint| &lint.lint);
62+
6063
//We have to use HTML here to be able to manually add an id.
6164
println!(r#"<h3 id="{title}">{title}</h3>"#);
6265
println!();
@@ -68,13 +71,19 @@ fn print_warnings(title: &str, warnings: &[LintJson]) {
6871
println!("```");
6972
println!();
7073
}
74+
75+
if let Some(redacted_msg) = redacted_msg {
76+
println!("{redacted_msg}");
77+
}
7178
}
7279

73-
fn print_changed_diff(changed: &[(LintJson, LintJson)]) {
80+
fn print_changed_diff(mut changed: Vec<(LintJson, LintJson)>) {
7481
if changed.is_empty() {
7582
return;
7683
}
7784

85+
let redacted_msg = limit_by_lint(&mut changed, |(lint, _)| &lint.lint);
86+
7887
//We have to use HTML here to be able to manually add an id.
7988
println!(r#"<h3 id="changed">Changed</h3>"#);
8089
println!();
@@ -99,6 +108,10 @@ fn print_changed_diff(changed: &[(LintJson, LintJson)]) {
99108
}
100109
println!("```");
101110
}
111+
112+
if let Some(redacted_msg) = redacted_msg {
113+
println!("{redacted_msg}");
114+
}
102115
}
103116

104117
pub(crate) fn diff(old_path: &Path, new_path: &Path) {
@@ -130,9 +143,65 @@ pub(crate) fn diff(old_path: &Path, new_path: &Path) {
130143
println!();
131144
println!();
132145

133-
print_warnings("Added", &added);
134-
print_warnings("Removed", &removed);
135-
print_changed_diff(&changed);
146+
print_warnings("Added", added);
147+
print_warnings("Removed", removed);
148+
print_changed_diff(changed);
149+
}
150+
151+
/// This function limits the number of lints in the collection if needed.
152+
///
153+
/// It's honestly amazing that a function like this is needed. But some restriction
154+
/// lints (Looking at you `implicit_return` and `if_then_some_else_none`) trigger a lot
155+
/// like 60'000+ times in our CI.
156+
///
157+
/// Each lint in the list will be limited to 200 messages
158+
fn limit_by_lint<T, F>(list: &mut Vec<T>, lint_key: F) -> Option<String>
159+
where
160+
F: Fn(&T) -> &str,
161+
{
162+
const PER_LINT_LIMIT: usize = 200;
163+
164+
// Everything is fine, nothing to see here.
165+
if list.len() < PER_LINT_LIMIT {
166+
return None;
167+
}
168+
169+
let mut keyed_list: Vec<_> = list
170+
.drain(..)
171+
.map(|warning| (lint_key(&warning).to_string(), warning))
172+
.collect();
173+
174+
keyed_list.sort_unstable_by(|(a, _), (b, _)| a.cmp(b));
175+
176+
let last_idx = keyed_list.len() - 1;
177+
let mut current_key = keyed_list[0].0.clone();
178+
let mut current_ctn = 0;
179+
let mut limit_message = String::new();
180+
keyed_list
181+
.drain(..)
182+
.enumerate()
183+
.filter_map(|(idx, (key, warning))| {
184+
if key != current_key || idx == last_idx {
185+
if current_ctn >= PER_LINT_LIMIT {
186+
writeln!(
187+
&mut limit_message,
188+
"* Hid {} messages for `{}`",
189+
current_ctn - PER_LINT_LIMIT,
190+
key
191+
)
192+
.unwrap();
193+
}
194+
current_key = key;
195+
current_ctn = 0;
196+
}
197+
198+
current_ctn += 1;
199+
200+
(current_ctn < PER_LINT_LIMIT).then_some(warning)
201+
})
202+
.collect_into(list);
203+
204+
Some(limit_message)
136205
}
137206

138207
/// This generates the `x added` string for the start of the job summery.

0 commit comments

Comments
 (0)