aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_ide_api
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_ide_api')
-rw-r--r--crates/ra_ide_api/src/completion/presentation.rs140
1 files changed, 84 insertions, 56 deletions
diff --git a/crates/ra_ide_api/src/completion/presentation.rs b/crates/ra_ide_api/src/completion/presentation.rs
index 400a266a2..b7807ef8e 100644
--- a/crates/ra_ide_api/src/completion/presentation.rs
+++ b/crates/ra_ide_api/src/completion/presentation.rs
@@ -44,48 +44,56 @@ impl Completions {
44 ) { 44 ) {
45 use hir::ModuleDef::*; 45 use hir::ModuleDef::*;
46 46
47 let mut completion_kind = CompletionKind::Reference; 47 let completion_kind = match resolution {
48 let (kind, docs) = match resolution { 48 ScopeDef::ModuleDef(BuiltinType(..)) => CompletionKind::BuiltinType,
49 ScopeDef::ModuleDef(Module(it)) => (CompletionItemKind::Module, it.docs(ctx.db)), 49 _ => CompletionKind::Reference,
50 };
51
52 let kind = match resolution {
53 ScopeDef::ModuleDef(Module(..)) => CompletionItemKind::Module,
50 ScopeDef::ModuleDef(Function(func)) => { 54 ScopeDef::ModuleDef(Function(func)) => {
51 return self.add_function_with_name(ctx, Some(local_name), *func); 55 return self.add_function_with_name(ctx, Some(local_name), *func);
52 } 56 }
53 ScopeDef::ModuleDef(Adt(adt)) => { 57 ScopeDef::ModuleDef(Adt(hir::Adt::Struct(_))) => CompletionItemKind::Struct,
54 return self.add_adt_with_name(ctx, local_name, *adt); 58 // FIXME: add CompletionItemKind::Union
55 } 59 ScopeDef::ModuleDef(Adt(hir::Adt::Union(_))) => CompletionItemKind::Struct,
56 ScopeDef::ModuleDef(EnumVariant(it)) => { 60 ScopeDef::ModuleDef(Adt(hir::Adt::Enum(_))) => CompletionItemKind::Enum,
57 (CompletionItemKind::EnumVariant, it.docs(ctx.db)) 61
58 } 62 ScopeDef::ModuleDef(EnumVariant(..)) => CompletionItemKind::EnumVariant,
59 ScopeDef::ModuleDef(Const(it)) => (CompletionItemKind::Const, it.docs(ctx.db)), 63 ScopeDef::ModuleDef(Const(..)) => CompletionItemKind::Const,
60 ScopeDef::ModuleDef(Static(it)) => (CompletionItemKind::Static, it.docs(ctx.db)), 64 ScopeDef::ModuleDef(Static(..)) => CompletionItemKind::Static,
61 ScopeDef::ModuleDef(Trait(it)) => (CompletionItemKind::Trait, it.docs(ctx.db)), 65 ScopeDef::ModuleDef(Trait(..)) => CompletionItemKind::Trait,
62 ScopeDef::ModuleDef(TypeAlias(it)) => (CompletionItemKind::TypeAlias, it.docs(ctx.db)), 66 ScopeDef::ModuleDef(TypeAlias(..)) => CompletionItemKind::TypeAlias,
63 ScopeDef::ModuleDef(BuiltinType(..)) => { 67 ScopeDef::ModuleDef(BuiltinType(..)) => CompletionItemKind::BuiltinType,
64 completion_kind = CompletionKind::BuiltinType; 68 ScopeDef::GenericParam(..) => CompletionItemKind::TypeParam,
65 (CompletionItemKind::BuiltinType, None) 69 ScopeDef::LocalBinding(..) => CompletionItemKind::Binding,
66 } 70 // (does this need its own kind?)
67 ScopeDef::GenericParam(..) => (CompletionItemKind::TypeParam, None), 71 ScopeDef::AdtSelfType(..) | ScopeDef::ImplSelfType(..) => CompletionItemKind::TypeParam,
68 ScopeDef::LocalBinding(..) => (CompletionItemKind::Binding, None),
69 ScopeDef::AdtSelfType(..) | ScopeDef::ImplSelfType(..) => (
70 CompletionItemKind::TypeParam, // (does this need its own kind?)
71 None,
72 ),
73 ScopeDef::MacroDef(mac) => { 72 ScopeDef::MacroDef(mac) => {
74 self.add_macro(ctx, Some(local_name), *mac); 73 return self.add_macro(ctx, Some(local_name), *mac);
75 return;
76 } 74 }
77 ScopeDef::Unknown => { 75 ScopeDef::Unknown => {
78 self.add(CompletionItem::new( 76 return self.add(CompletionItem::new(
79 CompletionKind::Reference, 77 CompletionKind::Reference,
80 ctx.source_range(), 78 ctx.source_range(),
81 local_name, 79 local_name,
82 )); 80 ));
83 return;
84 } 81 }
85 }; 82 };
86 83
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),
92 _ => None,
93 };
94
87 let mut completion_item = 95 let mut completion_item =
88 CompletionItem::new(completion_kind, ctx.source_range(), local_name); 96 CompletionItem::new(completion_kind, ctx.source_range(), local_name.clone());
89 if let ScopeDef::LocalBinding(pat_id) = resolution { 97 if let ScopeDef::LocalBinding(pat_id) = resolution {
90 let ty = ctx 98 let ty = ctx
91 .analyzer 99 .analyzer
@@ -94,6 +102,25 @@ impl Completions {
94 .map(|t| t.display(ctx.db).to_string()); 102 .map(|t| t.display(ctx.db).to_string());
95 completion_item = completion_item.set_detail(ty); 103 completion_item = completion_item.set_detail(ty);
96 }; 104 };
105
106 // If not an import, add parenthesis automatically.
107 if ctx.is_path_type
108 && !ctx.has_type_args
109 && ctx.db.feature_flags.get("completion.insertion.add-call-parenthesis")
110 {
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()),
114 _ => None,
115 };
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.insert_snippet(format!("{}<$0>", local_name));
120 }
121 }
122 }
123
97 completion_item.kind(kind).set_documentation(docs).add_to(self) 124 completion_item.kind(kind).set_documentation(docs).add_to(self)
98 } 125 }
99 126
@@ -169,32 +196,6 @@ impl Completions {
169 self.add(builder) 196 self.add(builder)
170 } 197 }
171 198
172 fn add_adt_with_name(&mut self, ctx: &CompletionContext, name: String, adt: hir::Adt) {
173 let mut builder =
174 CompletionItem::new(CompletionKind::Reference, ctx.source_range(), name.clone());
175
176 let kind = match adt {
177 hir::Adt::Struct(_) => CompletionItemKind::Struct,
178 // FIXME: add CompletionItemKind::Union
179 hir::Adt::Union(_) => CompletionItemKind::Struct,
180 hir::Adt::Enum(_) => CompletionItemKind::Enum,
181 };
182 let docs = adt.docs(ctx.db);
183
184 // If not an import, add parenthesis automatically.
185 if ctx.is_path_type
186 && !ctx.has_type_args
187 && ctx.db.feature_flags.get("completion.insertion.add-call-parenthesis")
188 {
189 if has_non_default_type_params(adt, ctx.db) {
190 tested_by!(inserts_angle_brackets_for_generics);
191 builder = builder.insert_snippet(format!("{}<$0>", name));
192 }
193 }
194
195 builder.kind(kind).set_documentation(docs).add_to(self)
196 }
197
198 pub(crate) fn add_const(&mut self, ctx: &CompletionContext, constant: hir::Const) { 199 pub(crate) fn add_const(&mut self, ctx: &CompletionContext, constant: hir::Const) {
199 let ast_node = constant.source(ctx.db).ast; 200 let ast_node = constant.source(ctx.db).ast;
200 let name = match ast_node.name() { 201 let name = match ast_node.name() {
@@ -243,8 +244,8 @@ impl Completions {
243 } 244 }
244} 245}
245 246
246fn has_non_default_type_params(adt: hir::Adt, db: &db::RootDatabase) -> bool { 247fn has_non_default_type_params(def: hir::GenericDef, db: &db::RootDatabase) -> bool {
247 let subst = db.generic_defaults(adt.into()); 248 let subst = db.generic_defaults(def);
248 subst.iter().any(|ty| ty == &Ty::Unknown) 249 subst.iter().any(|ty| ty == &Ty::Unknown)
249} 250}
250 251
@@ -449,6 +450,33 @@ mod tests {
449 assert_debug_snapshot!( 450 assert_debug_snapshot!(
450 do_reference_completion( 451 do_reference_completion(
451 r" 452 r"
453 type Vec<T> = (T,);
454 fn foo(xs: Ve<|>)
455 "
456 ),
457 @r###"
458 [
459 CompletionItem {
460 label: "Vec",
461 source_range: [64; 66),
462 delete: [64; 66),
463 insert: "Vec<$0>",
464 kind: TypeAlias,
465 },
466 CompletionItem {
467 label: "foo",
468 source_range: [64; 66),
469 delete: [64; 66),
470 insert: "foo($0)",
471 kind: Function,
472 detail: "fn foo(xs: Ve)",
473 },
474 ]
475 "###
476 );
477 assert_debug_snapshot!(
478 do_reference_completion(
479 r"
452 struct Vec<T = i128> {} 480 struct Vec<T = i128> {}
453 fn foo(xs: Ve<|>) 481 fn foo(xs: Ve<|>)
454 " 482 "