Unnamed repository; edit this file 'description' to name the repository.
-rw-r--r--crates/rust-analyzer/src/flycheck.rs46
-rw-r--r--crates/rust-analyzer/tests/slow-tests/flycheck.rs42
2 files changed, 67 insertions, 21 deletions
diff --git a/crates/rust-analyzer/src/flycheck.rs b/crates/rust-analyzer/src/flycheck.rs
index c41696bf3f..aad8bece95 100644
--- a/crates/rust-analyzer/src/flycheck.rs
+++ b/crates/rust-analyzer/src/flycheck.rs
@@ -673,27 +673,31 @@ impl FlycheckActor {
if self.diagnostics_received == DiagnosticsReceived::NotYet {
tracing::trace!(flycheck_id = self.id, "clearing diagnostics");
// We finished without receiving any diagnostics.
- // Clear everything for good measure
- match &self.scope {
- FlycheckScope::Workspace => {
- self.send(FlycheckMessage::ClearDiagnostics {
- id: self.id,
- kind: ClearDiagnosticsKind::All(ClearScope::Workspace),
- });
- }
- FlycheckScope::Package { package, workspace_deps } => {
- for pkg in
- std::iter::once(package).chain(workspace_deps.iter().flatten())
- {
- self.send(FlycheckMessage::ClearDiagnostics {
- id: self.id,
- kind: ClearDiagnosticsKind::All(ClearScope::Package(
- pkg.clone(),
- )),
- });
- }
- }
- }
+ //
+ // `cargo check` generally outputs something, even if there are no
+ // warnings/errors, so we always know which package was checked.
+ //
+ // ```text
+ // $ cargo check --message-format=json 2>/dev/null
+ // {"reason":"compiler-artifact","package_id":"path+file:///Users/wilfred/tmp/scratch#0.1.0",...}
+ // ```
+ //
+ // However, rustc only returns JSON if there are diagnostics present, so a
+ // build without warnings or errors has an empty output.
+ //
+ // ```
+ // $ rustc --error-format=json bad.rs
+ // {"$message_type":"diagnostic","message":"mismatched types","...}
+ //
+ // $ rustc --error-format=json good.rs
+ // ```
+ //
+ // So if we got zero diagnostics, it was almost certainly a check that
+ // wasn't specific to a package.
+ self.send(FlycheckMessage::ClearDiagnostics {
+ id: self.id,
+ kind: ClearDiagnosticsKind::All(ClearScope::Workspace),
+ });
} else if res.is_ok() {
// We clear diagnostics for packages on
// `[CargoCheckMessage::CompilerArtifact]` but there seem to be setups where
diff --git a/crates/rust-analyzer/tests/slow-tests/flycheck.rs b/crates/rust-analyzer/tests/slow-tests/flycheck.rs
index c1d53fb33a..c6f1f81139 100644
--- a/crates/rust-analyzer/tests/slow-tests/flycheck.rs
+++ b/crates/rust-analyzer/tests/slow-tests/flycheck.rs
@@ -110,3 +110,45 @@ fn main() {}
diagnostics.diagnostics,
);
}
+
+#[test]
+fn test_flycheck_diagnostics_with_override_command_cleared_after_fix() {
+ if skip_slow_tests() {
+ return;
+ }
+
+ // Start with a program that is lint clean.
+ let server = Project::with_fixture(
+ r#"
+//- /Cargo.toml
+[package]
+name = "foo"
+version = "0.0.0"
+
+//- /src/main.rs
+fn main() {}
+"#,
+ )
+ .with_config(serde_json::json!({
+ "checkOnSave": true,
+ "check": {
+ "overrideCommand": ["rustc", "--error-format=json", "$saved_file"]
+ }
+ }))
+ .server()
+ .wait_until_workspace_is_loaded();
+
+ // Introduce an unused variable.
+ server.write_file_and_save("src/main.rs", "fn main() {\n let x = 1;\n}\n".to_owned());
+
+ let diags = server.wait_for_diagnostics();
+ assert!(
+ diags.diagnostics.iter().any(|d| d.message.contains("unused variable")),
+ "expected unused variable diagnostic, got: {:?}",
+ diags.diagnostics,
+ );
+
+ // Fix it and verify that diagnostics are cleared.
+ server.write_file_and_save("src/main.rs", "fn main() {\n let _x = 1;\n}\n".to_owned());
+ server.wait_for_diagnostics_cleared();
+}