aboutsummaryrefslogtreecommitdiff
path: root/crates/completion/src/presentation.rs
diff options
context:
space:
mode:
Diffstat (limited to 'crates/completion/src/presentation.rs')
-rw-r--r--crates/completion/src/presentation.rs1412
1 files changed, 0 insertions, 1412 deletions
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}