From bdd23d1498136e73898273927bb0a6e88a45fe1f Mon Sep 17 00:00:00 2001 From: Hirochika Matsumoto Date: Tue, 4 Jan 2022 00:18:32 +0900 Subject: [PATCH] Introduce a linter for diagnostic messages --- Cargo.lock | 42 ++++++++++++++++++++++++++++ src/tools/compiletest/Cargo.toml | 1 + src/tools/compiletest/src/header.rs | 11 ++++++++ src/tools/compiletest/src/json.rs | 10 +++++++ src/tools/compiletest/src/runtest.rs | 14 +++++++++- 5 files changed, 77 insertions(+), 1 deletion(-) diff --git a/Cargo.lock b/Cargo.lock index cd50defbe6f6c..ebe84a8e60f97 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -693,6 +693,7 @@ name = "compiletest" version = "0.0.0" dependencies = [ "colored", + "diaglint", "diff", "getopts", "glob", @@ -947,6 +948,19 @@ dependencies = [ "syn", ] +[[package]] +name = "diaglint" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3730e1cddacaff508f3dfc1cc050e27e2823a55c44664e0b3a64cbc1008b37f8" +dependencies = [ + "annotate-snippets", + "nom", + "nom_locate", + "serde", + "serde_json", +] + [[package]] name = "diff" version = "0.1.12" @@ -2252,6 +2266,12 @@ dependencies = [ "macro-utils", ] +[[package]] +name = "minimal-lexical" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c835948974f68e0bd58636fc6c5b1fbff7b297e3046f11b3b3c18bbac012c6d" + [[package]] name = "miniz_oxide" version = "0.4.0" @@ -2311,6 +2331,28 @@ version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e4a24736216ec316047a1fc4252e27dabb04218aa4a3f37c6e7ddbf1f9782b54" +[[package]] +name = "nom" +version = "7.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ffd9d26838a953b4af82cbeb9f1592c6798916983959be223a7124e992742c1" +dependencies = [ + "memchr", + "minimal-lexical", + "version_check", +] + +[[package]] +name = "nom_locate" +version = "4.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37794436ca3029a3089e0b95d42da1f0b565ad271e4d3bb4bad0c7bb70b10605" +dependencies = [ + "bytecount", + "memchr", + "nom", +] + [[package]] name = "ntapi" version = "0.3.6" diff --git a/src/tools/compiletest/Cargo.toml b/src/tools/compiletest/Cargo.toml index 23e49539969a0..adca1b674c673 100644 --- a/src/tools/compiletest/Cargo.toml +++ b/src/tools/compiletest/Cargo.toml @@ -6,6 +6,7 @@ edition = "2021" [dependencies] colored = "2" diff = "0.1.10" +diaglint = "0.1.8" unified-diff = "0.2.1" getopts = "0.2" tracing = "0.1" diff --git a/src/tools/compiletest/src/header.rs b/src/tools/compiletest/src/header.rs index 5fcaa452ca30e..928d740a33887 100644 --- a/src/tools/compiletest/src/header.rs +++ b/src/tools/compiletest/src/header.rs @@ -145,6 +145,8 @@ pub struct TestProps { pub run_rustfix: bool, // If true, `rustfix` will only apply `MachineApplicable` suggestions. pub rustfix_only_machine_applicable: bool, + // Lints to ignore when checking diagnostics. + pub ignored_diaglints: Vec, pub assembly_output: Option, // If true, the test is expected to ICE pub should_ice: bool, @@ -188,6 +190,7 @@ impl TestProps { failure_status: -1, run_rustfix: false, rustfix_only_machine_applicable: false, + ignored_diaglints: vec![], assembly_output: None, should_ice: false, stderr_per_bitwidth: false, @@ -358,6 +361,10 @@ impl TestProps { config.parse_rustfix_only_machine_applicable(ln); } + if let Some(ignored_diaglint) = config.parse_ignored_diaglints(ln) { + self.ignored_diaglints.push(ignored_diaglint); + } + if self.assembly_output.is_none() { self.assembly_output = config.parse_assembly_output(ln); } @@ -618,6 +625,10 @@ impl Config { self.parse_name_directive(line, "stderr-per-bitwidth") } + fn parse_ignored_diaglints(&self, line: &str) -> Option { + self.parse_name_value_directive(line, "ignored-diaglints").map(|r| r.trim().to_string()) + } + fn parse_assembly_output(&self, line: &str) -> Option { self.parse_name_value_directive(line, "assembly-output").map(|r| r.trim().to_string()) } diff --git a/src/tools/compiletest/src/json.rs b/src/tools/compiletest/src/json.rs index a5ff779a4abfb..25bab14bf8220 100644 --- a/src/tools/compiletest/src/json.rs +++ b/src/tools/compiletest/src/json.rs @@ -83,6 +83,16 @@ pub fn rustfix_diagnostics_only(output: &str) -> String { .collect() } +/// Tries to return a line that would successfully parsed into `Diagnostic`. +/// Returns `None` if `output` does not contain diagnostics. +pub fn diaglint_diagnostics_only(output: &str) -> Option { + output + .lines() + .filter(|line| line.starts_with('{')) + .find(|line| serde_json::from_str::(line).is_ok()) + .map(|line| line.to_owned()) +} + pub fn extract_rendered(output: &str) -> String { output .lines() diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs index f039ba59d231c..310f2c7a9efa1 100644 --- a/src/tools/compiletest/src/runtest.rs +++ b/src/tools/compiletest/src/runtest.rs @@ -3172,11 +3172,12 @@ impl<'test> TestCx<'test> { debug!( "run_ui_test: explicit={:?} config.compare_mode={:?} expected_errors={:?} \ - proc_res.status={:?} props.error_patterns={:?}", + proc_res.status={:?}, proc_res.stderr={:?}, props.error_patterns={:?}", explicit, self.config.compare_mode, expected_errors, proc_res.status, + proc_res.stderr, self.props.error_patterns ); if !explicit && self.config.compare_mode.is_none() { @@ -3217,6 +3218,17 @@ impl<'test> TestCx<'test> { self.fatal_proc_rec("fixed code is still producing diagnostics", &res); } } + + let diaglint_input = json::diaglint_diagnostics_only(&proc_res.stderr); + if let Some(input) = diaglint_input { + let outputs = diaglint::LintRunner::default() + .register_default_rules() + .unregister_rules(&self.props.ignored_diaglints) + .run(&input); + for output in outputs { + self.fatal_proc_rec(&output, &proc_res); + } + } } fn run_mir_opt_test(&self) {