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,
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());
95 let mut builder = CompletionItem::new(CompletionKind::Reference, ctx.source_range(), name)
96 .kind(if sig.has_self_param() {
97 CompletionItemKind::Method
99 CompletionItemKind::Function
101 .set_documentation(func.docs(ctx.db))
102 .set_detail(function_item_label(ctx, func));
103 // If not an import, add parenthesis automatically.
104 if ctx.use_item_syntax.is_none() && !ctx.is_call {
105 tested_by!(inserts_parens_for_function_calls);
107 if sig.params().is_empty() || sig.has_self_param() && sig.params().len() == 1 {
108 format!("{}()$0", sig.name())
110 format!("{}($0)", sig.name())
112 builder = builder.insert_snippet(snippet);
117 pub(crate) fn add_const(&mut self, ctx: &CompletionContext, constant: hir::Const) {
118 let (_file_id, cosnt_def) = constant.source(ctx.db);
119 let name = match cosnt_def.name() {
123 CompletionItem::new(CompletionKind::Reference, ctx.source_range(), name.text().to_string())
124 .from_const(ctx, constant)
128 pub(crate) fn add_type(&mut self, ctx: &CompletionContext, type_alias: hir::Type) {
129 let (_file_id, type_def) = type_alias.source(ctx.db);
130 let name = match type_def.name() {
134 CompletionItem::new(CompletionKind::Reference, ctx.source_range(), name.text().to_string())
135 .from_type(ctx, type_alias)
139 pub(crate) fn add_enum_variant(&mut self, ctx: &CompletionContext, variant: hir::EnumVariant) {
140 let name = match variant.name(ctx.db) {
144 let detail_types = variant.fields(ctx.db).into_iter().map(|field| field.ty(ctx.db));
145 let detail = join(detail_types).separator(", ").surround_with("(", ")").to_string();
147 CompletionItem::new(CompletionKind::Reference, ctx.source_range(), name.to_string())
148 .kind(CompletionItemKind::EnumVariant)
149 .set_documentation(variant.docs(ctx.db))
155 fn function_item_label(ctx: &CompletionContext, function: hir::Function) -> Option<String> {
156 let node = function.source(ctx.db).1;
157 function_label(&node)
162 use test_utils::covers;
164 use crate::completion::{CompletionKind, completion_item::check_completion};
166 fn check_reference_completion(code: &str, expected_completions: &str) {
167 check_completion(code, expected_completions, CompletionKind::Reference);
171 fn inserts_parens_for_function_calls() {
172 covers!(inserts_parens_for_function_calls);
173 check_reference_completion(
174 "inserts_parens_for_function_calls1",
180 check_reference_completion(
181 "inserts_parens_for_function_calls2",
183 fn with_args(x: i32, y: String) {}
184 fn main() { with_<|> }
187 check_reference_completion(
188 "inserts_parens_for_function_calls3",
202 fn dont_render_function_parens_in_use_item() {
203 check_reference_completion(
204 "dont_render_function_parens_in_use_item",
207 mod m { pub fn foo() {} }
214 fn dont_render_function_parens_if_already_call() {
215 check_reference_completion(
216 "dont_render_function_parens_if_already_call",
225 check_reference_completion(
226 "dont_render_function_parens_if_already_call_assoc_fn",
230 impl Foo { fn new() -> Foo {} }