Merge pull request #21571 from Wilfred/check_type_names

fix: Stale diagnostics with rust-project.json and rustc JSON
This commit is contained in:
Lukas Wirth 2026-02-07 13:17:19 +00:00 committed by GitHub
commit 36058bfc0f
No known key found for this signature in database
GPG key ID: B5690EEEBB952194

View file

@ -421,11 +421,17 @@ struct FlycheckActor {
diagnostics_received: DiagnosticsReceived,
}
#[derive(PartialEq)]
#[derive(PartialEq, Debug)]
enum DiagnosticsReceived {
Yes,
No,
YesAndClearedForAll,
/// We started a flycheck, but we haven't seen any diagnostics yet.
NotYet,
/// We received a non-zero number of diagnostics from rustc or clippy (via
/// cargo or custom check command). This means there were errors or
/// warnings.
AtLeastOne,
/// We received a non-zero number of diagnostics, and the scope is
/// workspace, so we've discarded the previous workspace diagnostics.
AtLeastOneAndClearedWorkspace,
}
#[allow(clippy::large_enum_variant)]
@ -522,7 +528,7 @@ impl FlycheckActor {
command_handle: None,
command_receiver: None,
diagnostics_cleared_for: Default::default(),
diagnostics_received: DiagnosticsReceived::No,
diagnostics_received: DiagnosticsReceived::NotYet,
}
}
@ -641,7 +647,7 @@ impl FlycheckActor {
error
);
}
if self.diagnostics_received == DiagnosticsReceived::No {
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
@ -735,41 +741,70 @@ impl FlycheckActor {
flycheck_id = self.id,
message = diagnostic.message,
package_id = package_id.as_ref().map(|it| it.as_str()),
scope = ?self.scope,
"diagnostic received"
);
if self.diagnostics_received == DiagnosticsReceived::No {
self.diagnostics_received = DiagnosticsReceived::Yes;
}
if let Some(package_id) = &package_id {
if self.diagnostics_cleared_for.insert(package_id.clone()) {
tracing::trace!(
flycheck_id = self.id,
package_id = package_id.as_str(),
"clearing diagnostics"
);
self.send(FlycheckMessage::ClearDiagnostics {
match &self.scope {
FlycheckScope::Workspace => {
if self.diagnostics_received == DiagnosticsReceived::NotYet {
self.send(FlycheckMessage::ClearDiagnostics {
id: self.id,
kind: ClearDiagnosticsKind::All(ClearScope::Workspace),
});
self.diagnostics_received =
DiagnosticsReceived::AtLeastOneAndClearedWorkspace;
}
if let Some(package_id) = package_id {
tracing::warn!(
"Ignoring package label {:?} and applying diagnostics to the whole workspace",
package_id
);
}
self.send(FlycheckMessage::AddDiagnostic {
id: self.id,
kind: ClearDiagnosticsKind::All(ClearScope::Package(
package_id.clone(),
)),
generation: self.generation,
package_id: None,
workspace_root: self.root.clone(),
diagnostic,
});
}
FlycheckScope::Package { package: flycheck_package, .. } => {
if self.diagnostics_received == DiagnosticsReceived::NotYet {
self.diagnostics_received = DiagnosticsReceived::AtLeastOne;
}
// If the package has been set in the diagnostic JSON, respect that. Otherwise, use the
// package that the current flycheck is scoped to. This is useful when a project is
// directly using rustc for its checks (e.g. custom check commands in rust-project.json).
let package_id = package_id.unwrap_or(flycheck_package.clone());
if self.diagnostics_cleared_for.insert(package_id.clone()) {
tracing::trace!(
flycheck_id = self.id,
package_id = package_id.as_str(),
"clearing diagnostics"
);
self.send(FlycheckMessage::ClearDiagnostics {
id: self.id,
kind: ClearDiagnosticsKind::All(ClearScope::Package(
package_id.clone(),
)),
});
}
self.send(FlycheckMessage::AddDiagnostic {
id: self.id,
generation: self.generation,
package_id: Some(package_id),
workspace_root: self.root.clone(),
diagnostic,
});
}
} else if self.diagnostics_received
!= DiagnosticsReceived::YesAndClearedForAll
{
self.diagnostics_received = DiagnosticsReceived::YesAndClearedForAll;
self.send(FlycheckMessage::ClearDiagnostics {
id: self.id,
kind: ClearDiagnosticsKind::All(ClearScope::Workspace),
});
}
self.send(FlycheckMessage::AddDiagnostic {
id: self.id,
generation: self.generation,
package_id,
workspace_root: self.root.clone(),
diagnostic,
});
}
},
}
@ -793,7 +828,7 @@ impl FlycheckActor {
fn clear_diagnostics_state(&mut self) {
self.diagnostics_cleared_for.clear();
self.diagnostics_received = DiagnosticsReceived::No;
self.diagnostics_received = DiagnosticsReceived::NotYet;
}
fn explicit_check_command(