diff options
Diffstat (limited to 'crates/completion/src/completions.rs')
-rw-r--r-- | crates/completion/src/completions.rs | 1082 |
1 files changed, 8 insertions, 1074 deletions
diff --git a/crates/completion/src/completions.rs b/crates/completion/src/completions.rs index 434366b12..b54771fcd 100644 --- a/crates/completion/src/completions.rs +++ b/crates/completion/src/completions.rs | |||
@@ -14,15 +14,9 @@ pub(crate) mod macro_in_item_position; | |||
14 | pub(crate) mod trait_impl; | 14 | pub(crate) mod trait_impl; |
15 | pub(crate) mod mod_; | 15 | pub(crate) mod mod_; |
16 | 16 | ||
17 | use hir::{HasAttrs, HirDisplay, ModPath, Mutability, ScopeDef, Type}; | 17 | use hir::{ModPath, ScopeDef, Type}; |
18 | use test_utils::mark; | ||
19 | 18 | ||
20 | use crate::{ | 19 | use crate::{item::Builder, render::*, CompletionContext, CompletionItem}; |
21 | item::Builder, | ||
22 | render::{ConstRender, EnumVariantRender, FunctionRender, MacroRender, TypeAliasRender}, | ||
23 | CompletionContext, CompletionItem, CompletionItemKind, CompletionKind, CompletionScore, | ||
24 | RootDatabase, | ||
25 | }; | ||
26 | 20 | ||
27 | /// Represents an in-progress set of completions being built. | 21 | /// Represents an in-progress set of completions being built. |
28 | #[derive(Debug, Default)] | 22 | #[derive(Debug, Default)] |
@@ -58,27 +52,13 @@ impl Completions { | |||
58 | } | 52 | } |
59 | 53 | ||
60 | pub(crate) fn add_field(&mut self, ctx: &CompletionContext, field: hir::Field, ty: &Type) { | 54 | pub(crate) fn add_field(&mut self, ctx: &CompletionContext, field: hir::Field, ty: &Type) { |
61 | let is_deprecated = is_deprecated(field, ctx.db); | 55 | let item = Render::new(ctx.into()).add_field(field, ty); |
62 | let name = field.name(ctx.db); | 56 | self.add(item); |
63 | let mut item = | ||
64 | CompletionItem::new(CompletionKind::Reference, ctx.source_range(), name.to_string()) | ||
65 | .kind(CompletionItemKind::Field) | ||
66 | .detail(ty.display(ctx.db).to_string()) | ||
67 | .set_documentation(field.docs(ctx.db)) | ||
68 | .set_deprecated(is_deprecated); | ||
69 | |||
70 | if let Some(score) = compute_score(ctx, &ty, &name.to_string()) { | ||
71 | item = item.set_score(score); | ||
72 | } | ||
73 | |||
74 | item.add_to(self); | ||
75 | } | 57 | } |
76 | 58 | ||
77 | pub(crate) fn add_tuple_field(&mut self, ctx: &CompletionContext, field: usize, ty: &Type) { | 59 | pub(crate) fn add_tuple_field(&mut self, ctx: &CompletionContext, field: usize, ty: &Type) { |
78 | CompletionItem::new(CompletionKind::Reference, ctx.source_range(), field.to_string()) | 60 | let item = Render::new(ctx.into()).add_tuple_field(field, ty); |
79 | .kind(CompletionItemKind::Field) | 61 | self.add(item); |
80 | .detail(ty.display(ctx.db).to_string()) | ||
81 | .add_to(self); | ||
82 | } | 62 | } |
83 | 63 | ||
84 | pub(crate) fn add_resolution( | 64 | pub(crate) fn add_resolution( |
@@ -87,100 +67,9 @@ impl Completions { | |||
87 | local_name: String, | 67 | local_name: String, |
88 | resolution: &ScopeDef, | 68 | resolution: &ScopeDef, |
89 | ) { | 69 | ) { |
90 | use hir::ModuleDef::*; | 70 | if let Some(item) = Render::new(ctx.into()).render_resolution(local_name, resolution) { |
91 | 71 | self.add(item); | |
92 | let completion_kind = match resolution { | ||
93 | ScopeDef::ModuleDef(BuiltinType(..)) => CompletionKind::BuiltinType, | ||
94 | _ => CompletionKind::Reference, | ||
95 | }; | ||
96 | |||
97 | let kind = match resolution { | ||
98 | ScopeDef::ModuleDef(Module(..)) => CompletionItemKind::Module, | ||
99 | ScopeDef::ModuleDef(Function(func)) => { | ||
100 | self.add_function(ctx, *func, Some(local_name)); | ||
101 | return; | ||
102 | } | ||
103 | ScopeDef::ModuleDef(Adt(hir::Adt::Struct(_))) => CompletionItemKind::Struct, | ||
104 | // FIXME: add CompletionItemKind::Union | ||
105 | ScopeDef::ModuleDef(Adt(hir::Adt::Union(_))) => CompletionItemKind::Struct, | ||
106 | ScopeDef::ModuleDef(Adt(hir::Adt::Enum(_))) => CompletionItemKind::Enum, | ||
107 | |||
108 | ScopeDef::ModuleDef(EnumVariant(var)) => { | ||
109 | self.add_enum_variant(ctx, *var, Some(local_name)); | ||
110 | return; | ||
111 | } | ||
112 | ScopeDef::ModuleDef(Const(..)) => CompletionItemKind::Const, | ||
113 | ScopeDef::ModuleDef(Static(..)) => CompletionItemKind::Static, | ||
114 | ScopeDef::ModuleDef(Trait(..)) => CompletionItemKind::Trait, | ||
115 | ScopeDef::ModuleDef(TypeAlias(..)) => CompletionItemKind::TypeAlias, | ||
116 | ScopeDef::ModuleDef(BuiltinType(..)) => CompletionItemKind::BuiltinType, | ||
117 | ScopeDef::GenericParam(..) => CompletionItemKind::TypeParam, | ||
118 | ScopeDef::Local(..) => CompletionItemKind::Binding, | ||
119 | // (does this need its own kind?) | ||
120 | ScopeDef::AdtSelfType(..) | ScopeDef::ImplSelfType(..) => CompletionItemKind::TypeParam, | ||
121 | ScopeDef::MacroDef(mac) => { | ||
122 | self.add_macro(ctx, Some(local_name), *mac); | ||
123 | return; | ||
124 | } | ||
125 | ScopeDef::Unknown => { | ||
126 | CompletionItem::new(CompletionKind::Reference, ctx.source_range(), local_name) | ||
127 | .kind(CompletionItemKind::UnresolvedReference) | ||
128 | .add_to(self); | ||
129 | return; | ||
130 | } | ||
131 | }; | ||
132 | |||
133 | let docs = match resolution { | ||
134 | ScopeDef::ModuleDef(Module(it)) => it.docs(ctx.db), | ||
135 | ScopeDef::ModuleDef(Adt(it)) => it.docs(ctx.db), | ||
136 | ScopeDef::ModuleDef(EnumVariant(it)) => it.docs(ctx.db), | ||
137 | ScopeDef::ModuleDef(Const(it)) => it.docs(ctx.db), | ||
138 | ScopeDef::ModuleDef(Static(it)) => it.docs(ctx.db), | ||
139 | ScopeDef::ModuleDef(Trait(it)) => it.docs(ctx.db), | ||
140 | ScopeDef::ModuleDef(TypeAlias(it)) => it.docs(ctx.db), | ||
141 | _ => None, | ||
142 | }; | ||
143 | |||
144 | let mut item = CompletionItem::new(completion_kind, ctx.source_range(), local_name.clone()); | ||
145 | if let ScopeDef::Local(local) = resolution { | ||
146 | let ty = local.ty(ctx.db); | ||
147 | if !ty.is_unknown() { | ||
148 | item = item.detail(ty.display(ctx.db).to_string()); | ||
149 | } | ||
150 | }; | ||
151 | |||
152 | let mut ref_match = None; | ||
153 | if let ScopeDef::Local(local) = resolution { | ||
154 | if let Some((active_name, active_type)) = ctx.active_name_and_type() { | ||
155 | let ty = local.ty(ctx.db); | ||
156 | if let Some(score) = | ||
157 | compute_score_from_active(&active_type, &active_name, &ty, &local_name) | ||
158 | { | ||
159 | item = item.set_score(score); | ||
160 | } | ||
161 | ref_match = refed_type_matches(&active_type, &active_name, &ty, &local_name); | ||
162 | } | ||
163 | } | ||
164 | |||
165 | // Add `<>` for generic types | ||
166 | if ctx.is_path_type && !ctx.has_type_args && ctx.config.add_call_parenthesis { | ||
167 | if let Some(cap) = ctx.config.snippet_cap { | ||
168 | let has_non_default_type_params = match resolution { | ||
169 | ScopeDef::ModuleDef(Adt(it)) => it.has_non_default_type_params(ctx.db), | ||
170 | ScopeDef::ModuleDef(TypeAlias(it)) => it.has_non_default_type_params(ctx.db), | ||
171 | _ => false, | ||
172 | }; | ||
173 | if has_non_default_type_params { | ||
174 | mark::hit!(inserts_angle_brackets_for_generics); | ||
175 | item = item | ||
176 | .lookup_by(local_name.clone()) | ||
177 | .label(format!("{}<…>", local_name)) | ||
178 | .insert_snippet(cap, format!("{}<$0>", local_name)); | ||
179 | } | ||
180 | } | ||
181 | } | 72 | } |
182 | |||
183 | item.kind(kind).set_documentation(docs).set_ref_match(ref_match).add_to(self) | ||
184 | } | 73 | } |
185 | 74 | ||
186 | pub(crate) fn add_macro( | 75 | pub(crate) fn add_macro( |
@@ -240,958 +129,3 @@ impl Completions { | |||
240 | self.add(item); | 129 | self.add(item); |
241 | } | 130 | } |
242 | } | 131 | } |
243 | |||
244 | fn compute_score_from_active( | ||
245 | active_type: &Type, | ||
246 | active_name: &str, | ||
247 | ty: &Type, | ||
248 | name: &str, | ||
249 | ) -> Option<CompletionScore> { | ||
250 | // Compute score | ||
251 | // For the same type | ||
252 | if active_type != ty { | ||
253 | return None; | ||
254 | } | ||
255 | |||
256 | let mut res = CompletionScore::TypeMatch; | ||
257 | |||
258 | // If same type + same name then go top position | ||
259 | if active_name == name { | ||
260 | res = CompletionScore::TypeAndNameMatch | ||
261 | } | ||
262 | |||
263 | Some(res) | ||
264 | } | ||
265 | fn refed_type_matches( | ||
266 | active_type: &Type, | ||
267 | active_name: &str, | ||
268 | ty: &Type, | ||
269 | name: &str, | ||
270 | ) -> Option<(Mutability, CompletionScore)> { | ||
271 | let derefed_active = active_type.remove_ref()?; | ||
272 | let score = compute_score_from_active(&derefed_active, &active_name, &ty, &name)?; | ||
273 | Some(( | ||
274 | if active_type.is_mutable_reference() { Mutability::Mut } else { Mutability::Shared }, | ||
275 | score, | ||
276 | )) | ||
277 | } | ||
278 | |||
279 | fn compute_score(ctx: &CompletionContext, ty: &Type, name: &str) -> Option<CompletionScore> { | ||
280 | let (active_name, active_type) = ctx.active_name_and_type()?; | ||
281 | compute_score_from_active(&active_type, &active_name, ty, name) | ||
282 | } | ||
283 | |||
284 | fn is_deprecated(node: impl HasAttrs, db: &RootDatabase) -> bool { | ||
285 | node.attrs(db).by_key("deprecated").exists() | ||
286 | } | ||
287 | |||
288 | #[cfg(test)] | ||
289 | mod tests { | ||
290 | use std::cmp::Reverse; | ||
291 | |||
292 | use expect_test::{expect, Expect}; | ||
293 | use test_utils::mark; | ||
294 | |||
295 | use crate::{ | ||
296 | test_utils::{check_edit, check_edit_with_config, do_completion, get_all_items}, | ||
297 | CompletionConfig, CompletionKind, CompletionScore, | ||
298 | }; | ||
299 | |||
300 | fn check(ra_fixture: &str, expect: Expect) { | ||
301 | let actual = do_completion(ra_fixture, CompletionKind::Reference); | ||
302 | expect.assert_debug_eq(&actual); | ||
303 | } | ||
304 | |||
305 | fn check_scores(ra_fixture: &str, expect: Expect) { | ||
306 | fn display_score(score: Option<CompletionScore>) -> &'static str { | ||
307 | match score { | ||
308 | Some(CompletionScore::TypeMatch) => "[type]", | ||
309 | Some(CompletionScore::TypeAndNameMatch) => "[type+name]", | ||
310 | None => "[]".into(), | ||
311 | } | ||
312 | } | ||
313 | |||
314 | let mut completions = get_all_items(CompletionConfig::default(), ra_fixture); | ||
315 | completions.sort_by_key(|it| (Reverse(it.score()), it.label().to_string())); | ||
316 | let actual = completions | ||
317 | .into_iter() | ||
318 | .filter(|it| it.completion_kind == CompletionKind::Reference) | ||
319 | .map(|it| { | ||
320 | let tag = it.kind().unwrap().tag(); | ||
321 | let score = display_score(it.score()); | ||
322 | format!("{} {} {}\n", tag, it.label(), score) | ||
323 | }) | ||
324 | .collect::<String>(); | ||
325 | expect.assert_eq(&actual); | ||
326 | } | ||
327 | |||
328 | #[test] | ||
329 | fn enum_detail_includes_record_fields() { | ||
330 | check( | ||
331 | r#" | ||
332 | enum Foo { Foo { x: i32, y: i32 } } | ||
333 | |||
334 | fn main() { Foo::Fo<|> } | ||
335 | "#, | ||
336 | expect![[r#" | ||
337 | [ | ||
338 | CompletionItem { | ||
339 | label: "Foo", | ||
340 | source_range: 54..56, | ||
341 | delete: 54..56, | ||
342 | insert: "Foo", | ||
343 | kind: EnumVariant, | ||
344 | detail: "{ x: i32, y: i32 }", | ||
345 | }, | ||
346 | ] | ||
347 | "#]], | ||
348 | ); | ||
349 | } | ||
350 | |||
351 | #[test] | ||
352 | fn enum_detail_doesnt_include_tuple_fields() { | ||
353 | check( | ||
354 | r#" | ||
355 | enum Foo { Foo (i32, i32) } | ||
356 | |||
357 | fn main() { Foo::Fo<|> } | ||
358 | "#, | ||
359 | expect![[r#" | ||
360 | [ | ||
361 | CompletionItem { | ||
362 | label: "Foo(…)", | ||
363 | source_range: 46..48, | ||
364 | delete: 46..48, | ||
365 | insert: "Foo($0)", | ||
366 | kind: EnumVariant, | ||
367 | lookup: "Foo", | ||
368 | detail: "(i32, i32)", | ||
369 | trigger_call_info: true, | ||
370 | }, | ||
371 | ] | ||
372 | "#]], | ||
373 | ); | ||
374 | } | ||
375 | |||
376 | #[test] | ||
377 | fn enum_detail_just_parentheses_for_unit() { | ||
378 | check( | ||
379 | r#" | ||
380 | enum Foo { Foo } | ||
381 | |||
382 | fn main() { Foo::Fo<|> } | ||
383 | "#, | ||
384 | expect![[r#" | ||
385 | [ | ||
386 | CompletionItem { | ||
387 | label: "Foo", | ||
388 | source_range: 35..37, | ||
389 | delete: 35..37, | ||
390 | insert: "Foo", | ||
391 | kind: EnumVariant, | ||
392 | detail: "()", | ||
393 | }, | ||
394 | ] | ||
395 | "#]], | ||
396 | ); | ||
397 | } | ||
398 | |||
399 | #[test] | ||
400 | fn lookup_enums_by_two_qualifiers() { | ||
401 | check( | ||
402 | r#" | ||
403 | mod m { | ||
404 | pub enum Spam { Foo, Bar(i32) } | ||
405 | } | ||
406 | fn main() { let _: m::Spam = S<|> } | ||
407 | "#, | ||
408 | expect![[r#" | ||
409 | [ | ||
410 | CompletionItem { | ||
411 | label: "Spam::Bar(…)", | ||
412 | source_range: 75..76, | ||
413 | delete: 75..76, | ||
414 | insert: "Spam::Bar($0)", | ||
415 | kind: EnumVariant, | ||
416 | lookup: "Spam::Bar", | ||
417 | detail: "(i32)", | ||
418 | trigger_call_info: true, | ||
419 | }, | ||
420 | CompletionItem { | ||
421 | label: "m", | ||
422 | source_range: 75..76, | ||
423 | delete: 75..76, | ||
424 | insert: "m", | ||
425 | kind: Module, | ||
426 | }, | ||
427 | CompletionItem { | ||
428 | label: "m::Spam::Foo", | ||
429 | source_range: 75..76, | ||
430 | delete: 75..76, | ||
431 | insert: "m::Spam::Foo", | ||
432 | kind: EnumVariant, | ||
433 | lookup: "Spam::Foo", | ||
434 | detail: "()", | ||
435 | }, | ||
436 | CompletionItem { | ||
437 | label: "main()", | ||
438 | source_range: 75..76, | ||
439 | delete: 75..76, | ||
440 | insert: "main()$0", | ||
441 | kind: Function, | ||
442 | lookup: "main", | ||
443 | detail: "fn main()", | ||
444 | }, | ||
445 | ] | ||
446 | "#]], | ||
447 | ) | ||
448 | } | ||
449 | |||
450 | #[test] | ||
451 | fn sets_deprecated_flag_in_items() { | ||
452 | check( | ||
453 | r#" | ||
454 | #[deprecated] | ||
455 | fn something_deprecated() {} | ||
456 | #[deprecated(since = "1.0.0")] | ||
457 | fn something_else_deprecated() {} | ||
458 | |||
459 | fn main() { som<|> } | ||
460 | "#, | ||
461 | expect![[r#" | ||
462 | [ | ||
463 | CompletionItem { | ||
464 | label: "main()", | ||
465 | source_range: 121..124, | ||
466 | delete: 121..124, | ||
467 | insert: "main()$0", | ||
468 | kind: Function, | ||
469 | lookup: "main", | ||
470 | detail: "fn main()", | ||
471 | }, | ||
472 | CompletionItem { | ||
473 | label: "something_deprecated()", | ||
474 | source_range: 121..124, | ||
475 | delete: 121..124, | ||
476 | insert: "something_deprecated()$0", | ||
477 | kind: Function, | ||
478 | lookup: "something_deprecated", | ||
479 | detail: "fn something_deprecated()", | ||
480 | deprecated: true, | ||
481 | }, | ||
482 | CompletionItem { | ||
483 | label: "something_else_deprecated()", | ||
484 | source_range: 121..124, | ||
485 | delete: 121..124, | ||
486 | insert: "something_else_deprecated()$0", | ||
487 | kind: Function, | ||
488 | lookup: "something_else_deprecated", | ||
489 | detail: "fn something_else_deprecated()", | ||
490 | deprecated: true, | ||
491 | }, | ||
492 | ] | ||
493 | "#]], | ||
494 | ); | ||
495 | |||
496 | check( | ||
497 | r#" | ||
498 | struct A { #[deprecated] the_field: u32 } | ||
499 | fn foo() { A { the<|> } } | ||
500 | "#, | ||
501 | expect![[r#" | ||
502 | [ | ||
503 | CompletionItem { | ||
504 | label: "the_field", | ||
505 | source_range: 57..60, | ||
506 | delete: 57..60, | ||
507 | insert: "the_field", | ||
508 | kind: Field, | ||
509 | detail: "u32", | ||
510 | deprecated: true, | ||
511 | }, | ||
512 | ] | ||
513 | "#]], | ||
514 | ); | ||
515 | } | ||
516 | |||
517 | #[test] | ||
518 | fn renders_docs() { | ||
519 | check( | ||
520 | r#" | ||
521 | struct S { | ||
522 | /// Field docs | ||
523 | foo: | ||
524 | } | ||
525 | impl S { | ||
526 | /// Method docs | ||
527 | fn bar(self) { self.<|> } | ||
528 | }"#, | ||
529 | expect![[r#" | ||
530 | [ | ||
531 | CompletionItem { | ||
532 | label: "bar()", | ||
533 | source_range: 94..94, | ||
534 | delete: 94..94, | ||
535 | insert: "bar()$0", | ||
536 | kind: Method, | ||
537 | lookup: "bar", | ||
538 | detail: "fn bar(self)", | ||
539 | documentation: Documentation( | ||
540 | "Method docs", | ||
541 | ), | ||
542 | }, | ||
543 | CompletionItem { | ||
544 | label: "foo", | ||
545 | source_range: 94..94, | ||
546 | delete: 94..94, | ||
547 | insert: "foo", | ||
548 | kind: Field, | ||
549 | detail: "{unknown}", | ||
550 | documentation: Documentation( | ||
551 | "Field docs", | ||
552 | ), | ||
553 | }, | ||
554 | ] | ||
555 | "#]], | ||
556 | ); | ||
557 | |||
558 | check( | ||
559 | r#" | ||
560 | use self::my<|>; | ||
561 | |||
562 | /// mod docs | ||
563 | mod my { } | ||
564 | |||
565 | /// enum docs | ||
566 | enum E { | ||
567 | /// variant docs | ||
568 | V | ||
569 | } | ||
570 | use self::E::*; | ||
571 | "#, | ||
572 | expect![[r#" | ||
573 | [ | ||
574 | CompletionItem { | ||
575 | label: "E", | ||
576 | source_range: 10..12, | ||
577 | delete: 10..12, | ||
578 | insert: "E", | ||
579 | kind: Enum, | ||
580 | documentation: Documentation( | ||
581 | "enum docs", | ||
582 | ), | ||
583 | }, | ||
584 | CompletionItem { | ||
585 | label: "V", | ||
586 | source_range: 10..12, | ||
587 | delete: 10..12, | ||
588 | insert: "V", | ||
589 | kind: EnumVariant, | ||
590 | detail: "()", | ||
591 | documentation: Documentation( | ||
592 | "variant docs", | ||
593 | ), | ||
594 | }, | ||
595 | CompletionItem { | ||
596 | label: "my", | ||
597 | source_range: 10..12, | ||
598 | delete: 10..12, | ||
599 | insert: "my", | ||
600 | kind: Module, | ||
601 | documentation: Documentation( | ||
602 | "mod docs", | ||
603 | ), | ||
604 | }, | ||
605 | ] | ||
606 | "#]], | ||
607 | ) | ||
608 | } | ||
609 | |||
610 | #[test] | ||
611 | fn dont_render_attrs() { | ||
612 | check( | ||
613 | r#" | ||
614 | struct S; | ||
615 | impl S { | ||
616 | #[inline] | ||
617 | fn the_method(&self) { } | ||
618 | } | ||
619 | fn foo(s: S) { s.<|> } | ||
620 | "#, | ||
621 | expect![[r#" | ||
622 | [ | ||
623 | CompletionItem { | ||
624 | label: "the_method()", | ||
625 | source_range: 81..81, | ||
626 | delete: 81..81, | ||
627 | insert: "the_method()$0", | ||
628 | kind: Method, | ||
629 | lookup: "the_method", | ||
630 | detail: "fn the_method(&self)", | ||
631 | }, | ||
632 | ] | ||
633 | "#]], | ||
634 | ) | ||
635 | } | ||
636 | |||
637 | #[test] | ||
638 | fn inserts_parens_for_function_calls() { | ||
639 | mark::check!(inserts_parens_for_function_calls); | ||
640 | check_edit( | ||
641 | "no_args", | ||
642 | r#" | ||
643 | fn no_args() {} | ||
644 | fn main() { no_<|> } | ||
645 | "#, | ||
646 | r#" | ||
647 | fn no_args() {} | ||
648 | fn main() { no_args()$0 } | ||
649 | "#, | ||
650 | ); | ||
651 | |||
652 | check_edit( | ||
653 | "with_args", | ||
654 | r#" | ||
655 | fn with_args(x: i32, y: String) {} | ||
656 | fn main() { with_<|> } | ||
657 | "#, | ||
658 | r#" | ||
659 | fn with_args(x: i32, y: String) {} | ||
660 | fn main() { with_args(${1:x}, ${2:y})$0 } | ||
661 | "#, | ||
662 | ); | ||
663 | |||
664 | check_edit( | ||
665 | "foo", | ||
666 | r#" | ||
667 | struct S; | ||
668 | impl S { | ||
669 | fn foo(&self) {} | ||
670 | } | ||
671 | fn bar(s: &S) { s.f<|> } | ||
672 | "#, | ||
673 | r#" | ||
674 | struct S; | ||
675 | impl S { | ||
676 | fn foo(&self) {} | ||
677 | } | ||
678 | fn bar(s: &S) { s.foo()$0 } | ||
679 | "#, | ||
680 | ); | ||
681 | |||
682 | check_edit( | ||
683 | "foo", | ||
684 | r#" | ||
685 | struct S {} | ||
686 | impl S { | ||
687 | fn foo(&self, x: i32) {} | ||
688 | } | ||
689 | fn bar(s: &S) { | ||
690 | s.f<|> | ||
691 | } | ||
692 | "#, | ||
693 | r#" | ||
694 | struct S {} | ||
695 | impl S { | ||
696 | fn foo(&self, x: i32) {} | ||
697 | } | ||
698 | fn bar(s: &S) { | ||
699 | s.foo(${1:x})$0 | ||
700 | } | ||
701 | "#, | ||
702 | ); | ||
703 | } | ||
704 | |||
705 | #[test] | ||
706 | fn suppress_arg_snippets() { | ||
707 | mark::check!(suppress_arg_snippets); | ||
708 | check_edit_with_config( | ||
709 | CompletionConfig { add_call_argument_snippets: false, ..CompletionConfig::default() }, | ||
710 | "with_args", | ||
711 | r#" | ||
712 | fn with_args(x: i32, y: String) {} | ||
713 | fn main() { with_<|> } | ||
714 | "#, | ||
715 | r#" | ||
716 | fn with_args(x: i32, y: String) {} | ||
717 | fn main() { with_args($0) } | ||
718 | "#, | ||
719 | ); | ||
720 | } | ||
721 | |||
722 | #[test] | ||
723 | fn strips_underscores_from_args() { | ||
724 | check_edit( | ||
725 | "foo", | ||
726 | r#" | ||
727 | fn foo(_foo: i32, ___bar: bool, ho_ge_: String) {} | ||
728 | fn main() { f<|> } | ||
729 | "#, | ||
730 | r#" | ||
731 | fn foo(_foo: i32, ___bar: bool, ho_ge_: String) {} | ||
732 | fn main() { foo(${1:foo}, ${2:bar}, ${3:ho_ge_})$0 } | ||
733 | "#, | ||
734 | ); | ||
735 | } | ||
736 | |||
737 | #[test] | ||
738 | fn insert_ref_when_matching_local_in_scope() { | ||
739 | check_edit( | ||
740 | "ref_arg", | ||
741 | r#" | ||
742 | struct Foo {} | ||
743 | fn ref_arg(x: &Foo) {} | ||
744 | fn main() { | ||
745 | let x = Foo {}; | ||
746 | ref_ar<|> | ||
747 | } | ||
748 | "#, | ||
749 | r#" | ||
750 | struct Foo {} | ||
751 | fn ref_arg(x: &Foo) {} | ||
752 | fn main() { | ||
753 | let x = Foo {}; | ||
754 | ref_arg(${1:&x})$0 | ||
755 | } | ||
756 | "#, | ||
757 | ); | ||
758 | } | ||
759 | |||
760 | #[test] | ||
761 | fn insert_mut_ref_when_matching_local_in_scope() { | ||
762 | check_edit( | ||
763 | "ref_arg", | ||
764 | r#" | ||
765 | struct Foo {} | ||
766 | fn ref_arg(x: &mut Foo) {} | ||
767 | fn main() { | ||
768 | let x = Foo {}; | ||
769 | ref_ar<|> | ||
770 | } | ||
771 | "#, | ||
772 | r#" | ||
773 | struct Foo {} | ||
774 | fn ref_arg(x: &mut Foo) {} | ||
775 | fn main() { | ||
776 | let x = Foo {}; | ||
777 | ref_arg(${1:&mut x})$0 | ||
778 | } | ||
779 | "#, | ||
780 | ); | ||
781 | } | ||
782 | |||
783 | #[test] | ||
784 | fn insert_ref_when_matching_local_in_scope_for_method() { | ||
785 | check_edit( | ||
786 | "apply_foo", | ||
787 | r#" | ||
788 | struct Foo {} | ||
789 | struct Bar {} | ||
790 | impl Bar { | ||
791 | fn apply_foo(&self, x: &Foo) {} | ||
792 | } | ||
793 | |||
794 | fn main() { | ||
795 | let x = Foo {}; | ||
796 | let y = Bar {}; | ||
797 | y.<|> | ||
798 | } | ||
799 | "#, | ||
800 | r#" | ||
801 | struct Foo {} | ||
802 | struct Bar {} | ||
803 | impl Bar { | ||
804 | fn apply_foo(&self, x: &Foo) {} | ||
805 | } | ||
806 | |||
807 | fn main() { | ||
808 | let x = Foo {}; | ||
809 | let y = Bar {}; | ||
810 | y.apply_foo(${1:&x})$0 | ||
811 | } | ||
812 | "#, | ||
813 | ); | ||
814 | } | ||
815 | |||
816 | #[test] | ||
817 | fn trim_mut_keyword_in_func_completion() { | ||
818 | check_edit( | ||
819 | "take_mutably", | ||
820 | r#" | ||
821 | fn take_mutably(mut x: &i32) {} | ||
822 | |||
823 | fn main() { | ||
824 | take_m<|> | ||
825 | } | ||
826 | "#, | ||
827 | r#" | ||
828 | fn take_mutably(mut x: &i32) {} | ||
829 | |||
830 | fn main() { | ||
831 | take_mutably(${1:x})$0 | ||
832 | } | ||
833 | "#, | ||
834 | ); | ||
835 | } | ||
836 | |||
837 | #[test] | ||
838 | fn inserts_parens_for_tuple_enums() { | ||
839 | mark::check!(inserts_parens_for_tuple_enums); | ||
840 | check_edit( | ||
841 | "Some", | ||
842 | r#" | ||
843 | enum Option<T> { Some(T), None } | ||
844 | use Option::*; | ||
845 | fn main() -> Option<i32> { | ||
846 | Som<|> | ||
847 | } | ||
848 | "#, | ||
849 | r#" | ||
850 | enum Option<T> { Some(T), None } | ||
851 | use Option::*; | ||
852 | fn main() -> Option<i32> { | ||
853 | Some($0) | ||
854 | } | ||
855 | "#, | ||
856 | ); | ||
857 | check_edit( | ||
858 | "Some", | ||
859 | r#" | ||
860 | enum Option<T> { Some(T), None } | ||
861 | use Option::*; | ||
862 | fn main(value: Option<i32>) { | ||
863 | match value { | ||
864 | Som<|> | ||
865 | } | ||
866 | } | ||
867 | "#, | ||
868 | r#" | ||
869 | enum Option<T> { Some(T), None } | ||
870 | use Option::*; | ||
871 | fn main(value: Option<i32>) { | ||
872 | match value { | ||
873 | Some($0) | ||
874 | } | ||
875 | } | ||
876 | "#, | ||
877 | ); | ||
878 | } | ||
879 | |||
880 | #[test] | ||
881 | fn dont_duplicate_pattern_parens() { | ||
882 | mark::check!(dont_duplicate_pattern_parens); | ||
883 | check_edit( | ||
884 | "Var", | ||
885 | r#" | ||
886 | enum E { Var(i32) } | ||
887 | fn main() { | ||
888 | match E::Var(92) { | ||
889 | E::<|>(92) => (), | ||
890 | } | ||
891 | } | ||
892 | "#, | ||
893 | r#" | ||
894 | enum E { Var(i32) } | ||
895 | fn main() { | ||
896 | match E::Var(92) { | ||
897 | E::Var(92) => (), | ||
898 | } | ||
899 | } | ||
900 | "#, | ||
901 | ); | ||
902 | } | ||
903 | |||
904 | #[test] | ||
905 | fn no_call_parens_if_fn_ptr_needed() { | ||
906 | mark::check!(no_call_parens_if_fn_ptr_needed); | ||
907 | check_edit( | ||
908 | "foo", | ||
909 | r#" | ||
910 | fn foo(foo: u8, bar: u8) {} | ||
911 | struct ManualVtable { f: fn(u8, u8) } | ||
912 | |||
913 | fn main() -> ManualVtable { | ||
914 | ManualVtable { f: f<|> } | ||
915 | } | ||
916 | "#, | ||
917 | r#" | ||
918 | fn foo(foo: u8, bar: u8) {} | ||
919 | struct ManualVtable { f: fn(u8, u8) } | ||
920 | |||
921 | fn main() -> ManualVtable { | ||
922 | ManualVtable { f: foo } | ||
923 | } | ||
924 | "#, | ||
925 | ); | ||
926 | } | ||
927 | |||
928 | #[test] | ||
929 | fn no_parens_in_use_item() { | ||
930 | mark::check!(no_parens_in_use_item); | ||
931 | check_edit( | ||
932 | "foo", | ||
933 | r#" | ||
934 | mod m { pub fn foo() {} } | ||
935 | use crate::m::f<|>; | ||
936 | "#, | ||
937 | r#" | ||
938 | mod m { pub fn foo() {} } | ||
939 | use crate::m::foo; | ||
940 | "#, | ||
941 | ); | ||
942 | } | ||
943 | |||
944 | #[test] | ||
945 | fn no_parens_in_call() { | ||
946 | check_edit( | ||
947 | "foo", | ||
948 | r#" | ||
949 | fn foo(x: i32) {} | ||
950 | fn main() { f<|>(); } | ||
951 | "#, | ||
952 | r#" | ||
953 | fn foo(x: i32) {} | ||
954 | fn main() { foo(); } | ||
955 | "#, | ||
956 | ); | ||
957 | check_edit( | ||
958 | "foo", | ||
959 | r#" | ||
960 | struct Foo; | ||
961 | impl Foo { fn foo(&self){} } | ||
962 | fn f(foo: &Foo) { foo.f<|>(); } | ||
963 | "#, | ||
964 | r#" | ||
965 | struct Foo; | ||
966 | impl Foo { fn foo(&self){} } | ||
967 | fn f(foo: &Foo) { foo.foo(); } | ||
968 | "#, | ||
969 | ); | ||
970 | } | ||
971 | |||
972 | #[test] | ||
973 | fn inserts_angle_brackets_for_generics() { | ||
974 | mark::check!(inserts_angle_brackets_for_generics); | ||
975 | check_edit( | ||
976 | "Vec", | ||
977 | r#" | ||
978 | struct Vec<T> {} | ||
979 | fn foo(xs: Ve<|>) | ||
980 | "#, | ||
981 | r#" | ||
982 | struct Vec<T> {} | ||
983 | fn foo(xs: Vec<$0>) | ||
984 | "#, | ||
985 | ); | ||
986 | check_edit( | ||
987 | "Vec", | ||
988 | r#" | ||
989 | type Vec<T> = (T,); | ||
990 | fn foo(xs: Ve<|>) | ||
991 | "#, | ||
992 | r#" | ||
993 | type Vec<T> = (T,); | ||
994 | fn foo(xs: Vec<$0>) | ||
995 | "#, | ||
996 | ); | ||
997 | check_edit( | ||
998 | "Vec", | ||
999 | r#" | ||
1000 | struct Vec<T = i128> {} | ||
1001 | fn foo(xs: Ve<|>) | ||
1002 | "#, | ||
1003 | r#" | ||
1004 | struct Vec<T = i128> {} | ||
1005 | fn foo(xs: Vec) | ||
1006 | "#, | ||
1007 | ); | ||
1008 | check_edit( | ||
1009 | "Vec", | ||
1010 | r#" | ||
1011 | struct Vec<T> {} | ||
1012 | fn foo(xs: Ve<|><i128>) | ||
1013 | "#, | ||
1014 | r#" | ||
1015 | struct Vec<T> {} | ||
1016 | fn foo(xs: Vec<i128>) | ||
1017 | "#, | ||
1018 | ); | ||
1019 | } | ||
1020 | |||
1021 | #[test] | ||
1022 | fn dont_insert_macro_call_parens_unncessary() { | ||
1023 | mark::check!(dont_insert_macro_call_parens_unncessary); | ||
1024 | check_edit( | ||
1025 | "frobnicate!", | ||
1026 | r#" | ||
1027 | //- /main.rs crate:main deps:foo | ||
1028 | use foo::<|>; | ||
1029 | //- /foo/lib.rs crate:foo | ||
1030 | #[macro_export] | ||
1031 | macro_rules frobnicate { () => () } | ||
1032 | "#, | ||
1033 | r#" | ||
1034 | use foo::frobnicate; | ||
1035 | "#, | ||
1036 | ); | ||
1037 | |||
1038 | check_edit( | ||
1039 | "frobnicate!", | ||
1040 | r#" | ||
1041 | macro_rules frobnicate { () => () } | ||
1042 | fn main() { frob<|>!(); } | ||
1043 | "#, | ||
1044 | r#" | ||
1045 | macro_rules frobnicate { () => () } | ||
1046 | fn main() { frobnicate!(); } | ||
1047 | "#, | ||
1048 | ); | ||
1049 | } | ||
1050 | |||
1051 | #[test] | ||
1052 | fn active_param_score() { | ||
1053 | mark::check!(active_param_type_match); | ||
1054 | check_scores( | ||
1055 | r#" | ||
1056 | struct S { foo: i64, bar: u32, baz: u32 } | ||
1057 | fn test(bar: u32) { } | ||
1058 | fn foo(s: S) { test(s.<|>) } | ||
1059 | "#, | ||
1060 | expect![[r#" | ||
1061 | fd bar [type+name] | ||
1062 | fd baz [type] | ||
1063 | fd foo [] | ||
1064 | "#]], | ||
1065 | ); | ||
1066 | } | ||
1067 | |||
1068 | #[test] | ||
1069 | fn record_field_scores() { | ||
1070 | mark::check!(record_field_type_match); | ||
1071 | check_scores( | ||
1072 | r#" | ||
1073 | struct A { foo: i64, bar: u32, baz: u32 } | ||
1074 | struct B { x: (), y: f32, bar: u32 } | ||
1075 | fn foo(a: A) { B { bar: a.<|> }; } | ||
1076 | "#, | ||
1077 | expect![[r#" | ||
1078 | fd bar [type+name] | ||
1079 | fd baz [type] | ||
1080 | fd foo [] | ||
1081 | "#]], | ||
1082 | ) | ||
1083 | } | ||
1084 | |||
1085 | #[test] | ||
1086 | fn record_field_and_call_scores() { | ||
1087 | check_scores( | ||
1088 | r#" | ||
1089 | struct A { foo: i64, bar: u32, baz: u32 } | ||
1090 | struct B { x: (), y: f32, bar: u32 } | ||
1091 | fn f(foo: i64) { } | ||
1092 | fn foo(a: A) { B { bar: f(a.<|>) }; } | ||
1093 | "#, | ||
1094 | expect![[r#" | ||
1095 | fd foo [type+name] | ||
1096 | fd bar [] | ||
1097 | fd baz [] | ||
1098 | "#]], | ||
1099 | ); | ||
1100 | check_scores( | ||
1101 | r#" | ||
1102 | struct A { foo: i64, bar: u32, baz: u32 } | ||
1103 | struct B { x: (), y: f32, bar: u32 } | ||
1104 | fn f(foo: i64) { } | ||
1105 | fn foo(a: A) { f(B { bar: a.<|> }); } | ||
1106 | "#, | ||
1107 | expect![[r#" | ||
1108 | fd bar [type+name] | ||
1109 | fd baz [type] | ||
1110 | fd foo [] | ||
1111 | "#]], | ||
1112 | ); | ||
1113 | } | ||
1114 | |||
1115 | #[test] | ||
1116 | fn prioritize_exact_ref_match() { | ||
1117 | check_scores( | ||
1118 | r#" | ||
1119 | struct WorldSnapshot { _f: () }; | ||
1120 | fn go(world: &WorldSnapshot) { go(w<|>) } | ||
1121 | "#, | ||
1122 | expect![[r#" | ||
1123 | bn world [type+name] | ||
1124 | st WorldSnapshot [] | ||
1125 | fn go(…) [] | ||
1126 | "#]], | ||
1127 | ); | ||
1128 | } | ||
1129 | |||
1130 | #[test] | ||
1131 | fn too_many_arguments() { | ||
1132 | check_scores( | ||
1133 | r#" | ||
1134 | struct Foo; | ||
1135 | fn f(foo: &Foo) { f(foo, w<|>) } | ||
1136 | "#, | ||
1137 | expect![[r#" | ||
1138 | st Foo [] | ||
1139 | fn f(…) [] | ||
1140 | bn foo [] | ||
1141 | "#]], | ||
1142 | ); | ||
1143 | } | ||
1144 | |||
1145 | #[test] | ||
1146 | fn guesses_macro_braces() { | ||
1147 | check_edit( | ||
1148 | "vec!", | ||
1149 | r#" | ||
1150 | /// Creates a [`Vec`] containing the arguments. | ||
1151 | /// | ||
1152 | /// ``` | ||
1153 | /// let v = vec![1, 2, 3]; | ||
1154 | /// assert_eq!(v[0], 1); | ||
1155 | /// assert_eq!(v[1], 2); | ||
1156 | /// assert_eq!(v[2], 3); | ||
1157 | /// ``` | ||
1158 | macro_rules! vec { () => {} } | ||
1159 | |||
1160 | fn fn main() { v<|> } | ||
1161 | "#, | ||
1162 | r#" | ||
1163 | /// Creates a [`Vec`] containing the arguments. | ||
1164 | /// | ||
1165 | /// ``` | ||
1166 | /// let v = vec![1, 2, 3]; | ||
1167 | /// assert_eq!(v[0], 1); | ||
1168 | /// assert_eq!(v[1], 2); | ||
1169 | /// assert_eq!(v[2], 3); | ||
1170 | /// ``` | ||
1171 | macro_rules! vec { () => {} } | ||
1172 | |||
1173 | fn fn main() { vec![$0] } | ||
1174 | "#, | ||
1175 | ); | ||
1176 | |||
1177 | check_edit( | ||
1178 | "foo!", | ||
1179 | r#" | ||
1180 | /// Foo | ||
1181 | /// | ||
1182 | /// Don't call `fooo!()` `fooo!()`, or `_foo![]` `_foo![]`, | ||
1183 | /// call as `let _=foo! { hello world };` | ||
1184 | macro_rules! foo { () => {} } | ||
1185 | fn main() { <|> } | ||
1186 | "#, | ||
1187 | r#" | ||
1188 | /// Foo | ||
1189 | /// | ||
1190 | /// Don't call `fooo!()` `fooo!()`, or `_foo![]` `_foo![]`, | ||
1191 | /// call as `let _=foo! { hello world };` | ||
1192 | macro_rules! foo { () => {} } | ||
1193 | fn main() { foo! {$0} } | ||
1194 | "#, | ||
1195 | ) | ||
1196 | } | ||
1197 | } | ||