Skip to content

Commit bdd23d1

Browse files
committed
Introduce a linter for diagnostic messages
1 parent cc65bf3 commit bdd23d1

File tree

5 files changed

+77
-1
lines changed

5 files changed

+77
-1
lines changed

Cargo.lock

+42
Original file line numberDiff line numberDiff line change
@@ -693,6 +693,7 @@ name = "compiletest"
693693
version = "0.0.0"
694694
dependencies = [
695695
"colored",
696+
"diaglint",
696697
"diff",
697698
"getopts",
698699
"glob",
@@ -947,6 +948,19 @@ dependencies = [
947948
"syn",
948949
]
949950

951+
[[package]]
952+
name = "diaglint"
953+
version = "0.1.8"
954+
source = "registry+https://github.com/rust-lang/crates.io-index"
955+
checksum = "3730e1cddacaff508f3dfc1cc050e27e2823a55c44664e0b3a64cbc1008b37f8"
956+
dependencies = [
957+
"annotate-snippets",
958+
"nom",
959+
"nom_locate",
960+
"serde",
961+
"serde_json",
962+
]
963+
950964
[[package]]
951965
name = "diff"
952966
version = "0.1.12"
@@ -2252,6 +2266,12 @@ dependencies = [
22522266
"macro-utils",
22532267
]
22542268

2269+
[[package]]
2270+
name = "minimal-lexical"
2271+
version = "0.1.3"
2272+
source = "registry+https://github.com/rust-lang/crates.io-index"
2273+
checksum = "0c835948974f68e0bd58636fc6c5b1fbff7b297e3046f11b3b3c18bbac012c6d"
2274+
22552275
[[package]]
22562276
name = "miniz_oxide"
22572277
version = "0.4.0"
@@ -2311,6 +2331,28 @@ version = "1.0.4"
23112331
source = "registry+https://github.com/rust-lang/crates.io-index"
23122332
checksum = "e4a24736216ec316047a1fc4252e27dabb04218aa4a3f37c6e7ddbf1f9782b54"
23132333

2334+
[[package]]
2335+
name = "nom"
2336+
version = "7.0.0"
2337+
source = "registry+https://github.com/rust-lang/crates.io-index"
2338+
checksum = "7ffd9d26838a953b4af82cbeb9f1592c6798916983959be223a7124e992742c1"
2339+
dependencies = [
2340+
"memchr",
2341+
"minimal-lexical",
2342+
"version_check",
2343+
]
2344+
2345+
[[package]]
2346+
name = "nom_locate"
2347+
version = "4.0.0"
2348+
source = "registry+https://github.com/rust-lang/crates.io-index"
2349+
checksum = "37794436ca3029a3089e0b95d42da1f0b565ad271e4d3bb4bad0c7bb70b10605"
2350+
dependencies = [
2351+
"bytecount",
2352+
"memchr",
2353+
"nom",
2354+
]
2355+
23142356
[[package]]
23152357
name = "ntapi"
23162358
version = "0.3.6"

src/tools/compiletest/Cargo.toml

+1
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ edition = "2021"
66
[dependencies]
77
colored = "2"
88
diff = "0.1.10"
9+
diaglint = "0.1.8"
910
unified-diff = "0.2.1"
1011
getopts = "0.2"
1112
tracing = "0.1"

src/tools/compiletest/src/header.rs

+11
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,8 @@ pub struct TestProps {
145145
pub run_rustfix: bool,
146146
// If true, `rustfix` will only apply `MachineApplicable` suggestions.
147147
pub rustfix_only_machine_applicable: bool,
148+
// Lints to ignore when checking diagnostics.
149+
pub ignored_diaglints: Vec<String>,
148150
pub assembly_output: Option<String>,
149151
// If true, the test is expected to ICE
150152
pub should_ice: bool,
@@ -188,6 +190,7 @@ impl TestProps {
188190
failure_status: -1,
189191
run_rustfix: false,
190192
rustfix_only_machine_applicable: false,
193+
ignored_diaglints: vec![],
191194
assembly_output: None,
192195
should_ice: false,
193196
stderr_per_bitwidth: false,
@@ -358,6 +361,10 @@ impl TestProps {
358361
config.parse_rustfix_only_machine_applicable(ln);
359362
}
360363

364+
if let Some(ignored_diaglint) = config.parse_ignored_diaglints(ln) {
365+
self.ignored_diaglints.push(ignored_diaglint);
366+
}
367+
361368
if self.assembly_output.is_none() {
362369
self.assembly_output = config.parse_assembly_output(ln);
363370
}
@@ -618,6 +625,10 @@ impl Config {
618625
self.parse_name_directive(line, "stderr-per-bitwidth")
619626
}
620627

628+
fn parse_ignored_diaglints(&self, line: &str) -> Option<String> {
629+
self.parse_name_value_directive(line, "ignored-diaglints").map(|r| r.trim().to_string())
630+
}
631+
621632
fn parse_assembly_output(&self, line: &str) -> Option<String> {
622633
self.parse_name_value_directive(line, "assembly-output").map(|r| r.trim().to_string())
623634
}

src/tools/compiletest/src/json.rs

+10
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,16 @@ pub fn rustfix_diagnostics_only(output: &str) -> String {
8383
.collect()
8484
}
8585

86+
/// Tries to return a line that would successfully parsed into `Diagnostic`.
87+
/// Returns `None` if `output` does not contain diagnostics.
88+
pub fn diaglint_diagnostics_only(output: &str) -> Option<String> {
89+
output
90+
.lines()
91+
.filter(|line| line.starts_with('{'))
92+
.find(|line| serde_json::from_str::<Diagnostic>(line).is_ok())
93+
.map(|line| line.to_owned())
94+
}
95+
8696
pub fn extract_rendered(output: &str) -> String {
8797
output
8898
.lines()

src/tools/compiletest/src/runtest.rs

+13-1
Original file line numberDiff line numberDiff line change
@@ -3172,11 +3172,12 @@ impl<'test> TestCx<'test> {
31723172

31733173
debug!(
31743174
"run_ui_test: explicit={:?} config.compare_mode={:?} expected_errors={:?} \
3175-
proc_res.status={:?} props.error_patterns={:?}",
3175+
proc_res.status={:?}, proc_res.stderr={:?}, props.error_patterns={:?}",
31763176
explicit,
31773177
self.config.compare_mode,
31783178
expected_errors,
31793179
proc_res.status,
3180+
proc_res.stderr,
31803181
self.props.error_patterns
31813182
);
31823183
if !explicit && self.config.compare_mode.is_none() {
@@ -3217,6 +3218,17 @@ impl<'test> TestCx<'test> {
32173218
self.fatal_proc_rec("fixed code is still producing diagnostics", &res);
32183219
}
32193220
}
3221+
3222+
let diaglint_input = json::diaglint_diagnostics_only(&proc_res.stderr);
3223+
if let Some(input) = diaglint_input {
3224+
let outputs = diaglint::LintRunner::default()
3225+
.register_default_rules()
3226+
.unregister_rules(&self.props.ignored_diaglints)
3227+
.run(&input);
3228+
for output in outputs {
3229+
self.fatal_proc_rec(&output, &proc_res);
3230+
}
3231+
}
32203232
}
32213233

32223234
fn run_mir_opt_test(&self) {

0 commit comments

Comments
 (0)