Unnamed repository; edit this file 'description' to name the repository.
-rw-r--r--crates/rust-analyzer/src/flycheck.rs107
1 files changed, 71 insertions, 36 deletions
diff --git a/crates/rust-analyzer/src/flycheck.rs b/crates/rust-analyzer/src/flycheck.rs
index eec4ea2599..c74f4550fd 100644
--- a/crates/rust-analyzer/src/flycheck.rs
+++ b/crates/rust-analyzer/src/flycheck.rs
@@ -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(