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