mirror of
https://github.com/rust-lang/rust-analyzer.git
synced 2025-10-22 00:01:53 +00:00
fix: Make flycheck clearing dependency-aware
This commit is contained in:
parent
b12a129347
commit
de3ad58b73
8 changed files with 213 additions and 43 deletions
|
@ -9,7 +9,7 @@
|
|||
use std::{cell::RefCell, io, mem, process::Command};
|
||||
|
||||
use base_db::Env;
|
||||
use cargo_metadata::{Message, camino::Utf8Path};
|
||||
use cargo_metadata::{Message, PackageId, camino::Utf8Path};
|
||||
use cfg::CfgAtom;
|
||||
use itertools::Itertools;
|
||||
use la_arena::ArenaMap;
|
||||
|
@ -18,6 +18,7 @@ use rustc_hash::{FxHashMap, FxHashSet};
|
|||
use serde::Deserialize as _;
|
||||
use stdx::never;
|
||||
use toolchain::Tool;
|
||||
use triomphe::Arc;
|
||||
|
||||
use crate::{
|
||||
CargoConfig, CargoFeatures, CargoWorkspace, InvocationStrategy, ManifestPath, Package, Sysroot,
|
||||
|
@ -284,7 +285,7 @@ impl WorkspaceBuildScripts {
|
|||
// NB: Cargo.toml could have been modified between `cargo metadata` and
|
||||
// `cargo check`. We shouldn't assume that package ids we see here are
|
||||
// exactly those from `config`.
|
||||
let mut by_id: FxHashMap<String, Package> = FxHashMap::default();
|
||||
let mut by_id: FxHashMap<Arc<PackageId>, Package> = FxHashMap::default();
|
||||
for package in workspace.packages() {
|
||||
outputs.insert(package, BuildScriptOutput::default());
|
||||
by_id.insert(workspace[package].id.clone(), package);
|
||||
|
@ -323,7 +324,7 @@ impl WorkspaceBuildScripts {
|
|||
// ideally this would be something like:
|
||||
// with_output_for: impl FnMut(&str, dyn FnOnce(&mut BuildScriptOutput)),
|
||||
// but owned trait objects aren't a thing
|
||||
mut with_output_for: impl FnMut(&str, &mut dyn FnMut(&str, &mut BuildScriptOutput)),
|
||||
mut with_output_for: impl FnMut(&PackageId, &mut dyn FnMut(&str, &mut BuildScriptOutput)),
|
||||
progress: &dyn Fn(String),
|
||||
) -> io::Result<Option<String>> {
|
||||
let errors = RefCell::new(String::new());
|
||||
|
@ -346,7 +347,7 @@ impl WorkspaceBuildScripts {
|
|||
|
||||
match message {
|
||||
Message::BuildScriptExecuted(mut message) => {
|
||||
with_output_for(&message.package_id.repr, &mut |name, data| {
|
||||
with_output_for(&message.package_id, &mut |name, data| {
|
||||
progress(format!("build script {name} run"));
|
||||
let cfgs = {
|
||||
let mut acc = Vec::new();
|
||||
|
@ -377,7 +378,7 @@ impl WorkspaceBuildScripts {
|
|||
});
|
||||
}
|
||||
Message::CompilerArtifact(message) => {
|
||||
with_output_for(&message.package_id.repr, &mut |name, data| {
|
||||
with_output_for(&message.package_id, &mut |name, data| {
|
||||
progress(format!("proc-macro {name} built"));
|
||||
if data.proc_macro_dylib_path == ProcMacroDylibPath::NotBuilt {
|
||||
data.proc_macro_dylib_path = ProcMacroDylibPath::NotProcMacro;
|
||||
|
|
|
@ -5,7 +5,7 @@ use std::str::from_utf8;
|
|||
|
||||
use anyhow::Context;
|
||||
use base_db::Env;
|
||||
use cargo_metadata::{CargoOpt, MetadataCommand};
|
||||
use cargo_metadata::{CargoOpt, MetadataCommand, PackageId};
|
||||
use la_arena::{Arena, Idx};
|
||||
use paths::{AbsPath, AbsPathBuf, Utf8Path, Utf8PathBuf};
|
||||
use rustc_hash::{FxHashMap, FxHashSet};
|
||||
|
@ -14,6 +14,7 @@ use serde_json::from_value;
|
|||
use span::Edition;
|
||||
use stdx::process::spawn_with_streaming_output;
|
||||
use toolchain::Tool;
|
||||
use triomphe::Arc;
|
||||
|
||||
use crate::cargo_config_file::make_lockfile_copy;
|
||||
use crate::{CfgOverrides, InvocationStrategy};
|
||||
|
@ -155,8 +156,8 @@ pub struct PackageData {
|
|||
pub features: FxHashMap<String, Vec<String>>,
|
||||
/// List of features enabled on this package
|
||||
pub active_features: Vec<String>,
|
||||
/// String representation of package id
|
||||
pub id: String,
|
||||
/// Package id
|
||||
pub id: Arc<PackageId>,
|
||||
/// Authors as given in the `Cargo.toml`
|
||||
pub authors: Vec<String>,
|
||||
/// Description as given in the `Cargo.toml`
|
||||
|
@ -173,6 +174,10 @@ pub struct PackageData {
|
|||
pub rust_version: Option<semver::Version>,
|
||||
/// The contents of [package.metadata.rust-analyzer]
|
||||
pub metadata: RustAnalyzerPackageMetaData,
|
||||
/// If this package is a member of the workspace, store all direct and transitive
|
||||
/// dependencies as long as they are workspace members, to track dependency relationships
|
||||
/// between members.
|
||||
pub all_member_deps: Option<FxHashSet<Package>>,
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Default, Debug, Clone, Eq, PartialEq)]
|
||||
|
@ -334,6 +339,8 @@ impl CargoWorkspace {
|
|||
let mut is_virtual_workspace = true;
|
||||
let mut requires_rustc_private = false;
|
||||
|
||||
let mut members = FxHashSet::default();
|
||||
|
||||
meta.packages.sort_by(|a, b| a.id.cmp(&b.id));
|
||||
for meta_pkg in meta.packages {
|
||||
let cargo_metadata::Package {
|
||||
|
@ -356,6 +363,7 @@ impl CargoWorkspace {
|
|||
rust_version,
|
||||
..
|
||||
} = meta_pkg;
|
||||
let id = Arc::new(id);
|
||||
let meta = from_value::<PackageMetadata>(metadata).unwrap_or_default();
|
||||
let edition = match edition {
|
||||
cargo_metadata::Edition::E2015 => Edition::Edition2015,
|
||||
|
@ -375,7 +383,7 @@ impl CargoWorkspace {
|
|||
let manifest = ManifestPath::try_from(AbsPathBuf::assert(manifest_path)).unwrap();
|
||||
is_virtual_workspace &= manifest != ws_manifest_path;
|
||||
let pkg = packages.alloc(PackageData {
|
||||
id: id.repr.clone(),
|
||||
id: id.clone(),
|
||||
name: name.to_string(),
|
||||
version,
|
||||
manifest: manifest.clone(),
|
||||
|
@ -395,7 +403,11 @@ impl CargoWorkspace {
|
|||
features: features.into_iter().collect(),
|
||||
active_features: Vec::new(),
|
||||
metadata: meta.rust_analyzer.unwrap_or_default(),
|
||||
all_member_deps: None,
|
||||
});
|
||||
if is_member {
|
||||
members.insert(pkg);
|
||||
}
|
||||
let pkg_data = &mut packages[pkg];
|
||||
requires_rustc_private |= pkg_data.metadata.rustc_private;
|
||||
pkg_by_id.insert(id, pkg);
|
||||
|
@ -440,6 +452,43 @@ impl CargoWorkspace {
|
|||
.extend(node.features.into_iter().map(|it| it.to_string()));
|
||||
}
|
||||
|
||||
fn saturate_all_member_deps(
|
||||
packages: &mut Arena<PackageData>,
|
||||
to_visit: Package,
|
||||
visited: &mut FxHashSet<Package>,
|
||||
members: &FxHashSet<Package>,
|
||||
) {
|
||||
let pkg_data = &mut packages[to_visit];
|
||||
|
||||
if !visited.insert(to_visit) {
|
||||
return;
|
||||
}
|
||||
|
||||
let deps: Vec<_> = pkg_data
|
||||
.dependencies
|
||||
.iter()
|
||||
.filter_map(|dep| {
|
||||
let pkg = dep.pkg;
|
||||
if members.contains(&pkg) { Some(pkg) } else { None }
|
||||
})
|
||||
.collect();
|
||||
|
||||
let mut all_member_deps = FxHashSet::from_iter(deps.iter().copied());
|
||||
for dep in deps {
|
||||
saturate_all_member_deps(packages, dep, visited, members);
|
||||
if let Some(transitives) = &packages[dep].all_member_deps {
|
||||
all_member_deps.extend(transitives);
|
||||
}
|
||||
}
|
||||
|
||||
packages[to_visit].all_member_deps = Some(all_member_deps);
|
||||
}
|
||||
|
||||
let mut visited = FxHashSet::default();
|
||||
for member in members.iter() {
|
||||
saturate_all_member_deps(&mut packages, *member, &mut visited, &members);
|
||||
}
|
||||
|
||||
CargoWorkspace {
|
||||
packages,
|
||||
targets,
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue