aboutsummaryrefslogtreecommitdiff
path: root/crates/ide/src/completion/complete_attribute.rs
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ide/src/completion/complete_attribute.rs')
-rw-r--r--crates/ide/src/completion/complete_attribute.rs653
1 files changed, 653 insertions, 0 deletions
diff --git a/crates/ide/src/completion/complete_attribute.rs b/crates/ide/src/completion/complete_attribute.rs
new file mode 100644
index 000000000..0abfaebcb
--- /dev/null
+++ b/crates/ide/src/completion/complete_attribute.rs
@@ -0,0 +1,653 @@
1//! Completion for attributes
2//!
3//! This module uses a bit of static metadata to provide completions
4//! for built-in attributes.
5
6use rustc_hash::FxHashSet;
7use syntax::{ast, AstNode, SyntaxKind};
8
9use crate::completion::{
10 completion_context::CompletionContext,
11 completion_item::{CompletionItem, CompletionItemKind, CompletionKind, Completions},
12 generated_features::FEATURES,
13};
14
15pub(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, FEATURES)
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
37fn 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
63struct AttrCompletion {
64 label: &'static str,
65 lookup: Option<&'static str>,
66 snippet: Option<&'static str>,
67 prefer_inner: bool,
68}
69
70impl AttrCompletion {
71 const fn prefer_inner(self) -> AttrCompletion {
72 AttrCompletion { prefer_inner: true, ..self }
73 }
74}
75
76const 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
84const 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
135fn 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
169fn 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
193fn 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
228fn 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
240struct 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]
248const 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
260pub(super) struct LintCompletion {
261 pub(super) label: &'static str,
262 pub(super) description: &'static str,
263}
264
265#[rustfmt::skip]
266const 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)]
385mod tests {
386 use expect_test::{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(<|>)]
400struct 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{<|>)]
545struct 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, <|>)]
556struct 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}