1 //! Completion for derives
2 use hir::{HasAttrs, ScopeDef};
3 use ide_db::SymbolKind;
4 use itertools::Itertools;
8 context::{CompletionContext, ExistingDerives, PathCompletionCtx, Qualified},
13 pub(crate) fn complete_derive_path(
14 acc: &mut Completions,
15 ctx: &CompletionContext<'_>,
16 path_ctx @ PathCompletionCtx { qualified, .. }: &PathCompletionCtx,
17 existing_derives: &ExistingDerives,
19 let core = ctx.famous_defs().core();
23 resolution: Some(hir::PathResolution::Def(hir::ModuleDef::Module(module))),
27 acc.add_super_keyword(ctx, *super_chain_len);
29 for (name, def) in module.scope(ctx.db, Some(ctx.module)) {
31 ScopeDef::ModuleDef(hir::ModuleDef::Macro(mac))
32 if !existing_derives.contains(&mac) && mac.is_derive(ctx.db) =>
34 acc.add_macro(ctx, path_ctx, mac, name)
36 ScopeDef::ModuleDef(hir::ModuleDef::Module(m)) => {
37 acc.add_module(ctx, path_ctx, m, name)
43 Qualified::Absolute => acc.add_crate_roots(ctx, path_ctx),
44 // only show modules in a fresh UseTree
46 ctx.process_all_names(&mut |name, def| {
48 ScopeDef::ModuleDef(hir::ModuleDef::Macro(mac))
49 if !existing_derives.contains(&mac) && mac.is_derive(ctx.db) =>
53 ScopeDef::ModuleDef(hir::ModuleDef::Module(m)) => {
54 return acc.add_module(ctx, path_ctx, m, name);
59 match (core, mac.module(ctx.db).krate()) {
60 // show derive dependencies for `core`/`std` derives
61 (Some(core), mac_krate) if core == mac_krate => {}
62 _ => return acc.add_macro(ctx, path_ctx, mac, name),
65 let name_ = name.to_smol_str();
66 let find = DEFAULT_DERIVE_DEPENDENCIES
68 .find(|derive_completion| derive_completion.label == name_);
71 Some(derive_completion) => {
72 let mut components = vec![derive_completion.label];
73 components.extend(derive_completion.dependencies.iter().filter(
77 .map(|it| it.name(ctx.db))
78 .any(|it| it.to_smol_str() == dependency)
81 let lookup = components.join(", ");
82 let label = Itertools::intersperse(components.into_iter().rev(), ", ");
84 let mut item = CompletionItem::new(
87 SmolStr::from_iter(label),
89 if let Some(docs) = mac.docs(ctx.db) {
90 item.documentation(docs);
92 item.lookup_by(lookup);
95 None => acc.add_macro(ctx, path_ctx, mac, name),
98 acc.add_nameref_keywords_with_colon(ctx);
100 Qualified::TypeAnchor { .. } | Qualified::With { .. } => {}
104 struct DeriveDependencies {
106 dependencies: &'static [&'static str],
109 /// Standard Rust derives that have dependencies
110 /// (the dependencies are needed so that the main derive don't break the compilation when added)
111 const DEFAULT_DERIVE_DEPENDENCIES: &[DeriveDependencies] = &[
112 DeriveDependencies { label: "Copy", dependencies: &["Clone"] },
113 DeriveDependencies { label: "Eq", dependencies: &["PartialEq"] },
114 DeriveDependencies { label: "Ord", dependencies: &["PartialOrd", "Eq", "PartialEq"] },
115 DeriveDependencies { label: "PartialOrd", dependencies: &["PartialEq"] },