aboutsummaryrefslogtreecommitdiff
path: root/crates/completion/src/completions/attribute.rs
diff options
context:
space:
mode:
Diffstat (limited to 'crates/completion/src/completions/attribute.rs')
-rw-r--r--crates/completion/src/completions/attribute.rs554
1 files changed, 0 insertions, 554 deletions
diff --git a/crates/completion/src/completions/attribute.rs b/crates/completion/src/completions/attribute.rs
deleted file mode 100644
index e5522980d..000000000
--- a/crates/completion/src/completions/attribute.rs
+++ /dev/null
@@ -1,554 +0,0 @@
1//! Completion for attributes
2//!
3//! This module uses a bit of static metadata to provide completions
4//! for built-in attributes.
5
6use itertools::Itertools;
7use rustc_hash::FxHashSet;
8use syntax::{ast, AstNode, T};
9
10use crate::{
11 context::CompletionContext,
12 generated_lint_completions::{CLIPPY_LINTS, FEATURES},
13 item::{CompletionItem, CompletionItemKind, CompletionKind},
14 Completions,
15};
16
17pub(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
41fn 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
64struct AttrCompletion {
65 label: &'static str,
66 lookup: Option<&'static str>,
67 snippet: Option<&'static str>,
68 prefer_inner: bool,
69}
70
71impl AttrCompletion {
72 const fn prefer_inner(self) -> AttrCompletion {
73 AttrCompletion { prefer_inner: true, ..self }
74 }
75}
76
77const 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
86const 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
153fn 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
182fn 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
205fn 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
239fn 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
251struct 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)
258const 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
270pub(crate) struct LintCompletion {
271 pub(crate) label: &'static str,
272 pub(crate) description: &'static str,
273}
274
275#[rustfmt::skip]
276const 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)]
395mod 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)]
410struct 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)]
431struct 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)]
442struct 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}