1 //! Completion for derives
2 use itertools::Itertools;
3 use rustc_hash::FxHashSet;
7 context::CompletionContext,
8 item::{CompletionItem, CompletionItemKind, CompletionKind},
12 pub(super) fn complete_derive(
13 acc: &mut Completions,
14 ctx: &CompletionContext,
15 derive_input: ast::TokenTree,
17 if let Some(existing_derives) = super::parse_comma_sep_input(derive_input) {
18 for derive_completion in DEFAULT_DERIVE_COMPLETIONS
20 .filter(|completion| !existing_derives.contains(completion.label))
22 let mut components = vec![derive_completion.label];
27 .filter(|&&dependency| !existing_derives.contains(dependency)),
29 let lookup = components.join(", ");
30 let label = components.iter().rev().join(", ");
32 CompletionItem::new(CompletionKind::Attribute, ctx.source_range(), label);
33 item.lookup_by(lookup).kind(CompletionItemKind::Attribute);
37 for custom_derive_name in get_derive_names_in_scope(ctx).difference(&existing_derives) {
38 let mut item = CompletionItem::new(
39 CompletionKind::Attribute,
43 item.kind(CompletionItemKind::Attribute);
49 fn get_derive_names_in_scope(ctx: &CompletionContext) -> FxHashSet<String> {
50 let mut result = FxHashSet::default();
51 ctx.scope.process_all_names(&mut |name, scope_def| {
52 if let hir::ScopeDef::MacroDef(mac) = scope_def {
53 if mac.kind() == hir::MacroKind::Derive {
54 result.insert(name.to_string());
61 struct DeriveCompletion {
63 dependencies: &'static [&'static str],
66 /// Standard Rust derives and the information about their dependencies
67 /// (the dependencies are needed so that the main derive don't break the compilation when added)
68 const DEFAULT_DERIVE_COMPLETIONS: &[DeriveCompletion] = &[
69 DeriveCompletion { label: "Clone", dependencies: &[] },
70 DeriveCompletion { label: "Copy", dependencies: &["Clone"] },
71 DeriveCompletion { label: "Debug", dependencies: &[] },
72 DeriveCompletion { label: "Default", dependencies: &[] },
73 DeriveCompletion { label: "Hash", dependencies: &[] },
74 DeriveCompletion { label: "PartialEq", dependencies: &[] },
75 DeriveCompletion { label: "Eq", dependencies: &["PartialEq"] },
76 DeriveCompletion { label: "PartialOrd", dependencies: &["PartialEq"] },
77 DeriveCompletion { label: "Ord", dependencies: &["PartialOrd", "Eq", "PartialEq"] },
82 use expect_test::{expect, Expect};
84 use crate::{test_utils::completion_list, CompletionKind};
86 fn check(ra_fixture: &str, expect: Expect) {
87 let actual = completion_list(ra_fixture, CompletionKind::Attribute);
88 expect.assert_eq(&actual);
92 fn no_completion_for_incorrect_derive() {
93 check(r#"#[derive{$0)] struct Test;"#, expect![[]])
99 r#"#[derive($0)] struct Test;"#,
108 at PartialEq, PartialOrd
109 at PartialEq, Eq, PartialOrd, Ord
115 fn derive_with_input() {
117 r#"#[derive(serde::Serialize, PartialEq, $0)] struct Test;"#,
126 at Eq, PartialOrd, Ord
132 fn derive_with_input2() {
134 r#"#[derive($0 serde::Serialize, PartialEq)] struct Test;"#,
143 at Eq, PartialOrd, Ord