Auto merge of #14910 - Veykril:cargo-features, r=Veykril

Filter out unused cargo features from config

Closes https://github.com/rust-lang/rust-analyzer/issues/11836
This commit is contained in:
bors 2023-05-26 20:17:24 +00:00
commit 7c81fff520
6 changed files with 50 additions and 12 deletions

View File

@ -58,7 +58,6 @@ jobs:
uses: actions/checkout@v3 uses: actions/checkout@v3
with: with:
ref: ${{ github.event.pull_request.head.sha }} ref: ${{ github.event.pull_request.head.sha }}
fetch-depth: 20
- name: Install Rust toolchain - name: Install Rust toolchain
run: | run: |

1
Cargo.lock generated
View File

@ -1334,6 +1334,7 @@ dependencies = [
"cargo_metadata", "cargo_metadata",
"cfg", "cfg",
"expect-test", "expect-test",
"itertools",
"la-arena", "la-arena",
"paths", "paths",
"profile", "profile",

View File

@ -21,6 +21,7 @@ serde.workspace = true
triomphe.workspace = true triomphe.workspace = true
anyhow = "1.0.62" anyhow = "1.0.62"
la-arena = { version = "0.3.0", path = "../../lib/la-arena" } la-arena = { version = "0.3.0", path = "../../lib/la-arena" }
itertools = "0.10.5"
# local deps # local deps
base-db.workspace = true base-db.workspace = true

View File

@ -14,9 +14,10 @@
}; };
use cargo_metadata::{camino::Utf8Path, Message}; use cargo_metadata::{camino::Utf8Path, Message};
use itertools::Itertools;
use la_arena::ArenaMap; use la_arena::ArenaMap;
use paths::{AbsPath, AbsPathBuf}; use paths::{AbsPath, AbsPathBuf};
use rustc_hash::FxHashMap; use rustc_hash::{FxHashMap, FxHashSet};
use semver::Version; use semver::Version;
use serde::Deserialize; use serde::Deserialize;
@ -56,7 +57,10 @@ fn is_unchanged(&self) -> bool {
} }
impl WorkspaceBuildScripts { impl WorkspaceBuildScripts {
fn build_command(config: &CargoConfig) -> io::Result<Command> { fn build_command(
config: &CargoConfig,
allowed_features: &FxHashSet<String>,
) -> io::Result<Command> {
let mut cmd = match config.run_build_script_command.as_deref() { let mut cmd = match config.run_build_script_command.as_deref() {
Some([program, args @ ..]) => { Some([program, args @ ..]) => {
let mut cmd = Command::new(program); let mut cmd = Command::new(program);
@ -88,7 +92,12 @@ fn build_command(config: &CargoConfig) -> io::Result<Command> {
} }
if !features.is_empty() { if !features.is_empty() {
cmd.arg("--features"); cmd.arg("--features");
cmd.arg(features.join(" ")); cmd.arg(
features
.iter()
.filter(|&feat| allowed_features.contains(feat))
.join(","),
);
} }
} }
} }
@ -127,13 +136,20 @@ pub(crate) fn run_for_workspace(
} }
.as_ref(); .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), .. }) Ok(WorkspaceBuildScripts { error: Some(error), .. })
if toolchain.as_ref().map_or(false, |it| *it >= RUST_1_62) => if toolchain.as_ref().map_or(false, |it| *it >= RUST_1_62) =>
{ {
// building build scripts failed, attempt to build with --keep-going so // building build scripts failed, attempt to build with --keep-going so
// that we potentially get more build data // 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"); cmd.args(["-Z", "unstable-options", "--keep-going"]).env("RUSTC_BOOTSTRAP", "1");
let mut res = Self::run_per_ws(cmd, workspace, current_dir, progress)?; let mut res = Self::run_per_ws(cmd, workspace, current_dir, progress)?;
res.error = Some(error); res.error = Some(error);
@ -161,7 +177,7 @@ pub(crate) fn run_once(
)) ))
} }
}; };
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 // NB: Cargo.toml could have been modified between `cargo metadata` and
// `cargo check`. We shouldn't assume that package ids we see here are // `cargo check`. We shouldn't assume that package ids we see here are
// exactly those from `config`. // exactly those from `config`.

View File

@ -10,7 +10,7 @@
use cargo_metadata::{CargoOpt, MetadataCommand}; use cargo_metadata::{CargoOpt, MetadataCommand};
use la_arena::{Arena, Idx}; use la_arena::{Arena, Idx};
use paths::{AbsPath, AbsPathBuf}; use paths::{AbsPath, AbsPathBuf};
use rustc_hash::FxHashMap; use rustc_hash::{FxHashMap, FxHashSet};
use serde::Deserialize; use serde::Deserialize;
use serde_json::from_value; use serde_json::from_value;
@ -491,6 +491,21 @@ pub fn parent_manifests(&self, manifest_path: &ManifestPath) -> Option<Vec<Manif
None None
} }
/// Returns the union of the features of all member crates in this workspace.
pub fn workspace_features(&self) -> FxHashSet<String> {
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 { fn is_unique(&self, name: &str) -> bool {
self.packages.iter().filter(|(_, v)| v.name == name).count() == 1 self.packages.iter().filter(|(_, v)| v.name == name).count() == 1
} }

View File

@ -5,6 +5,7 @@
use cfg::{CfgAtom, CfgExpr}; use cfg::{CfgAtom, CfgExpr};
use ide::{Cancellable, FileId, RunnableKind, TestId}; use ide::{Cancellable, FileId, RunnableKind, TestId};
use project_model::{self, CargoFeatures, ManifestPath, TargetKind}; use project_model::{self, CargoFeatures, ManifestPath, TargetKind};
use rustc_hash::FxHashSet;
use vfs::AbsPathBuf; use vfs::AbsPathBuf;
use crate::global_state::GlobalStateSnapshot; use crate::global_state::GlobalStateSnapshot;
@ -21,6 +22,7 @@ pub(crate) struct CargoTargetSpec {
pub(crate) target: String, pub(crate) target: String,
pub(crate) target_kind: TargetKind, pub(crate) target_kind: TargetKind,
pub(crate) required_features: Vec<String>, pub(crate) required_features: Vec<String>,
pub(crate) features: FxHashSet<String>,
} }
impl CargoTargetSpec { impl CargoTargetSpec {
@ -73,12 +75,13 @@ pub(crate) fn runnable_args(
} }
} }
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); let required_features = mem::take(&mut spec.required_features);
spec.push_to(&mut args, kind); spec.push_to(&mut args, kind);
required_features (allowed_features, required_features)
} else { } else {
Vec::new() (Default::default(), Default::default())
}; };
let cargo_config = snap.config.cargo(); let cargo_config = snap.config.cargo();
@ -97,7 +100,9 @@ pub(crate) fn runnable_args(
required_features(cfg, &mut feats); 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.extend(target_required_features);
feats.dedup(); feats.dedup();
@ -136,6 +141,7 @@ pub(crate) fn for_file(
target: target_data.name.clone(), target: target_data.name.clone(),
target_kind: target_data.kind, target_kind: target_data.kind,
required_features: target_data.required_features.clone(), required_features: target_data.required_features.clone(),
features: package_data.features.keys().cloned().collect(),
}; };
Ok(Some(res)) Ok(Some(res))