]> git.lizzy.rs Git - rust.git/blob - crates/ide_completion/src/render.rs
Merge #9785
[rust.git] / crates / ide_completion / src / render.rs
1 //! `render` module provides utilities for rendering completion suggestions
2 //! into code pieces that will be presented to user.
3
4 pub(crate) mod macro_;
5 pub(crate) mod function;
6 pub(crate) mod enum_variant;
7 pub(crate) mod const_;
8 pub(crate) mod pattern;
9 pub(crate) mod type_alias;
10 pub(crate) mod struct_literal;
11
12 mod builder_ext;
13
14 use hir::{AsAssocItem, HasAttrs, HirDisplay};
15 use ide_db::{
16     helpers::{item_name, SnippetCap},
17     RootDatabase, SymbolKind,
18 };
19 use syntax::TextRange;
20
21 use crate::{
22     context::{PathCompletionContext, PathKind},
23     item::{CompletionRelevanceTypeMatch, ImportEdit},
24     render::{enum_variant::render_variant, function::render_fn, macro_::render_macro},
25     CompletionContext, CompletionItem, CompletionItemKind, CompletionKind, CompletionRelevance,
26 };
27 /// Interface for data and methods required for items rendering.
28 #[derive(Debug)]
29 pub(crate) struct RenderContext<'a> {
30     completion: &'a CompletionContext<'a>,
31 }
32
33 impl<'a> RenderContext<'a> {
34     pub(crate) fn new(completion: &'a CompletionContext<'a>) -> RenderContext<'a> {
35         RenderContext { completion }
36     }
37
38     fn snippet_cap(&self) -> Option<SnippetCap> {
39         self.completion.config.snippet_cap
40     }
41
42     fn db(&self) -> &'a RootDatabase {
43         self.completion.db
44     }
45
46     fn source_range(&self) -> TextRange {
47         self.completion.source_range()
48     }
49
50     fn is_deprecated(&self, node: impl HasAttrs) -> bool {
51         let attrs = node.attrs(self.db());
52         attrs.by_key("deprecated").exists() || attrs.by_key("rustc_deprecated").exists()
53     }
54
55     fn is_deprecated_assoc_item(&self, as_assoc_item: impl AsAssocItem) -> bool {
56         let db = self.db();
57         let assoc = match as_assoc_item.as_assoc_item(db) {
58             Some(assoc) => assoc,
59             None => return false,
60         };
61
62         let is_assoc_deprecated = match assoc {
63             hir::AssocItem::Function(it) => self.is_deprecated(it),
64             hir::AssocItem::Const(it) => self.is_deprecated(it),
65             hir::AssocItem::TypeAlias(it) => self.is_deprecated(it),
66         };
67         is_assoc_deprecated
68             || assoc
69                 .containing_trait_or_trait_impl(db)
70                 .map(|trait_| self.is_deprecated(trait_))
71                 .unwrap_or(false)
72     }
73
74     fn docs(&self, node: impl HasAttrs) -> Option<hir::Documentation> {
75         node.docs(self.db())
76     }
77 }
78
79 pub(crate) fn render_field(
80     ctx: RenderContext<'_>,
81     receiver: Option<hir::Name>,
82     field: hir::Field,
83     ty: &hir::Type,
84 ) -> CompletionItem {
85     let is_deprecated = ctx.is_deprecated(field);
86     let name = field.name(ctx.db()).to_string();
87     let mut item = CompletionItem::new(
88         CompletionKind::Reference,
89         ctx.source_range(),
90         receiver.map_or_else(|| name.clone(), |receiver| format!("{}.{}", receiver, name)),
91     );
92     item.set_relevance(CompletionRelevance {
93         type_match: compute_type_match(ctx.completion, ty),
94         exact_name_match: compute_exact_name_match(ctx.completion, &name),
95         ..CompletionRelevance::default()
96     });
97     item.kind(SymbolKind::Field)
98         .detail(ty.display(ctx.db()).to_string())
99         .set_documentation(field.docs(ctx.db()))
100         .set_deprecated(is_deprecated)
101         .lookup_by(name);
102     if let Some(_ref_match) = compute_ref_match(ctx.completion, ty) {
103         // FIXME
104         // For now we don't properly calculate the edits for ref match
105         // completions on struct fields, so we've disabled them. See #8058.
106     }
107     item.build()
108 }
109
110 pub(crate) fn render_tuple_field(
111     ctx: RenderContext<'_>,
112     receiver: Option<hir::Name>,
113     field: usize,
114     ty: &hir::Type,
115 ) -> CompletionItem {
116     let mut item = CompletionItem::new(
117         CompletionKind::Reference,
118         ctx.source_range(),
119         receiver.map_or_else(|| field.to_string(), |receiver| format!("{}.{}", receiver, field)),
120     );
121     item.kind(SymbolKind::Field)
122         .detail(ty.display(ctx.db()).to_string())
123         .lookup_by(field.to_string());
124     item.build()
125 }
126
127 pub(crate) fn render_resolution(
128     ctx: RenderContext<'_>,
129     local_name: hir::Name,
130     resolution: &hir::ScopeDef,
131 ) -> Option<CompletionItem> {
132     render_resolution_(ctx, local_name, None, resolution)
133 }
134
135 pub(crate) fn render_resolution_with_import(
136     ctx: RenderContext<'_>,
137     import_edit: ImportEdit,
138 ) -> Option<CompletionItem> {
139     let resolution = hir::ScopeDef::from(import_edit.import.original_item);
140     let local_name = match resolution {
141         hir::ScopeDef::ModuleDef(hir::ModuleDef::Function(f)) => f.name(ctx.completion.db),
142         hir::ScopeDef::ModuleDef(hir::ModuleDef::Const(c)) => c.name(ctx.completion.db)?,
143         hir::ScopeDef::ModuleDef(hir::ModuleDef::TypeAlias(t)) => t.name(ctx.completion.db),
144         _ => item_name(ctx.db(), import_edit.import.original_item)?,
145     };
146     render_resolution_(ctx, local_name, Some(import_edit), &resolution).map(|mut item| {
147         item.completion_kind = CompletionKind::Magic;
148         item
149     })
150 }
151
152 fn render_resolution_(
153     ctx: RenderContext<'_>,
154     local_name: hir::Name,
155     import_to_add: Option<ImportEdit>,
156     resolution: &hir::ScopeDef,
157 ) -> Option<CompletionItem> {
158     let _p = profile::span("render_resolution");
159     use hir::ModuleDef::*;
160
161     let completion_kind = match resolution {
162         hir::ScopeDef::ModuleDef(BuiltinType(..)) => CompletionKind::BuiltinType,
163         _ => CompletionKind::Reference,
164     };
165
166     let kind = match resolution {
167         hir::ScopeDef::ModuleDef(Function(func)) => {
168             return render_fn(ctx, import_to_add, Some(local_name), *func);
169         }
170         hir::ScopeDef::ModuleDef(Variant(_)) if ctx.completion.is_pat_or_const.is_some() => {
171             CompletionItemKind::SymbolKind(SymbolKind::Variant)
172         }
173         hir::ScopeDef::ModuleDef(Variant(var)) => {
174             let item = render_variant(ctx, import_to_add, Some(local_name), *var, None);
175             return Some(item);
176         }
177         hir::ScopeDef::MacroDef(mac) => {
178             let item = render_macro(ctx, import_to_add, local_name, *mac);
179             return item;
180         }
181
182         hir::ScopeDef::ModuleDef(Module(..)) => CompletionItemKind::SymbolKind(SymbolKind::Module),
183         hir::ScopeDef::ModuleDef(Adt(adt)) => CompletionItemKind::SymbolKind(match adt {
184             hir::Adt::Struct(_) => SymbolKind::Struct,
185             hir::Adt::Union(_) => SymbolKind::Union,
186             hir::Adt::Enum(_) => SymbolKind::Enum,
187         }),
188         hir::ScopeDef::ModuleDef(Const(..)) => CompletionItemKind::SymbolKind(SymbolKind::Const),
189         hir::ScopeDef::ModuleDef(Static(..)) => CompletionItemKind::SymbolKind(SymbolKind::Static),
190         hir::ScopeDef::ModuleDef(Trait(..)) => CompletionItemKind::SymbolKind(SymbolKind::Trait),
191         hir::ScopeDef::ModuleDef(TypeAlias(..)) => {
192             CompletionItemKind::SymbolKind(SymbolKind::TypeAlias)
193         }
194         hir::ScopeDef::ModuleDef(BuiltinType(..)) => CompletionItemKind::BuiltinType,
195         hir::ScopeDef::GenericParam(param) => CompletionItemKind::SymbolKind(match param {
196             hir::GenericParam::TypeParam(_) => SymbolKind::TypeParam,
197             hir::GenericParam::LifetimeParam(_) => SymbolKind::LifetimeParam,
198             hir::GenericParam::ConstParam(_) => SymbolKind::ConstParam,
199         }),
200         hir::ScopeDef::Local(..) => CompletionItemKind::SymbolKind(SymbolKind::Local),
201         hir::ScopeDef::Label(..) => CompletionItemKind::SymbolKind(SymbolKind::Label),
202         hir::ScopeDef::AdtSelfType(..) | hir::ScopeDef::ImplSelfType(..) => {
203             CompletionItemKind::SymbolKind(SymbolKind::SelfParam)
204         }
205         hir::ScopeDef::Unknown => {
206             let mut item = CompletionItem::new(
207                 CompletionKind::Reference,
208                 ctx.source_range(),
209                 local_name.to_string(),
210             );
211             item.kind(CompletionItemKind::UnresolvedReference).add_import(import_to_add);
212             return Some(item.build());
213         }
214     };
215
216     let local_name = local_name.to_string();
217     let mut item = CompletionItem::new(completion_kind, ctx.source_range(), local_name.clone());
218     if let hir::ScopeDef::Local(local) = resolution {
219         let ty = local.ty(ctx.db());
220         if !ty.is_unknown() {
221             item.detail(ty.display(ctx.db()).to_string());
222         }
223
224         item.set_relevance(CompletionRelevance {
225             type_match: compute_type_match(ctx.completion, &ty),
226             exact_name_match: compute_exact_name_match(ctx.completion, &local_name),
227             is_local: true,
228             ..CompletionRelevance::default()
229         });
230
231         if let Some(ref_match) = compute_ref_match(ctx.completion, &ty) {
232             item.ref_match(ref_match);
233         }
234     };
235
236     // Add `<>` for generic types
237     if matches!(
238         ctx.completion.path_context,
239         Some(PathCompletionContext { kind: Some(PathKind::Type), has_type_args: false, .. })
240     ) && ctx.completion.config.add_call_parenthesis
241     {
242         if let Some(cap) = ctx.snippet_cap() {
243             let has_non_default_type_params = match resolution {
244                 hir::ScopeDef::ModuleDef(Adt(it)) => it.has_non_default_type_params(ctx.db()),
245                 hir::ScopeDef::ModuleDef(TypeAlias(it)) => it.has_non_default_type_params(ctx.db()),
246                 _ => false,
247             };
248             if has_non_default_type_params {
249                 cov_mark::hit!(inserts_angle_brackets_for_generics);
250                 item.lookup_by(local_name.clone())
251                     .label(format!("{}<…>", local_name))
252                     .insert_snippet(cap, format!("{}<$0>", local_name));
253             }
254         }
255     }
256     item.kind(kind)
257         .add_import(import_to_add)
258         .set_documentation(scope_def_docs(ctx.db(), resolution))
259         .set_deprecated(scope_def_is_deprecated(&ctx, resolution));
260     Some(item.build())
261 }
262
263 fn scope_def_docs(db: &RootDatabase, resolution: &hir::ScopeDef) -> Option<hir::Documentation> {
264     use hir::ModuleDef::*;
265     match resolution {
266         hir::ScopeDef::ModuleDef(Module(it)) => it.docs(db),
267         hir::ScopeDef::ModuleDef(Adt(it)) => it.docs(db),
268         hir::ScopeDef::ModuleDef(Variant(it)) => it.docs(db),
269         hir::ScopeDef::ModuleDef(Const(it)) => it.docs(db),
270         hir::ScopeDef::ModuleDef(Static(it)) => it.docs(db),
271         hir::ScopeDef::ModuleDef(Trait(it)) => it.docs(db),
272         hir::ScopeDef::ModuleDef(TypeAlias(it)) => it.docs(db),
273         _ => None,
274     }
275 }
276
277 fn scope_def_is_deprecated(ctx: &RenderContext<'_>, resolution: &hir::ScopeDef) -> bool {
278     match resolution {
279         hir::ScopeDef::ModuleDef(it) => ctx.is_deprecated_assoc_item(*it),
280         hir::ScopeDef::MacroDef(it) => ctx.is_deprecated(*it),
281         hir::ScopeDef::GenericParam(it) => ctx.is_deprecated(*it),
282         hir::ScopeDef::AdtSelfType(it) => ctx.is_deprecated(*it),
283         _ => false,
284     }
285 }
286
287 fn compute_type_match(
288     ctx: &CompletionContext,
289     completion_ty: &hir::Type,
290 ) -> Option<CompletionRelevanceTypeMatch> {
291     let expected_type = ctx.expected_type.as_ref()?;
292
293     // We don't ever consider unit type to be an exact type match, since
294     // nearly always this is not meaningful to the user.
295     if expected_type.is_unit() {
296         return None;
297     }
298
299     if completion_ty == expected_type {
300         Some(CompletionRelevanceTypeMatch::Exact)
301     } else if expected_type.could_unify_with(ctx.db, completion_ty) {
302         Some(CompletionRelevanceTypeMatch::CouldUnify)
303     } else {
304         None
305     }
306 }
307
308 fn compute_exact_name_match(ctx: &CompletionContext, completion_name: &str) -> bool {
309     ctx.expected_name.as_ref().map_or(false, |name| name.text() == completion_name)
310 }
311
312 fn compute_ref_match(
313     ctx: &CompletionContext,
314     completion_ty: &hir::Type,
315 ) -> Option<hir::Mutability> {
316     let expected_type = ctx.expected_type.as_ref()?;
317     if completion_ty != expected_type {
318         let expected_type_without_ref = expected_type.remove_ref()?;
319         if completion_ty.autoderef(ctx.db).any(|deref_ty| deref_ty == expected_type_without_ref) {
320             cov_mark::hit!(suggest_ref);
321             let mutability = if expected_type.is_mutable_reference() {
322                 hir::Mutability::Mut
323             } else {
324                 hir::Mutability::Shared
325             };
326             return Some(mutability);
327         };
328     }
329     None
330 }
331
332 #[cfg(test)]
333 mod tests {
334     use std::cmp;
335
336     use expect_test::{expect, Expect};
337     use itertools::Itertools;
338
339     use crate::{
340         item::CompletionRelevanceTypeMatch,
341         tests::{check_edit, do_completion, get_all_items, TEST_CONFIG},
342         CompletionKind, CompletionRelevance,
343     };
344
345     #[track_caller]
346     fn check(ra_fixture: &str, expect: Expect) {
347         let actual = do_completion(ra_fixture, CompletionKind::Reference);
348         expect.assert_debug_eq(&actual);
349     }
350
351     #[track_caller]
352     fn check_relevance(ra_fixture: &str, expect: Expect) {
353         check_relevance_for_kinds(&[CompletionKind::Reference], ra_fixture, expect)
354     }
355
356     #[track_caller]
357     fn check_relevance_for_kinds(kinds: &[CompletionKind], ra_fixture: &str, expect: Expect) {
358         let mut actual = get_all_items(TEST_CONFIG, ra_fixture);
359         actual.retain(|it| kinds.contains(&it.completion_kind));
360         actual.sort_by_key(|it| cmp::Reverse(it.relevance().score()));
361
362         let actual = actual
363             .into_iter()
364             .flat_map(|it| {
365                 let mut items = vec![];
366
367                 let tag = it.kind().unwrap().tag();
368                 let relevance = display_relevance(it.relevance());
369                 items.push(format!("{} {} {}\n", tag, it.label(), relevance));
370
371                 if let Some((mutability, relevance)) = it.ref_match() {
372                     let label = format!("&{}{}", mutability.as_keyword_for_ref(), it.label());
373                     let relevance = display_relevance(relevance);
374
375                     items.push(format!("{} {} {}\n", tag, label, relevance));
376                 }
377
378                 items
379             })
380             .collect::<String>();
381
382         expect.assert_eq(&actual);
383
384         fn display_relevance(relevance: CompletionRelevance) -> String {
385             let relevance_factors = vec![
386                 (relevance.type_match == Some(CompletionRelevanceTypeMatch::Exact), "type"),
387                 (
388                     relevance.type_match == Some(CompletionRelevanceTypeMatch::CouldUnify),
389                     "type_could_unify",
390                 ),
391                 (relevance.exact_name_match, "name"),
392                 (relevance.is_local, "local"),
393                 (relevance.exact_postfix_snippet_match, "snippet"),
394             ]
395             .into_iter()
396             .filter_map(|(cond, desc)| if cond { Some(desc) } else { None })
397             .join("+");
398
399             format!("[{}]", relevance_factors)
400         }
401     }
402
403     #[test]
404     fn enum_detail_includes_record_fields() {
405         check(
406             r#"
407 enum Foo { Foo { x: i32, y: i32 } }
408
409 fn main() { Foo::Fo$0 }
410 "#,
411             expect![[r#"
412                 [
413                     CompletionItem {
414                         label: "Foo",
415                         source_range: 54..56,
416                         delete: 54..56,
417                         insert: "Foo",
418                         kind: SymbolKind(
419                             Variant,
420                         ),
421                         detail: "{ x: i32, y: i32 }",
422                     },
423                 ]
424             "#]],
425         );
426     }
427
428     #[test]
429     fn enum_detail_doesnt_include_tuple_fields() {
430         check(
431             r#"
432 enum Foo { Foo (i32, i32) }
433
434 fn main() { Foo::Fo$0 }
435 "#,
436             expect![[r#"
437                 [
438                     CompletionItem {
439                         label: "Foo(…)",
440                         source_range: 46..48,
441                         delete: 46..48,
442                         insert: "Foo($0)",
443                         kind: SymbolKind(
444                             Variant,
445                         ),
446                         lookup: "Foo",
447                         detail: "(i32, i32)",
448                         trigger_call_info: true,
449                     },
450                 ]
451             "#]],
452         );
453     }
454
455     #[test]
456     fn fn_detail_includes_args_and_return_type() {
457         check(
458             r#"
459 fn foo<T>(a: u32, b: u32, t: T) -> (u32, T) { (a, t) }
460
461 fn main() { fo$0 }
462 "#,
463             expect![[r#"
464                 [
465                     CompletionItem {
466                         label: "foo(…)",
467                         source_range: 68..70,
468                         delete: 68..70,
469                         insert: "foo(${1:a}, ${2:b}, ${3:t})$0",
470                         kind: SymbolKind(
471                             Function,
472                         ),
473                         lookup: "foo",
474                         detail: "fn(u32, u32, T) -> (u32, T)",
475                         trigger_call_info: true,
476                     },
477                     CompletionItem {
478                         label: "main()",
479                         source_range: 68..70,
480                         delete: 68..70,
481                         insert: "main()$0",
482                         kind: SymbolKind(
483                             Function,
484                         ),
485                         lookup: "main",
486                         detail: "fn()",
487                     },
488                 ]
489             "#]],
490         );
491     }
492
493     #[test]
494     fn enum_detail_just_parentheses_for_unit() {
495         check(
496             r#"
497 enum Foo { Foo }
498
499 fn main() { Foo::Fo$0 }
500 "#,
501             expect![[r#"
502                 [
503                     CompletionItem {
504                         label: "Foo",
505                         source_range: 35..37,
506                         delete: 35..37,
507                         insert: "Foo",
508                         kind: SymbolKind(
509                             Variant,
510                         ),
511                         detail: "()",
512                     },
513                 ]
514             "#]],
515         );
516     }
517
518     #[test]
519     fn lookup_enums_by_two_qualifiers() {
520         check(
521             r#"
522 mod m {
523     pub enum Spam { Foo, Bar(i32) }
524 }
525 fn main() { let _: m::Spam = S$0 }
526 "#,
527             expect![[r#"
528                 [
529                     CompletionItem {
530                         label: "Spam::Bar(…)",
531                         source_range: 75..76,
532                         delete: 75..76,
533                         insert: "Spam::Bar($0)",
534                         kind: SymbolKind(
535                             Variant,
536                         ),
537                         lookup: "Spam::Bar",
538                         detail: "(i32)",
539                         relevance: CompletionRelevance {
540                             exact_name_match: false,
541                             type_match: Some(
542                                 Exact,
543                             ),
544                             is_local: false,
545                             exact_postfix_snippet_match: false,
546                         },
547                         trigger_call_info: true,
548                     },
549                     CompletionItem {
550                         label: "m",
551                         source_range: 75..76,
552                         delete: 75..76,
553                         insert: "m",
554                         kind: SymbolKind(
555                             Module,
556                         ),
557                     },
558                     CompletionItem {
559                         label: "m::Spam::Foo",
560                         source_range: 75..76,
561                         delete: 75..76,
562                         insert: "m::Spam::Foo",
563                         kind: SymbolKind(
564                             Variant,
565                         ),
566                         lookup: "Spam::Foo",
567                         detail: "()",
568                         relevance: CompletionRelevance {
569                             exact_name_match: false,
570                             type_match: Some(
571                                 Exact,
572                             ),
573                             is_local: false,
574                             exact_postfix_snippet_match: false,
575                         },
576                     },
577                     CompletionItem {
578                         label: "main()",
579                         source_range: 75..76,
580                         delete: 75..76,
581                         insert: "main()$0",
582                         kind: SymbolKind(
583                             Function,
584                         ),
585                         lookup: "main",
586                         detail: "fn()",
587                     },
588                 ]
589             "#]],
590         )
591     }
592
593     #[test]
594     fn sets_deprecated_flag_in_items() {
595         check(
596             r#"
597 #[deprecated]
598 fn something_deprecated() {}
599 #[rustc_deprecated(since = "1.0.0")]
600 fn something_else_deprecated() {}
601
602 fn main() { som$0 }
603 "#,
604             expect![[r#"
605                 [
606                     CompletionItem {
607                         label: "main()",
608                         source_range: 127..130,
609                         delete: 127..130,
610                         insert: "main()$0",
611                         kind: SymbolKind(
612                             Function,
613                         ),
614                         lookup: "main",
615                         detail: "fn()",
616                     },
617                     CompletionItem {
618                         label: "something_deprecated()",
619                         source_range: 127..130,
620                         delete: 127..130,
621                         insert: "something_deprecated()$0",
622                         kind: SymbolKind(
623                             Function,
624                         ),
625                         lookup: "something_deprecated",
626                         detail: "fn()",
627                         deprecated: true,
628                     },
629                     CompletionItem {
630                         label: "something_else_deprecated()",
631                         source_range: 127..130,
632                         delete: 127..130,
633                         insert: "something_else_deprecated()$0",
634                         kind: SymbolKind(
635                             Function,
636                         ),
637                         lookup: "something_else_deprecated",
638                         detail: "fn()",
639                         deprecated: true,
640                     },
641                 ]
642             "#]],
643         );
644
645         check(
646             r#"
647 struct A { #[deprecated] the_field: u32 }
648 fn foo() { A { the$0 } }
649 "#,
650             expect![[r#"
651                 [
652                     CompletionItem {
653                         label: "the_field",
654                         source_range: 57..60,
655                         delete: 57..60,
656                         insert: "the_field",
657                         kind: SymbolKind(
658                             Field,
659                         ),
660                         detail: "u32",
661                         deprecated: true,
662                         relevance: CompletionRelevance {
663                             exact_name_match: false,
664                             type_match: Some(
665                                 CouldUnify,
666                             ),
667                             is_local: false,
668                             exact_postfix_snippet_match: false,
669                         },
670                     },
671                 ]
672             "#]],
673         );
674     }
675
676     #[test]
677     fn renders_docs() {
678         check(
679             r#"
680 struct S {
681     /// Field docs
682     foo:
683 }
684 impl S {
685     /// Method docs
686     fn bar(self) { self.$0 }
687 }"#,
688             expect![[r#"
689                 [
690                     CompletionItem {
691                         label: "bar()",
692                         source_range: 94..94,
693                         delete: 94..94,
694                         insert: "bar()$0",
695                         kind: Method,
696                         lookup: "bar",
697                         detail: "fn(self)",
698                         documentation: Documentation(
699                             "Method docs",
700                         ),
701                     },
702                     CompletionItem {
703                         label: "foo",
704                         source_range: 94..94,
705                         delete: 94..94,
706                         insert: "foo",
707                         kind: SymbolKind(
708                             Field,
709                         ),
710                         detail: "{unknown}",
711                         documentation: Documentation(
712                             "Field docs",
713                         ),
714                     },
715                 ]
716             "#]],
717         );
718
719         check(
720             r#"
721 use self::my$0;
722
723 /// mod docs
724 mod my { }
725
726 /// enum docs
727 enum E {
728     /// variant docs
729     V
730 }
731 use self::E::*;
732 "#,
733             expect![[r#"
734                 [
735                     CompletionItem {
736                         label: "E",
737                         source_range: 10..12,
738                         delete: 10..12,
739                         insert: "E",
740                         kind: SymbolKind(
741                             Enum,
742                         ),
743                         documentation: Documentation(
744                             "enum docs",
745                         ),
746                     },
747                     CompletionItem {
748                         label: "V",
749                         source_range: 10..12,
750                         delete: 10..12,
751                         insert: "V",
752                         kind: SymbolKind(
753                             Variant,
754                         ),
755                         detail: "()",
756                         documentation: Documentation(
757                             "variant docs",
758                         ),
759                     },
760                     CompletionItem {
761                         label: "my",
762                         source_range: 10..12,
763                         delete: 10..12,
764                         insert: "my",
765                         kind: SymbolKind(
766                             Module,
767                         ),
768                         documentation: Documentation(
769                             "mod docs",
770                         ),
771                     },
772                 ]
773             "#]],
774         )
775     }
776
777     #[test]
778     fn dont_render_attrs() {
779         check(
780             r#"
781 struct S;
782 impl S {
783     #[inline]
784     fn the_method(&self) { }
785 }
786 fn foo(s: S) { s.$0 }
787 "#,
788             expect![[r#"
789                 [
790                     CompletionItem {
791                         label: "the_method()",
792                         source_range: 81..81,
793                         delete: 81..81,
794                         insert: "the_method()$0",
795                         kind: Method,
796                         lookup: "the_method",
797                         detail: "fn(&self)",
798                     },
799                 ]
800             "#]],
801         )
802     }
803
804     #[test]
805     fn no_call_parens_if_fn_ptr_needed() {
806         cov_mark::check!(no_call_parens_if_fn_ptr_needed);
807         check_edit(
808             "foo",
809             r#"
810 fn foo(foo: u8, bar: u8) {}
811 struct ManualVtable { f: fn(u8, u8) }
812
813 fn main() -> ManualVtable {
814     ManualVtable { f: f$0 }
815 }
816 "#,
817             r#"
818 fn foo(foo: u8, bar: u8) {}
819 struct ManualVtable { f: fn(u8, u8) }
820
821 fn main() -> ManualVtable {
822     ManualVtable { f: foo }
823 }
824 "#,
825         );
826     }
827
828     #[test]
829     fn no_parens_in_use_item() {
830         cov_mark::check!(no_parens_in_use_item);
831         check_edit(
832             "foo",
833             r#"
834 mod m { pub fn foo() {} }
835 use crate::m::f$0;
836 "#,
837             r#"
838 mod m { pub fn foo() {} }
839 use crate::m::foo;
840 "#,
841         );
842     }
843
844     #[test]
845     fn no_parens_in_call() {
846         check_edit(
847             "foo",
848             r#"
849 fn foo(x: i32) {}
850 fn main() { f$0(); }
851 "#,
852             r#"
853 fn foo(x: i32) {}
854 fn main() { foo(); }
855 "#,
856         );
857         check_edit(
858             "foo",
859             r#"
860 struct Foo;
861 impl Foo { fn foo(&self){} }
862 fn f(foo: &Foo) { foo.f$0(); }
863 "#,
864             r#"
865 struct Foo;
866 impl Foo { fn foo(&self){} }
867 fn f(foo: &Foo) { foo.foo(); }
868 "#,
869         );
870     }
871
872     #[test]
873     fn inserts_angle_brackets_for_generics() {
874         cov_mark::check!(inserts_angle_brackets_for_generics);
875         check_edit(
876             "Vec",
877             r#"
878 struct Vec<T> {}
879 fn foo(xs: Ve$0)
880 "#,
881             r#"
882 struct Vec<T> {}
883 fn foo(xs: Vec<$0>)
884 "#,
885         );
886         check_edit(
887             "Vec",
888             r#"
889 type Vec<T> = (T,);
890 fn foo(xs: Ve$0)
891 "#,
892             r#"
893 type Vec<T> = (T,);
894 fn foo(xs: Vec<$0>)
895 "#,
896         );
897         check_edit(
898             "Vec",
899             r#"
900 struct Vec<T = i128> {}
901 fn foo(xs: Ve$0)
902 "#,
903             r#"
904 struct Vec<T = i128> {}
905 fn foo(xs: Vec)
906 "#,
907         );
908         check_edit(
909             "Vec",
910             r#"
911 struct Vec<T> {}
912 fn foo(xs: Ve$0<i128>)
913 "#,
914             r#"
915 struct Vec<T> {}
916 fn foo(xs: Vec<i128>)
917 "#,
918         );
919     }
920
921     #[test]
922     fn active_param_relevance() {
923         check_relevance(
924             r#"
925 struct S { foo: i64, bar: u32, baz: u32 }
926 fn test(bar: u32) { }
927 fn foo(s: S) { test(s.$0) }
928 "#,
929             expect![[r#"
930                 fd bar [type+name]
931                 fd baz [type]
932                 fd foo []
933             "#]],
934         );
935     }
936
937     #[test]
938     fn record_field_relevances() {
939         check_relevance(
940             r#"
941 struct A { foo: i64, bar: u32, baz: u32 }
942 struct B { x: (), y: f32, bar: u32 }
943 fn foo(a: A) { B { bar: a.$0 }; }
944 "#,
945             expect![[r#"
946                 fd bar [type+name]
947                 fd baz [type]
948                 fd foo []
949             "#]],
950         )
951     }
952
953     #[test]
954     fn record_field_and_call_relevances() {
955         check_relevance(
956             r#"
957 struct A { foo: i64, bar: u32, baz: u32 }
958 struct B { x: (), y: f32, bar: u32 }
959 fn f(foo: i64) {  }
960 fn foo(a: A) { B { bar: f(a.$0) }; }
961 "#,
962             expect![[r#"
963                 fd foo [type+name]
964                 fd bar []
965                 fd baz []
966             "#]],
967         );
968         check_relevance(
969             r#"
970 struct A { foo: i64, bar: u32, baz: u32 }
971 struct B { x: (), y: f32, bar: u32 }
972 fn f(foo: i64) {  }
973 fn foo(a: A) { f(B { bar: a.$0 }); }
974 "#,
975             expect![[r#"
976                 fd bar [type+name]
977                 fd baz [type]
978                 fd foo []
979             "#]],
980         );
981     }
982
983     #[test]
984     fn prioritize_exact_ref_match() {
985         check_relevance(
986             r#"
987 struct WorldSnapshot { _f: () };
988 fn go(world: &WorldSnapshot) { go(w$0) }
989 "#,
990             expect![[r#"
991                 lc world [type+name+local]
992                 st WorldSnapshot []
993                 fn go(…) []
994             "#]],
995         );
996     }
997
998     #[test]
999     fn too_many_arguments() {
1000         cov_mark::check!(too_many_arguments);
1001         check_relevance(
1002             r#"
1003 struct Foo;
1004 fn f(foo: &Foo) { f(foo, w$0) }
1005 "#,
1006             expect![[r#"
1007                 lc foo [local]
1008                 st Foo []
1009                 fn f(…) []
1010             "#]],
1011         );
1012     }
1013
1014     #[test]
1015     fn score_fn_type_and_name_match() {
1016         check_relevance(
1017             r#"
1018 struct A { bar: u8 }
1019 fn baz() -> u8 { 0 }
1020 fn bar() -> u8 { 0 }
1021 fn f() { A { bar: b$0 }; }
1022 "#,
1023             expect![[r#"
1024                 fn bar() [type+name]
1025                 fn baz() [type]
1026                 st A []
1027                 fn f() []
1028             "#]],
1029         );
1030     }
1031
1032     #[test]
1033     fn score_method_type_and_name_match() {
1034         check_relevance(
1035             r#"
1036 fn baz(aaa: u32){}
1037 struct Foo;
1038 impl Foo {
1039 fn aaa(&self) -> u32 { 0 }
1040 fn bbb(&self) -> u32 { 0 }
1041 fn ccc(&self) -> u64 { 0 }
1042 }
1043 fn f() {
1044     baz(Foo.$0
1045 }
1046 "#,
1047             expect![[r#"
1048                 me aaa() [type+name]
1049                 me bbb() [type]
1050                 me ccc() []
1051             "#]],
1052         );
1053     }
1054
1055     #[test]
1056     fn score_method_name_match_only() {
1057         check_relevance(
1058             r#"
1059 fn baz(aaa: u32){}
1060 struct Foo;
1061 impl Foo {
1062 fn aaa(&self) -> u64 { 0 }
1063 }
1064 fn f() {
1065     baz(Foo.$0
1066 }
1067 "#,
1068             expect![[r#"
1069                 me aaa() [name]
1070             "#]],
1071         );
1072     }
1073
1074     #[test]
1075     fn suggest_ref_mut() {
1076         cov_mark::check!(suggest_ref);
1077         check_relevance(
1078             r#"
1079 struct S;
1080 fn foo(s: &mut S) {}
1081 fn main() {
1082     let mut s = S;
1083     foo($0);
1084 }
1085             "#,
1086             expect![[r#"
1087                 lc s [name+local]
1088                 lc &mut s [type+name+local]
1089                 st S []
1090                 fn main() []
1091                 fn foo(…) []
1092             "#]],
1093         );
1094         check_relevance(
1095             r#"
1096 struct S;
1097 fn foo(s: &mut S) {}
1098 fn main() {
1099     let mut s = S;
1100     foo(&mut $0);
1101 }
1102             "#,
1103             expect![[r#"
1104                 lc s [type+name+local]
1105                 st S []
1106                 fn main() []
1107                 fn foo(…) []
1108             "#]],
1109         );
1110     }
1111
1112     #[test]
1113     fn suggest_deref() {
1114         check_relevance(
1115             r#"
1116 //- minicore: deref
1117 struct S;
1118 struct T(S);
1119
1120 impl core::ops::Deref for T {
1121     type Target = S;
1122
1123     fn deref(&self) -> &Self::Target {
1124         &self.0
1125     }
1126 }
1127
1128 fn foo(s: &S) {}
1129
1130 fn main() {
1131     let t = T(S);
1132     let m = 123;
1133
1134     foo($0);
1135 }
1136             "#,
1137             expect![[r#"
1138                 lc m [local]
1139                 lc t [local]
1140                 lc &t [type+local]
1141                 st T []
1142                 st S []
1143                 fn main() []
1144                 fn foo(…) []
1145                 md core []
1146                 tt Sized []
1147             "#]],
1148         )
1149     }
1150
1151     #[test]
1152     fn suggest_deref_mut() {
1153         check_relevance(
1154             r#"
1155 //- minicore: deref_mut
1156 struct S;
1157 struct T(S);
1158
1159 impl core::ops::Deref for T {
1160     type Target = S;
1161
1162     fn deref(&self) -> &Self::Target {
1163         &self.0
1164     }
1165 }
1166
1167 impl core::ops::DerefMut for T {
1168     fn deref_mut(&mut self) -> &mut Self::Target {
1169         &mut self.0
1170     }
1171 }
1172
1173 fn foo(s: &mut S) {}
1174
1175 fn main() {
1176     let t = T(S);
1177     let m = 123;
1178
1179     foo($0);
1180 }
1181             "#,
1182             expect![[r#"
1183                 lc m [local]
1184                 lc t [local]
1185                 lc &mut t [type+local]
1186                 st T []
1187                 st S []
1188                 fn main() []
1189                 fn foo(…) []
1190                 md core []
1191                 tt Sized []
1192             "#]],
1193         )
1194     }
1195
1196     #[test]
1197     fn locals() {
1198         check_relevance(
1199             r#"
1200 fn foo(bar: u32) {
1201     let baz = 0;
1202
1203     f$0
1204 }
1205 "#,
1206             expect![[r#"
1207                 lc baz [local]
1208                 lc bar [local]
1209                 fn foo(…) []
1210             "#]],
1211         );
1212     }
1213
1214     #[test]
1215     fn enum_owned() {
1216         check_relevance(
1217             r#"
1218 enum Foo { A, B }
1219 fn foo() {
1220     bar($0);
1221 }
1222 fn bar(t: Foo) {}
1223 "#,
1224             expect![[r#"
1225                 ev Foo::A [type]
1226                 ev Foo::B [type]
1227                 en Foo []
1228                 fn bar(…) []
1229                 fn foo() []
1230             "#]],
1231         );
1232     }
1233
1234     #[test]
1235     fn enum_ref() {
1236         check_relevance(
1237             r#"
1238 enum Foo { A, B }
1239 fn foo() {
1240     bar($0);
1241 }
1242 fn bar(t: &Foo) {}
1243 "#,
1244             expect![[r#"
1245                 ev Foo::A []
1246                 ev &Foo::A [type]
1247                 ev Foo::B []
1248                 ev &Foo::B [type]
1249                 en Foo []
1250                 fn bar(…) []
1251                 fn foo() []
1252             "#]],
1253         );
1254     }
1255
1256     #[test]
1257     fn suggest_deref_fn_ret() {
1258         check_relevance(
1259             r#"
1260 //- minicore: deref
1261 struct S;
1262 struct T(S);
1263
1264 impl core::ops::Deref for T {
1265     type Target = S;
1266
1267     fn deref(&self) -> &Self::Target {
1268         &self.0
1269     }
1270 }
1271
1272 fn foo(s: &S) {}
1273 fn bar() -> T {}
1274
1275 fn main() {
1276     foo($0);
1277 }
1278 "#,
1279             expect![[r#"
1280                 st T []
1281                 st S []
1282                 fn main() []
1283                 fn bar() []
1284                 fn &bar() [type]
1285                 fn foo(…) []
1286                 md core []
1287                 tt Sized []
1288             "#]],
1289         )
1290     }
1291
1292     #[test]
1293     fn struct_field_method_ref() {
1294         check(
1295             r#"
1296 struct Foo { bar: u32 }
1297 impl Foo { fn baz(&self) -> u32 { 0 } }
1298
1299 fn foo(f: Foo) { let _: &u32 = f.b$0 }
1300 "#,
1301             // FIXME
1302             // Ideally we'd also suggest &f.bar and &f.baz() as exact
1303             // type matches. See #8058.
1304             expect![[r#"
1305                 [
1306                     CompletionItem {
1307                         label: "bar",
1308                         source_range: 98..99,
1309                         delete: 98..99,
1310                         insert: "bar",
1311                         kind: SymbolKind(
1312                             Field,
1313                         ),
1314                         detail: "u32",
1315                     },
1316                     CompletionItem {
1317                         label: "baz()",
1318                         source_range: 98..99,
1319                         delete: 98..99,
1320                         insert: "baz()$0",
1321                         kind: Method,
1322                         lookup: "baz",
1323                         detail: "fn(&self) -> u32",
1324                     },
1325                 ]
1326             "#]],
1327         );
1328     }
1329
1330     #[test]
1331     fn generic_enum() {
1332         check_relevance(
1333             r#"
1334 enum Foo<T> { A(T), B }
1335 // bar() should not be an exact type match
1336 // because the generic parameters are different
1337 fn bar() -> Foo<u8> { Foo::B }
1338 // FIXME baz() should be an exact type match
1339 // because the types could unify, but it currently
1340 // is not. This is due to the T here being
1341 // TyKind::Placeholder rather than TyKind::Missing.
1342 fn baz<T>() -> Foo<T> { Foo::B }
1343 fn foo() {
1344     let foo: Foo<u32> = Foo::B;
1345     let _: Foo<u32> = f$0;
1346 }
1347 "#,
1348             expect![[r#"
1349                 lc foo [type+local]
1350                 ev Foo::A(…) [type_could_unify]
1351                 ev Foo::B [type_could_unify]
1352                 fn foo() []
1353                 en Foo []
1354                 fn baz() []
1355                 fn bar() []
1356             "#]],
1357         );
1358     }
1359
1360     #[test]
1361     fn postfix_completion_relevance() {
1362         check_relevance_for_kinds(
1363             &[CompletionKind::Postfix, CompletionKind::Magic],
1364             r#"
1365 mod ops {
1366     pub trait Not {
1367         type Output;
1368         fn not(self) -> Self::Output;
1369     }
1370
1371     impl Not for bool {
1372         type Output = bool;
1373         fn not(self) -> bool { if self { false } else { true }}
1374     }
1375 }
1376
1377 fn main() {
1378     let _: bool = (9 > 2).not$0;
1379 }
1380 "#,
1381             expect![[r#"
1382                 sn not [snippet]
1383                 me not() (use ops::Not) [type_could_unify]
1384                 sn if []
1385                 sn while []
1386                 sn ref []
1387                 sn refm []
1388                 sn match []
1389                 sn box []
1390                 sn ok []
1391                 sn err []
1392                 sn some []
1393                 sn dbg []
1394                 sn dbgr []
1395                 sn call []
1396             "#]],
1397         );
1398     }
1399 }