1 //! Completion for derives
3 use itertools::Itertools;
4 use rustc_hash::FxHashMap;
8 context::CompletionContext,
9 item::{CompletionItem, CompletionItemKind, CompletionKind},
13 pub(super) fn complete_derive(
14 acc: &mut Completions,
15 ctx: &CompletionContext,
16 derive_input: ast::TokenTree,
18 if let Some(existing_derives) = super::parse_comma_sep_input(derive_input) {
19 for (derive, docs) in get_derive_names_in_scope(ctx) {
20 let (label, lookup) = if let Some(derive_completion) = DEFAULT_DERIVE_COMPLETIONS
22 .find(|derive_completion| derive_completion.label == derive)
24 let mut components = vec![derive_completion.label];
29 .filter(|&&dependency| !existing_derives.contains(dependency)),
31 let lookup = components.join(", ");
32 let label = components.iter().rev().join(", ");
38 CompletionItem::new(CompletionKind::Attribute, ctx.source_range(), label);
39 item.kind(CompletionItemKind::Attribute);
40 if let Some(docs) = docs {
41 item.documentation(docs);
43 if let Some(lookup) = lookup {
44 item.lookup_by(lookup);
51 fn get_derive_names_in_scope(
52 ctx: &CompletionContext,
53 ) -> FxHashMap<String, Option<hir::Documentation>> {
54 let mut result = FxHashMap::default();
55 ctx.scope.process_all_names(&mut |name, scope_def| {
56 if let hir::ScopeDef::MacroDef(mac) = scope_def {
57 if mac.kind() == hir::MacroKind::Derive {
58 result.insert(name.to_string(), mac.docs(ctx.db));
65 struct DeriveDependencies {
67 dependencies: &'static [&'static str],
70 /// Standard Rust derives that have dependencies
71 /// (the dependencies are needed so that the main derive don't break the compilation when added)
72 const DEFAULT_DERIVE_COMPLETIONS: &[DeriveDependencies] = &[
73 DeriveDependencies { label: "Copy", dependencies: &["Clone"] },
74 DeriveDependencies { label: "Eq", dependencies: &["PartialEq"] },
75 DeriveDependencies { label: "Ord", dependencies: &["PartialOrd", "Eq", "PartialEq"] },
76 DeriveDependencies { label: "PartialOrd", dependencies: &["PartialEq"] },
81 use expect_test::{expect, Expect};
83 use crate::{test_utils::completion_list, CompletionKind};
85 fn check(ra_fixture: &str, expect: Expect) {
86 let actual = completion_list(ra_fixture, CompletionKind::Attribute);
87 expect.assert_eq(&actual);
91 fn no_completion_for_incorrect_derive() {
92 check(r#"#[derive{$0)] struct Test;"#, expect![[]])
97 // FIXME: Add build-in derives to fixture.
98 check(r#"#[derive($0)] struct Test;"#, expect![[r#""#]]);
102 fn derive_with_input() {
103 // FIXME: Add build-in derives to fixture.
104 check(r#"#[derive(serde::Serialize, PartialEq, $0)] struct Test;"#, expect![[r#""#]])
108 fn derive_with_input2() {
109 // FIXME: Add build-in derives to fixture.
110 check(r#"#[derive($0 serde::Serialize, PartialEq)] struct Test;"#, expect![[r#""#]])