aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--crates/base_db/src/fixture.rs3
-rw-r--r--crates/base_db/src/input.rs13
-rw-r--r--crates/cfg/src/lib.rs20
-rw-r--r--crates/hir/src/lib.rs4
-rw-r--r--crates/ide/src/lib.rs1
-rw-r--r--crates/ide_completion/src/completions/attribute.rs15
-rw-r--r--crates/ide_completion/src/completions/attribute/cfg.rs112
-rw-r--r--crates/project_model/src/workspace.rs11
8 files changed, 179 insertions, 0 deletions
diff --git a/crates/base_db/src/fixture.rs b/crates/base_db/src/fixture.rs
index 6ce377710..7d5d12e63 100644
--- a/crates/base_db/src/fixture.rs
+++ b/crates/base_db/src/fixture.rs
@@ -128,6 +128,7 @@ impl ChangeFixture {
128 file_id, 128 file_id,
129 meta.edition, 129 meta.edition,
130 Some(crate_name.clone().into()), 130 Some(crate_name.clone().into()),
131 meta.cfg.clone(),
131 meta.cfg, 132 meta.cfg,
132 meta.env, 133 meta.env,
133 Default::default(), 134 Default::default(),
@@ -157,6 +158,7 @@ impl ChangeFixture {
157 crate_root, 158 crate_root,
158 Edition::Edition2018, 159 Edition::Edition2018,
159 Some(CrateName::new("test").unwrap().into()), 160 Some(CrateName::new("test").unwrap().into()),
161 default_cfg.clone(),
160 default_cfg, 162 default_cfg,
161 Env::default(), 163 Env::default(),
162 Default::default(), 164 Default::default(),
@@ -186,6 +188,7 @@ impl ChangeFixture {
186 Edition::Edition2021, 188 Edition::Edition2021,
187 Some(CrateDisplayName::from_canonical_name("core".to_string())), 189 Some(CrateDisplayName::from_canonical_name("core".to_string())),
188 CfgOptions::default(), 190 CfgOptions::default(),
191 CfgOptions::default(),
189 Env::default(), 192 Env::default(),
190 Vec::new(), 193 Vec::new(),
191 ); 194 );
diff --git a/crates/base_db/src/input.rs b/crates/base_db/src/input.rs
index 23cb0c839..0c51a59a0 100644
--- a/crates/base_db/src/input.rs
+++ b/crates/base_db/src/input.rs
@@ -189,6 +189,7 @@ pub struct CrateData {
189 /// `Dependency` matters), this name should only be used for UI. 189 /// `Dependency` matters), this name should only be used for UI.
190 pub display_name: Option<CrateDisplayName>, 190 pub display_name: Option<CrateDisplayName>,
191 pub cfg_options: CfgOptions, 191 pub cfg_options: CfgOptions,
192 pub potential_cfg_options: CfgOptions,
192 pub env: Env, 193 pub env: Env,
193 pub dependencies: Vec<Dependency>, 194 pub dependencies: Vec<Dependency>,
194 pub proc_macro: Vec<ProcMacro>, 195 pub proc_macro: Vec<ProcMacro>,
@@ -219,6 +220,7 @@ impl CrateGraph {
219 edition: Edition, 220 edition: Edition,
220 display_name: Option<CrateDisplayName>, 221 display_name: Option<CrateDisplayName>,
221 cfg_options: CfgOptions, 222 cfg_options: CfgOptions,
223 potential_cfg_options: CfgOptions,
222 env: Env, 224 env: Env,
223 proc_macro: Vec<ProcMacro>, 225 proc_macro: Vec<ProcMacro>,
224 ) -> CrateId { 226 ) -> CrateId {
@@ -227,6 +229,7 @@ impl CrateGraph {
227 edition, 229 edition,
228 display_name, 230 display_name,
229 cfg_options, 231 cfg_options,
232 potential_cfg_options,
230 env, 233 env,
231 proc_macro, 234 proc_macro,
232 dependencies: Vec::new(), 235 dependencies: Vec::new(),
@@ -504,6 +507,7 @@ mod tests {
504 Edition2018, 507 Edition2018,
505 None, 508 None,
506 CfgOptions::default(), 509 CfgOptions::default(),
510 CfgOptions::default(),
507 Env::default(), 511 Env::default(),
508 Default::default(), 512 Default::default(),
509 ); 513 );
@@ -512,6 +516,7 @@ mod tests {
512 Edition2018, 516 Edition2018,
513 None, 517 None,
514 CfgOptions::default(), 518 CfgOptions::default(),
519 CfgOptions::default(),
515 Env::default(), 520 Env::default(),
516 Default::default(), 521 Default::default(),
517 ); 522 );
@@ -520,6 +525,7 @@ mod tests {
520 Edition2018, 525 Edition2018,
521 None, 526 None,
522 CfgOptions::default(), 527 CfgOptions::default(),
528 CfgOptions::default(),
523 Env::default(), 529 Env::default(),
524 Default::default(), 530 Default::default(),
525 ); 531 );
@@ -536,6 +542,7 @@ mod tests {
536 Edition2018, 542 Edition2018,
537 None, 543 None,
538 CfgOptions::default(), 544 CfgOptions::default(),
545 CfgOptions::default(),
539 Env::default(), 546 Env::default(),
540 Default::default(), 547 Default::default(),
541 ); 548 );
@@ -544,6 +551,7 @@ mod tests {
544 Edition2018, 551 Edition2018,
545 None, 552 None,
546 CfgOptions::default(), 553 CfgOptions::default(),
554 CfgOptions::default(),
547 Env::default(), 555 Env::default(),
548 Default::default(), 556 Default::default(),
549 ); 557 );
@@ -559,6 +567,7 @@ mod tests {
559 Edition2018, 567 Edition2018,
560 None, 568 None,
561 CfgOptions::default(), 569 CfgOptions::default(),
570 CfgOptions::default(),
562 Env::default(), 571 Env::default(),
563 Default::default(), 572 Default::default(),
564 ); 573 );
@@ -567,6 +576,7 @@ mod tests {
567 Edition2018, 576 Edition2018,
568 None, 577 None,
569 CfgOptions::default(), 578 CfgOptions::default(),
579 CfgOptions::default(),
570 Env::default(), 580 Env::default(),
571 Default::default(), 581 Default::default(),
572 ); 582 );
@@ -575,6 +585,7 @@ mod tests {
575 Edition2018, 585 Edition2018,
576 None, 586 None,
577 CfgOptions::default(), 587 CfgOptions::default(),
588 CfgOptions::default(),
578 Env::default(), 589 Env::default(),
579 Default::default(), 590 Default::default(),
580 ); 591 );
@@ -590,6 +601,7 @@ mod tests {
590 Edition2018, 601 Edition2018,
591 None, 602 None,
592 CfgOptions::default(), 603 CfgOptions::default(),
604 CfgOptions::default(),
593 Env::default(), 605 Env::default(),
594 Default::default(), 606 Default::default(),
595 ); 607 );
@@ -598,6 +610,7 @@ mod tests {
598 Edition2018, 610 Edition2018,
599 None, 611 None,
600 CfgOptions::default(), 612 CfgOptions::default(),
613 CfgOptions::default(),
601 Env::default(), 614 Env::default(),
602 Default::default(), 615 Default::default(),
603 ); 616 );
diff --git a/crates/cfg/src/lib.rs b/crates/cfg/src/lib.rs
index 916d39a0b..9a4baa636 100644
--- a/crates/cfg/src/lib.rs
+++ b/crates/cfg/src/lib.rs
@@ -50,6 +50,26 @@ impl CfgOptions {
50 self.enabled.remove(&atom); 50 self.enabled.remove(&atom);
51 } 51 }
52 } 52 }
53
54 pub fn get_cfg_keys(&self) -> Vec<&SmolStr> {
55 self.enabled
56 .iter()
57 .map(|x| match x {
58 CfgAtom::Flag(key) => key,
59 CfgAtom::KeyValue { key, .. } => key,
60 })
61 .collect()
62 }
63
64 pub fn get_cfg_values(&self, cfg_key: &str) -> Vec<&SmolStr> {
65 self.enabled
66 .iter()
67 .filter_map(|x| match x {
68 CfgAtom::KeyValue { key, value } if cfg_key == key => Some(value),
69 _ => None,
70 })
71 .collect()
72 }
53} 73}
54 74
55#[derive(Clone, Debug, PartialEq, Eq)] 75#[derive(Clone, Debug, PartialEq, Eq)]
diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs
index 88490fea9..30cc34403 100644
--- a/crates/hir/src/lib.rs
+++ b/crates/hir/src/lib.rs
@@ -233,6 +233,10 @@ impl Crate {
233 pub fn cfg(&self, db: &dyn HirDatabase) -> CfgOptions { 233 pub fn cfg(&self, db: &dyn HirDatabase) -> CfgOptions {
234 db.crate_graph()[self.id].cfg_options.clone() 234 db.crate_graph()[self.id].cfg_options.clone()
235 } 235 }
236
237 pub fn potential_cfg(&self, db: &dyn HirDatabase) -> CfgOptions {
238 db.crate_graph()[self.id].potential_cfg_options.clone()
239 }
236} 240}
237 241
238#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] 242#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
diff --git a/crates/ide/src/lib.rs b/crates/ide/src/lib.rs
index 3798f32cc..aac084012 100644
--- a/crates/ide/src/lib.rs
+++ b/crates/ide/src/lib.rs
@@ -217,6 +217,7 @@ impl Analysis {
217 file_id, 217 file_id,
218 Edition::Edition2018, 218 Edition::Edition2018,
219 None, 219 None,
220 cfg_options.clone(),
220 cfg_options, 221 cfg_options,
221 Env::default(), 222 Env::default(),
222 Default::default(), 223 Default::default(),
diff --git a/crates/ide_completion/src/completions/attribute.rs b/crates/ide_completion/src/completions/attribute.rs
index 78fc30e16..cc4f4b2af 100644
--- a/crates/ide_completion/src/completions/attribute.rs
+++ b/crates/ide_completion/src/completions/attribute.rs
@@ -15,6 +15,7 @@ use crate::{
15 Completions, 15 Completions,
16}; 16};
17 17
18mod cfg;
18mod derive; 19mod derive;
19mod lint; 20mod lint;
20mod repr; 21mod repr;
@@ -30,6 +31,9 @@ pub(crate) fn complete_attribute(acc: &mut Completions, ctx: &CompletionContext)
30 lint::complete_lint(acc, ctx, token_tree.clone(), DEFAULT_LINTS); 31 lint::complete_lint(acc, ctx, token_tree.clone(), DEFAULT_LINTS);
31 lint::complete_lint(acc, ctx, token_tree, CLIPPY_LINTS); 32 lint::complete_lint(acc, ctx, token_tree, CLIPPY_LINTS);
32 } 33 }
34 "cfg" => {
35 cfg::complete_cfg(acc, ctx);
36 }
33 _ => (), 37 _ => (),
34 }, 38 },
35 (None, Some(_)) => (), 39 (None, Some(_)) => (),
@@ -852,4 +856,15 @@ mod tests {
852 "#]], 856 "#]],
853 ); 857 );
854 } 858 }
859
860 #[test]
861 fn test_cfg() {
862 check(
863 r#"#[cfg(target_endian = $0"#,
864 expect![[r#"
865 at little
866 at big
867"#]],
868 );
869 }
855} 870}
diff --git a/crates/ide_completion/src/completions/attribute/cfg.rs b/crates/ide_completion/src/completions/attribute/cfg.rs
new file mode 100644
index 000000000..847e6529a
--- /dev/null
+++ b/crates/ide_completion/src/completions/attribute/cfg.rs
@@ -0,0 +1,112 @@
1//! Completion for cfg
2
3use std::iter;
4
5use syntax::SyntaxKind;
6
7use crate::{
8 completions::Completions, context::CompletionContext, item::CompletionKind, CompletionItem,
9 CompletionItemKind,
10};
11
12pub(crate) fn complete_cfg(acc: &mut Completions, ctx: &CompletionContext) {
13 let add_completion = |item: &&str| {
14 let mut completion =
15 CompletionItem::new(CompletionKind::Attribute, ctx.source_range(), *item);
16 completion.insert_text(format!(r#""{}""#, item));
17 completion.kind(CompletionItemKind::Attribute);
18 acc.add(completion.build());
19 };
20
21 let previous = iter::successors(ctx.original_token.prev_token(), |t| {
22 (matches!(t.kind(), SyntaxKind::EQ) || t.kind().is_trivia())
23 .then(|| t.prev_token())
24 .flatten()
25 })
26 .find(|t| matches!(t.kind(), SyntaxKind::IDENT));
27
28 match previous.as_ref().map(|p| p.text()) {
29 Some("target_arch") => KNOWN_ARCH.iter().for_each(add_completion),
30 Some("target_env") => KNOWN_ENV.iter().for_each(add_completion),
31 Some("target_os") => KNOWN_OS.iter().for_each(add_completion),
32 Some("target_vendor") => KNOWN_VENDOR.iter().for_each(add_completion),
33 Some("target_endian") => ["little", "big"].iter().for_each(add_completion),
34 Some(name) => {
35 ctx.krate.map(|krate| {
36 krate.potential_cfg(ctx.db).get_cfg_values(&name).iter().for_each(|s| {
37 let mut item = CompletionItem::new(
38 CompletionKind::Attribute,
39 ctx.source_range(),
40 s.as_str(),
41 );
42 item.insert_text(format!(r#""{}""#, s));
43
44 acc.add(item.build());
45 })
46 });
47 }
48 None => {
49 ctx.krate.map(|krate| {
50 krate.potential_cfg(ctx.db).get_cfg_keys().iter().for_each(|s| {
51 let item = CompletionItem::new(
52 CompletionKind::Attribute,
53 ctx.source_range(),
54 s.as_str(),
55 );
56 acc.add(item.build());
57 })
58 });
59 }
60 };
61}
62
63const KNOWN_ARCH: [&'static str; 19] = [
64 "aarch64",
65 "arm",
66 "avr",
67 "hexagon",
68 "mips",
69 "mips64",
70 "msp430",
71 "nvptx64",
72 "powerpc",
73 "powerpc64",
74 "riscv32",
75 "riscv64",
76 "s390x",
77 "sparc",
78 "sparc64",
79 "wasm32",
80 "wasm64",
81 "x86",
82 "x86_64",
83];
84
85const KNOWN_ENV: [&'static str; 7] =
86 ["eabihf", "gnu", "gnueabihf", "msvc", "relibc", "sgx", "uclibc"];
87
88const KNOWN_OS: [&'static str; 20] = [
89 "cuda",
90 "dragonfly",
91 "emscripten",
92 "freebsd",
93 "fuchsia",
94 "haiku",
95 "hermit",
96 "illumos",
97 "l4re",
98 "linux",
99 "netbsd",
100 "none",
101 "openbsd",
102 "psp",
103 "redox",
104 "solaris",
105 "uefi",
106 "unknown",
107 "vxworks",
108 "windows",
109];
110
111const KNOWN_VENDOR: [&'static str; 8] =
112 ["apple", "fortanix", "nvidia", "pc", "sony", "unknown", "wrs", "uwp"];
diff --git a/crates/project_model/src/workspace.rs b/crates/project_model/src/workspace.rs
index d8217f714..e67ba2bd9 100644
--- a/crates/project_model/src/workspace.rs
+++ b/crates/project_model/src/workspace.rs
@@ -384,6 +384,7 @@ fn project_json_to_crate_graph(
384 file_id, 384 file_id,
385 krate.edition, 385 krate.edition,
386 krate.display_name.clone(), 386 krate.display_name.clone(),
387 cfg_options.clone(),
387 cfg_options, 388 cfg_options,
388 env, 389 env,
389 proc_macro.unwrap_or_default(), 390 proc_macro.unwrap_or_default(),
@@ -580,6 +581,7 @@ fn detached_files_to_crate_graph(
580 Edition::Edition2018, 581 Edition::Edition2018,
581 display_name, 582 display_name,
582 cfg_options.clone(), 583 cfg_options.clone(),
584 cfg_options.clone(),
583 Env::default(), 585 Env::default(),
584 Vec::new(), 586 Vec::new(),
585 ); 587 );
@@ -719,11 +721,19 @@ fn add_target_crate_root(
719 .unwrap_or_default(); 721 .unwrap_or_default();
720 722
721 let display_name = CrateDisplayName::from_canonical_name(cargo_name.to_string()); 723 let display_name = CrateDisplayName::from_canonical_name(cargo_name.to_string());
724 let mut potential_cfg_options = cfg_options.clone();
725 potential_cfg_options.extend(
726 pkg.features
727 .iter()
728 .map(|feat| CfgFlag::KeyValue { key: "feature".into(), value: feat.0.into() }),
729 );
730
722 let crate_id = crate_graph.add_crate_root( 731 let crate_id = crate_graph.add_crate_root(
723 file_id, 732 file_id,
724 edition, 733 edition,
725 Some(display_name), 734 Some(display_name),
726 cfg_options, 735 cfg_options,
736 potential_cfg_options,
727 env, 737 env,
728 proc_macro, 738 proc_macro,
729 ); 739 );
@@ -753,6 +763,7 @@ fn sysroot_to_crate_graph(
753 Edition::Edition2018, 763 Edition::Edition2018,
754 Some(display_name), 764 Some(display_name),
755 cfg_options.clone(), 765 cfg_options.clone(),
766 cfg_options.clone(),
756 env, 767 env,
757 proc_macro, 768 proc_macro,
758 ); 769 );