Unnamed repository; edit this file 'description' to name the repository.
-rw-r--r--crates/rust-analyzer/src/diagnostics.rs16
-rw-r--r--crates/rust-analyzer/src/flycheck.rs69
-rw-r--r--crates/rust-analyzer/src/global_state.rs52
-rw-r--r--crates/rust-analyzer/src/handlers/notification.rs42
4 files changed, 131 insertions, 48 deletions
diff --git a/crates/rust-analyzer/src/diagnostics.rs b/crates/rust-analyzer/src/diagnostics.rs
index 4a247800af..712960f13d 100644
--- a/crates/rust-analyzer/src/diagnostics.rs
+++ b/crates/rust-analyzer/src/diagnostics.rs
@@ -3,7 +3,6 @@ pub(crate) mod flycheck_to_proto;
use std::mem;
-use cargo_metadata::PackageId;
use ide::FileId;
use ide_db::{FxHashMap, base_db::DbPanicContext};
use itertools::Itertools;
@@ -12,10 +11,13 @@ use smallvec::SmallVec;
use stdx::iter_eq_by;
use triomphe::Arc;
-use crate::{global_state::GlobalStateSnapshot, lsp, lsp_ext, main_loop::DiagnosticsTaskKind};
+use crate::{
+ flycheck::PackageSpecifier, global_state::GlobalStateSnapshot, lsp, lsp_ext,
+ main_loop::DiagnosticsTaskKind,
+};
pub(crate) type CheckFixes =
- Arc<Vec<FxHashMap<Option<Arc<PackageId>>, FxHashMap<FileId, Vec<Fix>>>>>;
+ Arc<Vec<FxHashMap<Option<PackageSpecifier>, FxHashMap<FileId, Vec<Fix>>>>>;
#[derive(Debug, Default, Clone)]
pub struct DiagnosticsMapConfig {
@@ -29,7 +31,7 @@ pub(crate) type DiagnosticsGeneration = usize;
#[derive(Debug, Clone, Default)]
pub(crate) struct WorkspaceFlycheckDiagnostic {
- pub(crate) per_package: FxHashMap<Option<Arc<PackageId>>, PackageFlycheckDiagnostic>,
+ pub(crate) per_package: FxHashMap<Option<PackageSpecifier>, PackageFlycheckDiagnostic>,
}
#[derive(Debug, Clone)]
@@ -85,7 +87,7 @@ impl DiagnosticCollection {
pub(crate) fn clear_check_for_package(
&mut self,
flycheck_id: usize,
- package_id: Arc<PackageId>,
+ package_id: PackageSpecifier,
) {
let Some(check) = self.check.get_mut(flycheck_id) else {
return;
@@ -124,7 +126,7 @@ impl DiagnosticCollection {
pub(crate) fn clear_check_older_than_for_package(
&mut self,
flycheck_id: usize,
- package_id: Arc<PackageId>,
+ package_id: PackageSpecifier,
generation: DiagnosticsGeneration,
) {
let Some(check) = self.check.get_mut(flycheck_id) else {
@@ -154,7 +156,7 @@ impl DiagnosticCollection {
&mut self,
flycheck_id: usize,
generation: DiagnosticsGeneration,
- package_id: &Option<Arc<PackageId>>,
+ package_id: &Option<PackageSpecifier>,
file_id: FileId,
diagnostic: lsp_types::Diagnostic,
fix: Option<Box<Fix>>,
diff --git a/crates/rust-analyzer/src/flycheck.rs b/crates/rust-analyzer/src/flycheck.rs
index b062641691..2819ae98da 100644
--- a/crates/rust-analyzer/src/flycheck.rs
+++ b/crates/rust-analyzer/src/flycheck.rs
@@ -195,9 +195,9 @@ impl FlycheckHandle {
/// Schedule a re-start of the cargo check worker to do a package wide check.
pub(crate) fn restart_for_package(
&self,
- package: Arc<PackageId>,
+ package: PackageSpecifier,
target: Option<Target>,
- workspace_deps: Option<FxHashSet<Arc<PackageId>>>,
+ workspace_deps: Option<FxHashSet<PackageSpecifier>>,
) {
let generation = self.generation.fetch_add(1, Ordering::Relaxed) + 1;
self.sender
@@ -233,7 +233,7 @@ pub(crate) enum ClearDiagnosticsKind {
#[derive(Debug)]
pub(crate) enum ClearScope {
Workspace,
- Package(Arc<PackageId>),
+ Package(PackageSpecifier),
}
pub(crate) enum FlycheckMessage {
@@ -243,7 +243,7 @@ pub(crate) enum FlycheckMessage {
generation: DiagnosticsGeneration,
workspace_root: Arc<AbsPathBuf>,
diagnostic: Diagnostic,
- package_id: Option<Arc<PackageId>>,
+ package_id: Option<PackageSpecifier>,
},
/// Request clearing all outdated diagnostics.
@@ -295,7 +295,32 @@ pub(crate) enum Progress {
enum FlycheckScope {
Workspace,
- Package { package: Arc<PackageId>, workspace_deps: Option<FxHashSet<Arc<PackageId>>> },
+ Package {
+ // Either a cargo package or a $label in rust-project.check.overrideCommand
+ package: PackageSpecifier,
+ workspace_deps: Option<FxHashSet<PackageSpecifier>>,
+ },
+}
+
+#[derive(Debug, Hash, PartialEq, Eq, Clone)]
+pub(crate) enum PackageSpecifier {
+ Cargo {
+ /// The one in Cargo.toml, assumed to work with `cargo check -p {}` etc
+ package_id: Arc<PackageId>,
+ },
+ BuildInfo {
+ /// If a `build` field is present in rust-project.json, its label field
+ label: String,
+ },
+}
+
+impl PackageSpecifier {
+ pub(crate) fn as_str(&self) -> &str {
+ match self {
+ Self::Cargo { package_id } => &package_id.repr,
+ Self::BuildInfo { label } => label,
+ }
+ }
}
enum StateChange {
@@ -331,7 +356,7 @@ struct FlycheckActor {
command_handle: Option<CommandHandle<CargoCheckMessage>>,
/// The receiver side of the channel mentioned above.
command_receiver: Option<Receiver<CargoCheckMessage>>,
- diagnostics_cleared_for: FxHashSet<Arc<PackageId>>,
+ diagnostics_cleared_for: FxHashSet<PackageSpecifier>,
diagnostics_received: DiagnosticsReceived,
}
@@ -564,7 +589,10 @@ impl FlycheckActor {
msg.target.kind.iter().format_with(", ", |kind, f| f(&kind)),
)));
let package_id = Arc::new(msg.package_id);
- if self.diagnostics_cleared_for.insert(package_id.clone()) {
+ if self
+ .diagnostics_cleared_for
+ .insert(PackageSpecifier::Cargo { package_id: package_id.clone() })
+ {
tracing::trace!(
flycheck_id = self.id,
package_id = package_id.repr,
@@ -572,7 +600,9 @@ impl FlycheckActor {
);
self.send(FlycheckMessage::ClearDiagnostics {
id: self.id,
- kind: ClearDiagnosticsKind::All(ClearScope::Package(package_id)),
+ kind: ClearDiagnosticsKind::All(ClearScope::Package(
+ PackageSpecifier::Cargo { package_id },
+ )),
});
}
}
@@ -580,7 +610,7 @@ impl FlycheckActor {
tracing::trace!(
flycheck_id = self.id,
message = diagnostic.message,
- package_id = package_id.as_ref().map(|it| &it.repr),
+ package_id = package_id.as_ref().map(|it| it.as_str()),
"diagnostic received"
);
if self.diagnostics_received == DiagnosticsReceived::No {
@@ -590,7 +620,7 @@ impl FlycheckActor {
if self.diagnostics_cleared_for.insert(package_id.clone()) {
tracing::trace!(
flycheck_id = self.id,
- package_id = package_id.repr,
+ package_id = package_id.as_str(),
"clearing diagnostics"
);
self.send(FlycheckMessage::ClearDiagnostics {
@@ -666,7 +696,18 @@ impl FlycheckActor {
match scope {
FlycheckScope::Workspace => cmd.arg("--workspace"),
- FlycheckScope::Package { package, .. } => cmd.arg("-p").arg(&package.repr),
+ FlycheckScope::Package {
+ package: PackageSpecifier::Cargo { package_id },
+ ..
+ } => cmd.arg("-p").arg(&package_id.repr),
+ FlycheckScope::Package {
+ package: PackageSpecifier::BuildInfo { .. }, ..
+ } => {
+ // No way to flycheck this single package. All we have is a build label.
+ // There's no way to really say whether this build label happens to be
+ // a cargo canonical name, so we won't try.
+ return None;
+ }
};
if let Some(tgt) = target {
@@ -748,7 +789,7 @@ impl FlycheckActor {
#[allow(clippy::large_enum_variant)]
enum CargoCheckMessage {
CompilerArtifact(cargo_metadata::Artifact),
- Diagnostic { diagnostic: Diagnostic, package_id: Option<Arc<PackageId>> },
+ Diagnostic { diagnostic: Diagnostic, package_id: Option<PackageSpecifier> },
}
struct CargoCheckParser;
@@ -767,7 +808,9 @@ impl JsonLinesParser<CargoCheckMessage> for CargoCheckParser {
cargo_metadata::Message::CompilerMessage(msg) => {
Some(CargoCheckMessage::Diagnostic {
diagnostic: msg.message,
- package_id: Some(Arc::new(msg.package_id)),
+ package_id: Some(PackageSpecifier::Cargo {
+ package_id: Arc::new(msg.package_id),
+ }),
})
}
_ => None,
diff --git a/crates/rust-analyzer/src/global_state.rs b/crates/rust-analyzer/src/global_state.rs
index 68d65cdee6..0cfd0a141b 100644
--- a/crates/rust-analyzer/src/global_state.rs
+++ b/crates/rust-analyzer/src/global_state.rs
@@ -9,7 +9,6 @@ use std::{
time::{Duration, Instant},
};
-use cargo_metadata::PackageId;
use crossbeam_channel::{Receiver, Sender, unbounded};
use hir::ChangeWithProcMacros;
use ide::{Analysis, AnalysisHost, Cancellable, FileId, SourceRootId};
@@ -36,7 +35,7 @@ use crate::{
config::{Config, ConfigChange, ConfigErrors, RatomlFileKind},
diagnostics::{CheckFixes, DiagnosticCollection},
discover,
- flycheck::{FlycheckHandle, FlycheckMessage},
+ flycheck::{FlycheckHandle, FlycheckMessage, PackageSpecifier},
line_index::{LineEndings, LineIndex},
lsp::{from_proto, to_proto::url_from_abs_path},
lsp_ext,
@@ -845,20 +844,43 @@ impl GlobalStateSnapshot {
pub(crate) fn all_workspace_dependencies_for_package(
&self,
- package: &Arc<PackageId>,
- ) -> Option<FxHashSet<Arc<PackageId>>> {
- self.workspaces.iter().find_map(|workspace| match &workspace.kind {
- ProjectWorkspaceKind::Cargo { cargo, .. }
- | ProjectWorkspaceKind::DetachedFile { cargo: Some((cargo, _, _)), .. } => {
- let package = cargo.packages().find(|p| cargo[*p].id == *package)?;
-
- return cargo[package]
- .all_member_deps
- .as_ref()
- .map(|deps| deps.iter().map(|dep| cargo[*dep].id.clone()).collect());
+ package: &PackageSpecifier,
+ ) -> Option<FxHashSet<PackageSpecifier>> {
+ match package {
+ PackageSpecifier::Cargo { package_id } => {
+ self.workspaces.iter().find_map(|workspace| match &workspace.kind {
+ ProjectWorkspaceKind::Cargo { cargo, .. }
+ | ProjectWorkspaceKind::DetachedFile { cargo: Some((cargo, _, _)), .. } => {
+ let package = cargo.packages().find(|p| cargo[*p].id == *package_id)?;
+
+ cargo[package].all_member_deps.as_ref().map(|deps| {
+ deps.iter()
+ .map(|dep| cargo[*dep].id.clone())
+ .map(|p| PackageSpecifier::Cargo { package_id: p })
+ .collect()
+ })
+ }
+ _ => None,
+ })
}
- _ => None,
- })
+ PackageSpecifier::BuildInfo { label } => {
+ self.workspaces.iter().find_map(|workspace| match &workspace.kind {
+ ProjectWorkspaceKind::Json(p) => {
+ let krate = p.crate_by_label(label)?;
+ Some(
+ krate
+ .iter_deps()
+ .filter_map(|dep| p[dep].build.as_ref())
+ .map(|build| PackageSpecifier::BuildInfo {
+ label: build.label.clone(),
+ })
+ .collect(),
+ )
+ }
+ _ => None,
+ })
+ }
+ }
}
pub(crate) fn file_exists(&self, file_id: FileId) -> bool {
diff --git a/crates/rust-analyzer/src/handlers/notification.rs b/crates/rust-analyzer/src/handlers/notification.rs
index 4a6544508f..57adbbfe72 100644
--- a/crates/rust-analyzer/src/handlers/notification.rs
+++ b/crates/rust-analyzer/src/handlers/notification.rs
@@ -18,7 +18,7 @@ use vfs::{AbsPathBuf, ChangeKind, VfsPath};
use crate::{
config::{Config, ConfigChange},
- flycheck::{InvocationStrategy, Target},
+ flycheck::{InvocationStrategy, PackageSpecifier, Target},
global_state::{FetchWorkspaceRequest, GlobalState},
lsp::{from_proto, utils::apply_document_changes},
lsp_ext::{self, RunFlycheckParams},
@@ -328,22 +328,32 @@ fn run_flycheck(state: &mut GlobalState, vfs_path: VfsPath) -> bool {
}
InvocationStrategy::PerWorkspace => {
Box::new(move || {
- let target = TargetSpec::for_file(&world, file_id)?.and_then(|it| {
+ let target = TargetSpec::for_file(&world, file_id)?.map(|it| {
let tgt_kind = it.target_kind();
let (tgt_name, root, package) = match it {
- TargetSpec::Cargo(c) => (c.target, c.workspace_root, c.package_id),
- _ => return None,
+ TargetSpec::Cargo(c) => (
+ Some(c.target),
+ c.workspace_root,
+ PackageSpecifier::Cargo { package_id: c.package_id },
+ ),
+ TargetSpec::ProjectJson(p) => (
+ None,
+ p.project_root,
+ PackageSpecifier::BuildInfo { label: p.label.clone() },
+ ),
};
- let tgt = match tgt_kind {
- project_model::TargetKind::Bin => Target::Bin(tgt_name),
- project_model::TargetKind::Example => Target::Example(tgt_name),
- project_model::TargetKind::Test => Target::Test(tgt_name),
- project_model::TargetKind::Bench => Target::Benchmark(tgt_name),
- _ => return Some((None, root, package)),
- };
+ let tgt = tgt_name.and_then(|tgt_name| {
+ Some(match tgt_kind {
+ project_model::TargetKind::Bin => Target::Bin(tgt_name),
+ project_model::TargetKind::Example => Target::Example(tgt_name),
+ project_model::TargetKind::Test => Target::Test(tgt_name),
+ project_model::TargetKind::Bench => Target::Benchmark(tgt_name),
+ _ => return None,
+ })
+ });
- Some((Some(tgt), root, package))
+ (tgt, root, package)
});
tracing::debug!(?target, "flycheck target");
// we have a specific non-library target, attempt to only check that target, nothing
@@ -365,7 +375,13 @@ fn run_flycheck(state: &mut GlobalState, vfs_path: VfsPath) -> bool {
cargo: Some((cargo, _, _)),
..
} => *cargo.workspace_root() == root,
- _ => false,
+ project_model::ProjectWorkspaceKind::Json(p) => {
+ *p.project_root() == root
+ }
+ project_model::ProjectWorkspaceKind::DetachedFile {
+ cargo: None,
+ ..
+ } => false,
});
if let Some(idx) = package_workspace_idx {
let workspace_deps =