1 //! This modules takes care of rendering various defenitions as completion items.
2 use join_to_string::join;
3 use test_utils::tested_by;
4 use hir::{Docs, PerNs, Resolution};
5 use ra_syntax::ast::NameOwner;
7 use crate::completion::{
8 Completions, CompletionKind, CompletionItemKind, CompletionContext, CompletionItem,
9 function_label, const_label, type_label,
13 pub(crate) fn add_field(
15 ctx: &CompletionContext,
16 field: hir::StructField,
20 CompletionKind::Reference,
22 field.name(ctx.db).to_string(),
24 .kind(CompletionItemKind::Field)
25 .detail(field.ty(ctx.db).subst(substs).to_string())
26 .set_documentation(field.docs(ctx.db))
30 pub(crate) fn add_pos_field(&mut self, ctx: &CompletionContext, field: usize, ty: &hir::Ty) {
31 CompletionItem::new(CompletionKind::Reference, ctx.source_range(), field.to_string())
32 .kind(CompletionItemKind::Field)
33 .detail(ty.to_string())
37 pub(crate) fn add_resolution(
39 ctx: &CompletionContext,
41 resolution: &PerNs<Resolution>,
43 use hir::ModuleDef::*;
45 let def = resolution.as_ref().take_types().or_else(|| resolution.as_ref().take_values());
48 self.add(CompletionItem::new(
49 CompletionKind::Reference,
57 let (kind, docs) = match def {
58 Resolution::Def(Module(it)) => (CompletionItemKind::Module, it.docs(ctx.db)),
59 Resolution::Def(Function(func)) => {
60 return self.add_function_with_name(ctx, Some(local_name), *func);
62 Resolution::Def(Struct(it)) => (CompletionItemKind::Struct, it.docs(ctx.db)),
63 Resolution::Def(Enum(it)) => (CompletionItemKind::Enum, it.docs(ctx.db)),
64 Resolution::Def(EnumVariant(it)) => (CompletionItemKind::EnumVariant, it.docs(ctx.db)),
65 Resolution::Def(Const(it)) => (CompletionItemKind::Const, it.docs(ctx.db)),
66 Resolution::Def(Static(it)) => (CompletionItemKind::Static, it.docs(ctx.db)),
67 Resolution::Def(Trait(it)) => (CompletionItemKind::Trait, it.docs(ctx.db)),
68 Resolution::Def(Type(it)) => (CompletionItemKind::TypeAlias, it.docs(ctx.db)),
69 Resolution::GenericParam(..) => (CompletionItemKind::TypeParam, None),
70 Resolution::LocalBinding(..) => (CompletionItemKind::Binding, None),
71 Resolution::SelfType(..) => (
72 CompletionItemKind::TypeParam, // (does this need its own kind?)
76 CompletionItem::new(CompletionKind::Reference, ctx.source_range(), local_name)
78 .set_documentation(docs)
82 pub(crate) fn add_function(&mut self, ctx: &CompletionContext, func: hir::Function) {
83 self.add_function_with_name(ctx, None, func)
86 fn add_function_with_name(
88 ctx: &CompletionContext,
92 let sig = func.signature(ctx.db);
93 let name = name.unwrap_or_else(|| sig.name().to_string());
94 let (_, ast_node) = func.source(ctx.db);
95 let detail = function_label(&ast_node);
97 let mut builder = CompletionItem::new(CompletionKind::Reference, ctx.source_range(), name)
98 .kind(if sig.has_self_param() {
99 CompletionItemKind::Method
101 CompletionItemKind::Function
103 .set_documentation(func.docs(ctx.db))
105 // If not an import, add parenthesis automatically.
106 if ctx.use_item_syntax.is_none() && !ctx.is_call {
107 tested_by!(inserts_parens_for_function_calls);
109 if sig.params().is_empty() || sig.has_self_param() && sig.params().len() == 1 {
110 format!("{}()$0", sig.name())
112 format!("{}($0)", sig.name())
114 builder = builder.insert_snippet(snippet);
119 pub(crate) fn add_const(&mut self, ctx: &CompletionContext, constant: hir::Const) {
120 let (_file_id, ast_node) = constant.source(ctx.db);
121 let name = match ast_node.name() {
125 let (_, ast_node) = constant.source(ctx.db);
126 let detail = const_label(&ast_node);
128 CompletionItem::new(CompletionKind::Reference, ctx.source_range(), name.text().to_string())
129 .kind(CompletionItemKind::Const)
130 .set_documentation(constant.docs(ctx.db))
135 pub(crate) fn add_type(&mut self, ctx: &CompletionContext, type_alias: hir::Type) {
136 let (_file_id, type_def) = type_alias.source(ctx.db);
137 let name = match type_def.name() {
141 let (_, ast_node) = type_alias.source(ctx.db);
142 let detail = type_label(&ast_node);
144 CompletionItem::new(CompletionKind::Reference, ctx.source_range(), name.text().to_string())
145 .kind(CompletionItemKind::TypeAlias)
146 .set_documentation(type_alias.docs(ctx.db))
151 pub(crate) fn add_enum_variant(&mut self, ctx: &CompletionContext, variant: hir::EnumVariant) {
152 let name = match variant.name(ctx.db) {
156 let detail_types = variant.fields(ctx.db).into_iter().map(|field| field.ty(ctx.db));
157 let detail = join(detail_types).separator(", ").surround_with("(", ")").to_string();
159 CompletionItem::new(CompletionKind::Reference, ctx.source_range(), name.to_string())
160 .kind(CompletionItemKind::EnumVariant)
161 .set_documentation(variant.docs(ctx.db))
169 use test_utils::covers;
171 use crate::completion::{CompletionKind, completion_item::check_completion};
173 fn check_reference_completion(code: &str, expected_completions: &str) {
174 check_completion(code, expected_completions, CompletionKind::Reference);
178 fn inserts_parens_for_function_calls() {
179 covers!(inserts_parens_for_function_calls);
180 check_reference_completion(
181 "inserts_parens_for_function_calls1",
187 check_reference_completion(
188 "inserts_parens_for_function_calls2",
190 fn with_args(x: i32, y: String) {}
191 fn main() { with_<|> }
194 check_reference_completion(
195 "inserts_parens_for_function_calls3",
209 fn dont_render_function_parens_in_use_item() {
210 check_reference_completion(
211 "dont_render_function_parens_in_use_item",
214 mod m { pub fn foo() {} }
221 fn dont_render_function_parens_if_already_call() {
222 check_reference_completion(
223 "dont_render_function_parens_if_already_call",
232 check_reference_completion(
233 "dont_render_function_parens_if_already_call_assoc_fn",
237 impl Foo { fn new() -> Foo {} }