From 35b208aaa72b5848050ac4e2d3094ecd948cf3a5 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Fri, 26 May 2023 21:52:39 +0200 Subject: [PATCH] Filter out unused cargo features from config --- .github/workflows/ci.yaml | 1 - Cargo.lock | 1 + crates/project-model/Cargo.toml | 1 + crates/project-model/src/build_scripts.rs | 28 +++++++++++++++---- crates/project-model/src/cargo_workspace.rs | 17 ++++++++++- crates/rust-analyzer/src/cargo_target_spec.rs | 14 +++++++--- 6 files changed, 50 insertions(+), 12 deletions(-) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 220d88afe4..622da105fd 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -58,7 +58,6 @@ jobs: uses: actions/checkout@v3 with: ref: ${{ github.event.pull_request.head.sha }} - fetch-depth: 20 - name: Install Rust toolchain run: | diff --git a/Cargo.lock b/Cargo.lock index e7ae42a2d9..f9c5417ffb 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1334,6 +1334,7 @@ dependencies = [ "cargo_metadata", "cfg", "expect-test", + "itertools", "la-arena", "paths", "profile", diff --git a/crates/project-model/Cargo.toml b/crates/project-model/Cargo.toml index efe61eb8f6..3abff64a83 100644 --- a/crates/project-model/Cargo.toml +++ b/crates/project-model/Cargo.toml @@ -21,6 +21,7 @@ serde.workspace = true triomphe.workspace = true anyhow = "1.0.62" la-arena = { version = "0.3.0", path = "../../lib/la-arena" } +itertools = "0.10.5" # local deps base-db.workspace = true diff --git a/crates/project-model/src/build_scripts.rs b/crates/project-model/src/build_scripts.rs index fe4cbfc886..6cbf403cb2 100644 --- a/crates/project-model/src/build_scripts.rs +++ b/crates/project-model/src/build_scripts.rs @@ -14,9 +14,10 @@ use std::{ }; use cargo_metadata::{camino::Utf8Path, Message}; +use itertools::Itertools; use la_arena::ArenaMap; use paths::{AbsPath, AbsPathBuf}; -use rustc_hash::FxHashMap; +use rustc_hash::{FxHashMap, FxHashSet}; use semver::Version; use serde::Deserialize; @@ -56,7 +57,10 @@ impl BuildScriptOutput { } impl WorkspaceBuildScripts { - fn build_command(config: &CargoConfig) -> io::Result { + fn build_command( + config: &CargoConfig, + allowed_features: &FxHashSet, + ) -> io::Result { let mut cmd = match config.run_build_script_command.as_deref() { Some([program, args @ ..]) => { let mut cmd = Command::new(program); @@ -88,7 +92,12 @@ impl WorkspaceBuildScripts { } if !features.is_empty() { cmd.arg("--features"); - cmd.arg(features.join(" ")); + cmd.arg( + features + .iter() + .filter(|&feat| allowed_features.contains(feat)) + .join(","), + ); } } } @@ -127,13 +136,20 @@ impl WorkspaceBuildScripts { } .as_ref(); - match Self::run_per_ws(Self::build_command(config)?, workspace, current_dir, progress) { + let allowed_features = workspace.workspace_features(); + + match Self::run_per_ws( + Self::build_command(config, &allowed_features)?, + workspace, + current_dir, + progress, + ) { Ok(WorkspaceBuildScripts { error: Some(error), .. }) if toolchain.as_ref().map_or(false, |it| *it >= RUST_1_62) => { // building build scripts failed, attempt to build with --keep-going so // that we potentially get more build data - let mut cmd = Self::build_command(config)?; + let mut cmd = Self::build_command(config, &allowed_features)?; cmd.args(["-Z", "unstable-options", "--keep-going"]).env("RUSTC_BOOTSTRAP", "1"); let mut res = Self::run_per_ws(cmd, workspace, current_dir, progress)?; res.error = Some(error); @@ -161,7 +177,7 @@ impl WorkspaceBuildScripts { )) } }; - let cmd = Self::build_command(config)?; + let cmd = Self::build_command(config, &Default::default())?; // 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`. diff --git a/crates/project-model/src/cargo_workspace.rs b/crates/project-model/src/cargo_workspace.rs index e3fdeb448d..649a149504 100644 --- a/crates/project-model/src/cargo_workspace.rs +++ b/crates/project-model/src/cargo_workspace.rs @@ -10,7 +10,7 @@ use base_db::Edition; use cargo_metadata::{CargoOpt, MetadataCommand}; use la_arena::{Arena, Idx}; use paths::{AbsPath, AbsPathBuf}; -use rustc_hash::FxHashMap; +use rustc_hash::{FxHashMap, FxHashSet}; use serde::Deserialize; use serde_json::from_value; @@ -491,6 +491,21 @@ impl CargoWorkspace { None } + /// Returns the union of the features of all member crates in this workspace. + pub fn workspace_features(&self) -> FxHashSet { + self.packages() + .filter_map(|package| { + let package = &self[package]; + if package.is_member { + Some(package.features.keys().cloned()) + } else { + None + } + }) + .flatten() + .collect() + } + fn is_unique(&self, name: &str) -> bool { self.packages.iter().filter(|(_, v)| v.name == name).count() == 1 } diff --git a/crates/rust-analyzer/src/cargo_target_spec.rs b/crates/rust-analyzer/src/cargo_target_spec.rs index cf51cf15a0..3035dc3330 100644 --- a/crates/rust-analyzer/src/cargo_target_spec.rs +++ b/crates/rust-analyzer/src/cargo_target_spec.rs @@ -5,6 +5,7 @@ use std::mem; use cfg::{CfgAtom, CfgExpr}; use ide::{Cancellable, FileId, RunnableKind, TestId}; use project_model::{self, CargoFeatures, ManifestPath, TargetKind}; +use rustc_hash::FxHashSet; use vfs::AbsPathBuf; use crate::global_state::GlobalStateSnapshot; @@ -21,6 +22,7 @@ pub(crate) struct CargoTargetSpec { pub(crate) target: String, pub(crate) target_kind: TargetKind, pub(crate) required_features: Vec, + pub(crate) features: FxHashSet, } impl CargoTargetSpec { @@ -73,12 +75,13 @@ impl CargoTargetSpec { } } - let target_required_features = if let Some(mut spec) = spec { + let (allowed_features, target_required_features) = if let Some(mut spec) = spec { + let allowed_features = mem::take(&mut spec.features); let required_features = mem::take(&mut spec.required_features); spec.push_to(&mut args, kind); - required_features + (allowed_features, required_features) } else { - Vec::new() + (Default::default(), Default::default()) }; let cargo_config = snap.config.cargo(); @@ -97,7 +100,9 @@ impl CargoTargetSpec { required_features(cfg, &mut feats); } - feats.extend(features.iter().cloned()); + feats.extend( + features.iter().filter(|&feat| allowed_features.contains(feat)).cloned(), + ); feats.extend(target_required_features); feats.dedup(); @@ -136,6 +141,7 @@ impl CargoTargetSpec { target: target_data.name.clone(), target_kind: target_data.kind, required_features: target_data.required_features.clone(), + features: package_data.features.keys().cloned().collect(), }; Ok(Some(res))