1 //! This modules takes care of rendering various definitions as completion items.
3 use hir::{db::HirDatabase, Docs, HasSource, HirDisplay, ScopeDef, Ty, TypeWalk};
4 use join_to_string::join;
5 use ra_syntax::ast::NameOwner;
6 use test_utils::tested_by;
8 use crate::completion::{
9 db, CompletionContext, CompletionItem, CompletionItemKind, CompletionKind, Completions,
12 use crate::display::{const_label, function_label, macro_label, type_label};
15 pub(crate) fn add_field(
17 ctx: &CompletionContext,
18 field: hir::StructField,
22 CompletionKind::Reference,
24 field.name(ctx.db).to_string(),
26 .kind(CompletionItemKind::Field)
27 .detail(field.ty(ctx.db).subst(substs).display(ctx.db).to_string())
28 .set_documentation(field.docs(ctx.db))
32 pub(crate) fn add_tuple_field(&mut self, ctx: &CompletionContext, field: usize, ty: &hir::Ty) {
33 CompletionItem::new(CompletionKind::Reference, ctx.source_range(), field.to_string())
34 .kind(CompletionItemKind::Field)
35 .detail(ty.display(ctx.db).to_string())
39 pub(crate) fn add_resolution(
41 ctx: &CompletionContext,
43 resolution: &ScopeDef,
45 use hir::ModuleDef::*;
47 let completion_kind = match resolution {
48 ScopeDef::ModuleDef(BuiltinType(..)) => CompletionKind::BuiltinType,
49 _ => CompletionKind::Reference,
52 let kind = match resolution {
53 ScopeDef::ModuleDef(Module(..)) => CompletionItemKind::Module,
54 ScopeDef::ModuleDef(Function(func)) => {
55 return self.add_function_with_name(ctx, Some(local_name), *func);
57 ScopeDef::ModuleDef(Adt(hir::Adt::Struct(_))) => CompletionItemKind::Struct,
58 // FIXME: add CompletionItemKind::Union
59 ScopeDef::ModuleDef(Adt(hir::Adt::Union(_))) => CompletionItemKind::Struct,
60 ScopeDef::ModuleDef(Adt(hir::Adt::Enum(_))) => CompletionItemKind::Enum,
62 ScopeDef::ModuleDef(EnumVariant(..)) => CompletionItemKind::EnumVariant,
63 ScopeDef::ModuleDef(Const(..)) => CompletionItemKind::Const,
64 ScopeDef::ModuleDef(Static(..)) => CompletionItemKind::Static,
65 ScopeDef::ModuleDef(Trait(..)) => CompletionItemKind::Trait,
66 ScopeDef::ModuleDef(TypeAlias(..)) => CompletionItemKind::TypeAlias,
67 ScopeDef::ModuleDef(BuiltinType(..)) => CompletionItemKind::BuiltinType,
68 ScopeDef::GenericParam(..) => CompletionItemKind::TypeParam,
69 ScopeDef::LocalBinding(..) => CompletionItemKind::Binding,
70 // (does this need its own kind?)
71 ScopeDef::AdtSelfType(..) | ScopeDef::ImplSelfType(..) => CompletionItemKind::TypeParam,
72 ScopeDef::MacroDef(mac) => {
73 return self.add_macro(ctx, Some(local_name), *mac);
75 ScopeDef::Unknown => {
76 return self.add(CompletionItem::new(
77 CompletionKind::Reference,
84 let docs = match resolution {
85 ScopeDef::ModuleDef(Module(it)) => it.docs(ctx.db),
86 ScopeDef::ModuleDef(Adt(it)) => it.docs(ctx.db),
87 ScopeDef::ModuleDef(EnumVariant(it)) => it.docs(ctx.db),
88 ScopeDef::ModuleDef(Const(it)) => it.docs(ctx.db),
89 ScopeDef::ModuleDef(Static(it)) => it.docs(ctx.db),
90 ScopeDef::ModuleDef(Trait(it)) => it.docs(ctx.db),
91 ScopeDef::ModuleDef(TypeAlias(it)) => it.docs(ctx.db),
95 let mut completion_item =
96 CompletionItem::new(completion_kind, ctx.source_range(), local_name.clone());
97 if let ScopeDef::LocalBinding(pat_id) = resolution {
100 .type_of_pat_by_id(ctx.db, pat_id.clone())
101 .filter(|t| t != &Ty::Unknown)
102 .map(|t| t.display(ctx.db).to_string());
103 completion_item = completion_item.set_detail(ty);
106 // If not an import, add parenthesis automatically.
108 && !ctx.has_type_args
109 && ctx.db.feature_flags.get("completion.insertion.add-call-parenthesis")
111 let generic_def: Option<hir::GenericDef> = match resolution {
112 ScopeDef::ModuleDef(Adt(it)) => Some((*it).into()),
113 ScopeDef::ModuleDef(TypeAlias(it)) => Some((*it).into()),
116 if let Some(def) = generic_def {
117 if has_non_default_type_params(def, ctx.db) {
118 tested_by!(inserts_angle_brackets_for_generics);
119 completion_item = completion_item
120 .lookup_by(local_name.clone())
121 .label(format!("{}<…>", local_name))
122 .insert_snippet(format!("{}<$0>", local_name));
127 completion_item.kind(kind).set_documentation(docs).add_to(self)
130 pub(crate) fn add_function(&mut self, ctx: &CompletionContext, func: hir::Function) {
131 self.add_function_with_name(ctx, None, func)
134 pub(crate) fn add_macro(
136 ctx: &CompletionContext,
137 name: Option<String>,
138 macro_: hir::MacroDef,
140 let ast_node = macro_.source(ctx.db).ast;
141 if let Some(name) = name {
142 let detail = macro_label(&ast_node);
144 let macro_braces_to_insert = match name.as_str() {
148 let macro_declaration = name + "!";
150 let builder = CompletionItem::new(
151 CompletionKind::Reference,
155 .kind(CompletionItemKind::Macro)
156 .set_documentation(macro_.docs(ctx.db))
158 .insert_snippet(macro_declaration + macro_braces_to_insert);
164 fn add_function_with_name(
166 ctx: &CompletionContext,
167 name: Option<String>,
170 let data = func.data(ctx.db);
171 let name = name.unwrap_or_else(|| data.name().to_string());
172 let ast_node = func.source(ctx.db).ast;
173 let detail = function_label(&ast_node);
176 CompletionItem::new(CompletionKind::Reference, ctx.source_range(), name.clone())
177 .kind(if data.has_self_param() {
178 CompletionItemKind::Method
180 CompletionItemKind::Function
182 .set_documentation(func.docs(ctx.db))
185 // Add `<>` for generic types
186 if ctx.use_item_syntax.is_none()
188 && ctx.db.feature_flags.get("completion.insertion.add-call-parenthesis")
190 tested_by!(inserts_parens_for_function_calls);
191 let (snippet, label) =
192 if data.params().is_empty() || data.has_self_param() && data.params().len() == 1 {
193 (format!("{}()$0", data.name()), format!("{}()", name))
195 (format!("{}($0)", data.name()), format!("{}(…)", name))
197 builder = builder.lookup_by(name.clone()).label(label).insert_snippet(snippet);
203 pub(crate) fn add_const(&mut self, ctx: &CompletionContext, constant: hir::Const) {
204 let ast_node = constant.source(ctx.db).ast;
205 let name = match ast_node.name() {
209 let detail = const_label(&ast_node);
211 CompletionItem::new(CompletionKind::Reference, ctx.source_range(), name.text().to_string())
212 .kind(CompletionItemKind::Const)
213 .set_documentation(constant.docs(ctx.db))
218 pub(crate) fn add_type_alias(&mut self, ctx: &CompletionContext, type_alias: hir::TypeAlias) {
219 let type_def = type_alias.source(ctx.db).ast;
220 let name = match type_def.name() {
224 let detail = type_label(&type_def);
226 CompletionItem::new(CompletionKind::Reference, ctx.source_range(), name.text().to_string())
227 .kind(CompletionItemKind::TypeAlias)
228 .set_documentation(type_alias.docs(ctx.db))
233 pub(crate) fn add_enum_variant(&mut self, ctx: &CompletionContext, variant: hir::EnumVariant) {
234 let name = match variant.name(ctx.db) {
238 let detail_types = variant.fields(ctx.db).into_iter().map(|field| field.ty(ctx.db));
239 let detail = join(detail_types.map(|t| t.display(ctx.db).to_string()))
241 .surround_with("(", ")")
243 CompletionItem::new(CompletionKind::Reference, ctx.source_range(), name.to_string())
244 .kind(CompletionItemKind::EnumVariant)
245 .set_documentation(variant.docs(ctx.db))
251 fn has_non_default_type_params(def: hir::GenericDef, db: &db::RootDatabase) -> bool {
252 let subst = db.generic_defaults(def);
253 subst.iter().any(|ty| ty == &Ty::Unknown)
258 use crate::completion::{do_completion, CompletionItem, CompletionKind};
259 use insta::assert_debug_snapshot;
260 use test_utils::covers;
262 fn do_reference_completion(code: &str) -> Vec<CompletionItem> {
263 do_completion(code, CompletionKind::Reference)
267 fn inserts_parens_for_function_calls() {
268 covers!(inserts_parens_for_function_calls);
269 assert_debug_snapshot!(
270 do_reference_completion(
280 source_range: [61; 64),
289 source_range: [61; 64),
291 insert: "no_args()$0",
294 detail: "fn no_args()",
299 assert_debug_snapshot!(
300 do_reference_completion(
302 fn with_args(x: i32, y: String) {}
303 fn main() { with_<|> }
310 source_range: [80; 85),
318 label: "with_args(…)",
319 source_range: [80; 85),
321 insert: "with_args($0)",
324 detail: "fn with_args(x: i32, y: String)",
329 assert_debug_snapshot!(
330 do_reference_completion(
345 source_range: [163; 164),
350 detail: "fn foo(&self)",
358 fn dont_render_function_parens_in_use_item() {
359 assert_debug_snapshot!(
360 do_reference_completion(
363 mod m { pub fn foo() {} }
370 source_range: [40; 41),
374 detail: "pub fn foo()",
381 fn dont_render_function_parens_if_already_call() {
382 assert_debug_snapshot!(
383 do_reference_completion(
395 source_range: [35; 39),
397 insert: "frobnicate",
399 detail: "fn frobnicate()",
403 source_range: [35; 39),
411 assert_debug_snapshot!(
412 do_reference_completion(
416 impl Foo { fn new() -> Foo {} }
425 source_range: [67; 69),
429 detail: "fn new() -> Foo",
436 fn inserts_angle_brackets_for_generics() {
437 covers!(inserts_angle_brackets_for_generics);
438 assert_debug_snapshot!(
439 do_reference_completion(
449 source_range: [61; 63),
457 source_range: [61; 63),
462 detail: "fn foo(xs: Ve)",
467 assert_debug_snapshot!(
468 do_reference_completion(
478 source_range: [64; 66),
486 source_range: [64; 66),
491 detail: "fn foo(xs: Ve)",
496 assert_debug_snapshot!(
497 do_reference_completion(
499 struct Vec<T = i128> {}
507 source_range: [68; 70),
514 source_range: [68; 70),
519 detail: "fn foo(xs: Ve)",
524 assert_debug_snapshot!(
525 do_reference_completion(
528 fn foo(xs: Ve<|><i128>)
535 source_range: [61; 63),
542 source_range: [61; 63),
547 detail: "fn foo(xs: Ve<i128>)",