aboutsummaryrefslogtreecommitdiff
path: root/crates/completion
diff options
context:
space:
mode:
authorIgor Aleksanov <[email protected]>2020-10-25 08:32:41 +0000
committerIgor Aleksanov <[email protected]>2020-10-25 08:32:41 +0000
commit9822acac0d9913a64d5ebf5ecda967eecbea5037 (patch)
tree21e3e933712ec911c26407179e2ebcc050749bc0 /crates/completion
parentf731d910cbfe36bbdfa3a3f1415d5c48c4a79238 (diff)
Remove presentation module
Diffstat (limited to 'crates/completion')
-rw-r--r--crates/completion/src/completions.rs1417
-rw-r--r--crates/completion/src/lib.rs1
-rw-r--r--crates/completion/src/presentation.rs1412
3 files changed, 1409 insertions, 1421 deletions
diff --git a/crates/completion/src/completions.rs b/crates/completion/src/completions.rs
index db27bdd9c..4984df059 100644
--- a/crates/completion/src/completions.rs
+++ b/crates/completion/src/completions.rs
@@ -12,7 +12,15 @@ pub(crate) mod macro_in_item_position;
12pub(crate) mod trait_impl; 12pub(crate) mod trait_impl;
13pub(crate) mod mod_; 13pub(crate) mod mod_;
14 14
15use crate::item::{Builder, CompletionItem}; 15use hir::{HasAttrs, HasSource, HirDisplay, ModPath, Mutability, ScopeDef, StructKind, Type};
16use itertools::Itertools;
17use syntax::{ast::NameOwner, display::*};
18use test_utils::mark;
19
20use crate::{
21 item::Builder, CompletionContext, CompletionItem, CompletionItemKind, CompletionKind,
22 CompletionScore, RootDatabase,
23};
16 24
17/// Represents an in-progress set of completions being built. 25/// Represents an in-progress set of completions being built.
18#[derive(Debug, Default)] 26#[derive(Debug, Default)]
@@ -20,6 +28,20 @@ pub struct Completions {
20 buf: Vec<CompletionItem>, 28 buf: Vec<CompletionItem>,
21} 29}
22 30
31impl Into<Vec<CompletionItem>> for Completions {
32 fn into(self) -> Vec<CompletionItem> {
33 self.buf
34 }
35}
36
37impl Builder {
38 /// Convenience method, which allows to add a freshly created completion into accumulator
39 /// without binding it to the variable.
40 pub(crate) fn add_to(self, acc: &mut Completions) {
41 acc.add(self.build())
42 }
43}
44
23impl Completions { 45impl Completions {
24 pub fn add(&mut self, item: CompletionItem) { 46 pub fn add(&mut self, item: CompletionItem) {
25 self.buf.push(item.into()) 47 self.buf.push(item.into())
@@ -32,18 +54,1397 @@ impl Completions {
32 { 54 {
33 items.into_iter().for_each(|item| self.add(item.into())) 55 items.into_iter().for_each(|item| self.add(item.into()))
34 } 56 }
57
58 pub(crate) fn add_field(&mut self, ctx: &CompletionContext, field: hir::Field, ty: &Type) {
59 let is_deprecated = is_deprecated(field, ctx.db);
60 let name = field.name(ctx.db);
61 let mut item =
62 CompletionItem::new(CompletionKind::Reference, ctx.source_range(), name.to_string())
63 .kind(CompletionItemKind::Field)
64 .detail(ty.display(ctx.db).to_string())
65 .set_documentation(field.docs(ctx.db))
66 .set_deprecated(is_deprecated);
67
68 if let Some(score) = compute_score(ctx, &ty, &name.to_string()) {
69 item = item.set_score(score);
70 }
71
72 item.add_to(self);
73 }
74
75 pub(crate) fn add_tuple_field(&mut self, ctx: &CompletionContext, field: usize, ty: &Type) {
76 CompletionItem::new(CompletionKind::Reference, ctx.source_range(), field.to_string())
77 .kind(CompletionItemKind::Field)
78 .detail(ty.display(ctx.db).to_string())
79 .add_to(self);
80 }
81
82 pub(crate) fn add_resolution(
83 &mut self,
84 ctx: &CompletionContext,
85 local_name: String,
86 resolution: &ScopeDef,
87 ) {
88 use hir::ModuleDef::*;
89
90 let completion_kind = match resolution {
91 ScopeDef::ModuleDef(BuiltinType(..)) => CompletionKind::BuiltinType,
92 _ => CompletionKind::Reference,
93 };
94
95 let kind = match resolution {
96 ScopeDef::ModuleDef(Module(..)) => CompletionItemKind::Module,
97 ScopeDef::ModuleDef(Function(func)) => {
98 self.add_function(ctx, *func, Some(local_name));
99 return;
100 }
101 ScopeDef::ModuleDef(Adt(hir::Adt::Struct(_))) => CompletionItemKind::Struct,
102 // FIXME: add CompletionItemKind::Union
103 ScopeDef::ModuleDef(Adt(hir::Adt::Union(_))) => CompletionItemKind::Struct,
104 ScopeDef::ModuleDef(Adt(hir::Adt::Enum(_))) => CompletionItemKind::Enum,
105
106 ScopeDef::ModuleDef(EnumVariant(var)) => {
107 self.add_enum_variant(ctx, *var, Some(local_name));
108 return;
109 }
110 ScopeDef::ModuleDef(Const(..)) => CompletionItemKind::Const,
111 ScopeDef::ModuleDef(Static(..)) => CompletionItemKind::Static,
112 ScopeDef::ModuleDef(Trait(..)) => CompletionItemKind::Trait,
113 ScopeDef::ModuleDef(TypeAlias(..)) => CompletionItemKind::TypeAlias,
114 ScopeDef::ModuleDef(BuiltinType(..)) => CompletionItemKind::BuiltinType,
115 ScopeDef::GenericParam(..) => CompletionItemKind::TypeParam,
116 ScopeDef::Local(..) => CompletionItemKind::Binding,
117 // (does this need its own kind?)
118 ScopeDef::AdtSelfType(..) | ScopeDef::ImplSelfType(..) => CompletionItemKind::TypeParam,
119 ScopeDef::MacroDef(mac) => {
120 self.add_macro(ctx, Some(local_name), *mac);
121 return;
122 }
123 ScopeDef::Unknown => {
124 CompletionItem::new(CompletionKind::Reference, ctx.source_range(), local_name)
125 .kind(CompletionItemKind::UnresolvedReference)
126 .add_to(self);
127 return;
128 }
129 };
130
131 let docs = match resolution {
132 ScopeDef::ModuleDef(Module(it)) => it.docs(ctx.db),
133 ScopeDef::ModuleDef(Adt(it)) => it.docs(ctx.db),
134 ScopeDef::ModuleDef(EnumVariant(it)) => it.docs(ctx.db),
135 ScopeDef::ModuleDef(Const(it)) => it.docs(ctx.db),
136 ScopeDef::ModuleDef(Static(it)) => it.docs(ctx.db),
137 ScopeDef::ModuleDef(Trait(it)) => it.docs(ctx.db),
138 ScopeDef::ModuleDef(TypeAlias(it)) => it.docs(ctx.db),
139 _ => None,
140 };
141
142 let mut item = CompletionItem::new(completion_kind, ctx.source_range(), local_name.clone());
143 if let ScopeDef::Local(local) = resolution {
144 let ty = local.ty(ctx.db);
145 if !ty.is_unknown() {
146 item = item.detail(ty.display(ctx.db).to_string());
147 }
148 };
149
150 let mut ref_match = None;
151 if let ScopeDef::Local(local) = resolution {
152 if let Some((active_name, active_type)) = ctx.active_name_and_type() {
153 let ty = local.ty(ctx.db);
154 if let Some(score) =
155 compute_score_from_active(&active_type, &active_name, &ty, &local_name)
156 {
157 item = item.set_score(score);
158 }
159 ref_match = refed_type_matches(&active_type, &active_name, &ty, &local_name);
160 }
161 }
162
163 // Add `<>` for generic types
164 if ctx.is_path_type && !ctx.has_type_args && ctx.config.add_call_parenthesis {
165 if let Some(cap) = ctx.config.snippet_cap {
166 let has_non_default_type_params = match resolution {
167 ScopeDef::ModuleDef(Adt(it)) => it.has_non_default_type_params(ctx.db),
168 ScopeDef::ModuleDef(TypeAlias(it)) => it.has_non_default_type_params(ctx.db),
169 _ => false,
170 };
171 if has_non_default_type_params {
172 mark::hit!(inserts_angle_brackets_for_generics);
173 item = item
174 .lookup_by(local_name.clone())
175 .label(format!("{}<…>", local_name))
176 .insert_snippet(cap, format!("{}<$0>", local_name));
177 }
178 }
179 }
180
181 item.kind(kind).set_documentation(docs).set_ref_match(ref_match).add_to(self)
182 }
183
184 pub(crate) fn add_macro(
185 &mut self,
186 ctx: &CompletionContext,
187 name: Option<String>,
188 macro_: hir::MacroDef,
189 ) {
190 // FIXME: Currently proc-macro do not have ast-node,
191 // such that it does not have source
192 if macro_.is_proc_macro() {
193 return;
194 }
195
196 let name = match name {
197 Some(it) => it,
198 None => return,
199 };
200
201 let ast_node = macro_.source(ctx.db).value;
202 let detail = macro_label(&ast_node);
203
204 let docs = macro_.docs(ctx.db);
205
206 let mut builder = CompletionItem::new(
207 CompletionKind::Reference,
208 ctx.source_range(),
209 &format!("{}!", name),
210 )
211 .kind(CompletionItemKind::Macro)
212 .set_documentation(docs.clone())
213 .set_deprecated(is_deprecated(macro_, ctx.db))
214 .detail(detail);
215
216 let needs_bang = ctx.use_item_syntax.is_none() && !ctx.is_macro_call;
217 builder = match ctx.config.snippet_cap {
218 Some(cap) if needs_bang => {
219 let docs = docs.as_ref().map_or("", |s| s.as_str());
220 let (bra, ket) = guess_macro_braces(&name, docs);
221 builder
222 .insert_snippet(cap, format!("{}!{}$0{}", name, bra, ket))
223 .label(format!("{}!{}…{}", name, bra, ket))
224 .lookup_by(format!("{}!", name))
225 }
226 None if needs_bang => builder.insert_text(format!("{}!", name)),
227 _ => {
228 mark::hit!(dont_insert_macro_call_parens_unncessary);
229 builder.insert_text(name)
230 }
231 };
232
233 self.add(builder.build());
234 }
235
236 pub(crate) fn add_function(
237 &mut self,
238 ctx: &CompletionContext,
239 func: hir::Function,
240 local_name: Option<String>,
241 ) {
242 fn add_arg(arg: &str, ty: &Type, ctx: &CompletionContext) -> String {
243 if let Some(derefed_ty) = ty.remove_ref() {
244 for (name, local) in ctx.locals.iter() {
245 if name == arg && local.ty(ctx.db) == derefed_ty {
246 return (if ty.is_mutable_reference() { "&mut " } else { "&" }).to_string()
247 + &arg.to_string();
248 }
249 }
250 }
251 arg.to_string()
252 };
253 let name = local_name.unwrap_or_else(|| func.name(ctx.db).to_string());
254 let ast_node = func.source(ctx.db).value;
255
256 let mut builder =
257 CompletionItem::new(CompletionKind::Reference, ctx.source_range(), name.clone())
258 .kind(if func.self_param(ctx.db).is_some() {
259 CompletionItemKind::Method
260 } else {
261 CompletionItemKind::Function
262 })
263 .set_documentation(func.docs(ctx.db))
264 .set_deprecated(is_deprecated(func, ctx.db))
265 .detail(function_declaration(&ast_node));
266
267 let params_ty = func.params(ctx.db);
268 let params = ast_node
269 .param_list()
270 .into_iter()
271 .flat_map(|it| it.params())
272 .zip(params_ty)
273 .flat_map(|(it, param_ty)| {
274 if let Some(pat) = it.pat() {
275 let name = pat.to_string();
276 let arg = name.trim_start_matches("mut ").trim_start_matches('_');
277 return Some(add_arg(arg, param_ty.ty(), ctx));
278 }
279 None
280 })
281 .collect();
282
283 builder = builder.add_call_parens(ctx, name, Params::Named(params));
284
285 self.add(builder.build())
286 }
287
288 pub(crate) fn add_const(&mut self, ctx: &CompletionContext, constant: hir::Const) {
289 let ast_node = constant.source(ctx.db).value;
290 let name = match ast_node.name() {
291 Some(name) => name,
292 _ => return,
293 };
294 let detail = const_label(&ast_node);
295
296 CompletionItem::new(CompletionKind::Reference, ctx.source_range(), name.text().to_string())
297 .kind(CompletionItemKind::Const)
298 .set_documentation(constant.docs(ctx.db))
299 .set_deprecated(is_deprecated(constant, ctx.db))
300 .detail(detail)
301 .add_to(self);
302 }
303
304 pub(crate) fn add_type_alias(&mut self, ctx: &CompletionContext, type_alias: hir::TypeAlias) {
305 let type_def = type_alias.source(ctx.db).value;
306 let name = match type_def.name() {
307 Some(name) => name,
308 _ => return,
309 };
310 let detail = type_label(&type_def);
311
312 CompletionItem::new(CompletionKind::Reference, ctx.source_range(), name.text().to_string())
313 .kind(CompletionItemKind::TypeAlias)
314 .set_documentation(type_alias.docs(ctx.db))
315 .set_deprecated(is_deprecated(type_alias, ctx.db))
316 .detail(detail)
317 .add_to(self);
318 }
319
320 pub(crate) fn add_qualified_enum_variant(
321 &mut self,
322 ctx: &CompletionContext,
323 variant: hir::EnumVariant,
324 path: ModPath,
325 ) {
326 self.add_enum_variant_impl(ctx, variant, None, Some(path))
327 }
328
329 pub(crate) fn add_enum_variant(
330 &mut self,
331 ctx: &CompletionContext,
332 variant: hir::EnumVariant,
333 local_name: Option<String>,
334 ) {
335 self.add_enum_variant_impl(ctx, variant, local_name, None)
336 }
337
338 fn add_enum_variant_impl(
339 &mut self,
340 ctx: &CompletionContext,
341 variant: hir::EnumVariant,
342 local_name: Option<String>,
343 path: Option<ModPath>,
344 ) {
345 let is_deprecated = is_deprecated(variant, ctx.db);
346 let name = local_name.unwrap_or_else(|| variant.name(ctx.db).to_string());
347 let (qualified_name, short_qualified_name) = match &path {
348 Some(path) => {
349 let full = path.to_string();
350 let short =
351 path.segments[path.segments.len().saturating_sub(2)..].iter().join("::");
352 (full, short)
353 }
354 None => (name.to_string(), name.to_string()),
355 };
356 let detail_types = variant
357 .fields(ctx.db)
358 .into_iter()
359 .map(|field| (field.name(ctx.db), field.signature_ty(ctx.db)));
360 let variant_kind = variant.kind(ctx.db);
361 let detail = match variant_kind {
362 StructKind::Tuple | StructKind::Unit => format!(
363 "({})",
364 detail_types.map(|(_, t)| t.display(ctx.db).to_string()).format(", ")
365 ),
366 StructKind::Record => format!(
367 "{{ {} }}",
368 detail_types
369 .map(|(n, t)| format!("{}: {}", n, t.display(ctx.db).to_string()))
370 .format(", ")
371 ),
372 };
373 let mut res = CompletionItem::new(
374 CompletionKind::Reference,
375 ctx.source_range(),
376 qualified_name.clone(),
377 )
378 .kind(CompletionItemKind::EnumVariant)
379 .set_documentation(variant.docs(ctx.db))
380 .set_deprecated(is_deprecated)
381 .detail(detail);
382
383 if variant_kind == StructKind::Tuple {
384 mark::hit!(inserts_parens_for_tuple_enums);
385 let params = Params::Anonymous(variant.fields(ctx.db).len());
386 res = res.add_call_parens(ctx, short_qualified_name, params)
387 } else if path.is_some() {
388 res = res.lookup_by(short_qualified_name);
389 }
390
391 res.add_to(self);
392 }
35} 393}
36 394
37impl Into<Vec<CompletionItem>> for Completions { 395fn compute_score_from_active(
38 fn into(self) -> Vec<CompletionItem> { 396 active_type: &Type,
39 self.buf 397 active_name: &str,
398 ty: &Type,
399 name: &str,
400) -> Option<CompletionScore> {
401 // Compute score
402 // For the same type
403 if active_type != ty {
404 return None;
405 }
406
407 let mut res = CompletionScore::TypeMatch;
408
409 // If same type + same name then go top position
410 if active_name == name {
411 res = CompletionScore::TypeAndNameMatch
412 }
413
414 Some(res)
415}
416fn refed_type_matches(
417 active_type: &Type,
418 active_name: &str,
419 ty: &Type,
420 name: &str,
421) -> Option<(Mutability, CompletionScore)> {
422 let derefed_active = active_type.remove_ref()?;
423 let score = compute_score_from_active(&derefed_active, &active_name, &ty, &name)?;
424 Some((
425 if active_type.is_mutable_reference() { Mutability::Mut } else { Mutability::Shared },
426 score,
427 ))
428}
429
430fn compute_score(ctx: &CompletionContext, ty: &Type, name: &str) -> Option<CompletionScore> {
431 let (active_name, active_type) = ctx.active_name_and_type()?;
432 compute_score_from_active(&active_type, &active_name, ty, name)
433}
434
435enum Params {
436 Named(Vec<String>),
437 Anonymous(usize),
438}
439
440impl Params {
441 fn len(&self) -> usize {
442 match self {
443 Params::Named(xs) => xs.len(),
444 Params::Anonymous(len) => *len,
445 }
446 }
447
448 fn is_empty(&self) -> bool {
449 self.len() == 0
40 } 450 }
41} 451}
42 452
43impl Builder { 453impl Builder {
44 /// Convenience method, which allows to add a freshly created completion into accumulator 454 fn add_call_parens(mut self, ctx: &CompletionContext, name: String, params: Params) -> Builder {
45 /// without binding it to the variable. 455 if !ctx.config.add_call_parenthesis {
46 pub(crate) fn add_to(self, acc: &mut Completions) { 456 return self;
47 acc.add(self.build()) 457 }
458 if ctx.use_item_syntax.is_some() {
459 mark::hit!(no_parens_in_use_item);
460 return self;
461 }
462 if ctx.is_pattern_call {
463 mark::hit!(dont_duplicate_pattern_parens);
464 return self;
465 }
466 if ctx.is_call {
467 return self;
468 }
469
470 // Don't add parentheses if the expected type is some function reference.
471 if let Some(ty) = &ctx.expected_type {
472 if ty.is_fn() {
473 mark::hit!(no_call_parens_if_fn_ptr_needed);
474 return self;
475 }
476 }
477
478 let cap = match ctx.config.snippet_cap {
479 Some(it) => it,
480 None => return self,
481 };
482 // If not an import, add parenthesis automatically.
483 mark::hit!(inserts_parens_for_function_calls);
484
485 let (snippet, label) = if params.is_empty() {
486 (format!("{}()$0", name), format!("{}()", name))
487 } else {
488 self = self.trigger_call_info();
489 let snippet = match (ctx.config.add_call_argument_snippets, params) {
490 (true, Params::Named(params)) => {
491 let function_params_snippet =
492 params.iter().enumerate().format_with(", ", |(index, param_name), f| {
493 f(&format_args!("${{{}:{}}}", index + 1, param_name))
494 });
495 format!("{}({})$0", name, function_params_snippet)
496 }
497 _ => {
498 mark::hit!(suppress_arg_snippets);
499 format!("{}($0)", name)
500 }
501 };
502
503 (snippet, format!("{}(…)", name))
504 };
505 self.lookup_by(name).label(label).insert_snippet(cap, snippet)
506 }
507}
508
509fn is_deprecated(node: impl HasAttrs, db: &RootDatabase) -> bool {
510 node.attrs(db).by_key("deprecated").exists()
511}
512
513fn guess_macro_braces(macro_name: &str, docs: &str) -> (&'static str, &'static str) {
514 let mut votes = [0, 0, 0];
515 for (idx, s) in docs.match_indices(&macro_name) {
516 let (before, after) = (&docs[..idx], &docs[idx + s.len()..]);
517 // Ensure to match the full word
518 if after.starts_with('!')
519 && !before.ends_with(|c: char| c == '_' || c.is_ascii_alphanumeric())
520 {
521 // It may have spaces before the braces like `foo! {}`
522 match after[1..].chars().find(|&c| !c.is_whitespace()) {
523 Some('{') => votes[0] += 1,
524 Some('[') => votes[1] += 1,
525 Some('(') => votes[2] += 1,
526 _ => {}
527 }
528 }
529 }
530
531 // Insert a space before `{}`.
532 // We prefer the last one when some votes equal.
533 let (_vote, (bra, ket)) = votes
534 .iter()
535 .zip(&[(" {", "}"), ("[", "]"), ("(", ")")])
536 .max_by_key(|&(&vote, _)| vote)
537 .unwrap();
538 (*bra, *ket)
539}
540
541#[cfg(test)]
542mod tests {
543 use std::cmp::Reverse;
544
545 use expect_test::{expect, Expect};
546 use test_utils::mark;
547
548 use crate::{
549 test_utils::{check_edit, check_edit_with_config, do_completion, get_all_items},
550 CompletionConfig, CompletionKind, CompletionScore,
551 };
552
553 fn check(ra_fixture: &str, expect: Expect) {
554 let actual = do_completion(ra_fixture, CompletionKind::Reference);
555 expect.assert_debug_eq(&actual);
556 }
557
558 fn check_scores(ra_fixture: &str, expect: Expect) {
559 fn display_score(score: Option<CompletionScore>) -> &'static str {
560 match score {
561 Some(CompletionScore::TypeMatch) => "[type]",
562 Some(CompletionScore::TypeAndNameMatch) => "[type+name]",
563 None => "[]".into(),
564 }
565 }
566
567 let mut completions = get_all_items(CompletionConfig::default(), ra_fixture);
568 completions.sort_by_key(|it| (Reverse(it.score()), it.label().to_string()));
569 let actual = completions
570 .into_iter()
571 .filter(|it| it.completion_kind == CompletionKind::Reference)
572 .map(|it| {
573 let tag = it.kind().unwrap().tag();
574 let score = display_score(it.score());
575 format!("{} {} {}\n", tag, it.label(), score)
576 })
577 .collect::<String>();
578 expect.assert_eq(&actual);
579 }
580
581 #[test]
582 fn enum_detail_includes_record_fields() {
583 check(
584 r#"
585enum Foo { Foo { x: i32, y: i32 } }
586
587fn main() { Foo::Fo<|> }
588"#,
589 expect![[r#"
590 [
591 CompletionItem {
592 label: "Foo",
593 source_range: 54..56,
594 delete: 54..56,
595 insert: "Foo",
596 kind: EnumVariant,
597 detail: "{ x: i32, y: i32 }",
598 },
599 ]
600 "#]],
601 );
602 }
603
604 #[test]
605 fn enum_detail_doesnt_include_tuple_fields() {
606 check(
607 r#"
608enum Foo { Foo (i32, i32) }
609
610fn main() { Foo::Fo<|> }
611"#,
612 expect![[r#"
613 [
614 CompletionItem {
615 label: "Foo(…)",
616 source_range: 46..48,
617 delete: 46..48,
618 insert: "Foo($0)",
619 kind: EnumVariant,
620 lookup: "Foo",
621 detail: "(i32, i32)",
622 trigger_call_info: true,
623 },
624 ]
625 "#]],
626 );
627 }
628
629 #[test]
630 fn enum_detail_just_parentheses_for_unit() {
631 check(
632 r#"
633enum Foo { Foo }
634
635fn main() { Foo::Fo<|> }
636"#,
637 expect![[r#"
638 [
639 CompletionItem {
640 label: "Foo",
641 source_range: 35..37,
642 delete: 35..37,
643 insert: "Foo",
644 kind: EnumVariant,
645 detail: "()",
646 },
647 ]
648 "#]],
649 );
650 }
651
652 #[test]
653 fn lookup_enums_by_two_qualifiers() {
654 check(
655 r#"
656mod m {
657 pub enum Spam { Foo, Bar(i32) }
658}
659fn main() { let _: m::Spam = S<|> }
660"#,
661 expect![[r#"
662 [
663 CompletionItem {
664 label: "Spam::Bar(…)",
665 source_range: 75..76,
666 delete: 75..76,
667 insert: "Spam::Bar($0)",
668 kind: EnumVariant,
669 lookup: "Spam::Bar",
670 detail: "(i32)",
671 trigger_call_info: true,
672 },
673 CompletionItem {
674 label: "m",
675 source_range: 75..76,
676 delete: 75..76,
677 insert: "m",
678 kind: Module,
679 },
680 CompletionItem {
681 label: "m::Spam::Foo",
682 source_range: 75..76,
683 delete: 75..76,
684 insert: "m::Spam::Foo",
685 kind: EnumVariant,
686 lookup: "Spam::Foo",
687 detail: "()",
688 },
689 CompletionItem {
690 label: "main()",
691 source_range: 75..76,
692 delete: 75..76,
693 insert: "main()$0",
694 kind: Function,
695 lookup: "main",
696 detail: "fn main()",
697 },
698 ]
699 "#]],
700 )
701 }
702
703 #[test]
704 fn sets_deprecated_flag_in_items() {
705 check(
706 r#"
707#[deprecated]
708fn something_deprecated() {}
709#[deprecated(since = "1.0.0")]
710fn something_else_deprecated() {}
711
712fn main() { som<|> }
713"#,
714 expect![[r#"
715 [
716 CompletionItem {
717 label: "main()",
718 source_range: 121..124,
719 delete: 121..124,
720 insert: "main()$0",
721 kind: Function,
722 lookup: "main",
723 detail: "fn main()",
724 },
725 CompletionItem {
726 label: "something_deprecated()",
727 source_range: 121..124,
728 delete: 121..124,
729 insert: "something_deprecated()$0",
730 kind: Function,
731 lookup: "something_deprecated",
732 detail: "fn something_deprecated()",
733 deprecated: true,
734 },
735 CompletionItem {
736 label: "something_else_deprecated()",
737 source_range: 121..124,
738 delete: 121..124,
739 insert: "something_else_deprecated()$0",
740 kind: Function,
741 lookup: "something_else_deprecated",
742 detail: "fn something_else_deprecated()",
743 deprecated: true,
744 },
745 ]
746 "#]],
747 );
748
749 check(
750 r#"
751struct A { #[deprecated] the_field: u32 }
752fn foo() { A { the<|> } }
753"#,
754 expect![[r#"
755 [
756 CompletionItem {
757 label: "the_field",
758 source_range: 57..60,
759 delete: 57..60,
760 insert: "the_field",
761 kind: Field,
762 detail: "u32",
763 deprecated: true,
764 },
765 ]
766 "#]],
767 );
768 }
769
770 #[test]
771 fn renders_docs() {
772 check(
773 r#"
774struct S {
775 /// Field docs
776 foo:
777}
778impl S {
779 /// Method docs
780 fn bar(self) { self.<|> }
781}"#,
782 expect![[r#"
783 [
784 CompletionItem {
785 label: "bar()",
786 source_range: 94..94,
787 delete: 94..94,
788 insert: "bar()$0",
789 kind: Method,
790 lookup: "bar",
791 detail: "fn bar(self)",
792 documentation: Documentation(
793 "Method docs",
794 ),
795 },
796 CompletionItem {
797 label: "foo",
798 source_range: 94..94,
799 delete: 94..94,
800 insert: "foo",
801 kind: Field,
802 detail: "{unknown}",
803 documentation: Documentation(
804 "Field docs",
805 ),
806 },
807 ]
808 "#]],
809 );
810
811 check(
812 r#"
813use self::my<|>;
814
815/// mod docs
816mod my { }
817
818/// enum docs
819enum E {
820 /// variant docs
821 V
822}
823use self::E::*;
824"#,
825 expect![[r#"
826 [
827 CompletionItem {
828 label: "E",
829 source_range: 10..12,
830 delete: 10..12,
831 insert: "E",
832 kind: Enum,
833 documentation: Documentation(
834 "enum docs",
835 ),
836 },
837 CompletionItem {
838 label: "V",
839 source_range: 10..12,
840 delete: 10..12,
841 insert: "V",
842 kind: EnumVariant,
843 detail: "()",
844 documentation: Documentation(
845 "variant docs",
846 ),
847 },
848 CompletionItem {
849 label: "my",
850 source_range: 10..12,
851 delete: 10..12,
852 insert: "my",
853 kind: Module,
854 documentation: Documentation(
855 "mod docs",
856 ),
857 },
858 ]
859 "#]],
860 )
861 }
862
863 #[test]
864 fn dont_render_attrs() {
865 check(
866 r#"
867struct S;
868impl S {
869 #[inline]
870 fn the_method(&self) { }
871}
872fn foo(s: S) { s.<|> }
873"#,
874 expect![[r#"
875 [
876 CompletionItem {
877 label: "the_method()",
878 source_range: 81..81,
879 delete: 81..81,
880 insert: "the_method()$0",
881 kind: Method,
882 lookup: "the_method",
883 detail: "fn the_method(&self)",
884 },
885 ]
886 "#]],
887 )
888 }
889
890 #[test]
891 fn inserts_parens_for_function_calls() {
892 mark::check!(inserts_parens_for_function_calls);
893 check_edit(
894 "no_args",
895 r#"
896fn no_args() {}
897fn main() { no_<|> }
898"#,
899 r#"
900fn no_args() {}
901fn main() { no_args()$0 }
902"#,
903 );
904
905 check_edit(
906 "with_args",
907 r#"
908fn with_args(x: i32, y: String) {}
909fn main() { with_<|> }
910"#,
911 r#"
912fn with_args(x: i32, y: String) {}
913fn main() { with_args(${1:x}, ${2:y})$0 }
914"#,
915 );
916
917 check_edit(
918 "foo",
919 r#"
920struct S;
921impl S {
922 fn foo(&self) {}
923}
924fn bar(s: &S) { s.f<|> }
925"#,
926 r#"
927struct S;
928impl S {
929 fn foo(&self) {}
930}
931fn bar(s: &S) { s.foo()$0 }
932"#,
933 );
934
935 check_edit(
936 "foo",
937 r#"
938struct S {}
939impl S {
940 fn foo(&self, x: i32) {}
941}
942fn bar(s: &S) {
943 s.f<|>
944}
945"#,
946 r#"
947struct S {}
948impl S {
949 fn foo(&self, x: i32) {}
950}
951fn bar(s: &S) {
952 s.foo(${1:x})$0
953}
954"#,
955 );
956 }
957
958 #[test]
959 fn suppress_arg_snippets() {
960 mark::check!(suppress_arg_snippets);
961 check_edit_with_config(
962 CompletionConfig { add_call_argument_snippets: false, ..CompletionConfig::default() },
963 "with_args",
964 r#"
965fn with_args(x: i32, y: String) {}
966fn main() { with_<|> }
967"#,
968 r#"
969fn with_args(x: i32, y: String) {}
970fn main() { with_args($0) }
971"#,
972 );
973 }
974
975 #[test]
976 fn strips_underscores_from_args() {
977 check_edit(
978 "foo",
979 r#"
980fn foo(_foo: i32, ___bar: bool, ho_ge_: String) {}
981fn main() { f<|> }
982"#,
983 r#"
984fn foo(_foo: i32, ___bar: bool, ho_ge_: String) {}
985fn main() { foo(${1:foo}, ${2:bar}, ${3:ho_ge_})$0 }
986"#,
987 );
988 }
989
990 #[test]
991 fn insert_ref_when_matching_local_in_scope() {
992 check_edit(
993 "ref_arg",
994 r#"
995struct Foo {}
996fn ref_arg(x: &Foo) {}
997fn main() {
998 let x = Foo {};
999 ref_ar<|>
1000}
1001"#,
1002 r#"
1003struct Foo {}
1004fn ref_arg(x: &Foo) {}
1005fn main() {
1006 let x = Foo {};
1007 ref_arg(${1:&x})$0
1008}
1009"#,
1010 );
1011 }
1012
1013 #[test]
1014 fn insert_mut_ref_when_matching_local_in_scope() {
1015 check_edit(
1016 "ref_arg",
1017 r#"
1018struct Foo {}
1019fn ref_arg(x: &mut Foo) {}
1020fn main() {
1021 let x = Foo {};
1022 ref_ar<|>
1023}
1024"#,
1025 r#"
1026struct Foo {}
1027fn ref_arg(x: &mut Foo) {}
1028fn main() {
1029 let x = Foo {};
1030 ref_arg(${1:&mut x})$0
1031}
1032"#,
1033 );
1034 }
1035
1036 #[test]
1037 fn insert_ref_when_matching_local_in_scope_for_method() {
1038 check_edit(
1039 "apply_foo",
1040 r#"
1041struct Foo {}
1042struct Bar {}
1043impl Bar {
1044 fn apply_foo(&self, x: &Foo) {}
1045}
1046
1047fn main() {
1048 let x = Foo {};
1049 let y = Bar {};
1050 y.<|>
1051}
1052"#,
1053 r#"
1054struct Foo {}
1055struct Bar {}
1056impl Bar {
1057 fn apply_foo(&self, x: &Foo) {}
1058}
1059
1060fn main() {
1061 let x = Foo {};
1062 let y = Bar {};
1063 y.apply_foo(${1:&x})$0
1064}
1065"#,
1066 );
1067 }
1068
1069 #[test]
1070 fn trim_mut_keyword_in_func_completion() {
1071 check_edit(
1072 "take_mutably",
1073 r#"
1074fn take_mutably(mut x: &i32) {}
1075
1076fn main() {
1077 take_m<|>
1078}
1079"#,
1080 r#"
1081fn take_mutably(mut x: &i32) {}
1082
1083fn main() {
1084 take_mutably(${1:x})$0
1085}
1086"#,
1087 );
1088 }
1089
1090 #[test]
1091 fn inserts_parens_for_tuple_enums() {
1092 mark::check!(inserts_parens_for_tuple_enums);
1093 check_edit(
1094 "Some",
1095 r#"
1096enum Option<T> { Some(T), None }
1097use Option::*;
1098fn main() -> Option<i32> {
1099 Som<|>
1100}
1101"#,
1102 r#"
1103enum Option<T> { Some(T), None }
1104use Option::*;
1105fn main() -> Option<i32> {
1106 Some($0)
1107}
1108"#,
1109 );
1110 check_edit(
1111 "Some",
1112 r#"
1113enum Option<T> { Some(T), None }
1114use Option::*;
1115fn main(value: Option<i32>) {
1116 match value {
1117 Som<|>
1118 }
1119}
1120"#,
1121 r#"
1122enum Option<T> { Some(T), None }
1123use Option::*;
1124fn main(value: Option<i32>) {
1125 match value {
1126 Some($0)
1127 }
1128}
1129"#,
1130 );
1131 }
1132
1133 #[test]
1134 fn dont_duplicate_pattern_parens() {
1135 mark::check!(dont_duplicate_pattern_parens);
1136 check_edit(
1137 "Var",
1138 r#"
1139enum E { Var(i32) }
1140fn main() {
1141 match E::Var(92) {
1142 E::<|>(92) => (),
1143 }
1144}
1145"#,
1146 r#"
1147enum E { Var(i32) }
1148fn main() {
1149 match E::Var(92) {
1150 E::Var(92) => (),
1151 }
1152}
1153"#,
1154 );
1155 }
1156
1157 #[test]
1158 fn no_call_parens_if_fn_ptr_needed() {
1159 mark::check!(no_call_parens_if_fn_ptr_needed);
1160 check_edit(
1161 "foo",
1162 r#"
1163fn foo(foo: u8, bar: u8) {}
1164struct ManualVtable { f: fn(u8, u8) }
1165
1166fn main() -> ManualVtable {
1167 ManualVtable { f: f<|> }
1168}
1169"#,
1170 r#"
1171fn foo(foo: u8, bar: u8) {}
1172struct ManualVtable { f: fn(u8, u8) }
1173
1174fn main() -> ManualVtable {
1175 ManualVtable { f: foo }
1176}
1177"#,
1178 );
1179 }
1180
1181 #[test]
1182 fn no_parens_in_use_item() {
1183 mark::check!(no_parens_in_use_item);
1184 check_edit(
1185 "foo",
1186 r#"
1187mod m { pub fn foo() {} }
1188use crate::m::f<|>;
1189"#,
1190 r#"
1191mod m { pub fn foo() {} }
1192use crate::m::foo;
1193"#,
1194 );
1195 }
1196
1197 #[test]
1198 fn no_parens_in_call() {
1199 check_edit(
1200 "foo",
1201 r#"
1202fn foo(x: i32) {}
1203fn main() { f<|>(); }
1204"#,
1205 r#"
1206fn foo(x: i32) {}
1207fn main() { foo(); }
1208"#,
1209 );
1210 check_edit(
1211 "foo",
1212 r#"
1213struct Foo;
1214impl Foo { fn foo(&self){} }
1215fn f(foo: &Foo) { foo.f<|>(); }
1216"#,
1217 r#"
1218struct Foo;
1219impl Foo { fn foo(&self){} }
1220fn f(foo: &Foo) { foo.foo(); }
1221"#,
1222 );
1223 }
1224
1225 #[test]
1226 fn inserts_angle_brackets_for_generics() {
1227 mark::check!(inserts_angle_brackets_for_generics);
1228 check_edit(
1229 "Vec",
1230 r#"
1231struct Vec<T> {}
1232fn foo(xs: Ve<|>)
1233"#,
1234 r#"
1235struct Vec<T> {}
1236fn foo(xs: Vec<$0>)
1237"#,
1238 );
1239 check_edit(
1240 "Vec",
1241 r#"
1242type Vec<T> = (T,);
1243fn foo(xs: Ve<|>)
1244"#,
1245 r#"
1246type Vec<T> = (T,);
1247fn foo(xs: Vec<$0>)
1248"#,
1249 );
1250 check_edit(
1251 "Vec",
1252 r#"
1253struct Vec<T = i128> {}
1254fn foo(xs: Ve<|>)
1255"#,
1256 r#"
1257struct Vec<T = i128> {}
1258fn foo(xs: Vec)
1259"#,
1260 );
1261 check_edit(
1262 "Vec",
1263 r#"
1264struct Vec<T> {}
1265fn foo(xs: Ve<|><i128>)
1266"#,
1267 r#"
1268struct Vec<T> {}
1269fn foo(xs: Vec<i128>)
1270"#,
1271 );
1272 }
1273
1274 #[test]
1275 fn dont_insert_macro_call_parens_unncessary() {
1276 mark::check!(dont_insert_macro_call_parens_unncessary);
1277 check_edit(
1278 "frobnicate!",
1279 r#"
1280//- /main.rs crate:main deps:foo
1281use foo::<|>;
1282//- /foo/lib.rs crate:foo
1283#[macro_export]
1284macro_rules frobnicate { () => () }
1285"#,
1286 r#"
1287use foo::frobnicate;
1288"#,
1289 );
1290
1291 check_edit(
1292 "frobnicate!",
1293 r#"
1294macro_rules frobnicate { () => () }
1295fn main() { frob<|>!(); }
1296"#,
1297 r#"
1298macro_rules frobnicate { () => () }
1299fn main() { frobnicate!(); }
1300"#,
1301 );
1302 }
1303
1304 #[test]
1305 fn active_param_score() {
1306 mark::check!(active_param_type_match);
1307 check_scores(
1308 r#"
1309struct S { foo: i64, bar: u32, baz: u32 }
1310fn test(bar: u32) { }
1311fn foo(s: S) { test(s.<|>) }
1312"#,
1313 expect![[r#"
1314 fd bar [type+name]
1315 fd baz [type]
1316 fd foo []
1317 "#]],
1318 );
1319 }
1320
1321 #[test]
1322 fn record_field_scores() {
1323 mark::check!(record_field_type_match);
1324 check_scores(
1325 r#"
1326struct A { foo: i64, bar: u32, baz: u32 }
1327struct B { x: (), y: f32, bar: u32 }
1328fn foo(a: A) { B { bar: a.<|> }; }
1329"#,
1330 expect![[r#"
1331 fd bar [type+name]
1332 fd baz [type]
1333 fd foo []
1334 "#]],
1335 )
1336 }
1337
1338 #[test]
1339 fn record_field_and_call_scores() {
1340 check_scores(
1341 r#"
1342struct A { foo: i64, bar: u32, baz: u32 }
1343struct B { x: (), y: f32, bar: u32 }
1344fn f(foo: i64) { }
1345fn foo(a: A) { B { bar: f(a.<|>) }; }
1346"#,
1347 expect![[r#"
1348 fd foo [type+name]
1349 fd bar []
1350 fd baz []
1351 "#]],
1352 );
1353 check_scores(
1354 r#"
1355struct A { foo: i64, bar: u32, baz: u32 }
1356struct B { x: (), y: f32, bar: u32 }
1357fn f(foo: i64) { }
1358fn foo(a: A) { f(B { bar: a.<|> }); }
1359"#,
1360 expect![[r#"
1361 fd bar [type+name]
1362 fd baz [type]
1363 fd foo []
1364 "#]],
1365 );
1366 }
1367
1368 #[test]
1369 fn prioritize_exact_ref_match() {
1370 check_scores(
1371 r#"
1372struct WorldSnapshot { _f: () };
1373fn go(world: &WorldSnapshot) { go(w<|>) }
1374"#,
1375 expect![[r#"
1376 bn world [type+name]
1377 st WorldSnapshot []
1378 fn go(…) []
1379 "#]],
1380 );
1381 }
1382
1383 #[test]
1384 fn too_many_arguments() {
1385 check_scores(
1386 r#"
1387struct Foo;
1388fn f(foo: &Foo) { f(foo, w<|>) }
1389"#,
1390 expect![[r#"
1391 st Foo []
1392 fn f(…) []
1393 bn foo []
1394 "#]],
1395 );
1396 }
1397
1398 #[test]
1399 fn guesses_macro_braces() {
1400 check_edit(
1401 "vec!",
1402 r#"
1403/// Creates a [`Vec`] containing the arguments.
1404///
1405/// ```
1406/// let v = vec![1, 2, 3];
1407/// assert_eq!(v[0], 1);
1408/// assert_eq!(v[1], 2);
1409/// assert_eq!(v[2], 3);
1410/// ```
1411macro_rules! vec { () => {} }
1412
1413fn fn main() { v<|> }
1414"#,
1415 r#"
1416/// Creates a [`Vec`] containing the arguments.
1417///
1418/// ```
1419/// let v = vec![1, 2, 3];
1420/// assert_eq!(v[0], 1);
1421/// assert_eq!(v[1], 2);
1422/// assert_eq!(v[2], 3);
1423/// ```
1424macro_rules! vec { () => {} }
1425
1426fn fn main() { vec![$0] }
1427"#,
1428 );
1429
1430 check_edit(
1431 "foo!",
1432 r#"
1433/// Foo
1434///
1435/// Don't call `fooo!()` `fooo!()`, or `_foo![]` `_foo![]`,
1436/// call as `let _=foo! { hello world };`
1437macro_rules! foo { () => {} }
1438fn main() { <|> }
1439"#,
1440 r#"
1441/// Foo
1442///
1443/// Don't call `fooo!()` `fooo!()`, or `_foo![]` `_foo![]`,
1444/// call as `let _=foo! { hello world };`
1445macro_rules! foo { () => {} }
1446fn main() { foo! {$0} }
1447"#,
1448 )
48 } 1449 }
49} 1450}
diff --git a/crates/completion/src/lib.rs b/crates/completion/src/lib.rs
index d8e5cf0da..89c0a9978 100644
--- a/crates/completion/src/lib.rs
+++ b/crates/completion/src/lib.rs
@@ -3,7 +3,6 @@
3mod config; 3mod config;
4mod item; 4mod item;
5mod context; 5mod context;
6mod presentation;
7mod patterns; 6mod patterns;
8mod generated_lint_completions; 7mod generated_lint_completions;
9#[cfg(test)] 8#[cfg(test)]
diff --git a/crates/completion/src/presentation.rs b/crates/completion/src/presentation.rs
deleted file mode 100644
index 17584f734..000000000
--- a/crates/completion/src/presentation.rs
+++ /dev/null
@@ -1,1412 +0,0 @@
1//! This modules takes care of rendering various definitions as completion items.
2//! It also handles scoring (sorting) completions.
3
4use hir::{HasAttrs, HasSource, HirDisplay, ModPath, Mutability, ScopeDef, StructKind, Type};
5use itertools::Itertools;
6use syntax::{ast::NameOwner, display::*};
7use test_utils::mark;
8
9use crate::{
10 // display::{const_label, function_declaration, macro_label, type_label},
11 CompletionScore,
12 RootDatabase,
13 {
14 item::Builder, CompletionContext, CompletionItem, CompletionItemKind, CompletionKind,
15 Completions,
16 },
17};
18
19impl Completions {
20 pub(crate) fn add_field(&mut self, ctx: &CompletionContext, field: hir::Field, ty: &Type) {
21 let is_deprecated = is_deprecated(field, ctx.db);
22 let name = field.name(ctx.db);
23 let mut item =
24 CompletionItem::new(CompletionKind::Reference, ctx.source_range(), name.to_string())
25 .kind(CompletionItemKind::Field)
26 .detail(ty.display(ctx.db).to_string())
27 .set_documentation(field.docs(ctx.db))
28 .set_deprecated(is_deprecated);
29
30 if let Some(score) = compute_score(ctx, &ty, &name.to_string()) {
31 item = item.set_score(score);
32 }
33
34 item.add_to(self);
35 }
36
37 pub(crate) fn add_tuple_field(&mut self, ctx: &CompletionContext, field: usize, ty: &Type) {
38 CompletionItem::new(CompletionKind::Reference, ctx.source_range(), field.to_string())
39 .kind(CompletionItemKind::Field)
40 .detail(ty.display(ctx.db).to_string())
41 .add_to(self);
42 }
43
44 pub(crate) fn add_resolution(
45 &mut self,
46 ctx: &CompletionContext,
47 local_name: String,
48 resolution: &ScopeDef,
49 ) {
50 use hir::ModuleDef::*;
51
52 let completion_kind = match resolution {
53 ScopeDef::ModuleDef(BuiltinType(..)) => CompletionKind::BuiltinType,
54 _ => CompletionKind::Reference,
55 };
56
57 let kind = match resolution {
58 ScopeDef::ModuleDef(Module(..)) => CompletionItemKind::Module,
59 ScopeDef::ModuleDef(Function(func)) => {
60 self.add_function(ctx, *func, Some(local_name));
61 return;
62 }
63 ScopeDef::ModuleDef(Adt(hir::Adt::Struct(_))) => CompletionItemKind::Struct,
64 // FIXME: add CompletionItemKind::Union
65 ScopeDef::ModuleDef(Adt(hir::Adt::Union(_))) => CompletionItemKind::Struct,
66 ScopeDef::ModuleDef(Adt(hir::Adt::Enum(_))) => CompletionItemKind::Enum,
67
68 ScopeDef::ModuleDef(EnumVariant(var)) => {
69 self.add_enum_variant(ctx, *var, Some(local_name));
70 return;
71 }
72 ScopeDef::ModuleDef(Const(..)) => CompletionItemKind::Const,
73 ScopeDef::ModuleDef(Static(..)) => CompletionItemKind::Static,
74 ScopeDef::ModuleDef(Trait(..)) => CompletionItemKind::Trait,
75 ScopeDef::ModuleDef(TypeAlias(..)) => CompletionItemKind::TypeAlias,
76 ScopeDef::ModuleDef(BuiltinType(..)) => CompletionItemKind::BuiltinType,
77 ScopeDef::GenericParam(..) => CompletionItemKind::TypeParam,
78 ScopeDef::Local(..) => CompletionItemKind::Binding,
79 // (does this need its own kind?)
80 ScopeDef::AdtSelfType(..) | ScopeDef::ImplSelfType(..) => CompletionItemKind::TypeParam,
81 ScopeDef::MacroDef(mac) => {
82 self.add_macro(ctx, Some(local_name), *mac);
83 return;
84 }
85 ScopeDef::Unknown => {
86 CompletionItem::new(CompletionKind::Reference, ctx.source_range(), local_name)
87 .kind(CompletionItemKind::UnresolvedReference)
88 .add_to(self);
89 return;
90 }
91 };
92
93 let docs = match resolution {
94 ScopeDef::ModuleDef(Module(it)) => it.docs(ctx.db),
95 ScopeDef::ModuleDef(Adt(it)) => it.docs(ctx.db),
96 ScopeDef::ModuleDef(EnumVariant(it)) => it.docs(ctx.db),
97 ScopeDef::ModuleDef(Const(it)) => it.docs(ctx.db),
98 ScopeDef::ModuleDef(Static(it)) => it.docs(ctx.db),
99 ScopeDef::ModuleDef(Trait(it)) => it.docs(ctx.db),
100 ScopeDef::ModuleDef(TypeAlias(it)) => it.docs(ctx.db),
101 _ => None,
102 };
103
104 let mut item = CompletionItem::new(completion_kind, ctx.source_range(), local_name.clone());
105 if let ScopeDef::Local(local) = resolution {
106 let ty = local.ty(ctx.db);
107 if !ty.is_unknown() {
108 item = item.detail(ty.display(ctx.db).to_string());
109 }
110 };
111
112 let mut ref_match = None;
113 if let ScopeDef::Local(local) = resolution {
114 if let Some((active_name, active_type)) = ctx.active_name_and_type() {
115 let ty = local.ty(ctx.db);
116 if let Some(score) =
117 compute_score_from_active(&active_type, &active_name, &ty, &local_name)
118 {
119 item = item.set_score(score);
120 }
121 ref_match = refed_type_matches(&active_type, &active_name, &ty, &local_name);
122 }
123 }
124
125 // Add `<>` for generic types
126 if ctx.is_path_type && !ctx.has_type_args && ctx.config.add_call_parenthesis {
127 if let Some(cap) = ctx.config.snippet_cap {
128 let has_non_default_type_params = match resolution {
129 ScopeDef::ModuleDef(Adt(it)) => it.has_non_default_type_params(ctx.db),
130 ScopeDef::ModuleDef(TypeAlias(it)) => it.has_non_default_type_params(ctx.db),
131 _ => false,
132 };
133 if has_non_default_type_params {
134 mark::hit!(inserts_angle_brackets_for_generics);
135 item = item
136 .lookup_by(local_name.clone())
137 .label(format!("{}<…>", local_name))
138 .insert_snippet(cap, format!("{}<$0>", local_name));
139 }
140 }
141 }
142
143 item.kind(kind).set_documentation(docs).set_ref_match(ref_match).add_to(self)
144 }
145
146 pub(crate) fn add_macro(
147 &mut self,
148 ctx: &CompletionContext,
149 name: Option<String>,
150 macro_: hir::MacroDef,
151 ) {
152 // FIXME: Currently proc-macro do not have ast-node,
153 // such that it does not have source
154 if macro_.is_proc_macro() {
155 return;
156 }
157
158 let name = match name {
159 Some(it) => it,
160 None => return,
161 };
162
163 let ast_node = macro_.source(ctx.db).value;
164 let detail = macro_label(&ast_node);
165
166 let docs = macro_.docs(ctx.db);
167
168 let mut builder = CompletionItem::new(
169 CompletionKind::Reference,
170 ctx.source_range(),
171 &format!("{}!", name),
172 )
173 .kind(CompletionItemKind::Macro)
174 .set_documentation(docs.clone())
175 .set_deprecated(is_deprecated(macro_, ctx.db))
176 .detail(detail);
177
178 let needs_bang = ctx.use_item_syntax.is_none() && !ctx.is_macro_call;
179 builder = match ctx.config.snippet_cap {
180 Some(cap) if needs_bang => {
181 let docs = docs.as_ref().map_or("", |s| s.as_str());
182 let (bra, ket) = guess_macro_braces(&name, docs);
183 builder
184 .insert_snippet(cap, format!("{}!{}$0{}", name, bra, ket))
185 .label(format!("{}!{}…{}", name, bra, ket))
186 .lookup_by(format!("{}!", name))
187 }
188 None if needs_bang => builder.insert_text(format!("{}!", name)),
189 _ => {
190 mark::hit!(dont_insert_macro_call_parens_unncessary);
191 builder.insert_text(name)
192 }
193 };
194
195 self.add(builder.build());
196 }
197
198 pub(crate) fn add_function(
199 &mut self,
200 ctx: &CompletionContext,
201 func: hir::Function,
202 local_name: Option<String>,
203 ) {
204 fn add_arg(arg: &str, ty: &Type, ctx: &CompletionContext) -> String {
205 if let Some(derefed_ty) = ty.remove_ref() {
206 for (name, local) in ctx.locals.iter() {
207 if name == arg && local.ty(ctx.db) == derefed_ty {
208 return (if ty.is_mutable_reference() { "&mut " } else { "&" }).to_string()
209 + &arg.to_string();
210 }
211 }
212 }
213 arg.to_string()
214 };
215 let name = local_name.unwrap_or_else(|| func.name(ctx.db).to_string());
216 let ast_node = func.source(ctx.db).value;
217
218 let mut builder =
219 CompletionItem::new(CompletionKind::Reference, ctx.source_range(), name.clone())
220 .kind(if func.self_param(ctx.db).is_some() {
221 CompletionItemKind::Method
222 } else {
223 CompletionItemKind::Function
224 })
225 .set_documentation(func.docs(ctx.db))
226 .set_deprecated(is_deprecated(func, ctx.db))
227 .detail(function_declaration(&ast_node));
228
229 let params_ty = func.params(ctx.db);
230 let params = ast_node
231 .param_list()
232 .into_iter()
233 .flat_map(|it| it.params())
234 .zip(params_ty)
235 .flat_map(|(it, param_ty)| {
236 if let Some(pat) = it.pat() {
237 let name = pat.to_string();
238 let arg = name.trim_start_matches("mut ").trim_start_matches('_');
239 return Some(add_arg(arg, param_ty.ty(), ctx));
240 }
241 None
242 })
243 .collect();
244
245 builder = builder.add_call_parens(ctx, name, Params::Named(params));
246
247 self.add(builder.build())
248 }
249
250 pub(crate) fn add_const(&mut self, ctx: &CompletionContext, constant: hir::Const) {
251 let ast_node = constant.source(ctx.db).value;
252 let name = match ast_node.name() {
253 Some(name) => name,
254 _ => return,
255 };
256 let detail = const_label(&ast_node);
257
258 CompletionItem::new(CompletionKind::Reference, ctx.source_range(), name.text().to_string())
259 .kind(CompletionItemKind::Const)
260 .set_documentation(constant.docs(ctx.db))
261 .set_deprecated(is_deprecated(constant, ctx.db))
262 .detail(detail)
263 .add_to(self);
264 }
265
266 pub(crate) fn add_type_alias(&mut self, ctx: &CompletionContext, type_alias: hir::TypeAlias) {
267 let type_def = type_alias.source(ctx.db).value;
268 let name = match type_def.name() {
269 Some(name) => name,
270 _ => return,
271 };
272 let detail = type_label(&type_def);
273
274 CompletionItem::new(CompletionKind::Reference, ctx.source_range(), name.text().to_string())
275 .kind(CompletionItemKind::TypeAlias)
276 .set_documentation(type_alias.docs(ctx.db))
277 .set_deprecated(is_deprecated(type_alias, ctx.db))
278 .detail(detail)
279 .add_to(self);
280 }
281
282 pub(crate) fn add_qualified_enum_variant(
283 &mut self,
284 ctx: &CompletionContext,
285 variant: hir::EnumVariant,
286 path: ModPath,
287 ) {
288 self.add_enum_variant_impl(ctx, variant, None, Some(path))
289 }
290
291 pub(crate) fn add_enum_variant(
292 &mut self,
293 ctx: &CompletionContext,
294 variant: hir::EnumVariant,
295 local_name: Option<String>,
296 ) {
297 self.add_enum_variant_impl(ctx, variant, local_name, None)
298 }
299
300 fn add_enum_variant_impl(
301 &mut self,
302 ctx: &CompletionContext,
303 variant: hir::EnumVariant,
304 local_name: Option<String>,
305 path: Option<ModPath>,
306 ) {
307 let is_deprecated = is_deprecated(variant, ctx.db);
308 let name = local_name.unwrap_or_else(|| variant.name(ctx.db).to_string());
309 let (qualified_name, short_qualified_name) = match &path {
310 Some(path) => {
311 let full = path.to_string();
312 let short =
313 path.segments[path.segments.len().saturating_sub(2)..].iter().join("::");
314 (full, short)
315 }
316 None => (name.to_string(), name.to_string()),
317 };
318 let detail_types = variant
319 .fields(ctx.db)
320 .into_iter()
321 .map(|field| (field.name(ctx.db), field.signature_ty(ctx.db)));
322 let variant_kind = variant.kind(ctx.db);
323 let detail = match variant_kind {
324 StructKind::Tuple | StructKind::Unit => format!(
325 "({})",
326 detail_types.map(|(_, t)| t.display(ctx.db).to_string()).format(", ")
327 ),
328 StructKind::Record => format!(
329 "{{ {} }}",
330 detail_types
331 .map(|(n, t)| format!("{}: {}", n, t.display(ctx.db).to_string()))
332 .format(", ")
333 ),
334 };
335 let mut res = CompletionItem::new(
336 CompletionKind::Reference,
337 ctx.source_range(),
338 qualified_name.clone(),
339 )
340 .kind(CompletionItemKind::EnumVariant)
341 .set_documentation(variant.docs(ctx.db))
342 .set_deprecated(is_deprecated)
343 .detail(detail);
344
345 if variant_kind == StructKind::Tuple {
346 mark::hit!(inserts_parens_for_tuple_enums);
347 let params = Params::Anonymous(variant.fields(ctx.db).len());
348 res = res.add_call_parens(ctx, short_qualified_name, params)
349 } else if path.is_some() {
350 res = res.lookup_by(short_qualified_name);
351 }
352
353 res.add_to(self);
354 }
355}
356
357fn compute_score_from_active(
358 active_type: &Type,
359 active_name: &str,
360 ty: &Type,
361 name: &str,
362) -> Option<CompletionScore> {
363 // Compute score
364 // For the same type
365 if active_type != ty {
366 return None;
367 }
368
369 let mut res = CompletionScore::TypeMatch;
370
371 // If same type + same name then go top position
372 if active_name == name {
373 res = CompletionScore::TypeAndNameMatch
374 }
375
376 Some(res)
377}
378fn refed_type_matches(
379 active_type: &Type,
380 active_name: &str,
381 ty: &Type,
382 name: &str,
383) -> Option<(Mutability, CompletionScore)> {
384 let derefed_active = active_type.remove_ref()?;
385 let score = compute_score_from_active(&derefed_active, &active_name, &ty, &name)?;
386 Some((
387 if active_type.is_mutable_reference() { Mutability::Mut } else { Mutability::Shared },
388 score,
389 ))
390}
391
392fn compute_score(ctx: &CompletionContext, ty: &Type, name: &str) -> Option<CompletionScore> {
393 let (active_name, active_type) = ctx.active_name_and_type()?;
394 compute_score_from_active(&active_type, &active_name, ty, name)
395}
396
397enum Params {
398 Named(Vec<String>),
399 Anonymous(usize),
400}
401
402impl Params {
403 fn len(&self) -> usize {
404 match self {
405 Params::Named(xs) => xs.len(),
406 Params::Anonymous(len) => *len,
407 }
408 }
409
410 fn is_empty(&self) -> bool {
411 self.len() == 0
412 }
413}
414
415impl Builder {
416 fn add_call_parens(mut self, ctx: &CompletionContext, name: String, params: Params) -> Builder {
417 if !ctx.config.add_call_parenthesis {
418 return self;
419 }
420 if ctx.use_item_syntax.is_some() {
421 mark::hit!(no_parens_in_use_item);
422 return self;
423 }
424 if ctx.is_pattern_call {
425 mark::hit!(dont_duplicate_pattern_parens);
426 return self;
427 }
428 if ctx.is_call {
429 return self;
430 }
431
432 // Don't add parentheses if the expected type is some function reference.
433 if let Some(ty) = &ctx.expected_type {
434 if ty.is_fn() {
435 mark::hit!(no_call_parens_if_fn_ptr_needed);
436 return self;
437 }
438 }
439
440 let cap = match ctx.config.snippet_cap {
441 Some(it) => it,
442 None => return self,
443 };
444 // If not an import, add parenthesis automatically.
445 mark::hit!(inserts_parens_for_function_calls);
446
447 let (snippet, label) = if params.is_empty() {
448 (format!("{}()$0", name), format!("{}()", name))
449 } else {
450 self = self.trigger_call_info();
451 let snippet = match (ctx.config.add_call_argument_snippets, params) {
452 (true, Params::Named(params)) => {
453 let function_params_snippet =
454 params.iter().enumerate().format_with(", ", |(index, param_name), f| {
455 f(&format_args!("${{{}:{}}}", index + 1, param_name))
456 });
457 format!("{}({})$0", name, function_params_snippet)
458 }
459 _ => {
460 mark::hit!(suppress_arg_snippets);
461 format!("{}($0)", name)
462 }
463 };
464
465 (snippet, format!("{}(…)", name))
466 };
467 self.lookup_by(name).label(label).insert_snippet(cap, snippet)
468 }
469}
470
471fn is_deprecated(node: impl HasAttrs, db: &RootDatabase) -> bool {
472 node.attrs(db).by_key("deprecated").exists()
473}
474
475fn guess_macro_braces(macro_name: &str, docs: &str) -> (&'static str, &'static str) {
476 let mut votes = [0, 0, 0];
477 for (idx, s) in docs.match_indices(&macro_name) {
478 let (before, after) = (&docs[..idx], &docs[idx + s.len()..]);
479 // Ensure to match the full word
480 if after.starts_with('!')
481 && !before.ends_with(|c: char| c == '_' || c.is_ascii_alphanumeric())
482 {
483 // It may have spaces before the braces like `foo! {}`
484 match after[1..].chars().find(|&c| !c.is_whitespace()) {
485 Some('{') => votes[0] += 1,
486 Some('[') => votes[1] += 1,
487 Some('(') => votes[2] += 1,
488 _ => {}
489 }
490 }
491 }
492
493 // Insert a space before `{}`.
494 // We prefer the last one when some votes equal.
495 let (_vote, (bra, ket)) = votes
496 .iter()
497 .zip(&[(" {", "}"), ("[", "]"), ("(", ")")])
498 .max_by_key(|&(&vote, _)| vote)
499 .unwrap();
500 (*bra, *ket)
501}
502
503#[cfg(test)]
504mod tests {
505 use std::cmp::Reverse;
506
507 use expect_test::{expect, Expect};
508 use test_utils::mark;
509
510 use crate::{
511 test_utils::{check_edit, check_edit_with_config, do_completion, get_all_items},
512 CompletionConfig, CompletionKind, CompletionScore,
513 };
514
515 fn check(ra_fixture: &str, expect: Expect) {
516 let actual = do_completion(ra_fixture, CompletionKind::Reference);
517 expect.assert_debug_eq(&actual);
518 }
519
520 fn check_scores(ra_fixture: &str, expect: Expect) {
521 fn display_score(score: Option<CompletionScore>) -> &'static str {
522 match score {
523 Some(CompletionScore::TypeMatch) => "[type]",
524 Some(CompletionScore::TypeAndNameMatch) => "[type+name]",
525 None => "[]".into(),
526 }
527 }
528
529 let mut completions = get_all_items(CompletionConfig::default(), ra_fixture);
530 completions.sort_by_key(|it| (Reverse(it.score()), it.label().to_string()));
531 let actual = completions
532 .into_iter()
533 .filter(|it| it.completion_kind == CompletionKind::Reference)
534 .map(|it| {
535 let tag = it.kind().unwrap().tag();
536 let score = display_score(it.score());
537 format!("{} {} {}\n", tag, it.label(), score)
538 })
539 .collect::<String>();
540 expect.assert_eq(&actual);
541 }
542
543 #[test]
544 fn enum_detail_includes_record_fields() {
545 check(
546 r#"
547enum Foo { Foo { x: i32, y: i32 } }
548
549fn main() { Foo::Fo<|> }
550"#,
551 expect![[r#"
552 [
553 CompletionItem {
554 label: "Foo",
555 source_range: 54..56,
556 delete: 54..56,
557 insert: "Foo",
558 kind: EnumVariant,
559 detail: "{ x: i32, y: i32 }",
560 },
561 ]
562 "#]],
563 );
564 }
565
566 #[test]
567 fn enum_detail_doesnt_include_tuple_fields() {
568 check(
569 r#"
570enum Foo { Foo (i32, i32) }
571
572fn main() { Foo::Fo<|> }
573"#,
574 expect![[r#"
575 [
576 CompletionItem {
577 label: "Foo(…)",
578 source_range: 46..48,
579 delete: 46..48,
580 insert: "Foo($0)",
581 kind: EnumVariant,
582 lookup: "Foo",
583 detail: "(i32, i32)",
584 trigger_call_info: true,
585 },
586 ]
587 "#]],
588 );
589 }
590
591 #[test]
592 fn enum_detail_just_parentheses_for_unit() {
593 check(
594 r#"
595enum Foo { Foo }
596
597fn main() { Foo::Fo<|> }
598"#,
599 expect![[r#"
600 [
601 CompletionItem {
602 label: "Foo",
603 source_range: 35..37,
604 delete: 35..37,
605 insert: "Foo",
606 kind: EnumVariant,
607 detail: "()",
608 },
609 ]
610 "#]],
611 );
612 }
613
614 #[test]
615 fn lookup_enums_by_two_qualifiers() {
616 check(
617 r#"
618mod m {
619 pub enum Spam { Foo, Bar(i32) }
620}
621fn main() { let _: m::Spam = S<|> }
622"#,
623 expect![[r#"
624 [
625 CompletionItem {
626 label: "Spam::Bar(…)",
627 source_range: 75..76,
628 delete: 75..76,
629 insert: "Spam::Bar($0)",
630 kind: EnumVariant,
631 lookup: "Spam::Bar",
632 detail: "(i32)",
633 trigger_call_info: true,
634 },
635 CompletionItem {
636 label: "m",
637 source_range: 75..76,
638 delete: 75..76,
639 insert: "m",
640 kind: Module,
641 },
642 CompletionItem {
643 label: "m::Spam::Foo",
644 source_range: 75..76,
645 delete: 75..76,
646 insert: "m::Spam::Foo",
647 kind: EnumVariant,
648 lookup: "Spam::Foo",
649 detail: "()",
650 },
651 CompletionItem {
652 label: "main()",
653 source_range: 75..76,
654 delete: 75..76,
655 insert: "main()$0",
656 kind: Function,
657 lookup: "main",
658 detail: "fn main()",
659 },
660 ]
661 "#]],
662 )
663 }
664
665 #[test]
666 fn sets_deprecated_flag_in_items() {
667 check(
668 r#"
669#[deprecated]
670fn something_deprecated() {}
671#[deprecated(since = "1.0.0")]
672fn something_else_deprecated() {}
673
674fn main() { som<|> }
675"#,
676 expect![[r#"
677 [
678 CompletionItem {
679 label: "main()",
680 source_range: 121..124,
681 delete: 121..124,
682 insert: "main()$0",
683 kind: Function,
684 lookup: "main",
685 detail: "fn main()",
686 },
687 CompletionItem {
688 label: "something_deprecated()",
689 source_range: 121..124,
690 delete: 121..124,
691 insert: "something_deprecated()$0",
692 kind: Function,
693 lookup: "something_deprecated",
694 detail: "fn something_deprecated()",
695 deprecated: true,
696 },
697 CompletionItem {
698 label: "something_else_deprecated()",
699 source_range: 121..124,
700 delete: 121..124,
701 insert: "something_else_deprecated()$0",
702 kind: Function,
703 lookup: "something_else_deprecated",
704 detail: "fn something_else_deprecated()",
705 deprecated: true,
706 },
707 ]
708 "#]],
709 );
710
711 check(
712 r#"
713struct A { #[deprecated] the_field: u32 }
714fn foo() { A { the<|> } }
715"#,
716 expect![[r#"
717 [
718 CompletionItem {
719 label: "the_field",
720 source_range: 57..60,
721 delete: 57..60,
722 insert: "the_field",
723 kind: Field,
724 detail: "u32",
725 deprecated: true,
726 },
727 ]
728 "#]],
729 );
730 }
731
732 #[test]
733 fn renders_docs() {
734 check(
735 r#"
736struct S {
737 /// Field docs
738 foo:
739}
740impl S {
741 /// Method docs
742 fn bar(self) { self.<|> }
743}"#,
744 expect![[r#"
745 [
746 CompletionItem {
747 label: "bar()",
748 source_range: 94..94,
749 delete: 94..94,
750 insert: "bar()$0",
751 kind: Method,
752 lookup: "bar",
753 detail: "fn bar(self)",
754 documentation: Documentation(
755 "Method docs",
756 ),
757 },
758 CompletionItem {
759 label: "foo",
760 source_range: 94..94,
761 delete: 94..94,
762 insert: "foo",
763 kind: Field,
764 detail: "{unknown}",
765 documentation: Documentation(
766 "Field docs",
767 ),
768 },
769 ]
770 "#]],
771 );
772
773 check(
774 r#"
775use self::my<|>;
776
777/// mod docs
778mod my { }
779
780/// enum docs
781enum E {
782 /// variant docs
783 V
784}
785use self::E::*;
786"#,
787 expect![[r#"
788 [
789 CompletionItem {
790 label: "E",
791 source_range: 10..12,
792 delete: 10..12,
793 insert: "E",
794 kind: Enum,
795 documentation: Documentation(
796 "enum docs",
797 ),
798 },
799 CompletionItem {
800 label: "V",
801 source_range: 10..12,
802 delete: 10..12,
803 insert: "V",
804 kind: EnumVariant,
805 detail: "()",
806 documentation: Documentation(
807 "variant docs",
808 ),
809 },
810 CompletionItem {
811 label: "my",
812 source_range: 10..12,
813 delete: 10..12,
814 insert: "my",
815 kind: Module,
816 documentation: Documentation(
817 "mod docs",
818 ),
819 },
820 ]
821 "#]],
822 )
823 }
824
825 #[test]
826 fn dont_render_attrs() {
827 check(
828 r#"
829struct S;
830impl S {
831 #[inline]
832 fn the_method(&self) { }
833}
834fn foo(s: S) { s.<|> }
835"#,
836 expect![[r#"
837 [
838 CompletionItem {
839 label: "the_method()",
840 source_range: 81..81,
841 delete: 81..81,
842 insert: "the_method()$0",
843 kind: Method,
844 lookup: "the_method",
845 detail: "fn the_method(&self)",
846 },
847 ]
848 "#]],
849 )
850 }
851
852 #[test]
853 fn inserts_parens_for_function_calls() {
854 mark::check!(inserts_parens_for_function_calls);
855 check_edit(
856 "no_args",
857 r#"
858fn no_args() {}
859fn main() { no_<|> }
860"#,
861 r#"
862fn no_args() {}
863fn main() { no_args()$0 }
864"#,
865 );
866
867 check_edit(
868 "with_args",
869 r#"
870fn with_args(x: i32, y: String) {}
871fn main() { with_<|> }
872"#,
873 r#"
874fn with_args(x: i32, y: String) {}
875fn main() { with_args(${1:x}, ${2:y})$0 }
876"#,
877 );
878
879 check_edit(
880 "foo",
881 r#"
882struct S;
883impl S {
884 fn foo(&self) {}
885}
886fn bar(s: &S) { s.f<|> }
887"#,
888 r#"
889struct S;
890impl S {
891 fn foo(&self) {}
892}
893fn bar(s: &S) { s.foo()$0 }
894"#,
895 );
896
897 check_edit(
898 "foo",
899 r#"
900struct S {}
901impl S {
902 fn foo(&self, x: i32) {}
903}
904fn bar(s: &S) {
905 s.f<|>
906}
907"#,
908 r#"
909struct S {}
910impl S {
911 fn foo(&self, x: i32) {}
912}
913fn bar(s: &S) {
914 s.foo(${1:x})$0
915}
916"#,
917 );
918 }
919
920 #[test]
921 fn suppress_arg_snippets() {
922 mark::check!(suppress_arg_snippets);
923 check_edit_with_config(
924 CompletionConfig { add_call_argument_snippets: false, ..CompletionConfig::default() },
925 "with_args",
926 r#"
927fn with_args(x: i32, y: String) {}
928fn main() { with_<|> }
929"#,
930 r#"
931fn with_args(x: i32, y: String) {}
932fn main() { with_args($0) }
933"#,
934 );
935 }
936
937 #[test]
938 fn strips_underscores_from_args() {
939 check_edit(
940 "foo",
941 r#"
942fn foo(_foo: i32, ___bar: bool, ho_ge_: String) {}
943fn main() { f<|> }
944"#,
945 r#"
946fn foo(_foo: i32, ___bar: bool, ho_ge_: String) {}
947fn main() { foo(${1:foo}, ${2:bar}, ${3:ho_ge_})$0 }
948"#,
949 );
950 }
951
952 #[test]
953 fn insert_ref_when_matching_local_in_scope() {
954 check_edit(
955 "ref_arg",
956 r#"
957struct Foo {}
958fn ref_arg(x: &Foo) {}
959fn main() {
960 let x = Foo {};
961 ref_ar<|>
962}
963"#,
964 r#"
965struct Foo {}
966fn ref_arg(x: &Foo) {}
967fn main() {
968 let x = Foo {};
969 ref_arg(${1:&x})$0
970}
971"#,
972 );
973 }
974
975 #[test]
976 fn insert_mut_ref_when_matching_local_in_scope() {
977 check_edit(
978 "ref_arg",
979 r#"
980struct Foo {}
981fn ref_arg(x: &mut Foo) {}
982fn main() {
983 let x = Foo {};
984 ref_ar<|>
985}
986"#,
987 r#"
988struct Foo {}
989fn ref_arg(x: &mut Foo) {}
990fn main() {
991 let x = Foo {};
992 ref_arg(${1:&mut x})$0
993}
994"#,
995 );
996 }
997
998 #[test]
999 fn insert_ref_when_matching_local_in_scope_for_method() {
1000 check_edit(
1001 "apply_foo",
1002 r#"
1003struct Foo {}
1004struct Bar {}
1005impl Bar {
1006 fn apply_foo(&self, x: &Foo) {}
1007}
1008
1009fn main() {
1010 let x = Foo {};
1011 let y = Bar {};
1012 y.<|>
1013}
1014"#,
1015 r#"
1016struct Foo {}
1017struct Bar {}
1018impl Bar {
1019 fn apply_foo(&self, x: &Foo) {}
1020}
1021
1022fn main() {
1023 let x = Foo {};
1024 let y = Bar {};
1025 y.apply_foo(${1:&x})$0
1026}
1027"#,
1028 );
1029 }
1030
1031 #[test]
1032 fn trim_mut_keyword_in_func_completion() {
1033 check_edit(
1034 "take_mutably",
1035 r#"
1036fn take_mutably(mut x: &i32) {}
1037
1038fn main() {
1039 take_m<|>
1040}
1041"#,
1042 r#"
1043fn take_mutably(mut x: &i32) {}
1044
1045fn main() {
1046 take_mutably(${1:x})$0
1047}
1048"#,
1049 );
1050 }
1051
1052 #[test]
1053 fn inserts_parens_for_tuple_enums() {
1054 mark::check!(inserts_parens_for_tuple_enums);
1055 check_edit(
1056 "Some",
1057 r#"
1058enum Option<T> { Some(T), None }
1059use Option::*;
1060fn main() -> Option<i32> {
1061 Som<|>
1062}
1063"#,
1064 r#"
1065enum Option<T> { Some(T), None }
1066use Option::*;
1067fn main() -> Option<i32> {
1068 Some($0)
1069}
1070"#,
1071 );
1072 check_edit(
1073 "Some",
1074 r#"
1075enum Option<T> { Some(T), None }
1076use Option::*;
1077fn main(value: Option<i32>) {
1078 match value {
1079 Som<|>
1080 }
1081}
1082"#,
1083 r#"
1084enum Option<T> { Some(T), None }
1085use Option::*;
1086fn main(value: Option<i32>) {
1087 match value {
1088 Some($0)
1089 }
1090}
1091"#,
1092 );
1093 }
1094
1095 #[test]
1096 fn dont_duplicate_pattern_parens() {
1097 mark::check!(dont_duplicate_pattern_parens);
1098 check_edit(
1099 "Var",
1100 r#"
1101enum E { Var(i32) }
1102fn main() {
1103 match E::Var(92) {
1104 E::<|>(92) => (),
1105 }
1106}
1107"#,
1108 r#"
1109enum E { Var(i32) }
1110fn main() {
1111 match E::Var(92) {
1112 E::Var(92) => (),
1113 }
1114}
1115"#,
1116 );
1117 }
1118
1119 #[test]
1120 fn no_call_parens_if_fn_ptr_needed() {
1121 mark::check!(no_call_parens_if_fn_ptr_needed);
1122 check_edit(
1123 "foo",
1124 r#"
1125fn foo(foo: u8, bar: u8) {}
1126struct ManualVtable { f: fn(u8, u8) }
1127
1128fn main() -> ManualVtable {
1129 ManualVtable { f: f<|> }
1130}
1131"#,
1132 r#"
1133fn foo(foo: u8, bar: u8) {}
1134struct ManualVtable { f: fn(u8, u8) }
1135
1136fn main() -> ManualVtable {
1137 ManualVtable { f: foo }
1138}
1139"#,
1140 );
1141 }
1142
1143 #[test]
1144 fn no_parens_in_use_item() {
1145 mark::check!(no_parens_in_use_item);
1146 check_edit(
1147 "foo",
1148 r#"
1149mod m { pub fn foo() {} }
1150use crate::m::f<|>;
1151"#,
1152 r#"
1153mod m { pub fn foo() {} }
1154use crate::m::foo;
1155"#,
1156 );
1157 }
1158
1159 #[test]
1160 fn no_parens_in_call() {
1161 check_edit(
1162 "foo",
1163 r#"
1164fn foo(x: i32) {}
1165fn main() { f<|>(); }
1166"#,
1167 r#"
1168fn foo(x: i32) {}
1169fn main() { foo(); }
1170"#,
1171 );
1172 check_edit(
1173 "foo",
1174 r#"
1175struct Foo;
1176impl Foo { fn foo(&self){} }
1177fn f(foo: &Foo) { foo.f<|>(); }
1178"#,
1179 r#"
1180struct Foo;
1181impl Foo { fn foo(&self){} }
1182fn f(foo: &Foo) { foo.foo(); }
1183"#,
1184 );
1185 }
1186
1187 #[test]
1188 fn inserts_angle_brackets_for_generics() {
1189 mark::check!(inserts_angle_brackets_for_generics);
1190 check_edit(
1191 "Vec",
1192 r#"
1193struct Vec<T> {}
1194fn foo(xs: Ve<|>)
1195"#,
1196 r#"
1197struct Vec<T> {}
1198fn foo(xs: Vec<$0>)
1199"#,
1200 );
1201 check_edit(
1202 "Vec",
1203 r#"
1204type Vec<T> = (T,);
1205fn foo(xs: Ve<|>)
1206"#,
1207 r#"
1208type Vec<T> = (T,);
1209fn foo(xs: Vec<$0>)
1210"#,
1211 );
1212 check_edit(
1213 "Vec",
1214 r#"
1215struct Vec<T = i128> {}
1216fn foo(xs: Ve<|>)
1217"#,
1218 r#"
1219struct Vec<T = i128> {}
1220fn foo(xs: Vec)
1221"#,
1222 );
1223 check_edit(
1224 "Vec",
1225 r#"
1226struct Vec<T> {}
1227fn foo(xs: Ve<|><i128>)
1228"#,
1229 r#"
1230struct Vec<T> {}
1231fn foo(xs: Vec<i128>)
1232"#,
1233 );
1234 }
1235
1236 #[test]
1237 fn dont_insert_macro_call_parens_unncessary() {
1238 mark::check!(dont_insert_macro_call_parens_unncessary);
1239 check_edit(
1240 "frobnicate!",
1241 r#"
1242//- /main.rs crate:main deps:foo
1243use foo::<|>;
1244//- /foo/lib.rs crate:foo
1245#[macro_export]
1246macro_rules frobnicate { () => () }
1247"#,
1248 r#"
1249use foo::frobnicate;
1250"#,
1251 );
1252
1253 check_edit(
1254 "frobnicate!",
1255 r#"
1256macro_rules frobnicate { () => () }
1257fn main() { frob<|>!(); }
1258"#,
1259 r#"
1260macro_rules frobnicate { () => () }
1261fn main() { frobnicate!(); }
1262"#,
1263 );
1264 }
1265
1266 #[test]
1267 fn active_param_score() {
1268 mark::check!(active_param_type_match);
1269 check_scores(
1270 r#"
1271struct S { foo: i64, bar: u32, baz: u32 }
1272fn test(bar: u32) { }
1273fn foo(s: S) { test(s.<|>) }
1274"#,
1275 expect![[r#"
1276 fd bar [type+name]
1277 fd baz [type]
1278 fd foo []
1279 "#]],
1280 );
1281 }
1282
1283 #[test]
1284 fn record_field_scores() {
1285 mark::check!(record_field_type_match);
1286 check_scores(
1287 r#"
1288struct A { foo: i64, bar: u32, baz: u32 }
1289struct B { x: (), y: f32, bar: u32 }
1290fn foo(a: A) { B { bar: a.<|> }; }
1291"#,
1292 expect![[r#"
1293 fd bar [type+name]
1294 fd baz [type]
1295 fd foo []
1296 "#]],
1297 )
1298 }
1299
1300 #[test]
1301 fn record_field_and_call_scores() {
1302 check_scores(
1303 r#"
1304struct A { foo: i64, bar: u32, baz: u32 }
1305struct B { x: (), y: f32, bar: u32 }
1306fn f(foo: i64) { }
1307fn foo(a: A) { B { bar: f(a.<|>) }; }
1308"#,
1309 expect![[r#"
1310 fd foo [type+name]
1311 fd bar []
1312 fd baz []
1313 "#]],
1314 );
1315 check_scores(
1316 r#"
1317struct A { foo: i64, bar: u32, baz: u32 }
1318struct B { x: (), y: f32, bar: u32 }
1319fn f(foo: i64) { }
1320fn foo(a: A) { f(B { bar: a.<|> }); }
1321"#,
1322 expect![[r#"
1323 fd bar [type+name]
1324 fd baz [type]
1325 fd foo []
1326 "#]],
1327 );
1328 }
1329
1330 #[test]
1331 fn prioritize_exact_ref_match() {
1332 check_scores(
1333 r#"
1334struct WorldSnapshot { _f: () };
1335fn go(world: &WorldSnapshot) { go(w<|>) }
1336"#,
1337 expect![[r#"
1338 bn world [type+name]
1339 st WorldSnapshot []
1340 fn go(…) []
1341 "#]],
1342 );
1343 }
1344
1345 #[test]
1346 fn too_many_arguments() {
1347 check_scores(
1348 r#"
1349struct Foo;
1350fn f(foo: &Foo) { f(foo, w<|>) }
1351"#,
1352 expect![[r#"
1353 st Foo []
1354 fn f(…) []
1355 bn foo []
1356 "#]],
1357 );
1358 }
1359
1360 #[test]
1361 fn guesses_macro_braces() {
1362 check_edit(
1363 "vec!",
1364 r#"
1365/// Creates a [`Vec`] containing the arguments.
1366///
1367/// ```
1368/// let v = vec![1, 2, 3];
1369/// assert_eq!(v[0], 1);
1370/// assert_eq!(v[1], 2);
1371/// assert_eq!(v[2], 3);
1372/// ```
1373macro_rules! vec { () => {} }
1374
1375fn fn main() { v<|> }
1376"#,
1377 r#"
1378/// Creates a [`Vec`] containing the arguments.
1379///
1380/// ```
1381/// let v = vec![1, 2, 3];
1382/// assert_eq!(v[0], 1);
1383/// assert_eq!(v[1], 2);
1384/// assert_eq!(v[2], 3);
1385/// ```
1386macro_rules! vec { () => {} }
1387
1388fn fn main() { vec![$0] }
1389"#,
1390 );
1391
1392 check_edit(
1393 "foo!",
1394 r#"
1395/// Foo
1396///
1397/// Don't call `fooo!()` `fooo!()`, or `_foo![]` `_foo![]`,
1398/// call as `let _=foo! { hello world };`
1399macro_rules! foo { () => {} }
1400fn main() { <|> }
1401"#,
1402 r#"
1403/// Foo
1404///
1405/// Don't call `fooo!()` `fooo!()`, or `_foo![]` `_foo![]`,
1406/// call as `let _=foo! { hello world };`
1407macro_rules! foo { () => {} }
1408fn main() { foo! {$0} }
1409"#,
1410 )
1411 }
1412}