fix: Stale diagnostics with rust-project.json and rustc JSON
PR #18043 changed flycheck to be scoped to the relevant package. This broke projects using check commands that invoke rustc directly, because diagnostic JSON from rustc doesn't contain the package ID. This was visible in the rust-analyzer logs when RA_LOG is set to `rust_analyzer::flycheck=trace`. Before: 2026-02-02T07:03:48.020184937-08:00 TRACE diagnostic received flycheck_id=0 mismatched types package_id=None scope=Workspace ... 2026-02-02T07:03:55.082046488-08:00 TRACE clearing diagnostics flycheck_id=0 scope=Workspace After: 2026-02-02T07:14:32.760707785-08:00 TRACE diagnostic received flycheck_id=0 mismatched types package_id=None scope=Package { package: BuildInfo { label: "fbcode//rust_devx/rust-guess-deps:rust-guess-deps" }, workspace_deps: Some({}) } ... 2026-02-02T07:14:48.355981415-08:00 TRACE clearing diagnostics flycheck_id=0 scope=Package { package: BuildInfo { label: "fbcode//rust_devx/rust-guess-deps:rust-guess-deps" }, workspace_deps: Some({}) } Previously r-a assumed that a diagnostic without a package ID applied to the whole workspace. We would insert the diagnostic at the workspace level, but then only clear diagnostics for the package. As a result, red squiggles would get 'stuck'. Users who had fixed compilation issues would still see the old red squiggles until they introduced a new compilation error. Instead, always apply diagnostics to the current package if flycheck is scoped to a package and the diagnostic doesn't specify a package. This makes CargoCheckEvent(None) and CargoCheckEvent(Some(_)) more consistent, as they now both match on scope.
This commit is contained in:
parent
df2a3f8e04
commit
93dece9ae7
1 changed files with 58 additions and 30 deletions
|
|
@ -740,42 +740,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::NotYet {
|
||||
self.diagnostics_received = DiagnosticsReceived::AtLeastOne;
|
||||
}
|
||||
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::AtLeastOneAndClearedWorkspace
|
||||
{
|
||||
self.diagnostics_received =
|
||||
DiagnosticsReceived::AtLeastOneAndClearedWorkspace;
|
||||
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,
|
||||
});
|
||||
}
|
||||
},
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue