diff options
Diffstat (limited to 'crates/ide_completion/src/completions/attribute')
3 files changed, 243 insertions, 25 deletions
diff --git a/crates/ide_completion/src/completions/attribute/derive.rs b/crates/ide_completion/src/completions/attribute/derive.rs index d526824fb..6fe41e0d6 100644 --- a/crates/ide_completion/src/completions/attribute/derive.rs +++ b/crates/ide_completion/src/completions/attribute/derive.rs | |||
@@ -31,6 +31,8 @@ pub(super) fn complete_derive( | |||
31 | let lookup = components.join(", "); | 31 | let lookup = components.join(", "); |
32 | let label = components.iter().rev().join(", "); | 32 | let label = components.iter().rev().join(", "); |
33 | (label, Some(lookup)) | 33 | (label, Some(lookup)) |
34 | } else if existing_derives.contains(&derive) { | ||
35 | continue; | ||
34 | } else { | 36 | } else { |
35 | (derive, None) | 37 | (derive, None) |
36 | }; | 38 | }; |
@@ -80,10 +82,31 @@ const DEFAULT_DERIVE_COMPLETIONS: &[DeriveDependencies] = &[ | |||
80 | mod tests { | 82 | mod tests { |
81 | use expect_test::{expect, Expect}; | 83 | use expect_test::{expect, Expect}; |
82 | 84 | ||
83 | use crate::{test_utils::completion_list, CompletionKind}; | 85 | use crate::tests::completion_list; |
84 | 86 | ||
85 | fn check(ra_fixture: &str, expect: Expect) { | 87 | fn check(ra_fixture: &str, expect: Expect) { |
86 | let actual = completion_list(ra_fixture, CompletionKind::Attribute); | 88 | let builtin_derives = r#" |
89 | #[rustc_builtin_macro] | ||
90 | pub macro Clone {} | ||
91 | #[rustc_builtin_macro] | ||
92 | pub macro Copy {} | ||
93 | #[rustc_builtin_macro] | ||
94 | pub macro Default {} | ||
95 | #[rustc_builtin_macro] | ||
96 | pub macro Debug {} | ||
97 | #[rustc_builtin_macro] | ||
98 | pub macro Hash {} | ||
99 | #[rustc_builtin_macro] | ||
100 | pub macro PartialEq {} | ||
101 | #[rustc_builtin_macro] | ||
102 | pub macro Eq {} | ||
103 | #[rustc_builtin_macro] | ||
104 | pub macro PartialOrd {} | ||
105 | #[rustc_builtin_macro] | ||
106 | pub macro Ord {} | ||
107 | |||
108 | "#; | ||
109 | let actual = completion_list(&format!("{} {}", builtin_derives, ra_fixture)); | ||
87 | expect.assert_eq(&actual); | 110 | expect.assert_eq(&actual); |
88 | } | 111 | } |
89 | 112 | ||
@@ -93,56 +116,53 @@ mod tests { | |||
93 | } | 116 | } |
94 | 117 | ||
95 | #[test] | 118 | #[test] |
96 | #[ignore] // FIXME: Fixtures cant test proc-macros/derives yet as we cant specify them in fixtures | ||
97 | fn empty_derive() { | 119 | fn empty_derive() { |
98 | check( | 120 | check( |
99 | r#"#[derive($0)] struct Test;"#, | 121 | r#"#[derive($0)] struct Test;"#, |
100 | expect![[r#" | 122 | expect![[r#" |
101 | at Clone | 123 | at PartialEq |
102 | at Clone, Copy | 124 | at Default |
103 | at Debug | 125 | at PartialEq, Eq |
104 | at Default | 126 | at PartialEq, Eq, PartialOrd, Ord |
105 | at Hash | 127 | at Clone, Copy |
106 | at PartialEq | 128 | at Debug |
107 | at PartialEq, Eq | 129 | at Clone |
108 | at PartialEq, PartialOrd | 130 | at Hash |
109 | at PartialEq, Eq, PartialOrd, Ord | 131 | at PartialEq, PartialOrd |
110 | "#]], | 132 | "#]], |
111 | ); | 133 | ); |
112 | } | 134 | } |
113 | 135 | ||
114 | #[test] | 136 | #[test] |
115 | #[ignore] // FIXME: Fixtures cant test proc-macros/derives yet as we cant specify them in fixtures | ||
116 | fn derive_with_input() { | 137 | fn derive_with_input() { |
117 | check( | 138 | check( |
118 | r#"#[derive(serde::Serialize, PartialEq, $0)] struct Test;"#, | 139 | r#"#[derive(serde::Serialize, PartialEq, $0)] struct Test;"#, |
119 | expect![[r#" | 140 | expect![[r#" |
120 | at Clone | 141 | at Default |
142 | at Eq | ||
143 | at Eq, PartialOrd, Ord | ||
121 | at Clone, Copy | 144 | at Clone, Copy |
122 | at Debug | 145 | at Debug |
123 | at Default | 146 | at Clone |
124 | at Hash | 147 | at Hash |
125 | at Eq | ||
126 | at PartialOrd | 148 | at PartialOrd |
127 | at Eq, PartialOrd, Ord | ||
128 | "#]], | 149 | "#]], |
129 | ) | 150 | ) |
130 | } | 151 | } |
131 | 152 | ||
132 | #[test] | 153 | #[test] |
133 | #[ignore] // FIXME: Fixtures cant test proc-macros/derives yet as we cant specify them in fixtures | ||
134 | fn derive_with_input2() { | 154 | fn derive_with_input2() { |
135 | check( | 155 | check( |
136 | r#"#[derive($0 serde::Serialize, PartialEq)] struct Test;"#, | 156 | r#"#[derive($0 serde::Serialize, PartialEq)] struct Test;"#, |
137 | expect![[r#" | 157 | expect![[r#" |
138 | at Clone | 158 | at Default |
159 | at Eq | ||
160 | at Eq, PartialOrd, Ord | ||
139 | at Clone, Copy | 161 | at Clone, Copy |
140 | at Debug | 162 | at Debug |
141 | at Default | 163 | at Clone |
142 | at Hash | 164 | at Hash |
143 | at Eq | ||
144 | at PartialOrd | 165 | at PartialOrd |
145 | at Eq, PartialOrd, Ord | ||
146 | "#]], | 166 | "#]], |
147 | ) | 167 | ) |
148 | } | 168 | } |
diff --git a/crates/ide_completion/src/completions/attribute/lint.rs b/crates/ide_completion/src/completions/attribute/lint.rs index ca99e9759..1ddc38986 100644 --- a/crates/ide_completion/src/completions/attribute/lint.rs +++ b/crates/ide_completion/src/completions/attribute/lint.rs | |||
@@ -33,8 +33,7 @@ pub(super) fn complete_lint( | |||
33 | 33 | ||
34 | #[cfg(test)] | 34 | #[cfg(test)] |
35 | mod tests { | 35 | mod tests { |
36 | 36 | use crate::tests::check_edit; | |
37 | use crate::test_utils::check_edit; | ||
38 | 37 | ||
39 | #[test] | 38 | #[test] |
40 | fn check_empty() { | 39 | fn check_empty() { |
diff --git a/crates/ide_completion/src/completions/attribute/repr.rs b/crates/ide_completion/src/completions/attribute/repr.rs new file mode 100644 index 000000000..92a262a43 --- /dev/null +++ b/crates/ide_completion/src/completions/attribute/repr.rs | |||
@@ -0,0 +1,199 @@ | |||
1 | //! Completion for representations. | ||
2 | |||
3 | use syntax::ast; | ||
4 | |||
5 | use crate::{ | ||
6 | context::CompletionContext, | ||
7 | item::{CompletionItem, CompletionItemKind, CompletionKind}, | ||
8 | Completions, | ||
9 | }; | ||
10 | |||
11 | pub(super) fn complete_repr( | ||
12 | acc: &mut Completions, | ||
13 | ctx: &CompletionContext, | ||
14 | derive_input: ast::TokenTree, | ||
15 | ) { | ||
16 | if let Some(existing_reprs) = super::parse_comma_sep_input(derive_input) { | ||
17 | for repr_completion in REPR_COMPLETIONS { | ||
18 | if existing_reprs | ||
19 | .iter() | ||
20 | .any(|it| repr_completion.label == it || repr_completion.collides.contains(&&**it)) | ||
21 | { | ||
22 | continue; | ||
23 | } | ||
24 | let mut item = CompletionItem::new( | ||
25 | CompletionKind::Attribute, | ||
26 | ctx.source_range(), | ||
27 | repr_completion.label, | ||
28 | ); | ||
29 | item.kind(CompletionItemKind::Attribute); | ||
30 | if let Some(lookup) = repr_completion.lookup { | ||
31 | item.lookup_by(lookup); | ||
32 | } | ||
33 | if let Some((snippet, cap)) = repr_completion.snippet.zip(ctx.config.snippet_cap) { | ||
34 | item.insert_snippet(cap, snippet); | ||
35 | } | ||
36 | item.add_to(acc); | ||
37 | } | ||
38 | } | ||
39 | } | ||
40 | |||
41 | struct ReprCompletion { | ||
42 | label: &'static str, | ||
43 | snippet: Option<&'static str>, | ||
44 | lookup: Option<&'static str>, | ||
45 | collides: &'static [&'static str], | ||
46 | } | ||
47 | |||
48 | const fn attr(label: &'static str, collides: &'static [&'static str]) -> ReprCompletion { | ||
49 | ReprCompletion { label, snippet: None, lookup: None, collides } | ||
50 | } | ||
51 | |||
52 | #[rustfmt::skip] | ||
53 | const REPR_COMPLETIONS: &[ReprCompletion] = &[ | ||
54 | ReprCompletion { label: "align($0)", snippet: Some("align($0)"), lookup: Some("align"), collides: &["transparent", "packed"] }, | ||
55 | attr("packed", &["transparent", "align"]), | ||
56 | attr("transparent", &["C", "u8", "u16", "u32", "u64", "u128", "usize", "i8", "i16", "i32", "i64", "i128", "isize"]), | ||
57 | attr("C", &["transparent"]), | ||
58 | attr("u8", &["transparent", "u16", "u32", "u64", "u128", "usize", "i8", "i16", "i32", "i64", "i128", "isize"]), | ||
59 | attr("u16", &["transparent", "u8", "u32", "u64", "u128", "usize", "i8", "i16", "i32", "i64", "i128", "isize"]), | ||
60 | attr("u32", &["transparent", "u8", "u16", "u64", "u128", "usize", "i8", "i16", "i32", "i64", "i128", "isize"]), | ||
61 | attr("u64", &["transparent", "u8", "u16", "u32", "u128", "usize", "i8", "i16", "i32", "i64", "i128", "isize"]), | ||
62 | attr("u128", &["transparent", "u8", "u16", "u32", "u64", "usize", "i8", "i16", "i32", "i64", "i128", "isize"]), | ||
63 | attr("usize", &["transparent", "u8", "u16", "u32", "u64", "u128", "i8", "i16", "i32", "i64", "i128", "isize"]), | ||
64 | attr("i8", &["transparent", "u8", "u16", "u32", "u64", "u128", "usize", "i16", "i32", "i64", "i128", "isize"]), | ||
65 | attr("i16", &["transparent", "u8", "u16", "u32", "u64", "u128", "usize", "i8", "i32", "i64", "i128", "isize"]), | ||
66 | attr("i32", &["transparent", "u8", "u16", "u32", "u64", "u128", "usize", "i8", "i16", "i64", "i128", "isize"]), | ||
67 | attr("i64", &["transparent", "u8", "u16", "u32", "u64", "u128", "usize", "i8", "i16", "i32", "i128", "isize"]), | ||
68 | attr("i28", &["transparent", "u8", "u16", "u32", "u64", "u128", "usize", "i8", "i16", "i32", "i64", "isize"]), | ||
69 | attr("isize", &["transparent", "u8", "u16", "u32", "u64", "u128", "usize", "i8", "i16", "i32", "i64", "i128"]), | ||
70 | ]; | ||
71 | |||
72 | #[cfg(test)] | ||
73 | mod tests { | ||
74 | use expect_test::{expect, Expect}; | ||
75 | |||
76 | use crate::tests::completion_list; | ||
77 | |||
78 | fn check(ra_fixture: &str, expect: Expect) { | ||
79 | let actual = completion_list(ra_fixture); | ||
80 | expect.assert_eq(&actual); | ||
81 | } | ||
82 | |||
83 | #[test] | ||
84 | fn no_completion_for_incorrect_repr() { | ||
85 | check(r#"#[repr{$0)] struct Test;"#, expect![[]]) | ||
86 | } | ||
87 | |||
88 | #[test] | ||
89 | fn empty() { | ||
90 | check( | ||
91 | r#"#[repr($0)] struct Test;"#, | ||
92 | expect![[r#" | ||
93 | at align($0) | ||
94 | at packed | ||
95 | at transparent | ||
96 | at C | ||
97 | at u8 | ||
98 | at u16 | ||
99 | at u32 | ||
100 | at u64 | ||
101 | at u128 | ||
102 | at usize | ||
103 | at i8 | ||
104 | at i16 | ||
105 | at i32 | ||
106 | at i64 | ||
107 | at i28 | ||
108 | at isize | ||
109 | "#]], | ||
110 | ); | ||
111 | } | ||
112 | |||
113 | #[test] | ||
114 | fn transparent() { | ||
115 | check(r#"#[repr(transparent, $0)] struct Test;"#, expect![[r#""#]]); | ||
116 | } | ||
117 | |||
118 | #[test] | ||
119 | fn align() { | ||
120 | check( | ||
121 | r#"#[repr(align(1), $0)] struct Test;"#, | ||
122 | expect![[r#" | ||
123 | at align($0) | ||
124 | at transparent | ||
125 | at C | ||
126 | at u8 | ||
127 | at u16 | ||
128 | at u32 | ||
129 | at u64 | ||
130 | at u128 | ||
131 | at usize | ||
132 | at i8 | ||
133 | at i16 | ||
134 | at i32 | ||
135 | at i64 | ||
136 | at i28 | ||
137 | at isize | ||
138 | "#]], | ||
139 | ); | ||
140 | } | ||
141 | |||
142 | #[test] | ||
143 | fn packed() { | ||
144 | check( | ||
145 | r#"#[repr(packed, $0)] struct Test;"#, | ||
146 | expect![[r#" | ||
147 | at transparent | ||
148 | at C | ||
149 | at u8 | ||
150 | at u16 | ||
151 | at u32 | ||
152 | at u64 | ||
153 | at u128 | ||
154 | at usize | ||
155 | at i8 | ||
156 | at i16 | ||
157 | at i32 | ||
158 | at i64 | ||
159 | at i28 | ||
160 | at isize | ||
161 | "#]], | ||
162 | ); | ||
163 | } | ||
164 | |||
165 | #[test] | ||
166 | fn c() { | ||
167 | check( | ||
168 | r#"#[repr(C, $0)] struct Test;"#, | ||
169 | expect![[r#" | ||
170 | at align($0) | ||
171 | at packed | ||
172 | at u8 | ||
173 | at u16 | ||
174 | at u32 | ||
175 | at u64 | ||
176 | at u128 | ||
177 | at usize | ||
178 | at i8 | ||
179 | at i16 | ||
180 | at i32 | ||
181 | at i64 | ||
182 | at i28 | ||
183 | at isize | ||
184 | "#]], | ||
185 | ); | ||
186 | } | ||
187 | |||
188 | #[test] | ||
189 | fn prim() { | ||
190 | check( | ||
191 | r#"#[repr(usize, $0)] struct Test;"#, | ||
192 | expect![[r#" | ||
193 | at align($0) | ||
194 | at packed | ||
195 | at C | ||
196 | "#]], | ||
197 | ); | ||
198 | } | ||
199 | } | ||