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