aboutsummaryrefslogtreecommitdiff
path: root/crates/completion/src/completions/attribute.rs
diff options
context:
space:
mode:
authorIgor Aleksanov <[email protected]>2020-10-25 07:59:15 +0000
committerIgor Aleksanov <[email protected]>2020-10-25 07:59:15 +0000
commit19c10672023ead0c1d64486154b6c4145b649568 (patch)
tree691d5fe8dcfbca897c05cde78a1a0f9c99d1afbb /crates/completion/src/completions/attribute.rs
parentbf84e4958ee31c59e5b78f60059d69a73ef659bb (diff)
Reorganize completions structure
Diffstat (limited to 'crates/completion/src/completions/attribute.rs')
-rw-r--r--crates/completion/src/completions/attribute.rs534
1 files changed, 534 insertions, 0 deletions
diff --git a/crates/completion/src/completions/attribute.rs b/crates/completion/src/completions/attribute.rs
new file mode 100644
index 000000000..3d517c886
--- /dev/null
+++ b/crates/completion/src/completions/attribute.rs
@@ -0,0 +1,534 @@
1//! Completion for attributes
2//!
3//! This module uses a bit of static metadata to provide completions
4//! for built-in attributes.
5
6use rustc_hash::FxHashSet;
7use syntax::{ast, AstNode, SyntaxKind};
8
9use crate::{
10 context::CompletionContext,
11 generated_lint_completions::{CLIPPY_LINTS, FEATURES},
12 item::{CompletionItem, CompletionItemKind, CompletionKind, Completions},
13};
14
15pub(crate) fn complete_attribute(acc: &mut Completions, ctx: &CompletionContext) -> Option<()> {
16 if ctx.mod_declaration_under_caret.is_some() {
17 return None;
18 }
19
20 let attribute = ctx.attribute_under_caret.as_ref()?;
21 match (attribute.path(), attribute.token_tree()) {
22 (Some(path), Some(token_tree)) if path.to_string() == "derive" => {
23 complete_derive(acc, ctx, token_tree)
24 }
25 (Some(path), Some(token_tree)) if path.to_string() == "feature" => {
26 complete_lint(acc, ctx, token_tree, FEATURES);
27 }
28 (Some(path), Some(token_tree))
29 if ["allow", "warn", "deny", "forbid"]
30 .iter()
31 .any(|lint_level| lint_level == &path.to_string()) =>
32 {
33 complete_lint(acc, ctx, token_tree.clone(), DEFAULT_LINT_COMPLETIONS);
34 complete_lint(acc, ctx, token_tree, CLIPPY_LINTS);
35 }
36 (_, Some(_token_tree)) => {}
37 _ => complete_attribute_start(acc, ctx, attribute),
38 }
39 Some(())
40}
41
42fn complete_attribute_start(acc: &mut Completions, ctx: &CompletionContext, attribute: &ast::Attr) {
43 for attr_completion in ATTRIBUTES {
44 let mut item = CompletionItem::new(
45 CompletionKind::Attribute,
46 ctx.source_range(),
47 attr_completion.label,
48 )
49 .kind(CompletionItemKind::Attribute);
50
51 if let Some(lookup) = attr_completion.lookup {
52 item = item.lookup_by(lookup);
53 }
54
55 match (attr_completion.snippet, ctx.config.snippet_cap) {
56 (Some(snippet), Some(cap)) => {
57 item = item.insert_snippet(cap, snippet);
58 }
59 _ => {}
60 }
61
62 if attribute.kind() == ast::AttrKind::Inner || !attr_completion.prefer_inner {
63 acc.add(item);
64 }
65 }
66}
67
68struct AttrCompletion {
69 label: &'static str,
70 lookup: Option<&'static str>,
71 snippet: Option<&'static str>,
72 prefer_inner: bool,
73}
74
75impl AttrCompletion {
76 const fn prefer_inner(self) -> AttrCompletion {
77 AttrCompletion { prefer_inner: true, ..self }
78 }
79}
80
81const fn attr(
82 label: &'static str,
83 lookup: Option<&'static str>,
84 snippet: Option<&'static str>,
85) -> AttrCompletion {
86 AttrCompletion { label, lookup, snippet, prefer_inner: false }
87}
88
89const ATTRIBUTES: &[AttrCompletion] = &[
90 attr("allow(…)", Some("allow"), Some("allow(${0:lint})")),
91 attr("cfg_attr(…)", Some("cfg_attr"), Some("cfg_attr(${1:predicate}, ${0:attr})")),
92 attr("cfg(…)", Some("cfg"), Some("cfg(${0:predicate})")),
93 attr("deny(…)", Some("deny"), Some("deny(${0:lint})")),
94 attr(r#"deprecated = "…""#, Some("deprecated"), Some(r#"deprecated = "${0:reason}""#)),
95 attr("derive(…)", Some("derive"), Some(r#"derive(${0:Debug})"#)),
96 attr(r#"doc = "…""#, Some("doc"), Some(r#"doc = "${0:docs}""#)),
97 attr("feature(…)", Some("feature"), Some("feature(${0:flag})")).prefer_inner(),
98 attr("forbid(…)", Some("forbid"), Some("forbid(${0:lint})")),
99 // FIXME: resolve through macro resolution?
100 attr("global_allocator", None, None).prefer_inner(),
101 attr(r#"ignore = "…""#, Some("ignore"), Some(r#"ignore = "${0:reason}""#)),
102 attr("inline(…)", Some("inline"), Some("inline(${0:lint})")),
103 attr(r#"link_name = "…""#, Some("link_name"), Some(r#"link_name = "${0:symbol_name}""#)),
104 attr("link", None, None),
105 attr("macro_export", None, None),
106 attr("macro_use", None, None),
107 attr(r#"must_use = "…""#, Some("must_use"), Some(r#"must_use = "${0:reason}""#)),
108 attr("no_mangle", None, None),
109 attr("no_std", None, None).prefer_inner(),
110 attr("non_exhaustive", None, None),
111 attr("panic_handler", None, None).prefer_inner(),
112 attr("path = \"…\"", Some("path"), Some("path =\"${0:path}\"")),
113 attr("proc_macro", None, None),
114 attr("proc_macro_attribute", None, None),
115 attr("proc_macro_derive(…)", Some("proc_macro_derive"), Some("proc_macro_derive(${0:Trait})")),
116 attr("recursion_limit = …", Some("recursion_limit"), Some("recursion_limit = ${0:128}"))
117 .prefer_inner(),
118 attr("repr(…)", Some("repr"), Some("repr(${0:C})")),
119 attr(
120 "should_panic(…)",
121 Some("should_panic"),
122 Some(r#"should_panic(expected = "${0:reason}")"#),
123 ),
124 attr(
125 r#"target_feature = "…""#,
126 Some("target_feature"),
127 Some("target_feature = \"${0:feature}\""),
128 ),
129 attr("test", None, None),
130 attr("used", None, None),
131 attr("warn(…)", Some("warn"), Some("warn(${0:lint})")),
132 attr(
133 r#"windows_subsystem = "…""#,
134 Some("windows_subsystem"),
135 Some(r#"windows_subsystem = "${0:subsystem}""#),
136 )
137 .prefer_inner(),
138];
139
140fn complete_derive(acc: &mut Completions, ctx: &CompletionContext, derive_input: ast::TokenTree) {
141 if let Ok(existing_derives) = parse_comma_sep_input(derive_input) {
142 for derive_completion in DEFAULT_DERIVE_COMPLETIONS
143 .into_iter()
144 .filter(|completion| !existing_derives.contains(completion.label))
145 {
146 let mut label = derive_completion.label.to_owned();
147 for dependency in derive_completion
148 .dependencies
149 .into_iter()
150 .filter(|&&dependency| !existing_derives.contains(dependency))
151 {
152 label.push_str(", ");
153 label.push_str(dependency);
154 }
155 acc.add(
156 CompletionItem::new(CompletionKind::Attribute, ctx.source_range(), label)
157 .kind(CompletionItemKind::Attribute),
158 );
159 }
160
161 for custom_derive_name in get_derive_names_in_scope(ctx).difference(&existing_derives) {
162 acc.add(
163 CompletionItem::new(
164 CompletionKind::Attribute,
165 ctx.source_range(),
166 custom_derive_name,
167 )
168 .kind(CompletionItemKind::Attribute),
169 );
170 }
171 }
172}
173
174fn complete_lint(
175 acc: &mut Completions,
176 ctx: &CompletionContext,
177 derive_input: ast::TokenTree,
178 lints_completions: &[LintCompletion],
179) {
180 if let Ok(existing_lints) = parse_comma_sep_input(derive_input) {
181 for lint_completion in lints_completions
182 .into_iter()
183 .filter(|completion| !existing_lints.contains(completion.label))
184 {
185 acc.add(
186 CompletionItem::new(
187 CompletionKind::Attribute,
188 ctx.source_range(),
189 lint_completion.label,
190 )
191 .kind(CompletionItemKind::Attribute)
192 .detail(lint_completion.description),
193 );
194 }
195 }
196}
197
198fn parse_comma_sep_input(derive_input: ast::TokenTree) -> Result<FxHashSet<String>, ()> {
199 match (derive_input.left_delimiter_token(), derive_input.right_delimiter_token()) {
200 (Some(left_paren), Some(right_paren))
201 if left_paren.kind() == SyntaxKind::L_PAREN
202 && right_paren.kind() == SyntaxKind::R_PAREN =>
203 {
204 let mut input_derives = FxHashSet::default();
205 let mut current_derive = String::new();
206 for token in derive_input
207 .syntax()
208 .children_with_tokens()
209 .filter_map(|token| token.into_token())
210 .skip_while(|token| token != &left_paren)
211 .skip(1)
212 .take_while(|token| token != &right_paren)
213 {
214 if SyntaxKind::COMMA == token.kind() {
215 if !current_derive.is_empty() {
216 input_derives.insert(current_derive);
217 current_derive = String::new();
218 }
219 } else {
220 current_derive.push_str(token.to_string().trim());
221 }
222 }
223
224 if !current_derive.is_empty() {
225 input_derives.insert(current_derive);
226 }
227 Ok(input_derives)
228 }
229 _ => Err(()),
230 }
231}
232
233fn get_derive_names_in_scope(ctx: &CompletionContext) -> FxHashSet<String> {
234 let mut result = FxHashSet::default();
235 ctx.scope.process_all_names(&mut |name, scope_def| {
236 if let hir::ScopeDef::MacroDef(mac) = scope_def {
237 if mac.is_derive_macro() {
238 result.insert(name.to_string());
239 }
240 }
241 });
242 result
243}
244
245struct DeriveCompletion {
246 label: &'static str,
247 dependencies: &'static [&'static str],
248}
249
250/// Standard Rust derives and the information about their dependencies
251/// (the dependencies are needed so that the main derive don't break the compilation when added)
252#[rustfmt::skip]
253const DEFAULT_DERIVE_COMPLETIONS: &[DeriveCompletion] = &[
254 DeriveCompletion { label: "Clone", dependencies: &[] },
255 DeriveCompletion { label: "Copy", dependencies: &["Clone"] },
256 DeriveCompletion { label: "Debug", dependencies: &[] },
257 DeriveCompletion { label: "Default", dependencies: &[] },
258 DeriveCompletion { label: "Hash", dependencies: &[] },
259 DeriveCompletion { label: "PartialEq", dependencies: &[] },
260 DeriveCompletion { label: "Eq", dependencies: &["PartialEq"] },
261 DeriveCompletion { label: "PartialOrd", dependencies: &["PartialEq"] },
262 DeriveCompletion { label: "Ord", dependencies: &["PartialOrd", "Eq", "PartialEq"] },
263];
264
265pub(crate) struct LintCompletion {
266 pub(crate) label: &'static str,
267 pub(crate) description: &'static str,
268}
269
270#[rustfmt::skip]
271const DEFAULT_LINT_COMPLETIONS: &[LintCompletion] = &[
272 LintCompletion { label: "absolute_paths_not_starting_with_crate", description: r#"fully qualified paths that start with a module name instead of `crate`, `self`, or an extern crate name"# },
273 LintCompletion { label: "anonymous_parameters", description: r#"detects anonymous parameters"# },
274 LintCompletion { label: "box_pointers", description: r#"use of owned (Box type) heap memory"# },
275 LintCompletion { label: "deprecated_in_future", description: r#"detects use of items that will be deprecated in a future version"# },
276 LintCompletion { label: "elided_lifetimes_in_paths", description: r#"hidden lifetime parameters in types are deprecated"# },
277 LintCompletion { label: "explicit_outlives_requirements", description: r#"outlives requirements can be inferred"# },
278 LintCompletion { label: "indirect_structural_match", description: r#"pattern with const indirectly referencing non-structural-match type"# },
279 LintCompletion { label: "keyword_idents", description: r#"detects edition keywords being used as an identifier"# },
280 LintCompletion { label: "macro_use_extern_crate", description: r#"the `#[macro_use]` attribute is now deprecated in favor of using macros via the module system"# },
281 LintCompletion { label: "meta_variable_misuse", description: r#"possible meta-variable misuse at macro definition"# },
282 LintCompletion { label: "missing_copy_implementations", description: r#"detects potentially-forgotten implementations of `Copy`"# },
283 LintCompletion { label: "missing_crate_level_docs", description: r#"detects crates with no crate-level documentation"# },
284 LintCompletion { label: "missing_debug_implementations", description: r#"detects missing implementations of Debug"# },
285 LintCompletion { label: "missing_docs", description: r#"detects missing documentation for public members"# },
286 LintCompletion { label: "missing_doc_code_examples", description: r#"detects publicly-exported items without code samples in their documentation"# },
287 LintCompletion { label: "non_ascii_idents", description: r#"detects non-ASCII identifiers"# },
288 LintCompletion { label: "private_doc_tests", description: r#"detects code samples in docs of private items not documented by rustdoc"# },
289 LintCompletion { label: "single_use_lifetimes", description: r#"detects lifetime parameters that are only used once"# },
290 LintCompletion { label: "trivial_casts", description: r#"detects trivial casts which could be removed"# },
291 LintCompletion { label: "trivial_numeric_casts", description: r#"detects trivial casts of numeric types which could be removed"# },
292 LintCompletion { label: "unaligned_references", description: r#"detects unaligned references to fields of packed structs"# },
293 LintCompletion { label: "unreachable_pub", description: r#"`pub` items not reachable from crate root"# },
294 LintCompletion { label: "unsafe_code", description: r#"usage of `unsafe` code"# },
295 LintCompletion { label: "unsafe_op_in_unsafe_fn", description: r#"unsafe operations in unsafe functions without an explicit unsafe block are deprecated"# },
296 LintCompletion { label: "unstable_features", description: r#"enabling unstable features (deprecated. do not use)"# },
297 LintCompletion { label: "unused_crate_dependencies", description: r#"crate dependencies that are never used"# },
298 LintCompletion { label: "unused_extern_crates", description: r#"extern crates that are never used"# },
299 LintCompletion { label: "unused_import_braces", description: r#"unnecessary braces around an imported item"# },
300 LintCompletion { label: "unused_lifetimes", description: r#"detects lifetime parameters that are never used"# },
301 LintCompletion { label: "unused_qualifications", description: r#"detects unnecessarily qualified names"# },
302 LintCompletion { label: "unused_results", description: r#"unused result of an expression in a statement"# },
303 LintCompletion { label: "variant_size_differences", description: r#"detects enums with widely varying variant sizes"# },
304 LintCompletion { label: "array_into_iter", description: r#"detects calling `into_iter` on arrays"# },
305 LintCompletion { label: "asm_sub_register", description: r#"using only a subset of a register for inline asm inputs"# },
306 LintCompletion { label: "bare_trait_objects", description: r#"suggest using `dyn Trait` for trait objects"# },
307 LintCompletion { label: "bindings_with_variant_name", description: r#"detects pattern bindings with the same name as one of the matched variants"# },
308 LintCompletion { label: "cenum_impl_drop_cast", description: r#"a C-like enum implementing Drop is cast"# },
309 LintCompletion { label: "clashing_extern_declarations", description: r#"detects when an extern fn has been declared with the same name but different types"# },
310 LintCompletion { label: "coherence_leak_check", description: r#"distinct impls distinguished only by the leak-check code"# },
311 LintCompletion { label: "confusable_idents", description: r#"detects visually confusable pairs between identifiers"# },
312 LintCompletion { label: "dead_code", description: r#"detect unused, unexported items"# },
313 LintCompletion { label: "deprecated", description: r#"detects use of deprecated items"# },
314 LintCompletion { label: "ellipsis_inclusive_range_patterns", description: r#"`...` range patterns are deprecated"# },
315 LintCompletion { label: "exported_private_dependencies", description: r#"public interface leaks type from a private dependency"# },
316 LintCompletion { label: "illegal_floating_point_literal_pattern", description: r#"floating-point literals cannot be used in patterns"# },
317 LintCompletion { label: "improper_ctypes", description: r#"proper use of libc types in foreign modules"# },
318 LintCompletion { label: "improper_ctypes_definitions", description: r#"proper use of libc types in foreign item definitions"# },
319 LintCompletion { label: "incomplete_features", description: r#"incomplete features that may function improperly in some or all cases"# },
320 LintCompletion { label: "inline_no_sanitize", description: r#"detects incompatible use of `#[inline(always)]` and `#[no_sanitize(...)]`"# },
321 LintCompletion { label: "intra_doc_link_resolution_failure", description: r#"failures in resolving intra-doc link targets"# },
322 LintCompletion { label: "invalid_codeblock_attributes", description: r#"codeblock attribute looks a lot like a known one"# },
323 LintCompletion { label: "invalid_value", description: r#"an invalid value is being created (such as a NULL reference)"# },
324 LintCompletion { label: "irrefutable_let_patterns", description: r#"detects irrefutable patterns in if-let and while-let statements"# },
325 LintCompletion { label: "late_bound_lifetime_arguments", description: r#"detects generic lifetime arguments in path segments with late bound lifetime parameters"# },
326 LintCompletion { label: "mixed_script_confusables", description: r#"detects Unicode scripts whose mixed script confusables codepoints are solely used"# },
327 LintCompletion { label: "mutable_borrow_reservation_conflict", description: r#"reservation of a two-phased borrow conflicts with other shared borrows"# },
328 LintCompletion { label: "non_camel_case_types", description: r#"types, variants, traits and type parameters should have camel case names"# },
329 LintCompletion { label: "non_shorthand_field_patterns", description: r#"using `Struct { x: x }` instead of `Struct { x }` in a pattern"# },
330 LintCompletion { label: "non_snake_case", description: r#"variables, methods, functions, lifetime parameters and modules should have snake case names"# },
331 LintCompletion { label: "non_upper_case_globals", description: r#"static constants should have uppercase identifiers"# },
332 LintCompletion { label: "no_mangle_generic_items", description: r#"generic items must be mangled"# },
333 LintCompletion { label: "overlapping_patterns", description: r#"detects overlapping patterns"# },
334 LintCompletion { label: "path_statements", description: r#"path statements with no effect"# },
335 LintCompletion { label: "private_in_public", description: r#"detect private items in public interfaces not caught by the old implementation"# },
336 LintCompletion { label: "proc_macro_derive_resolution_fallback", description: r#"detects proc macro derives using inaccessible names from parent modules"# },
337 LintCompletion { label: "redundant_semicolons", description: r#"detects unnecessary trailing semicolons"# },
338 LintCompletion { label: "renamed_and_removed_lints", description: r#"lints that have been renamed or removed"# },
339 LintCompletion { label: "safe_packed_borrows", description: r#"safe borrows of fields of packed structs were erroneously allowed"# },
340 LintCompletion { label: "stable_features", description: r#"stable features found in `#[feature]` directive"# },
341 LintCompletion { label: "trivial_bounds", description: r#"these bounds don't depend on an type parameters"# },
342 LintCompletion { label: "type_alias_bounds", description: r#"bounds in type aliases are not enforced"# },
343 LintCompletion { label: "tyvar_behind_raw_pointer", description: r#"raw pointer to an inference variable"# },
344 LintCompletion { label: "uncommon_codepoints", description: r#"detects uncommon Unicode codepoints in identifiers"# },
345 LintCompletion { label: "unconditional_recursion", description: r#"functions that cannot return without calling themselves"# },
346 LintCompletion { label: "unknown_lints", description: r#"unrecognized lint attribute"# },
347 LintCompletion { label: "unnameable_test_items", description: r#"detects an item that cannot be named being marked as `#[test_case]`"# },
348 LintCompletion { label: "unreachable_code", description: r#"detects unreachable code paths"# },
349 LintCompletion { label: "unreachable_patterns", description: r#"detects unreachable patterns"# },
350 LintCompletion { label: "unstable_name_collisions", description: r#"detects name collision with an existing but unstable method"# },
351 LintCompletion { label: "unused_allocation", description: r#"detects unnecessary allocations that can be eliminated"# },
352 LintCompletion { label: "unused_assignments", description: r#"detect assignments that will never be read"# },
353 LintCompletion { label: "unused_attributes", description: r#"detects attributes that were not used by the compiler"# },
354 LintCompletion { label: "unused_braces", description: r#"unnecessary braces around an expression"# },
355 LintCompletion { label: "unused_comparisons", description: r#"comparisons made useless by limits of the types involved"# },
356 LintCompletion { label: "unused_doc_comments", description: r#"detects doc comments that aren't used by rustdoc"# },
357 LintCompletion { label: "unused_features", description: r#"unused features found in crate-level `#[feature]` directives"# },
358 LintCompletion { label: "unused_imports", description: r#"imports that are never used"# },
359 LintCompletion { label: "unused_labels", description: r#"detects labels that are never used"# },
360 LintCompletion { label: "unused_macros", description: r#"detects macros that were not used"# },
361 LintCompletion { label: "unused_must_use", description: r#"unused result of a type flagged as `#[must_use]`"# },
362 LintCompletion { label: "unused_mut", description: r#"detect mut variables which don't need to be mutable"# },
363 LintCompletion { label: "unused_parens", description: r#"`if`, `match`, `while` and `return` do not need parentheses"# },
364 LintCompletion { label: "unused_unsafe", description: r#"unnecessary use of an `unsafe` block"# },
365 LintCompletion { label: "unused_variables", description: r#"detect variables which are not used in any way"# },
366 LintCompletion { label: "warnings", description: r#"mass-change the level for lints which produce warnings"# },
367 LintCompletion { label: "where_clauses_object_safety", description: r#"checks the object safety of where clauses"# },
368 LintCompletion { label: "while_true", description: r#"suggest using `loop { }` instead of `while true { }`"# },
369 LintCompletion { label: "ambiguous_associated_items", description: r#"ambiguous associated items"# },
370 LintCompletion { label: "arithmetic_overflow", description: r#"arithmetic operation overflows"# },
371 LintCompletion { label: "conflicting_repr_hints", description: r#"conflicts between `#[repr(..)]` hints that were previously accepted and used in practice"# },
372 LintCompletion { label: "const_err", description: r#"constant evaluation detected erroneous expression"# },
373 LintCompletion { label: "ill_formed_attribute_input", description: r#"ill-formed attribute inputs that were previously accepted and used in practice"# },
374 LintCompletion { label: "incomplete_include", description: r#"trailing content in included file"# },
375 LintCompletion { label: "invalid_type_param_default", description: r#"type parameter default erroneously allowed in invalid location"# },
376 LintCompletion { label: "macro_expanded_macro_exports_accessed_by_absolute_paths", description: r#"macro-expanded `macro_export` macros from the current crate cannot be referred to by absolute paths"# },
377 LintCompletion { label: "missing_fragment_specifier", description: r#"detects missing fragment specifiers in unused `macro_rules!` patterns"# },
378 LintCompletion { label: "mutable_transmutes", description: r#"mutating transmuted &mut T from &T may cause undefined behavior"# },
379 LintCompletion { label: "no_mangle_const_items", description: r#"const items will not have their symbols exported"# },
380 LintCompletion { label: "order_dependent_trait_objects", description: r#"trait-object types were treated as different depending on marker-trait order"# },
381 LintCompletion { label: "overflowing_literals", description: r#"literal out of range for its type"# },
382 LintCompletion { label: "patterns_in_fns_without_body", description: r#"patterns in functions without body were erroneously allowed"# },
383 LintCompletion { label: "pub_use_of_private_extern_crate", description: r#"detect public re-exports of private extern crates"# },
384 LintCompletion { label: "soft_unstable", description: r#"a feature gate that doesn't break dependent crates"# },
385 LintCompletion { label: "unconditional_panic", description: r#"operation will cause a panic at runtime"# },
386 LintCompletion { label: "unknown_crate_types", description: r#"unknown crate type found in `#[crate_type]` directive"# },
387];
388
389#[cfg(test)]
390mod tests {
391 use expect_test::{expect, Expect};
392
393 use crate::{test_utils::completion_list, CompletionKind};
394
395 fn check(ra_fixture: &str, expect: Expect) {
396 let actual = completion_list(ra_fixture, CompletionKind::Attribute);
397 expect.assert_eq(&actual);
398 }
399
400 #[test]
401 fn empty_derive_completion() {
402 check(
403 r#"
404#[derive(<|>)]
405struct Test {}
406 "#,
407 expect![[r#"
408 at Clone
409 at Copy, Clone
410 at Debug
411 at Default
412 at Eq, PartialEq
413 at Hash
414 at Ord, PartialOrd, Eq, PartialEq
415 at PartialEq
416 at PartialOrd, PartialEq
417 "#]],
418 );
419 }
420
421 #[test]
422 fn no_completion_for_incorrect_derive() {
423 check(
424 r#"
425#[derive{<|>)]
426struct Test {}
427"#,
428 expect![[r#""#]],
429 )
430 }
431
432 #[test]
433 fn derive_with_input_completion() {
434 check(
435 r#"
436#[derive(serde::Serialize, PartialEq, <|>)]
437struct Test {}
438"#,
439 expect![[r#"
440 at Clone
441 at Copy, Clone
442 at Debug
443 at Default
444 at Eq
445 at Hash
446 at Ord, PartialOrd, Eq
447 at PartialOrd
448 "#]],
449 )
450 }
451
452 #[test]
453 fn test_attribute_completion() {
454 check(
455 r#"#[<|>]"#,
456 expect![[r#"
457 at allow(…)
458 at cfg(…)
459 at cfg_attr(…)
460 at deny(…)
461 at deprecated = "…"
462 at derive(…)
463 at doc = "…"
464 at forbid(…)
465 at ignore = "…"
466 at inline(…)
467 at link
468 at link_name = "…"
469 at macro_export
470 at macro_use
471 at must_use = "…"
472 at no_mangle
473 at non_exhaustive
474 at path = "…"
475 at proc_macro
476 at proc_macro_attribute
477 at proc_macro_derive(…)
478 at repr(…)
479 at should_panic(…)
480 at target_feature = "…"
481 at test
482 at used
483 at warn(…)
484 "#]],
485 )
486 }
487
488 #[test]
489 fn test_attribute_completion_inside_nested_attr() {
490 check(r#"#[cfg(<|>)]"#, expect![[]])
491 }
492
493 #[test]
494 fn test_inner_attribute_completion() {
495 check(
496 r"#![<|>]",
497 expect![[r#"
498 at allow(…)
499 at cfg(…)
500 at cfg_attr(…)
501 at deny(…)
502 at deprecated = "…"
503 at derive(…)
504 at doc = "…"
505 at feature(…)
506 at forbid(…)
507 at global_allocator
508 at ignore = "…"
509 at inline(…)
510 at link
511 at link_name = "…"
512 at macro_export
513 at macro_use
514 at must_use = "…"
515 at no_mangle
516 at no_std
517 at non_exhaustive
518 at panic_handler
519 at path = "…"
520 at proc_macro
521 at proc_macro_attribute
522 at proc_macro_derive(…)
523 at recursion_limit = …
524 at repr(…)
525 at should_panic(…)
526 at target_feature = "…"
527 at test
528 at used
529 at warn(…)
530 at windows_subsystem = "…"
531 "#]],
532 );
533 }
534}