From 2607c09fddef36da0d6f0a84625db5e20a5ebde3 Mon Sep 17 00:00:00 2001 From: Chayim Refael Friedman Date: Mon, 12 Aug 2024 02:47:31 +0300 Subject: [PATCH] Allow declaring cfg groups in rust-project.json, to help sharing common cfgs --- crates/project-model/src/project_json.rs | 34 +- crates/project-model/src/tests.rs | 6 + .../project-model/test_data/cfg-groups.json | 26 + .../output/rust_project_cfg_groups.txt | 545 ++++++++++++++++++ docs/user/manual.adoc | 12 + 5 files changed, 619 insertions(+), 4 deletions(-) create mode 100644 crates/project-model/test_data/cfg-groups.json create mode 100644 crates/project-model/test_data/output/rust_project_cfg_groups.txt diff --git a/crates/project-model/src/project_json.rs b/crates/project-model/src/project_json.rs index 7dea0c3839..a09c7a77ab 100644 --- a/crates/project-model/src/project_json.rs +++ b/crates/project-model/src/project_json.rs @@ -52,7 +52,7 @@ use base_db::{CrateDisplayName, CrateName}; use cfg::CfgAtom; use paths::{AbsPath, AbsPathBuf, Utf8PathBuf}; -use rustc_hash::FxHashMap; +use rustc_hash::{FxHashMap, FxHashSet}; use serde::{de, Deserialize, Serialize}; use span::Edition; @@ -122,6 +122,25 @@ impl ProjectJson { None => None, }; + let cfg = crate_data + .cfg_groups + .iter() + .flat_map(|cfg_extend| { + let cfg_group = data.cfg_groups.get(cfg_extend); + match cfg_group { + Some(cfg_group) => cfg_group.0.iter().cloned(), + None => { + tracing::error!( + "Unknown cfg group `{cfg_extend}` in crate `{}`", + crate_data.display_name.as_deref().unwrap_or(""), + ); + [].iter().cloned() + } + } + }) + .chain(crate_data.cfg.0) + .collect(); + Crate { display_name: crate_data .display_name @@ -131,7 +150,7 @@ impl ProjectJson { edition: crate_data.edition.into(), version: crate_data.version.as_ref().map(ToString::to_string), deps: crate_data.deps, - cfg: crate_data.cfg, + cfg, target: crate_data.target, env: crate_data.env, proc_macro_dylib_path: crate_data @@ -306,11 +325,17 @@ pub enum RunnableKind { pub struct ProjectJsonData { sysroot: Option, sysroot_src: Option, + #[serde(default)] + cfg_groups: FxHashMap, crates: Vec, #[serde(default)] runnables: Vec, } +#[derive(Serialize, Deserialize, Debug, Clone, Eq, PartialEq, Default)] +#[serde(transparent)] +struct CfgList(#[serde(with = "cfg_")] Vec); + #[derive(Serialize, Deserialize, Debug, Clone, Eq, PartialEq)] struct CrateData { display_name: Option, @@ -320,8 +345,9 @@ struct CrateData { version: Option, deps: Vec, #[serde(default)] - #[serde(with = "cfg_")] - cfg: Vec, + cfg_groups: FxHashSet, + #[serde(default)] + cfg: CfgList, target: Option, #[serde(default)] env: FxHashMap, diff --git a/crates/project-model/src/tests.rs b/crates/project-model/src/tests.rs index e3bc81e196..8c0b475584 100644 --- a/crates/project-model/src/tests.rs +++ b/crates/project-model/src/tests.rs @@ -233,6 +233,12 @@ fn rust_project_hello_world_project_model() { ); } +#[test] +fn rust_project_cfg_groups() { + let (crate_graph, _proc_macros) = load_rust_project("cfg-groups.json"); + check_crate_graph(crate_graph, expect_file!["../test_data/output/rust_project_cfg_groups.txt"]); +} + #[test] fn rust_project_is_proc_macro_has_proc_macro_dep() { let (crate_graph, _proc_macros) = load_rust_project("is-proc-macro-project.json"); diff --git a/crates/project-model/test_data/cfg-groups.json b/crates/project-model/test_data/cfg-groups.json new file mode 100644 index 0000000000..29f83afd9d --- /dev/null +++ b/crates/project-model/test_data/cfg-groups.json @@ -0,0 +1,26 @@ +{ + "sysroot_src": null, + "cfg_groups": { + "group1": ["group1_cfg=\"some_config\"", "group1_other_cfg=\"other_config\""], + "group2": ["group2_cfg=\"yet_another_config\""] + }, + "crates": [ + { + "display_name": "hello_world", + "root_module": "$ROOT$src/lib.rs", + "edition": "2018", + "cfg_groups": ["group1", "group2"], + "deps": [], + "is_workspace_member": true + }, + { + "display_name": "other_crate", + "root_module": "$ROOT$src/lib.rs", + "edition": "2018", + "cfg_groups": ["group2"], + "cfg": ["group2_cfg=\"fourth_config\"", "unrelated_cfg"], + "deps": [], + "is_workspace_member": true + } + ] +} diff --git a/crates/project-model/test_data/output/rust_project_cfg_groups.txt b/crates/project-model/test_data/output/rust_project_cfg_groups.txt new file mode 100644 index 0000000000..8261e5a2d9 --- /dev/null +++ b/crates/project-model/test_data/output/rust_project_cfg_groups.txt @@ -0,0 +1,545 @@ +{ + 0: CrateData { + root_file_id: FileId( + 1, + ), + edition: Edition2021, + version: None, + display_name: Some( + CrateDisplayName { + crate_name: CrateName( + "alloc", + ), + canonical_name: "alloc", + }, + ), + cfg_options: CfgOptions( + [ + "debug_assertions", + "miri", + ], + ), + potential_cfg_options: None, + env: Env { + entries: {}, + }, + dependencies: [ + Dependency { + crate_id: Idx::(1), + name: CrateName( + "core", + ), + prelude: true, + sysroot: false, + }, + ], + origin: Lang( + Alloc, + ), + is_proc_macro: false, + }, + 1: CrateData { + root_file_id: FileId( + 2, + ), + edition: Edition2021, + version: None, + display_name: Some( + CrateDisplayName { + crate_name: CrateName( + "core", + ), + canonical_name: "core", + }, + ), + cfg_options: CfgOptions( + [ + "debug_assertions", + "miri", + ], + ), + potential_cfg_options: None, + env: Env { + entries: {}, + }, + dependencies: [], + origin: Lang( + Core, + ), + is_proc_macro: false, + }, + 2: CrateData { + root_file_id: FileId( + 3, + ), + edition: Edition2021, + version: None, + display_name: Some( + CrateDisplayName { + crate_name: CrateName( + "panic_abort", + ), + canonical_name: "panic_abort", + }, + ), + cfg_options: CfgOptions( + [ + "debug_assertions", + "miri", + ], + ), + potential_cfg_options: None, + env: Env { + entries: {}, + }, + dependencies: [], + origin: Lang( + Other, + ), + is_proc_macro: false, + }, + 3: CrateData { + root_file_id: FileId( + 4, + ), + edition: Edition2021, + version: None, + display_name: Some( + CrateDisplayName { + crate_name: CrateName( + "panic_unwind", + ), + canonical_name: "panic_unwind", + }, + ), + cfg_options: CfgOptions( + [ + "debug_assertions", + "miri", + ], + ), + potential_cfg_options: None, + env: Env { + entries: {}, + }, + dependencies: [], + origin: Lang( + Other, + ), + is_proc_macro: false, + }, + 4: CrateData { + root_file_id: FileId( + 5, + ), + edition: Edition2021, + version: None, + display_name: Some( + CrateDisplayName { + crate_name: CrateName( + "proc_macro", + ), + canonical_name: "proc_macro", + }, + ), + cfg_options: CfgOptions( + [ + "debug_assertions", + "miri", + ], + ), + potential_cfg_options: None, + env: Env { + entries: {}, + }, + dependencies: [ + Dependency { + crate_id: Idx::(6), + name: CrateName( + "std", + ), + prelude: true, + sysroot: false, + }, + Dependency { + crate_id: Idx::(1), + name: CrateName( + "core", + ), + prelude: true, + sysroot: false, + }, + ], + origin: Lang( + ProcMacro, + ), + is_proc_macro: false, + }, + 5: CrateData { + root_file_id: FileId( + 6, + ), + edition: Edition2021, + version: None, + display_name: Some( + CrateDisplayName { + crate_name: CrateName( + "profiler_builtins", + ), + canonical_name: "profiler_builtins", + }, + ), + cfg_options: CfgOptions( + [ + "debug_assertions", + "miri", + ], + ), + potential_cfg_options: None, + env: Env { + entries: {}, + }, + dependencies: [], + origin: Lang( + Other, + ), + is_proc_macro: false, + }, + 6: CrateData { + root_file_id: FileId( + 7, + ), + edition: Edition2021, + version: None, + display_name: Some( + CrateDisplayName { + crate_name: CrateName( + "std", + ), + canonical_name: "std", + }, + ), + cfg_options: CfgOptions( + [ + "debug_assertions", + "miri", + ], + ), + potential_cfg_options: None, + env: Env { + entries: {}, + }, + dependencies: [ + Dependency { + crate_id: Idx::(0), + name: CrateName( + "alloc", + ), + prelude: true, + sysroot: false, + }, + Dependency { + crate_id: Idx::(3), + name: CrateName( + "panic_unwind", + ), + prelude: true, + sysroot: false, + }, + Dependency { + crate_id: Idx::(2), + name: CrateName( + "panic_abort", + ), + prelude: true, + sysroot: false, + }, + Dependency { + crate_id: Idx::(1), + name: CrateName( + "core", + ), + prelude: true, + sysroot: false, + }, + Dependency { + crate_id: Idx::(5), + name: CrateName( + "profiler_builtins", + ), + prelude: true, + sysroot: false, + }, + Dependency { + crate_id: Idx::(9), + name: CrateName( + "unwind", + ), + prelude: true, + sysroot: false, + }, + Dependency { + crate_id: Idx::(7), + name: CrateName( + "std_detect", + ), + prelude: true, + sysroot: false, + }, + Dependency { + crate_id: Idx::(8), + name: CrateName( + "test", + ), + prelude: true, + sysroot: false, + }, + ], + origin: Lang( + Std, + ), + is_proc_macro: false, + }, + 7: CrateData { + root_file_id: FileId( + 8, + ), + edition: Edition2021, + version: None, + display_name: Some( + CrateDisplayName { + crate_name: CrateName( + "std_detect", + ), + canonical_name: "std_detect", + }, + ), + cfg_options: CfgOptions( + [ + "debug_assertions", + "miri", + ], + ), + potential_cfg_options: None, + env: Env { + entries: {}, + }, + dependencies: [], + origin: Lang( + Other, + ), + is_proc_macro: false, + }, + 8: CrateData { + root_file_id: FileId( + 9, + ), + edition: Edition2021, + version: None, + display_name: Some( + CrateDisplayName { + crate_name: CrateName( + "test", + ), + canonical_name: "test", + }, + ), + cfg_options: CfgOptions( + [ + "debug_assertions", + "miri", + ], + ), + potential_cfg_options: None, + env: Env { + entries: {}, + }, + dependencies: [], + origin: Lang( + Test, + ), + is_proc_macro: false, + }, + 9: CrateData { + root_file_id: FileId( + 10, + ), + edition: Edition2021, + version: None, + display_name: Some( + CrateDisplayName { + crate_name: CrateName( + "unwind", + ), + canonical_name: "unwind", + }, + ), + cfg_options: CfgOptions( + [ + "debug_assertions", + "miri", + ], + ), + potential_cfg_options: None, + env: Env { + entries: {}, + }, + dependencies: [], + origin: Lang( + Other, + ), + is_proc_macro: false, + }, + 10: CrateData { + root_file_id: FileId( + 11, + ), + edition: Edition2018, + version: None, + display_name: Some( + CrateDisplayName { + crate_name: CrateName( + "hello_world", + ), + canonical_name: "hello_world", + }, + ), + cfg_options: CfgOptions( + [ + "group1_cfg=some_config", + "group1_other_cfg=other_config", + "group2_cfg=yet_another_config", + "rust_analyzer", + ], + ), + potential_cfg_options: None, + env: Env { + entries: {}, + }, + dependencies: [ + Dependency { + crate_id: Idx::(1), + name: CrateName( + "core", + ), + prelude: true, + sysroot: true, + }, + Dependency { + crate_id: Idx::(0), + name: CrateName( + "alloc", + ), + prelude: false, + sysroot: true, + }, + Dependency { + crate_id: Idx::(6), + name: CrateName( + "std", + ), + prelude: true, + sysroot: true, + }, + Dependency { + crate_id: Idx::(8), + name: CrateName( + "test", + ), + prelude: false, + sysroot: true, + }, + Dependency { + crate_id: Idx::(4), + name: CrateName( + "proc_macro", + ), + prelude: false, + sysroot: true, + }, + ], + origin: Local { + repo: None, + name: Some( + "hello_world", + ), + }, + is_proc_macro: false, + }, + 11: CrateData { + root_file_id: FileId( + 12, + ), + edition: Edition2018, + version: None, + display_name: Some( + CrateDisplayName { + crate_name: CrateName( + "other_crate", + ), + canonical_name: "other_crate", + }, + ), + cfg_options: CfgOptions( + [ + "group2_cfg=fourth_config", + "group2_cfg=yet_another_config", + "rust_analyzer", + "unrelated_cfg", + ], + ), + potential_cfg_options: None, + env: Env { + entries: {}, + }, + dependencies: [ + Dependency { + crate_id: Idx::(1), + name: CrateName( + "core", + ), + prelude: true, + sysroot: true, + }, + Dependency { + crate_id: Idx::(0), + name: CrateName( + "alloc", + ), + prelude: false, + sysroot: true, + }, + Dependency { + crate_id: Idx::(6), + name: CrateName( + "std", + ), + prelude: true, + sysroot: true, + }, + Dependency { + crate_id: Idx::(8), + name: CrateName( + "test", + ), + prelude: false, + sysroot: true, + }, + Dependency { + crate_id: Idx::(4), + name: CrateName( + "proc_macro", + ), + prelude: false, + sysroot: true, + }, + ], + origin: Local { + repo: None, + name: Some( + "other_crate", + ), + }, + is_proc_macro: false, + }, +} \ No newline at end of file diff --git a/docs/user/manual.adoc b/docs/user/manual.adoc index 703ec66921..246ebdab2c 100644 --- a/docs/user/manual.adoc +++ b/docs/user/manual.adoc @@ -705,6 +705,12 @@ interface JsonProject { /// several different "sysroots" in one graph of /// crates. sysroot_src?: string; + /// List of groups of common cfg values, to allow + /// sharing them between crates. + /// + /// Maps from group name to its cfgs. Cfg follow + /// the same format as `Crate.cfg`. + cfg_groups?: { [key: string]: string[]; }; /// The set of crates comprising the current /// project. Must include all transitive /// dependencies as well as sysroot crate (libstd, @@ -754,6 +760,12 @@ interface Crate { include_dirs: string[], exclude_dirs: string[], }, + /// List of cfg groups this crate inherits. + /// + /// All cfg in these groups will be concatenated to + /// `cfg`. It is impossible to replace a value from + /// the groups. + cfg_groups?: string[]; /// The set of cfgs activated for a given crate, like /// `["unix", "feature=\"foo\"", "feature=\"bar\""]`. cfg: string[];