diff options
-rw-r--r-- | crates/base_db/src/fixture.rs | 2 | ||||
-rw-r--r-- | crates/base_db/src/input.rs | 13 | ||||
-rw-r--r-- | crates/cfg/src/lib.rs | 20 | ||||
-rw-r--r-- | crates/hir/src/lib.rs | 4 | ||||
-rw-r--r-- | crates/ide/src/lib.rs | 1 | ||||
-rw-r--r-- | crates/ide_completion/src/completions/attribute.rs | 15 | ||||
-rw-r--r-- | crates/ide_completion/src/completions/attribute/cfg.rs | 126 | ||||
-rw-r--r-- | crates/project_model/src/workspace.rs | 4 |
8 files changed, 185 insertions, 0 deletions
diff --git a/crates/base_db/src/fixture.rs b/crates/base_db/src/fixture.rs index 6ce377710..6d3b1266e 100644 --- a/crates/base_db/src/fixture.rs +++ b/crates/base_db/src/fixture.rs | |||
@@ -131,6 +131,7 @@ impl ChangeFixture { | |||
131 | meta.cfg, | 131 | meta.cfg, |
132 | meta.env, | 132 | meta.env, |
133 | Default::default(), | 133 | Default::default(), |
134 | Default::default(), | ||
134 | ); | 135 | ); |
135 | let prev = crates.insert(crate_name.clone(), crate_id); | 136 | let prev = crates.insert(crate_name.clone(), crate_id); |
136 | assert!(prev.is_none()); | 137 | assert!(prev.is_none()); |
@@ -160,6 +161,7 @@ impl ChangeFixture { | |||
160 | default_cfg, | 161 | default_cfg, |
161 | Env::default(), | 162 | Env::default(), |
162 | Default::default(), | 163 | Default::default(), |
164 | Default::default(), | ||
163 | ); | 165 | ); |
164 | } else { | 166 | } else { |
165 | for (from, to) in crate_deps { | 167 | for (from, to) in crate_deps { |
diff --git a/crates/base_db/src/input.rs b/crates/base_db/src/input.rs index 23cb0c839..d99388f71 100644 --- a/crates/base_db/src/input.rs +++ b/crates/base_db/src/input.rs | |||
@@ -192,6 +192,7 @@ pub struct CrateData { | |||
192 | pub env: Env, | 192 | pub env: Env, |
193 | pub dependencies: Vec<Dependency>, | 193 | pub dependencies: Vec<Dependency>, |
194 | pub proc_macro: Vec<ProcMacro>, | 194 | pub proc_macro: Vec<ProcMacro>, |
195 | pub features: FxHashMap<String, Vec<String>>, | ||
195 | } | 196 | } |
196 | 197 | ||
197 | #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] | 198 | #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] |
@@ -221,6 +222,7 @@ impl CrateGraph { | |||
221 | cfg_options: CfgOptions, | 222 | cfg_options: CfgOptions, |
222 | env: Env, | 223 | env: Env, |
223 | proc_macro: Vec<ProcMacro>, | 224 | proc_macro: Vec<ProcMacro>, |
225 | features: FxHashMap<String, Vec<String>>, | ||
224 | ) -> CrateId { | 226 | ) -> CrateId { |
225 | let data = CrateData { | 227 | let data = CrateData { |
226 | root_file_id: file_id, | 228 | root_file_id: file_id, |
@@ -230,6 +232,7 @@ impl CrateGraph { | |||
230 | env, | 232 | env, |
231 | proc_macro, | 233 | proc_macro, |
232 | dependencies: Vec::new(), | 234 | dependencies: Vec::new(), |
235 | features, | ||
233 | }; | 236 | }; |
234 | let crate_id = CrateId(self.arena.len() as u32); | 237 | let crate_id = CrateId(self.arena.len() as u32); |
235 | let prev = self.arena.insert(crate_id, data); | 238 | let prev = self.arena.insert(crate_id, data); |
@@ -506,6 +509,7 @@ mod tests { | |||
506 | CfgOptions::default(), | 509 | CfgOptions::default(), |
507 | Env::default(), | 510 | Env::default(), |
508 | Default::default(), | 511 | Default::default(), |
512 | Default::default(), | ||
509 | ); | 513 | ); |
510 | let crate2 = graph.add_crate_root( | 514 | let crate2 = graph.add_crate_root( |
511 | FileId(2u32), | 515 | FileId(2u32), |
@@ -514,6 +518,7 @@ mod tests { | |||
514 | CfgOptions::default(), | 518 | CfgOptions::default(), |
515 | Env::default(), | 519 | Env::default(), |
516 | Default::default(), | 520 | Default::default(), |
521 | Default::default(), | ||
517 | ); | 522 | ); |
518 | let crate3 = graph.add_crate_root( | 523 | let crate3 = graph.add_crate_root( |
519 | FileId(3u32), | 524 | FileId(3u32), |
@@ -522,6 +527,7 @@ mod tests { | |||
522 | CfgOptions::default(), | 527 | CfgOptions::default(), |
523 | Env::default(), | 528 | Env::default(), |
524 | Default::default(), | 529 | Default::default(), |
530 | Default::default(), | ||
525 | ); | 531 | ); |
526 | assert!(graph.add_dep(crate1, CrateName::new("crate2").unwrap(), crate2).is_ok()); | 532 | assert!(graph.add_dep(crate1, CrateName::new("crate2").unwrap(), crate2).is_ok()); |
527 | assert!(graph.add_dep(crate2, CrateName::new("crate3").unwrap(), crate3).is_ok()); | 533 | assert!(graph.add_dep(crate2, CrateName::new("crate3").unwrap(), crate3).is_ok()); |
@@ -538,6 +544,7 @@ mod tests { | |||
538 | CfgOptions::default(), | 544 | CfgOptions::default(), |
539 | Env::default(), | 545 | Env::default(), |
540 | Default::default(), | 546 | Default::default(), |
547 | Default::default(), | ||
541 | ); | 548 | ); |
542 | let crate2 = graph.add_crate_root( | 549 | let crate2 = graph.add_crate_root( |
543 | FileId(2u32), | 550 | FileId(2u32), |
@@ -546,6 +553,7 @@ mod tests { | |||
546 | CfgOptions::default(), | 553 | CfgOptions::default(), |
547 | Env::default(), | 554 | Env::default(), |
548 | Default::default(), | 555 | Default::default(), |
556 | Default::default(), | ||
549 | ); | 557 | ); |
550 | assert!(graph.add_dep(crate1, CrateName::new("crate2").unwrap(), crate2).is_ok()); | 558 | assert!(graph.add_dep(crate1, CrateName::new("crate2").unwrap(), crate2).is_ok()); |
551 | assert!(graph.add_dep(crate2, CrateName::new("crate2").unwrap(), crate2).is_err()); | 559 | assert!(graph.add_dep(crate2, CrateName::new("crate2").unwrap(), crate2).is_err()); |
@@ -561,6 +569,7 @@ mod tests { | |||
561 | CfgOptions::default(), | 569 | CfgOptions::default(), |
562 | Env::default(), | 570 | Env::default(), |
563 | Default::default(), | 571 | Default::default(), |
572 | Default::default(), | ||
564 | ); | 573 | ); |
565 | let crate2 = graph.add_crate_root( | 574 | let crate2 = graph.add_crate_root( |
566 | FileId(2u32), | 575 | FileId(2u32), |
@@ -569,6 +578,7 @@ mod tests { | |||
569 | CfgOptions::default(), | 578 | CfgOptions::default(), |
570 | Env::default(), | 579 | Env::default(), |
571 | Default::default(), | 580 | Default::default(), |
581 | Default::default(), | ||
572 | ); | 582 | ); |
573 | let crate3 = graph.add_crate_root( | 583 | let crate3 = graph.add_crate_root( |
574 | FileId(3u32), | 584 | FileId(3u32), |
@@ -577,6 +587,7 @@ mod tests { | |||
577 | CfgOptions::default(), | 587 | CfgOptions::default(), |
578 | Env::default(), | 588 | Env::default(), |
579 | Default::default(), | 589 | Default::default(), |
590 | Default::default(), | ||
580 | ); | 591 | ); |
581 | assert!(graph.add_dep(crate1, CrateName::new("crate2").unwrap(), crate2).is_ok()); | 592 | assert!(graph.add_dep(crate1, CrateName::new("crate2").unwrap(), crate2).is_ok()); |
582 | assert!(graph.add_dep(crate2, CrateName::new("crate3").unwrap(), crate3).is_ok()); | 593 | assert!(graph.add_dep(crate2, CrateName::new("crate3").unwrap(), crate3).is_ok()); |
@@ -592,6 +603,7 @@ mod tests { | |||
592 | CfgOptions::default(), | 603 | CfgOptions::default(), |
593 | Env::default(), | 604 | Env::default(), |
594 | Default::default(), | 605 | Default::default(), |
606 | Default::default(), | ||
595 | ); | 607 | ); |
596 | let crate2 = graph.add_crate_root( | 608 | let crate2 = graph.add_crate_root( |
597 | FileId(2u32), | 609 | FileId(2u32), |
@@ -600,6 +612,7 @@ mod tests { | |||
600 | CfgOptions::default(), | 612 | CfgOptions::default(), |
601 | Env::default(), | 613 | Env::default(), |
602 | Default::default(), | 614 | Default::default(), |
615 | Default::default(), | ||
603 | ); | 616 | ); |
604 | assert!(graph | 617 | assert!(graph |
605 | .add_dep(crate1, CrateName::normalize_dashes("crate-name-with-dashes"), crate2) | 618 | .add_dep(crate1, CrateName::normalize_dashes("crate-name-with-dashes"), crate2) |
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..2b2aaec94 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 features(&self, db: &dyn HirDatabase) -> Vec<String> { | ||
238 | db.crate_graph()[self.id].features.iter().map(|(feat, _)| feat.clone()).collect() | ||
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..0693869a2 100644 --- a/crates/ide/src/lib.rs +++ b/crates/ide/src/lib.rs | |||
@@ -220,6 +220,7 @@ impl Analysis { | |||
220 | cfg_options, | 220 | cfg_options, |
221 | Env::default(), | 221 | Env::default(), |
222 | Default::default(), | 222 | Default::default(), |
223 | Default::default(), | ||
223 | ); | 224 | ); |
224 | change.change_file(file_id, Some(Arc::new(text))); | 225 | change.change_file(file_id, Some(Arc::new(text))); |
225 | change.set_crate_graph(crate_graph); | 226 | change.set_crate_graph(crate_graph); |
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 | ||
18 | mod cfg; | ||
18 | mod derive; | 19 | mod derive; |
19 | mod lint; | 20 | mod lint; |
20 | mod repr; | 21 | mod 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..71e659563 --- /dev/null +++ b/crates/ide_completion/src/completions/attribute/cfg.rs | |||
@@ -0,0 +1,126 @@ | |||
1 | //! Completion for cfg | ||
2 | |||
3 | use std::iter; | ||
4 | |||
5 | use syntax::SyntaxKind; | ||
6 | |||
7 | use crate::{ | ||
8 | completions::Completions, context::CompletionContext, item::CompletionKind, CompletionItem, | ||
9 | CompletionItemKind, | ||
10 | }; | ||
11 | |||
12 | pub(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("feature") => { | ||
30 | ctx.krate.map(|krate| { | ||
31 | krate.features(ctx.db).iter().for_each(|f| { | ||
32 | let mut item = CompletionItem::new( | ||
33 | CompletionKind::Attribute, | ||
34 | ctx.source_range(), | ||
35 | f.clone(), | ||
36 | ); | ||
37 | item.insert_text(format!(r#""{}""#, f)); | ||
38 | |||
39 | acc.add(item.build()) | ||
40 | }) | ||
41 | }); | ||
42 | } | ||
43 | Some("target_arch") => KNOWN_ARCH.iter().for_each(add_completion), | ||
44 | Some("target_env") => KNOWN_ENV.iter().for_each(add_completion), | ||
45 | Some("target_os") => KNOWN_OS.iter().for_each(add_completion), | ||
46 | Some("target_vendor") => KNOWN_VENDOR.iter().for_each(add_completion), | ||
47 | Some("target_endian") => ["little", "big"].iter().for_each(add_completion), | ||
48 | Some(name) => { | ||
49 | ctx.krate.map(|krate| { | ||
50 | krate.cfg(ctx.db).get_cfg_values(&name).iter().for_each(|s| { | ||
51 | let mut item = CompletionItem::new( | ||
52 | CompletionKind::Attribute, | ||
53 | ctx.source_range(), | ||
54 | s.as_str(), | ||
55 | ); | ||
56 | item.insert_text(format!(r#""{}""#, s)); | ||
57 | |||
58 | acc.add(item.build()); | ||
59 | }) | ||
60 | }); | ||
61 | } | ||
62 | None => { | ||
63 | ctx.krate.map(|krate| { | ||
64 | krate.cfg(ctx.db).get_cfg_keys().iter().for_each(|s| { | ||
65 | let item = CompletionItem::new( | ||
66 | CompletionKind::Attribute, | ||
67 | ctx.source_range(), | ||
68 | s.as_str(), | ||
69 | ); | ||
70 | acc.add(item.build()); | ||
71 | }) | ||
72 | }); | ||
73 | } | ||
74 | }; | ||
75 | } | ||
76 | |||
77 | const KNOWN_ARCH: [&'static str; 19] = [ | ||
78 | "aarch64", | ||
79 | "arm", | ||
80 | "avr", | ||
81 | "hexagon", | ||
82 | "mips", | ||
83 | "mips64", | ||
84 | "msp430", | ||
85 | "nvptx64", | ||
86 | "powerpc", | ||
87 | "powerpc64", | ||
88 | "riscv32", | ||
89 | "riscv64", | ||
90 | "s390x", | ||
91 | "sparc", | ||
92 | "sparc64", | ||
93 | "wasm32", | ||
94 | "wasm64", | ||
95 | "x86", | ||
96 | "x86_64", | ||
97 | ]; | ||
98 | |||
99 | const KNOWN_ENV: [&'static str; 7] = | ||
100 | ["eabihf", "gnu", "gnueabihf", "msvc", "relibc", "sgx", "uclibc"]; | ||
101 | |||
102 | const KNOWN_OS: [&'static str; 20] = [ | ||
103 | "cuda", | ||
104 | "dragonfly", | ||
105 | "emscripten", | ||
106 | "freebsd", | ||
107 | "fuchsia", | ||
108 | "haiku", | ||
109 | "hermit", | ||
110 | "illumos", | ||
111 | "l4re", | ||
112 | "linux", | ||
113 | "netbsd", | ||
114 | "none", | ||
115 | "openbsd", | ||
116 | "psp", | ||
117 | "redox", | ||
118 | "solaris", | ||
119 | "uefi", | ||
120 | "unknown", | ||
121 | "vxworks", | ||
122 | "windows", | ||
123 | ]; | ||
124 | |||
125 | const KNOWN_VENDOR: [&'static str; 8] = | ||
126 | ["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..9ee3fc1a3 100644 --- a/crates/project_model/src/workspace.rs +++ b/crates/project_model/src/workspace.rs | |||
@@ -387,6 +387,7 @@ fn project_json_to_crate_graph( | |||
387 | cfg_options, | 387 | cfg_options, |
388 | env, | 388 | env, |
389 | proc_macro.unwrap_or_default(), | 389 | proc_macro.unwrap_or_default(), |
390 | Default::default(), | ||
390 | ), | 391 | ), |
391 | ) | 392 | ) |
392 | }) | 393 | }) |
@@ -582,6 +583,7 @@ fn detached_files_to_crate_graph( | |||
582 | cfg_options.clone(), | 583 | cfg_options.clone(), |
583 | Env::default(), | 584 | Env::default(), |
584 | Vec::new(), | 585 | Vec::new(), |
586 | Default::default(), | ||
585 | ); | 587 | ); |
586 | 588 | ||
587 | for (name, krate) in public_deps.iter() { | 589 | for (name, krate) in public_deps.iter() { |
@@ -726,6 +728,7 @@ fn add_target_crate_root( | |||
726 | cfg_options, | 728 | cfg_options, |
727 | env, | 729 | env, |
728 | proc_macro, | 730 | proc_macro, |
731 | pkg.features.clone(), | ||
729 | ); | 732 | ); |
730 | 733 | ||
731 | crate_id | 734 | crate_id |
@@ -755,6 +758,7 @@ fn sysroot_to_crate_graph( | |||
755 | cfg_options.clone(), | 758 | cfg_options.clone(), |
756 | env, | 759 | env, |
757 | proc_macro, | 760 | proc_macro, |
761 | Default::default(), | ||
758 | ); | 762 | ); |
759 | Some((krate, crate_id)) | 763 | Some((krate, crate_id)) |
760 | }) | 764 | }) |