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