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