aboutsummaryrefslogtreecommitdiff
path: root/crates/ide_completion/src/completions/attribute/derive.rs
diff options
context:
space:
mode:
authorLukas Wirth <[email protected]>2021-05-27 22:40:33 +0100
committerLukas Wirth <[email protected]>2021-05-27 22:40:33 +0100
commitab9c6ea4dd2c1a3b71fe50469627b0b518350896 (patch)
treea89334bfe632065a7dab5a737f04706d59b6e4fc /crates/ide_completion/src/completions/attribute/derive.rs
parentfc37e2f953a0d200e875c4711c1b0bf79a75a2a2 (diff)
Split attribute completion module into attribute, derive and lint modules
Diffstat (limited to 'crates/ide_completion/src/completions/attribute/derive.rs')
-rw-r--r--crates/ide_completion/src/completions/attribute/derive.rs141
1 files changed, 141 insertions, 0 deletions
diff --git a/crates/ide_completion/src/completions/attribute/derive.rs b/crates/ide_completion/src/completions/attribute/derive.rs
new file mode 100644
index 000000000..c14b03ea4
--- /dev/null
+++ b/crates/ide_completion/src/completions/attribute/derive.rs
@@ -0,0 +1,141 @@
1use itertools::Itertools;
2use rustc_hash::FxHashSet;
3use syntax::ast;
4
5use crate::{
6 context::CompletionContext,
7 item::{CompletionItem, CompletionItemKind, CompletionKind},
8 Completions,
9};
10
11pub(super) fn complete_derive(
12 acc: &mut Completions,
13 ctx: &CompletionContext,
14 derive_input: ast::TokenTree,
15) {
16 if let Ok(existing_derives) = super::parse_comma_sep_input(derive_input) {
17 for derive_completion in DEFAULT_DERIVE_COMPLETIONS
18 .iter()
19 .filter(|completion| !existing_derives.contains(completion.label))
20 {
21 let mut components = vec![derive_completion.label];
22 components.extend(
23 derive_completion
24 .dependencies
25 .iter()
26 .filter(|&&dependency| !existing_derives.contains(dependency)),
27 );
28 let lookup = components.join(", ");
29 let label = components.iter().rev().join(", ");
30 let mut item =
31 CompletionItem::new(CompletionKind::Attribute, ctx.source_range(), label);
32 item.lookup_by(lookup).kind(CompletionItemKind::Attribute);
33 item.add_to(acc);
34 }
35
36 for custom_derive_name in get_derive_names_in_scope(ctx).difference(&existing_derives) {
37 let mut item = CompletionItem::new(
38 CompletionKind::Attribute,
39 ctx.source_range(),
40 custom_derive_name,
41 );
42 item.kind(CompletionItemKind::Attribute);
43 item.add_to(acc);
44 }
45 }
46}
47fn get_derive_names_in_scope(ctx: &CompletionContext) -> FxHashSet<String> {
48 let mut result = FxHashSet::default();
49 ctx.scope.process_all_names(&mut |name, scope_def| {
50 if let hir::ScopeDef::MacroDef(mac) = scope_def {
51 // FIXME kind() doesn't check whether proc-macro is a derive
52 if mac.kind() == hir::MacroKind::Derive || mac.kind() == hir::MacroKind::ProcMacro {
53 result.insert(name.to_string());
54 }
55 }
56 });
57 result
58}
59
60struct DeriveCompletion {
61 label: &'static str,
62 dependencies: &'static [&'static str],
63}
64
65/// Standard Rust derives and the information about their dependencies
66/// (the dependencies are needed so that the main derive don't break the compilation when added)
67const DEFAULT_DERIVE_COMPLETIONS: &[DeriveCompletion] = &[
68 DeriveCompletion { label: "Clone", dependencies: &[] },
69 DeriveCompletion { label: "Copy", dependencies: &["Clone"] },
70 DeriveCompletion { label: "Debug", dependencies: &[] },
71 DeriveCompletion { label: "Default", dependencies: &[] },
72 DeriveCompletion { label: "Hash", dependencies: &[] },
73 DeriveCompletion { label: "PartialEq", dependencies: &[] },
74 DeriveCompletion { label: "Eq", dependencies: &["PartialEq"] },
75 DeriveCompletion { label: "PartialOrd", dependencies: &["PartialEq"] },
76 DeriveCompletion { label: "Ord", dependencies: &["PartialOrd", "Eq", "PartialEq"] },
77];
78
79#[cfg(test)]
80mod tests {
81 use expect_test::{expect, Expect};
82
83 use crate::{test_utils::completion_list, CompletionKind};
84
85 fn check(ra_fixture: &str, expect: Expect) {
86 let actual = completion_list(ra_fixture, CompletionKind::Attribute);
87 expect.assert_eq(&actual);
88 }
89
90 #[test]
91 fn empty_derive_completion() {
92 check(
93 r#"
94#[derive($0)]
95struct Test {}
96 "#,
97 expect![[r#"
98 at Clone
99 at Clone, Copy
100 at Debug
101 at Default
102 at Hash
103 at PartialEq
104 at PartialEq, Eq
105 at PartialEq, PartialOrd
106 at PartialEq, Eq, PartialOrd, Ord
107 "#]],
108 );
109 }
110
111 #[test]
112 fn no_completion_for_incorrect_derive() {
113 check(
114 r#"
115#[derive{$0)]
116struct Test {}
117"#,
118 expect![[r#""#]],
119 )
120 }
121
122 #[test]
123 fn derive_with_input_completion() {
124 check(
125 r#"
126#[derive(serde::Serialize, PartialEq, $0)]
127struct Test {}
128"#,
129 expect![[r#"
130 at Clone
131 at Clone, Copy
132 at Debug
133 at Default
134 at Hash
135 at Eq
136 at PartialOrd
137 at Eq, PartialOrd, Ord
138 "#]],
139 )
140 }
141}