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