aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_ide/src/completion
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_ide/src/completion')
-rw-r--r--crates/ra_ide/src/completion/complete_attribute.rs861
-rw-r--r--crates/ra_ide/src/completion/complete_dot.rs994
-rw-r--r--crates/ra_ide/src/completion/complete_fn_param.rs131
-rw-r--r--crates/ra_ide/src/completion/complete_keyword.rs1102
-rw-r--r--crates/ra_ide/src/completion/complete_macro_in_item_position.rs137
-rw-r--r--crates/ra_ide/src/completion/complete_pattern.rs126
-rw-r--r--crates/ra_ide/src/completion/complete_postfix.rs639
-rw-r--r--crates/ra_ide/src/completion/complete_qualified_path.rs1506
-rw-r--r--crates/ra_ide/src/completion/complete_record.rs546
-rw-r--r--crates/ra_ide/src/completion/complete_snippet.rs106
-rw-r--r--crates/ra_ide/src/completion/complete_trait_impl.rs464
-rw-r--r--crates/ra_ide/src/completion/complete_unqualified_path.rs1615
-rw-r--r--crates/ra_ide/src/completion/completion_context.rs83
-rw-r--r--crates/ra_ide/src/completion/completion_item.rs32
-rw-r--r--crates/ra_ide/src/completion/patterns.rs194
-rw-r--r--crates/ra_ide/src/completion/presentation.rs1639
-rw-r--r--crates/ra_ide/src/completion/test_utils.rs111
17 files changed, 3450 insertions, 6836 deletions
diff --git a/crates/ra_ide/src/completion/complete_attribute.rs b/crates/ra_ide/src/completion/complete_attribute.rs
index fb3f0b743..d268c92be 100644
--- a/crates/ra_ide/src/completion/complete_attribute.rs
+++ b/crates/ra_ide/src/completion/complete_attribute.rs
@@ -20,6 +20,7 @@ pub(super) fn complete_attribute(acc: &mut Completions, ctx: &CompletionContext)
20 { 20 {
21 complete_derive(acc, ctx, token_tree) 21 complete_derive(acc, ctx, token_tree)
22 } 22 }
23 (_, Some(ast::AttrInput::TokenTree(_token_tree))) => {}
23 _ => complete_attribute_start(acc, ctx, attribute), 24 _ => complete_attribute_start(acc, ctx, attribute),
24 } 25 }
25 Some(()) 26 Some(())
@@ -34,6 +35,10 @@ fn complete_attribute_start(acc: &mut Completions, ctx: &CompletionContext, attr
34 ) 35 )
35 .kind(CompletionItemKind::Attribute); 36 .kind(CompletionItemKind::Attribute);
36 37
38 if let Some(lookup) = attr_completion.lookup {
39 item = item.lookup_by(lookup);
40 }
41
37 match (attr_completion.snippet, ctx.config.snippet_cap) { 42 match (attr_completion.snippet, ctx.config.snippet_cap) {
38 (Some(snippet), Some(cap)) => { 43 (Some(snippet), Some(cap)) => {
39 item = item.insert_snippet(cap, snippet); 44 item = item.insert_snippet(cap, snippet);
@@ -41,7 +46,7 @@ fn complete_attribute_start(acc: &mut Completions, ctx: &CompletionContext, attr
41 _ => {} 46 _ => {}
42 } 47 }
43 48
44 if attribute.kind() == ast::AttrKind::Inner || !attr_completion.should_be_inner { 49 if attribute.kind() == ast::AttrKind::Inner || !attr_completion.prefer_inner {
45 acc.add(item); 50 acc.add(item);
46 } 51 }
47 } 52 }
@@ -49,85 +54,74 @@ fn complete_attribute_start(acc: &mut Completions, ctx: &CompletionContext, attr
49 54
50struct AttrCompletion { 55struct AttrCompletion {
51 label: &'static str, 56 label: &'static str,
57 lookup: Option<&'static str>,
58 snippet: Option<&'static str>,
59 prefer_inner: bool,
60}
61
62impl AttrCompletion {
63 const fn prefer_inner(self) -> AttrCompletion {
64 AttrCompletion { prefer_inner: true, ..self }
65 }
66}
67
68const fn attr(
69 label: &'static str,
70 lookup: Option<&'static str>,
52 snippet: Option<&'static str>, 71 snippet: Option<&'static str>,
53 should_be_inner: bool, 72) -> AttrCompletion {
73 AttrCompletion { label, lookup, snippet, prefer_inner: false }
54} 74}
55 75
56const ATTRIBUTES: &[AttrCompletion] = &[ 76const ATTRIBUTES: &[AttrCompletion] = &[
57 AttrCompletion { label: "allow", snippet: Some("allow(${0:lint})"), should_be_inner: false }, 77 attr("allow(…)", Some("allow"), Some("allow(${0:lint})")),
58 AttrCompletion { 78 attr("cfg_attr(…)", Some("cfg_attr"), Some("cfg_attr(${1:predicate}, ${0:attr})")),
59 label: "cfg_attr", 79 attr("cfg(…)", Some("cfg"), Some("cfg(${0:predicate})")),
60 snippet: Some("cfg_attr(${1:predicate}, ${0:attr})"), 80 attr("deny(…)", Some("deny"), Some("deny(${0:lint})")),
61 should_be_inner: false, 81 attr(r#"deprecated = "…""#, Some("deprecated"), Some(r#"deprecated = "${0:reason}""#)),
62 }, 82 attr("derive(…)", Some("derive"), Some(r#"derive(${0:Debug})"#)),
63 AttrCompletion { label: "cfg", snippet: Some("cfg(${0:predicate})"), should_be_inner: false }, 83 attr(r#"doc = "…""#, Some("doc"), Some(r#"doc = "${0:docs}""#)),
64 AttrCompletion { label: "deny", snippet: Some("deny(${0:lint})"), should_be_inner: false }, 84 attr("feature(…)", Some("feature"), Some("feature(${0:flag})")).prefer_inner(),
65 AttrCompletion { 85 attr("forbid(…)", Some("forbid"), Some("forbid(${0:lint})")),
66 label: "deprecated",
67 snippet: Some(r#"deprecated = "${0:reason}""#),
68 should_be_inner: false,
69 },
70 AttrCompletion {
71 label: "derive",
72 snippet: Some(r#"derive(${0:Debug})"#),
73 should_be_inner: false,
74 },
75 AttrCompletion { label: "doc", snippet: Some(r#"doc = "${0:docs}""#), should_be_inner: false },
76 AttrCompletion { label: "feature", snippet: Some("feature(${0:flag})"), should_be_inner: true },
77 AttrCompletion { label: "forbid", snippet: Some("forbid(${0:lint})"), should_be_inner: false },
78 // FIXME: resolve through macro resolution? 86 // FIXME: resolve through macro resolution?
79 AttrCompletion { label: "global_allocator", snippet: None, should_be_inner: true }, 87 attr("global_allocator", None, None).prefer_inner(),
80 AttrCompletion { label: "ignore", snippet: Some("ignore(${0:lint})"), should_be_inner: false }, 88 attr(r#"ignore = "…""#, Some("ignore"), Some(r#"ignore = "${0:reason}""#)),
81 AttrCompletion { label: "inline", snippet: Some("inline(${0:lint})"), should_be_inner: false }, 89 attr("inline(…)", Some("inline"), Some("inline(${0:lint})")),
82 AttrCompletion { 90 attr(r#"link_name = "…""#, Some("link_name"), Some(r#"link_name = "${0:symbol_name}""#)),
83 label: "link_name", 91 attr("link", None, None),
84 snippet: Some(r#"link_name = "${0:symbol_name}""#), 92 attr("macro_export", None, None),
85 should_be_inner: false, 93 attr("macro_use", None, None),
86 }, 94 attr(r#"must_use = "…""#, Some("must_use"), Some(r#"must_use = "${0:reason}""#)),
87 AttrCompletion { label: "link", snippet: None, should_be_inner: false }, 95 attr("no_mangle", None, None),
88 AttrCompletion { label: "macro_export", snippet: None, should_be_inner: false }, 96 attr("no_std", None, None).prefer_inner(),
89 AttrCompletion { label: "macro_use", snippet: None, should_be_inner: false }, 97 attr("non_exhaustive", None, None),
90 AttrCompletion { 98 attr("panic_handler", None, None).prefer_inner(),
91 label: "must_use", 99 attr("path = \"…\"", Some("path"), Some("path =\"${0:path}\"")),
92 snippet: Some(r#"must_use = "${0:reason}""#), 100 attr("proc_macro", None, None),
93 should_be_inner: false, 101 attr("proc_macro_attribute", None, None),
94 }, 102 attr("proc_macro_derive(…)", Some("proc_macro_derive"), Some("proc_macro_derive(${0:Trait})")),
95 AttrCompletion { label: "no_mangle", snippet: None, should_be_inner: false }, 103 attr("recursion_limit = …", Some("recursion_limit"), Some("recursion_limit = ${0:128}"))
96 AttrCompletion { label: "no_std", snippet: None, should_be_inner: true }, 104 .prefer_inner(),
97 AttrCompletion { label: "non_exhaustive", snippet: None, should_be_inner: false }, 105 attr("repr(…)", Some("repr"), Some("repr(${0:C})")),
98 AttrCompletion { label: "panic_handler", snippet: None, should_be_inner: true }, 106 attr(
99 AttrCompletion { label: "path", snippet: Some("path =\"${0:path}\""), should_be_inner: false }, 107 "should_panic(…)",
100 AttrCompletion { label: "proc_macro", snippet: None, should_be_inner: false }, 108 Some("should_panic"),
101 AttrCompletion { label: "proc_macro_attribute", snippet: None, should_be_inner: false }, 109 Some(r#"should_panic(expected = "${0:reason}")"#),
102 AttrCompletion { 110 ),
103 label: "proc_macro_derive", 111 attr(
104 snippet: Some("proc_macro_derive(${0:Trait})"), 112 r#"target_feature = "…""#,
105 should_be_inner: false, 113 Some("target_feature"),
106 }, 114 Some("target_feature = \"${0:feature}\""),
107 AttrCompletion { 115 ),
108 label: "recursion_limit", 116 attr("test", None, None),
109 snippet: Some("recursion_limit = ${0:128}"), 117 attr("used", None, None),
110 should_be_inner: true, 118 attr("warn(…)", Some("warn"), Some("warn(${0:lint})")),
111 }, 119 attr(
112 AttrCompletion { label: "repr", snippet: Some("repr(${0:C})"), should_be_inner: false }, 120 r#"windows_subsystem = "…""#,
113 AttrCompletion { 121 Some("windows_subsystem"),
114 label: "should_panic", 122 Some(r#"windows_subsystem = "${0:subsystem}""#),
115 snippet: Some(r#"should_panic(expected = "${0:reason}")"#), 123 )
116 should_be_inner: false, 124 .prefer_inner(),
117 },
118 AttrCompletion {
119 label: "target_feature",
120 snippet: Some("target_feature = \"${0:feature}\""),
121 should_be_inner: false,
122 },
123 AttrCompletion { label: "test", snippet: None, should_be_inner: false },
124 AttrCompletion { label: "used", snippet: None, should_be_inner: false },
125 AttrCompletion { label: "warn", snippet: Some("warn(${0:lint})"), should_be_inner: false },
126 AttrCompletion {
127 label: "windows_subsystem",
128 snippet: Some(r#"windows_subsystem = "${0:subsystem}""#),
129 should_be_inner: true,
130 },
131]; 125];
132 126
133fn complete_derive(acc: &mut Completions, ctx: &CompletionContext, derive_input: ast::TokenTree) { 127fn complete_derive(acc: &mut Completions, ctx: &CompletionContext, derive_input: ast::TokenTree) {
@@ -201,7 +195,7 @@ fn parse_derive_input(derive_input: ast::TokenTree) -> Result<FxHashSet<String>,
201 195
202fn get_derive_names_in_scope(ctx: &CompletionContext) -> FxHashSet<String> { 196fn get_derive_names_in_scope(ctx: &CompletionContext) -> FxHashSet<String> {
203 let mut result = FxHashSet::default(); 197 let mut result = FxHashSet::default();
204 ctx.scope().process_all_names(&mut |name, scope_def| { 198 ctx.scope.process_all_names(&mut |name, scope_def| {
205 if let hir::ScopeDef::MacroDef(mac) = scope_def { 199 if let hir::ScopeDef::MacroDef(mac) = scope_def {
206 if mac.is_derive_macro() { 200 if mac.is_derive_macro() {
207 result.insert(name.to_string()); 201 result.insert(name.to_string());
@@ -232,624 +226,147 @@ const DEFAULT_DERIVE_COMPLETIONS: &[DeriveCompletion] = &[
232 226
233#[cfg(test)] 227#[cfg(test)]
234mod tests { 228mod tests {
235 use crate::completion::{test_utils::do_completion, CompletionItem, CompletionKind}; 229 use expect::{expect, Expect};
236 use insta::assert_debug_snapshot; 230
231 use crate::completion::{test_utils::completion_list, CompletionKind};
237 232
238 fn do_attr_completion(code: &str) -> Vec<CompletionItem> { 233 fn check(ra_fixture: &str, expect: Expect) {
239 do_completion(code, CompletionKind::Attribute) 234 let actual = completion_list(ra_fixture, CompletionKind::Attribute);
235 expect.assert_eq(&actual);
240 } 236 }
241 237
242 #[test] 238 #[test]
243 fn empty_derive_completion() { 239 fn empty_derive_completion() {
244 assert_debug_snapshot!( 240 check(
245 do_attr_completion( 241 r#"
246 r" 242#[derive(<|>)]
247 #[derive(<|>)] 243struct Test {}
248 struct Test {} 244 "#,
249 ", 245 expect![[r#"
250 ), 246 at Clone
251 @r###" 247 at Copy, Clone
252 [ 248 at Debug
253 CompletionItem { 249 at Default
254 label: "Clone", 250 at Eq, PartialEq
255 source_range: 30..30, 251 at Hash
256 delete: 30..30, 252 at Ord, PartialOrd, Eq, PartialEq
257 insert: "Clone", 253 at PartialEq
258 kind: Attribute, 254 at PartialOrd, PartialEq
259 }, 255 "#]],
260 CompletionItem {
261 label: "Copy, Clone",
262 source_range: 30..30,
263 delete: 30..30,
264 insert: "Copy, Clone",
265 kind: Attribute,
266 },
267 CompletionItem {
268 label: "Debug",
269 source_range: 30..30,
270 delete: 30..30,
271 insert: "Debug",
272 kind: Attribute,
273 },
274 CompletionItem {
275 label: "Default",
276 source_range: 30..30,
277 delete: 30..30,
278 insert: "Default",
279 kind: Attribute,
280 },
281 CompletionItem {
282 label: "Eq, PartialEq",
283 source_range: 30..30,
284 delete: 30..30,
285 insert: "Eq, PartialEq",
286 kind: Attribute,
287 },
288 CompletionItem {
289 label: "Hash",
290 source_range: 30..30,
291 delete: 30..30,
292 insert: "Hash",
293 kind: Attribute,
294 },
295 CompletionItem {
296 label: "Ord, PartialOrd, Eq, PartialEq",
297 source_range: 30..30,
298 delete: 30..30,
299 insert: "Ord, PartialOrd, Eq, PartialEq",
300 kind: Attribute,
301 },
302 CompletionItem {
303 label: "PartialEq",
304 source_range: 30..30,
305 delete: 30..30,
306 insert: "PartialEq",
307 kind: Attribute,
308 },
309 CompletionItem {
310 label: "PartialOrd, PartialEq",
311 source_range: 30..30,
312 delete: 30..30,
313 insert: "PartialOrd, PartialEq",
314 kind: Attribute,
315 },
316 ]
317 "###
318 ); 256 );
319 } 257 }
320 258
321 #[test] 259 #[test]
322 fn no_completion_for_incorrect_derive() { 260 fn no_completion_for_incorrect_derive() {
323 assert_debug_snapshot!( 261 check(
324 do_attr_completion( 262 r#"
325 r" 263#[derive{<|>)]
326 #[derive{<|>)] 264struct Test {}
327 struct Test {} 265"#,
328 ", 266 expect![[r#""#]],
329 ), 267 )
330 @"[]"
331 );
332 } 268 }
333 269
334 #[test] 270 #[test]
335 fn derive_with_input_completion() { 271 fn derive_with_input_completion() {
336 assert_debug_snapshot!( 272 check(
337 do_attr_completion( 273 r#"
338 r" 274#[derive(serde::Serialize, PartialEq, <|>)]
339 #[derive(serde::Serialize, PartialEq, <|>)] 275struct Test {}
340 struct Test {} 276"#,
341 ", 277 expect![[r#"
342 ), 278 at Clone
343 @r###" 279 at Copy, Clone
344 [ 280 at Debug
345 CompletionItem { 281 at Default
346 label: "Clone", 282 at Eq
347 source_range: 59..59, 283 at Hash
348 delete: 59..59, 284 at Ord, PartialOrd, Eq
349 insert: "Clone", 285 at PartialOrd
350 kind: Attribute, 286 "#]],
351 }, 287 )
352 CompletionItem {
353 label: "Copy, Clone",
354 source_range: 59..59,
355 delete: 59..59,
356 insert: "Copy, Clone",
357 kind: Attribute,
358 },
359 CompletionItem {
360 label: "Debug",
361 source_range: 59..59,
362 delete: 59..59,
363 insert: "Debug",
364 kind: Attribute,
365 },
366 CompletionItem {
367 label: "Default",
368 source_range: 59..59,
369 delete: 59..59,
370 insert: "Default",
371 kind: Attribute,
372 },
373 CompletionItem {
374 label: "Eq",
375 source_range: 59..59,
376 delete: 59..59,
377 insert: "Eq",
378 kind: Attribute,
379 },
380 CompletionItem {
381 label: "Hash",
382 source_range: 59..59,
383 delete: 59..59,
384 insert: "Hash",
385 kind: Attribute,
386 },
387 CompletionItem {
388 label: "Ord, PartialOrd, Eq",
389 source_range: 59..59,
390 delete: 59..59,
391 insert: "Ord, PartialOrd, Eq",
392 kind: Attribute,
393 },
394 CompletionItem {
395 label: "PartialOrd",
396 source_range: 59..59,
397 delete: 59..59,
398 insert: "PartialOrd",
399 kind: Attribute,
400 },
401 ]
402 "###
403 );
404 } 288 }
405 289
406 #[test] 290 #[test]
407 fn test_attribute_completion() { 291 fn test_attribute_completion() {
408 assert_debug_snapshot!( 292 check(
409 do_attr_completion( 293 r#"#[<|>]"#,
410 r" 294 expect![[r#"
411 #[<|>] 295 at allow(…)
412 ", 296 at cfg(…)
413 ), 297 at cfg_attr(…)
414 @r###" 298 at deny(…)
415 [ 299 at deprecated = "…"
416 CompletionItem { 300 at derive(…)
417 label: "allow", 301 at doc = "…"
418 source_range: 19..19, 302 at forbid(…)
419 delete: 19..19, 303 at ignore = "…"
420 insert: "allow(${0:lint})", 304 at inline(…)
421 kind: Attribute, 305 at link
422 }, 306 at link_name = "…"
423 CompletionItem { 307 at macro_export
424 label: "cfg", 308 at macro_use
425 source_range: 19..19, 309 at must_use = "…"
426 delete: 19..19, 310 at no_mangle
427 insert: "cfg(${0:predicate})", 311 at non_exhaustive
428 kind: Attribute, 312 at path = "…"
429 }, 313 at proc_macro
430 CompletionItem { 314 at proc_macro_attribute
431 label: "cfg_attr", 315 at proc_macro_derive(…)
432 source_range: 19..19, 316 at repr(…)
433 delete: 19..19, 317 at should_panic(…)
434 insert: "cfg_attr(${1:predicate}, ${0:attr})", 318 at target_feature = "…"
435 kind: Attribute, 319 at test
436 }, 320 at used
437 CompletionItem { 321 at warn(…)
438 label: "deny", 322 "#]],
439 source_range: 19..19, 323 )
440 delete: 19..19, 324 }
441 insert: "deny(${0:lint})", 325
442 kind: Attribute, 326 #[test]
443 }, 327 fn test_attribute_completion_inside_nested_attr() {
444 CompletionItem { 328 check(r#"#[allow(<|>)]"#, expect![[]])
445 label: "deprecated",
446 source_range: 19..19,
447 delete: 19..19,
448 insert: "deprecated = \"${0:reason}\"",
449 kind: Attribute,
450 },
451 CompletionItem {
452 label: "derive",
453 source_range: 19..19,
454 delete: 19..19,
455 insert: "derive(${0:Debug})",
456 kind: Attribute,
457 },
458 CompletionItem {
459 label: "doc",
460 source_range: 19..19,
461 delete: 19..19,
462 insert: "doc = \"${0:docs}\"",
463 kind: Attribute,
464 },
465 CompletionItem {
466 label: "forbid",
467 source_range: 19..19,
468 delete: 19..19,
469 insert: "forbid(${0:lint})",
470 kind: Attribute,
471 },
472 CompletionItem {
473 label: "ignore",
474 source_range: 19..19,
475 delete: 19..19,
476 insert: "ignore(${0:lint})",
477 kind: Attribute,
478 },
479 CompletionItem {
480 label: "inline",
481 source_range: 19..19,
482 delete: 19..19,
483 insert: "inline(${0:lint})",
484 kind: Attribute,
485 },
486 CompletionItem {
487 label: "link",
488 source_range: 19..19,
489 delete: 19..19,
490 insert: "link",
491 kind: Attribute,
492 },
493 CompletionItem {
494 label: "link_name",
495 source_range: 19..19,
496 delete: 19..19,
497 insert: "link_name = \"${0:symbol_name}\"",
498 kind: Attribute,
499 },
500 CompletionItem {
501 label: "macro_export",
502 source_range: 19..19,
503 delete: 19..19,
504 insert: "macro_export",
505 kind: Attribute,
506 },
507 CompletionItem {
508 label: "macro_use",
509 source_range: 19..19,
510 delete: 19..19,
511 insert: "macro_use",
512 kind: Attribute,
513 },
514 CompletionItem {
515 label: "must_use",
516 source_range: 19..19,
517 delete: 19..19,
518 insert: "must_use = \"${0:reason}\"",
519 kind: Attribute,
520 },
521 CompletionItem {
522 label: "no_mangle",
523 source_range: 19..19,
524 delete: 19..19,
525 insert: "no_mangle",
526 kind: Attribute,
527 },
528 CompletionItem {
529 label: "non_exhaustive",
530 source_range: 19..19,
531 delete: 19..19,
532 insert: "non_exhaustive",
533 kind: Attribute,
534 },
535 CompletionItem {
536 label: "path",
537 source_range: 19..19,
538 delete: 19..19,
539 insert: "path =\"${0:path}\"",
540 kind: Attribute,
541 },
542 CompletionItem {
543 label: "proc_macro",
544 source_range: 19..19,
545 delete: 19..19,
546 insert: "proc_macro",
547 kind: Attribute,
548 },
549 CompletionItem {
550 label: "proc_macro_attribute",
551 source_range: 19..19,
552 delete: 19..19,
553 insert: "proc_macro_attribute",
554 kind: Attribute,
555 },
556 CompletionItem {
557 label: "proc_macro_derive",
558 source_range: 19..19,
559 delete: 19..19,
560 insert: "proc_macro_derive(${0:Trait})",
561 kind: Attribute,
562 },
563 CompletionItem {
564 label: "repr",
565 source_range: 19..19,
566 delete: 19..19,
567 insert: "repr(${0:C})",
568 kind: Attribute,
569 },
570 CompletionItem {
571 label: "should_panic",
572 source_range: 19..19,
573 delete: 19..19,
574 insert: "should_panic(expected = \"${0:reason}\")",
575 kind: Attribute,
576 },
577 CompletionItem {
578 label: "target_feature",
579 source_range: 19..19,
580 delete: 19..19,
581 insert: "target_feature = \"${0:feature}\"",
582 kind: Attribute,
583 },
584 CompletionItem {
585 label: "test",
586 source_range: 19..19,
587 delete: 19..19,
588 insert: "test",
589 kind: Attribute,
590 },
591 CompletionItem {
592 label: "used",
593 source_range: 19..19,
594 delete: 19..19,
595 insert: "used",
596 kind: Attribute,
597 },
598 CompletionItem {
599 label: "warn",
600 source_range: 19..19,
601 delete: 19..19,
602 insert: "warn(${0:lint})",
603 kind: Attribute,
604 },
605 ]
606 "###
607 );
608 } 329 }
609 330
610 #[test] 331 #[test]
611 fn test_inner_attribute_completion() { 332 fn test_inner_attribute_completion() {
612 assert_debug_snapshot!( 333 check(
613 do_attr_completion( 334 r"#![<|>]",
614 r" 335 expect![[r#"
615 #![<|>] 336 at allow(…)
616 ", 337 at cfg(…)
617 ), 338 at cfg_attr(…)
618 @r###" 339 at deny(…)
619 [ 340 at deprecated = "…"
620 CompletionItem { 341 at derive(…)
621 label: "allow", 342 at doc = "…"
622 source_range: 20..20, 343 at feature(…)
623 delete: 20..20, 344 at forbid(…)
624 insert: "allow(${0:lint})", 345 at global_allocator
625 kind: Attribute, 346 at ignore = "…"
626 }, 347 at inline(…)
627 CompletionItem { 348 at link
628 label: "cfg", 349 at link_name = "…"
629 source_range: 20..20, 350 at macro_export
630 delete: 20..20, 351 at macro_use
631 insert: "cfg(${0:predicate})", 352 at must_use = "…"
632 kind: Attribute, 353 at no_mangle
633 }, 354 at no_std
634 CompletionItem { 355 at non_exhaustive
635 label: "cfg_attr", 356 at panic_handler
636 source_range: 20..20, 357 at path = "…"
637 delete: 20..20, 358 at proc_macro
638 insert: "cfg_attr(${1:predicate}, ${0:attr})", 359 at proc_macro_attribute
639 kind: Attribute, 360 at proc_macro_derive(…)
640 }, 361 at recursion_limit = …
641 CompletionItem { 362 at repr(…)
642 label: "deny", 363 at should_panic(…)
643 source_range: 20..20, 364 at target_feature = "…"
644 delete: 20..20, 365 at test
645 insert: "deny(${0:lint})", 366 at used
646 kind: Attribute, 367 at warn(…)
647 }, 368 at windows_subsystem = "…"
648 CompletionItem { 369 "#]],
649 label: "deprecated",
650 source_range: 20..20,
651 delete: 20..20,
652 insert: "deprecated = \"${0:reason}\"",
653 kind: Attribute,
654 },
655 CompletionItem {
656 label: "derive",
657 source_range: 20..20,
658 delete: 20..20,
659 insert: "derive(${0:Debug})",
660 kind: Attribute,
661 },
662 CompletionItem {
663 label: "doc",
664 source_range: 20..20,
665 delete: 20..20,
666 insert: "doc = \"${0:docs}\"",
667 kind: Attribute,
668 },
669 CompletionItem {
670 label: "feature",
671 source_range: 20..20,
672 delete: 20..20,
673 insert: "feature(${0:flag})",
674 kind: Attribute,
675 },
676 CompletionItem {
677 label: "forbid",
678 source_range: 20..20,
679 delete: 20..20,
680 insert: "forbid(${0:lint})",
681 kind: Attribute,
682 },
683 CompletionItem {
684 label: "global_allocator",
685 source_range: 20..20,
686 delete: 20..20,
687 insert: "global_allocator",
688 kind: Attribute,
689 },
690 CompletionItem {
691 label: "ignore",
692 source_range: 20..20,
693 delete: 20..20,
694 insert: "ignore(${0:lint})",
695 kind: Attribute,
696 },
697 CompletionItem {
698 label: "inline",
699 source_range: 20..20,
700 delete: 20..20,
701 insert: "inline(${0:lint})",
702 kind: Attribute,
703 },
704 CompletionItem {
705 label: "link",
706 source_range: 20..20,
707 delete: 20..20,
708 insert: "link",
709 kind: Attribute,
710 },
711 CompletionItem {
712 label: "link_name",
713 source_range: 20..20,
714 delete: 20..20,
715 insert: "link_name = \"${0:symbol_name}\"",
716 kind: Attribute,
717 },
718 CompletionItem {
719 label: "macro_export",
720 source_range: 20..20,
721 delete: 20..20,
722 insert: "macro_export",
723 kind: Attribute,
724 },
725 CompletionItem {
726 label: "macro_use",
727 source_range: 20..20,
728 delete: 20..20,
729 insert: "macro_use",
730 kind: Attribute,
731 },
732 CompletionItem {
733 label: "must_use",
734 source_range: 20..20,
735 delete: 20..20,
736 insert: "must_use = \"${0:reason}\"",
737 kind: Attribute,
738 },
739 CompletionItem {
740 label: "no_mangle",
741 source_range: 20..20,
742 delete: 20..20,
743 insert: "no_mangle",
744 kind: Attribute,
745 },
746 CompletionItem {
747 label: "no_std",
748 source_range: 20..20,
749 delete: 20..20,
750 insert: "no_std",
751 kind: Attribute,
752 },
753 CompletionItem {
754 label: "non_exhaustive",
755 source_range: 20..20,
756 delete: 20..20,
757 insert: "non_exhaustive",
758 kind: Attribute,
759 },
760 CompletionItem {
761 label: "panic_handler",
762 source_range: 20..20,
763 delete: 20..20,
764 insert: "panic_handler",
765 kind: Attribute,
766 },
767 CompletionItem {
768 label: "path",
769 source_range: 20..20,
770 delete: 20..20,
771 insert: "path =\"${0:path}\"",
772 kind: Attribute,
773 },
774 CompletionItem {
775 label: "proc_macro",
776 source_range: 20..20,
777 delete: 20..20,
778 insert: "proc_macro",
779 kind: Attribute,
780 },
781 CompletionItem {
782 label: "proc_macro_attribute",
783 source_range: 20..20,
784 delete: 20..20,
785 insert: "proc_macro_attribute",
786 kind: Attribute,
787 },
788 CompletionItem {
789 label: "proc_macro_derive",
790 source_range: 20..20,
791 delete: 20..20,
792 insert: "proc_macro_derive(${0:Trait})",
793 kind: Attribute,
794 },
795 CompletionItem {
796 label: "recursion_limit",
797 source_range: 20..20,
798 delete: 20..20,
799 insert: "recursion_limit = ${0:128}",
800 kind: Attribute,
801 },
802 CompletionItem {
803 label: "repr",
804 source_range: 20..20,
805 delete: 20..20,
806 insert: "repr(${0:C})",
807 kind: Attribute,
808 },
809 CompletionItem {
810 label: "should_panic",
811 source_range: 20..20,
812 delete: 20..20,
813 insert: "should_panic(expected = \"${0:reason}\")",
814 kind: Attribute,
815 },
816 CompletionItem {
817 label: "target_feature",
818 source_range: 20..20,
819 delete: 20..20,
820 insert: "target_feature = \"${0:feature}\"",
821 kind: Attribute,
822 },
823 CompletionItem {
824 label: "test",
825 source_range: 20..20,
826 delete: 20..20,
827 insert: "test",
828 kind: Attribute,
829 },
830 CompletionItem {
831 label: "used",
832 source_range: 20..20,
833 delete: 20..20,
834 insert: "used",
835 kind: Attribute,
836 },
837 CompletionItem {
838 label: "warn",
839 source_range: 20..20,
840 delete: 20..20,
841 insert: "warn(${0:lint})",
842 kind: Attribute,
843 },
844 CompletionItem {
845 label: "windows_subsystem",
846 source_range: 20..20,
847 delete: 20..20,
848 insert: "windows_subsystem = \"${0:subsystem}\"",
849 kind: Attribute,
850 },
851 ]
852 "###
853 ); 370 );
854 } 371 }
855} 372}
diff --git a/crates/ra_ide/src/completion/complete_dot.rs b/crates/ra_ide/src/completion/complete_dot.rs
index 05f825c6f..532665285 100644
--- a/crates/ra_ide/src/completion/complete_dot.rs
+++ b/crates/ra_ide/src/completion/complete_dot.rs
@@ -1,17 +1,12 @@
1//! FIXME: write short doc here 1//! Completes references after dot (fields and method calls).
2 2
3use hir::{HasVisibility, Type}; 3use hir::{HasVisibility, Type};
4
5use crate::{
6 completion::{
7 completion_context::CompletionContext,
8 completion_item::{CompletionKind, Completions},
9 },
10 CompletionItem,
11};
12use rustc_hash::FxHashSet; 4use rustc_hash::FxHashSet;
5use test_utils::mark;
13 6
14/// Complete dot accesses, i.e. fields or methods (and .await syntax). 7use crate::completion::{completion_context::CompletionContext, completion_item::Completions};
8
9/// Complete dot accesses, i.e. fields or methods.
15pub(super) fn complete_dot(acc: &mut Completions, ctx: &CompletionContext) { 10pub(super) fn complete_dot(acc: &mut Completions, ctx: &CompletionContext) {
16 let dot_receiver = match &ctx.dot_receiver { 11 let dot_receiver = match &ctx.dot_receiver {
17 Some(expr) => expr, 12 Some(expr) => expr,
@@ -23,24 +18,18 @@ pub(super) fn complete_dot(acc: &mut Completions, ctx: &CompletionContext) {
23 _ => return, 18 _ => return,
24 }; 19 };
25 20
26 if !ctx.is_call { 21 if ctx.is_call {
22 mark::hit!(test_no_struct_field_completion_for_method_call);
23 } else {
27 complete_fields(acc, ctx, &receiver_ty); 24 complete_fields(acc, ctx, &receiver_ty);
28 } 25 }
29 complete_methods(acc, ctx, &receiver_ty); 26 complete_methods(acc, ctx, &receiver_ty);
30
31 // Suggest .await syntax for types that implement Future trait
32 if receiver_ty.impls_future(ctx.db) {
33 CompletionItem::new(CompletionKind::Keyword, ctx.source_range(), "await")
34 .detail("expr.await")
35 .insert_text("await")
36 .add_to(acc);
37 }
38} 27}
39 28
40fn complete_fields(acc: &mut Completions, ctx: &CompletionContext, receiver: &Type) { 29fn complete_fields(acc: &mut Completions, ctx: &CompletionContext, receiver: &Type) {
41 for receiver in receiver.autoderef(ctx.db) { 30 for receiver in receiver.autoderef(ctx.db) {
42 for (field, ty) in receiver.fields(ctx.db) { 31 for (field, ty) in receiver.fields(ctx.db) {
43 if ctx.scope().module().map_or(false, |m| !field.is_visible_from(ctx.db, m)) { 32 if ctx.scope.module().map_or(false, |m| !field.is_visible_from(ctx.db, m)) {
44 // Skip private field. FIXME: If the definition location of the 33 // Skip private field. FIXME: If the definition location of the
45 // field is editable, we should show the completion 34 // field is editable, we should show the completion
46 continue; 35 continue;
@@ -57,10 +46,10 @@ fn complete_fields(acc: &mut Completions, ctx: &CompletionContext, receiver: &Ty
57fn complete_methods(acc: &mut Completions, ctx: &CompletionContext, receiver: &Type) { 46fn complete_methods(acc: &mut Completions, ctx: &CompletionContext, receiver: &Type) {
58 if let Some(krate) = ctx.krate { 47 if let Some(krate) = ctx.krate {
59 let mut seen_methods = FxHashSet::default(); 48 let mut seen_methods = FxHashSet::default();
60 let traits_in_scope = ctx.scope().traits_in_scope(); 49 let traits_in_scope = ctx.scope.traits_in_scope();
61 receiver.iterate_method_candidates(ctx.db, krate, &traits_in_scope, None, |_ty, func| { 50 receiver.iterate_method_candidates(ctx.db, krate, &traits_in_scope, None, |_ty, func| {
62 if func.has_self_param(ctx.db) 51 if func.has_self_param(ctx.db)
63 && ctx.scope().module().map_or(true, |m| func.is_visible_from(ctx.db, m)) 52 && ctx.scope.module().map_or(true, |m| func.is_visible_from(ctx.db, m))
64 && seen_methods.insert(func.name(ctx.db)) 53 && seen_methods.insert(func.name(ctx.db))
65 { 54 {
66 acc.add_function(ctx, func, None); 55 acc.add_function(ctx, func, None);
@@ -72,801 +61,356 @@ fn complete_methods(acc: &mut Completions, ctx: &CompletionContext, receiver: &T
72 61
73#[cfg(test)] 62#[cfg(test)]
74mod tests { 63mod tests {
75 use crate::completion::{test_utils::do_completion, CompletionItem, CompletionKind}; 64 use expect::{expect, Expect};
76 use insta::assert_debug_snapshot; 65 use test_utils::mark;
66
67 use crate::completion::{test_utils::completion_list, CompletionKind};
77 68
78 fn do_ref_completion(code: &str) -> Vec<CompletionItem> { 69 fn check(ra_fixture: &str, expect: Expect) {
79 do_completion(code, CompletionKind::Reference) 70 let actual = completion_list(ra_fixture, CompletionKind::Reference);
71 expect.assert_eq(&actual);
80 } 72 }
81 73
82 #[test] 74 #[test]
83 fn test_struct_field_completion() { 75 fn test_struct_field_and_method_completion() {
84 assert_debug_snapshot!( 76 check(
85 do_ref_completion( 77 r#"
86 r" 78struct S { foo: u32 }
87 struct A { the_field: u32 } 79impl S {
88 fn foo(a: A) { 80 fn bar(&self) {}
89 a.<|> 81}
90 } 82fn foo(s: S) { s.<|> }
91 ", 83"#,
92 ), 84 expect![[r#"
93 @r###" 85 me bar() fn bar(&self)
94 [ 86 fd foo u32
95 CompletionItem { 87 "#]],
96 label: "the_field",
97 source_range: 94..94,
98 delete: 94..94,
99 insert: "the_field",
100 kind: Field,
101 detail: "u32",
102 },
103 ]
104 "###
105 ); 88 );
106 } 89 }
107 90
108 #[test] 91 #[test]
109 fn test_struct_field_completion_self() { 92 fn test_struct_field_completion_self() {
110 assert_debug_snapshot!( 93 check(
111 do_ref_completion( 94 r#"
112 r" 95struct S { the_field: (u32,) }
113 struct A { 96impl S {
114 /// This is the_field 97 fn foo(self) { self.<|> }
115 the_field: (u32,) 98}
116 } 99"#,
117 impl A { 100 expect![[r#"
118 fn foo(self) { 101 me foo() fn foo(self)
119 self.<|> 102 fd the_field (u32,)
120 } 103 "#]],
121 } 104 )
122 ",
123 ),
124 @r###"
125 [
126 CompletionItem {
127 label: "foo()",
128 source_range: 187..187,
129 delete: 187..187,
130 insert: "foo()$0",
131 kind: Method,
132 lookup: "foo",
133 detail: "fn foo(self)",
134 },
135 CompletionItem {
136 label: "the_field",
137 source_range: 187..187,
138 delete: 187..187,
139 insert: "the_field",
140 kind: Field,
141 detail: "(u32,)",
142 documentation: Documentation(
143 "This is the_field",
144 ),
145 },
146 ]
147 "###
148 );
149 } 105 }
150 106
151 #[test] 107 #[test]
152 fn test_struct_field_completion_autoderef() { 108 fn test_struct_field_completion_autoderef() {
153 assert_debug_snapshot!( 109 check(
154 do_ref_completion( 110 r#"
155 r" 111struct A { the_field: (u32, i32) }
156 struct A { the_field: (u32, i32) } 112impl A {
157 impl A { 113 fn foo(&self) { self.<|> }
158 fn foo(&self) { 114}
159 self.<|> 115"#,
160 } 116 expect![[r#"
161 } 117 me foo() fn foo(&self)
162 ", 118 fd the_field (u32, i32)
163 ), 119 "#]],
164 @r###" 120 )
165 [
166 CompletionItem {
167 label: "foo()",
168 source_range: 126..126,
169 delete: 126..126,
170 insert: "foo()$0",
171 kind: Method,
172 lookup: "foo",
173 detail: "fn foo(&self)",
174 },
175 CompletionItem {
176 label: "the_field",
177 source_range: 126..126,
178 delete: 126..126,
179 insert: "the_field",
180 kind: Field,
181 detail: "(u32, i32)",
182 },
183 ]
184 "###
185 );
186 } 121 }
187 122
188 #[test] 123 #[test]
189 fn test_no_struct_field_completion_for_method_call() { 124 fn test_no_struct_field_completion_for_method_call() {
190 assert_debug_snapshot!( 125 mark::check!(test_no_struct_field_completion_for_method_call);
191 do_ref_completion( 126 check(
192 r" 127 r#"
193 struct A { the_field: u32 } 128struct A { the_field: u32 }
194 fn foo(a: A) { 129fn foo(a: A) { a.<|>() }
195 a.<|>() 130"#,
196 } 131 expect![[""]],
197 ",
198 ),
199 @"[]"
200 ); 132 );
201 } 133 }
202 134
203 #[test] 135 #[test]
204 fn test_struct_field_visibility_private() { 136 fn test_visibility_filtering() {
205 assert_debug_snapshot!( 137 check(
206 do_ref_completion( 138 r#"
207 r" 139mod inner {
208 mod inner { 140 pub struct A {
209 struct A { 141 private_field: u32,
210 private_field: u32, 142 pub pub_field: u32,
211 pub pub_field: u32, 143 pub(crate) crate_field: u32,
212 pub(crate) crate_field: u32, 144 pub(super) super_field: u32,
213 pub(super) super_field: u32,
214 }
215 }
216 fn foo(a: inner::A) {
217 a.<|>
218 }
219 ",
220 ),
221 @r###"
222 [
223 CompletionItem {
224 label: "crate_field",
225 source_range: 313..313,
226 delete: 313..313,
227 insert: "crate_field",
228 kind: Field,
229 detail: "u32",
230 },
231 CompletionItem {
232 label: "pub_field",
233 source_range: 313..313,
234 delete: 313..313,
235 insert: "pub_field",
236 kind: Field,
237 detail: "u32",
238 },
239 CompletionItem {
240 label: "super_field",
241 source_range: 313..313,
242 delete: 313..313,
243 insert: "super_field",
244 kind: Field,
245 detail: "u32",
246 },
247 ]
248 "###
249 );
250 } 145 }
251 146}
252 #[test] 147fn foo(a: inner::A) { a.<|> }
253 fn test_union_field_completion() { 148"#,
254 assert_debug_snapshot!( 149 expect![[r#"
255 do_ref_completion( 150 fd crate_field u32
256 r" 151 fd pub_field u32
257 union Un { 152 fd super_field u32
258 field: u8, 153 "#]],
259 other: u16,
260 }
261
262 fn foo(u: Un) {
263 u.<|>
264 }
265 ",
266 ),
267 @r###"
268 [
269 CompletionItem {
270 label: "field",
271 source_range: 140..140,
272 delete: 140..140,
273 insert: "field",
274 kind: Field,
275 detail: "u8",
276 },
277 CompletionItem {
278 label: "other",
279 source_range: 140..140,
280 delete: 140..140,
281 insert: "other",
282 kind: Field,
283 detail: "u16",
284 },
285 ]
286 "###
287 ); 154 );
288 }
289 155
290 #[test] 156 check(
291 fn test_method_completion() { 157 r#"
292 assert_debug_snapshot!( 158struct A {}
293 do_ref_completion( 159mod m {
294 r" 160 impl super::A {
295 struct A {} 161 fn private_method(&self) {}
296 impl A { 162 pub(super) fn the_method(&self) {}
297 fn the_method(&self) {} 163 }
298 } 164}
299 fn foo(a: A) { 165fn foo(a: A) { a.<|> }
300 a.<|> 166"#,
301 } 167 expect![[r#"
302 ", 168 me the_method() pub(super) fn the_method(&self)
303 ), 169 "#]],
304 @r###"
305 [
306 CompletionItem {
307 label: "the_method()",
308 source_range: 144..144,
309 delete: 144..144,
310 insert: "the_method()$0",
311 kind: Method,
312 lookup: "the_method",
313 detail: "fn the_method(&self)",
314 },
315 ]
316 "###
317 ); 170 );
318 } 171 }
319 172
320 #[test] 173 #[test]
321 fn test_method_completion_only_fitting_impls() { 174 fn test_union_field_completion() {
322 assert_debug_snapshot!( 175 check(
323 do_ref_completion( 176 r#"
324 r" 177union U { field: u8, other: u16 }
325 struct A<T> {} 178fn foo(u: U) { u.<|> }
326 impl A<u32> { 179"#,
327 fn the_method(&self) {} 180 expect![[r#"
328 } 181 fd field u8
329 impl A<i32> { 182 fd other u16
330 fn the_other_method(&self) {} 183 "#]],
331 }
332 fn foo(a: A<u32>) {
333 a.<|>
334 }
335 ",
336 ),
337 @r###"
338 [
339 CompletionItem {
340 label: "the_method()",
341 source_range: 243..243,
342 delete: 243..243,
343 insert: "the_method()$0",
344 kind: Method,
345 lookup: "the_method",
346 detail: "fn the_method(&self)",
347 },
348 ]
349 "###
350 ); 184 );
351 } 185 }
352 186
353 #[test] 187 #[test]
354 fn test_method_completion_private() { 188 fn test_method_completion_only_fitting_impls() {
355 assert_debug_snapshot!( 189 check(
356 do_ref_completion( 190 r#"
357 r" 191struct A<T> {}
358 struct A {} 192impl A<u32> {
359 mod m { 193 fn the_method(&self) {}
360 impl super::A { 194}
361 fn private_method(&self) {} 195impl A<i32> {
362 pub(super) fn the_method(&self) {} 196 fn the_other_method(&self) {}
363 } 197}
364 } 198fn foo(a: A<u32>) { a.<|> }
365 fn foo(a: A) { 199"#,
366 a.<|> 200 expect![[r#"
367 } 201 me the_method() fn the_method(&self)
368 ", 202 "#]],
369 ), 203 )
370 @r###"
371 [
372 CompletionItem {
373 label: "the_method()",
374 source_range: 256..256,
375 delete: 256..256,
376 insert: "the_method()$0",
377 kind: Method,
378 lookup: "the_method",
379 detail: "pub(super) fn the_method(&self)",
380 },
381 ]
382 "###
383 );
384 } 204 }
385 205
386 #[test] 206 #[test]
387 fn test_trait_method_completion() { 207 fn test_trait_method_completion() {
388 assert_debug_snapshot!( 208 check(
389 do_ref_completion( 209 r#"
390 r" 210struct A {}
391 struct A {} 211trait Trait { fn the_method(&self); }
392 trait Trait { fn the_method(&self); } 212impl Trait for A {}
393 impl Trait for A {} 213fn foo(a: A) { a.<|> }
394 fn foo(a: A) { 214"#,
395 a.<|> 215 expect![[r#"
396 } 216 me the_method() fn the_method(&self)
397 ", 217 "#]],
398 ),
399 @r###"
400 [
401 CompletionItem {
402 label: "the_method()",
403 source_range: 151..151,
404 delete: 151..151,
405 insert: "the_method()$0",
406 kind: Method,
407 lookup: "the_method",
408 detail: "fn the_method(&self)",
409 },
410 ]
411 "###
412 ); 218 );
413 } 219 }
414 220
415 #[test] 221 #[test]
416 fn test_trait_method_completion_deduplicated() { 222 fn test_trait_method_completion_deduplicated() {
417 assert_debug_snapshot!( 223 check(
418 do_ref_completion( 224 r"
419 r" 225struct A {}
420 struct A {} 226trait Trait { fn the_method(&self); }
421 trait Trait { fn the_method(&self); } 227impl<T> Trait for T {}
422 impl<T> Trait for T {} 228fn foo(a: &A) { a.<|> }
423 fn foo(a: &A) { 229",
424 a.<|> 230 expect![[r#"
425 } 231 me the_method() fn the_method(&self)
426 ", 232 "#]],
427 ),
428 @r###"
429 [
430 CompletionItem {
431 label: "the_method()",
432 source_range: 155..155,
433 delete: 155..155,
434 insert: "the_method()$0",
435 kind: Method,
436 lookup: "the_method",
437 detail: "fn the_method(&self)",
438 },
439 ]
440 "###
441 ); 233 );
442 } 234 }
443 235
444 #[test] 236 #[test]
445 fn completes_trait_method_from_other_module() { 237 fn completes_trait_method_from_other_module() {
446 assert_debug_snapshot!( 238 check(
447 do_ref_completion(
448 r"
449 struct A {}
450 mod m {
451 pub trait Trait { fn the_method(&self); }
452 }
453 use m::Trait;
454 impl Trait for A {}
455 fn foo(a: A) {
456 a.<|>
457 }
458 ",
459 ),
460 @r###"
461 [
462 CompletionItem {
463 label: "the_method()",
464 source_range: 219..219,
465 delete: 219..219,
466 insert: "the_method()$0",
467 kind: Method,
468 lookup: "the_method",
469 detail: "fn the_method(&self)",
470 },
471 ]
472 "###
473 );
474 }
475
476 #[test]
477 fn test_no_non_self_method() {
478 assert_debug_snapshot!(
479 do_ref_completion(
480 r" 239 r"
481 struct A {} 240struct A {}
482 impl A { 241mod m {
483 fn the_method() {} 242 pub trait Trait { fn the_method(&self); }
484 } 243}
485 fn foo(a: A) { 244use m::Trait;
486 a.<|> 245impl Trait for A {}
487 } 246fn foo(a: A) { a.<|> }
488 ", 247",
489 ), 248 expect![[r#"
490 @"[]" 249 me the_method() fn the_method(&self)
250 "#]],
491 ); 251 );
492 } 252 }
493 253
494 #[test] 254 #[test]
495 fn test_method_attr_filtering() { 255 fn test_no_non_self_method() {
496 assert_debug_snapshot!( 256 check(
497 do_ref_completion( 257 r#"
498 r" 258struct A {}
499 struct A {} 259impl A {
500 impl A { 260 fn the_method() {}
501 #[inline] 261}
502 fn the_method(&self) { 262fn foo(a: A) {
503 let x = 1; 263 a.<|>
504 let y = 2; 264}
505 } 265"#,
506 } 266 expect![[""]],
507 fn foo(a: A) {
508 a.<|>
509 }
510 ",
511 ),
512 @r###"
513 [
514 CompletionItem {
515 label: "the_method()",
516 source_range: 249..249,
517 delete: 249..249,
518 insert: "the_method()$0",
519 kind: Method,
520 lookup: "the_method",
521 detail: "fn the_method(&self)",
522 },
523 ]
524 "###
525 ); 267 );
526 } 268 }
527 269
528 #[test] 270 #[test]
529 fn test_tuple_field_completion() { 271 fn test_tuple_field_completion() {
530 assert_debug_snapshot!( 272 check(
531 do_ref_completion( 273 r#"
532 r" 274fn foo() {
533 fn foo() { 275 let b = (0, 3.14);
534 let b = (0, 3.14); 276 b.<|>
535 b.<|> 277}
536 } 278"#,
537 ", 279 expect![[r#"
538 ), 280 fd 0 i32
539 @r###" 281 fd 1 f64
540 [ 282 "#]],
541 CompletionItem { 283 )
542 label: "0",
543 source_range: 75..75,
544 delete: 75..75,
545 insert: "0",
546 kind: Field,
547 detail: "i32",
548 },
549 CompletionItem {
550 label: "1",
551 source_range: 75..75,
552 delete: 75..75,
553 insert: "1",
554 kind: Field,
555 detail: "f64",
556 },
557 ]
558 "###
559 );
560 } 284 }
561 285
562 #[test] 286 #[test]
563 fn test_tuple_field_inference() { 287 fn test_tuple_field_inference() {
564 assert_debug_snapshot!( 288 check(
565 do_ref_completion( 289 r#"
566 r" 290pub struct S;
567 pub struct S; 291impl S { pub fn blah(&self) {} }
568 impl S {
569 pub fn blah(&self) {}
570 }
571 292
572 struct T(S); 293struct T(S);
573 294
574 impl T { 295impl T {
575 fn foo(&self) { 296 fn foo(&self) {
576 // FIXME: This doesn't work without the trailing `a` as `0.` is a float 297 // FIXME: This doesn't work without the trailing `a` as `0.` is a float
577 self.0.a<|> 298 self.0.a<|>
578 }
579 }
580 ",
581 ),
582 @r###"
583 [
584 CompletionItem {
585 label: "blah()",
586 source_range: 299..300,
587 delete: 299..300,
588 insert: "blah()$0",
589 kind: Method,
590 lookup: "blah",
591 detail: "pub fn blah(&self)",
592 },
593 ]
594 "###
595 );
596 } 299 }
597 300}
598 #[test] 301"#,
599 fn test_completion_works_in_consts() { 302 expect![[r#"
600 assert_debug_snapshot!( 303 me blah() pub fn blah(&self)
601 do_ref_completion( 304 "#]],
602 r"
603 struct A { the_field: u32 }
604 const X: u32 = {
605 A { the_field: 92 }.<|>
606 };
607 ",
608 ),
609 @r###"
610 [
611 CompletionItem {
612 label: "the_field",
613 source_range: 106..106,
614 delete: 106..106,
615 insert: "the_field",
616 kind: Field,
617 detail: "u32",
618 },
619 ]
620 "###
621 ); 305 );
622 } 306 }
623 307
624 #[test] 308 #[test]
625 fn test_completion_await_impls_future() { 309 fn test_completion_works_in_consts() {
626 assert_debug_snapshot!( 310 check(
627 do_completion( 311 r#"
628 r###" 312struct A { the_field: u32 }
629 //- /main.rs 313const X: u32 = {
630 use std::future::*; 314 A { the_field: 92 }.<|>
631 struct A {} 315};
632 impl Future for A {} 316"#,
633 fn foo(a: A) { 317 expect![[r#"
634 a.<|> 318 fd the_field u32
635 } 319 "#]],
636
637 //- /std/lib.rs
638 pub mod future {
639 #[lang = "future_trait"]
640 pub trait Future {}
641 }
642 "###, CompletionKind::Keyword),
643 @r###"
644 [
645 CompletionItem {
646 label: "await",
647 source_range: 74..74,
648 delete: 74..74,
649 insert: "await",
650 detail: "expr.await",
651 },
652 ]
653 "###
654 )
655 }
656
657 #[test]
658 fn test_super_super_completion() {
659 assert_debug_snapshot!(
660 do_ref_completion(
661 r"
662 mod a {
663 const A: usize = 0;
664
665 mod b {
666 const B: usize = 0;
667
668 mod c {
669 use super::super::<|>
670 }
671 }
672 }
673 ",
674 ),
675 @r###"
676 [
677 CompletionItem {
678 label: "A",
679 source_range: 217..217,
680 delete: 217..217,
681 insert: "A",
682 kind: Const,
683 },
684 CompletionItem {
685 label: "b",
686 source_range: 217..217,
687 delete: 217..217,
688 insert: "b",
689 kind: Module,
690 },
691 ]
692 "###
693 ); 320 );
694 } 321 }
695 322
696 #[test] 323 #[test]
697 fn works_in_simple_macro_1() { 324 fn works_in_simple_macro_1() {
698 assert_debug_snapshot!( 325 check(
699 do_ref_completion( 326 r#"
700 r" 327macro_rules! m { ($e:expr) => { $e } }
701 macro_rules! m { ($e:expr) => { $e } } 328struct A { the_field: u32 }
702 struct A { the_field: u32 } 329fn foo(a: A) {
703 fn foo(a: A) { 330 m!(a.x<|>)
704 m!(a.x<|>) 331}
705 } 332"#,
706 ", 333 expect![[r#"
707 ), 334 fd the_field u32
708 @r###" 335 "#]],
709 [
710 CompletionItem {
711 label: "the_field",
712 source_range: 156..157,
713 delete: 156..157,
714 insert: "the_field",
715 kind: Field,
716 detail: "u32",
717 },
718 ]
719 "###
720 );
721 }
722
723 #[test]
724 fn works_in_simple_macro_recursive() {
725 assert_debug_snapshot!(
726 do_ref_completion(
727 r"
728 macro_rules! m { ($e:expr) => { $e } }
729 struct A { the_field: u32 }
730 fn foo(a: A) {
731 m!(a.x<|>)
732 }
733 ",
734 ),
735 @r###"
736 [
737 CompletionItem {
738 label: "the_field",
739 source_range: 156..157,
740 delete: 156..157,
741 insert: "the_field",
742 kind: Field,
743 detail: "u32",
744 },
745 ]
746 "###
747 ); 336 );
748 } 337 }
749 338
750 #[test] 339 #[test]
751 fn works_in_simple_macro_2() { 340 fn works_in_simple_macro_2() {
752 // this doesn't work yet because the macro doesn't expand without the token -- maybe it can be fixed with better recovery 341 // this doesn't work yet because the macro doesn't expand without the token -- maybe it can be fixed with better recovery
753 assert_debug_snapshot!( 342 check(
754 do_ref_completion( 343 r#"
755 r" 344macro_rules! m { ($e:expr) => { $e } }
756 macro_rules! m { ($e:expr) => { $e } } 345struct A { the_field: u32 }
757 struct A { the_field: u32 } 346fn foo(a: A) {
758 fn foo(a: A) { 347 m!(a.<|>)
759 m!(a.<|>) 348}
760 } 349"#,
761 ", 350 expect![[r#"
762 ), 351 fd the_field u32
763 @r###" 352 "#]],
764 [
765 CompletionItem {
766 label: "the_field",
767 source_range: 156..156,
768 delete: 156..156,
769 insert: "the_field",
770 kind: Field,
771 detail: "u32",
772 },
773 ]
774 "###
775 ); 353 );
776 } 354 }
777 355
778 #[test] 356 #[test]
779 fn works_in_simple_macro_recursive_1() { 357 fn works_in_simple_macro_recursive_1() {
780 assert_debug_snapshot!( 358 check(
781 do_ref_completion( 359 r#"
782 r" 360macro_rules! m { ($e:expr) => { $e } }
783 macro_rules! m { ($e:expr) => { $e } } 361struct A { the_field: u32 }
784 struct A { the_field: u32 } 362fn foo(a: A) {
785 fn foo(a: A) { 363 m!(m!(m!(a.x<|>)))
786 m!(m!(m!(a.x<|>))) 364}
787 } 365"#,
788 ", 366 expect![[r#"
789 ), 367 fd the_field u32
790 @r###" 368 "#]],
791 [
792 CompletionItem {
793 label: "the_field",
794 source_range: 162..163,
795 delete: 162..163,
796 insert: "the_field",
797 kind: Field,
798 detail: "u32",
799 },
800 ]
801 "###
802 ); 369 );
803 } 370 }
804 371
805 #[test] 372 #[test]
806 fn macro_expansion_resilient() { 373 fn macro_expansion_resilient() {
807 assert_debug_snapshot!( 374 check(
808 do_ref_completion( 375 r#"
809 r" 376macro_rules! dbg {
810 macro_rules! dbg { 377 () => {};
811 () => {}; 378 ($val:expr) => {
812 ($val:expr) => { 379 match $val { tmp => { tmp } }
813 match $val { tmp => { tmp } } 380 };
814 }; 381 // Trailing comma with single argument is ignored
815 // Trailing comma with single argument is ignored 382 ($val:expr,) => { $crate::dbg!($val) };
816 ($val:expr,) => { $crate::dbg!($val) }; 383 ($($val:expr),+ $(,)?) => {
817 ($($val:expr),+ $(,)?) => { 384 ($($crate::dbg!($val)),+,)
818 ($($crate::dbg!($val)),+,) 385 };
819 }; 386}
820 } 387struct A { the_field: u32 }
821 struct A { the_field: u32 } 388fn foo(a: A) {
822 fn foo(a: A) { 389 dbg!(a.<|>)
823 dbg!(a.<|>) 390}
824 } 391"#,
825 ", 392 expect![[r#"
826 ), 393 fd the_field u32
827 @r###" 394 "#]],
828 [
829 CompletionItem {
830 label: "the_field",
831 source_range: 552..552,
832 delete: 552..552,
833 insert: "the_field",
834 kind: Field,
835 detail: "u32",
836 },
837 ]
838 "###
839 ); 395 );
840 } 396 }
841 397
842 #[test] 398 #[test]
843 fn test_method_completion_3547() { 399 fn test_method_completion_issue_3547() {
844 assert_debug_snapshot!( 400 check(
845 do_ref_completion( 401 r#"
846 r" 402struct HashSet<T> {}
847 struct HashSet<T> {} 403impl<T> HashSet<T> {
848 impl<T> HashSet<T> { 404 pub fn the_method(&self) {}
849 pub fn the_method(&self) {} 405}
850 } 406fn foo() {
851 fn foo() { 407 let s: HashSet<_>;
852 let s: HashSet<_>; 408 s.<|>
853 s.<|> 409}
854 } 410"#,
855 ", 411 expect![[r#"
856 ), 412 me the_method() pub fn the_method(&self)
857 @r###" 413 "#]],
858 [
859 CompletionItem {
860 label: "the_method()",
861 source_range: 201..201,
862 delete: 201..201,
863 insert: "the_method()$0",
864 kind: Method,
865 lookup: "the_method",
866 detail: "pub fn the_method(&self)",
867 },
868 ]
869 "###
870 ); 414 );
871 } 415 }
872} 416}
diff --git a/crates/ra_ide/src/completion/complete_fn_param.rs b/crates/ra_ide/src/completion/complete_fn_param.rs
index a661932a3..db2abb4f1 100644
--- a/crates/ra_ide/src/completion/complete_fn_param.rs
+++ b/crates/ra_ide/src/completion/complete_fn_param.rs
@@ -1,4 +1,4 @@
1//! FIXME: write short doc here 1//! See `complete_fn_param`.
2 2
3use ra_syntax::{ 3use ra_syntax::{
4 ast::{self, ModuleItemOwner}, 4 ast::{self, ModuleItemOwner},
@@ -18,6 +18,7 @@ pub(super) fn complete_fn_param(acc: &mut Completions, ctx: &CompletionContext)
18 } 18 }
19 19
20 let mut params = FxHashMap::default(); 20 let mut params = FxHashMap::default();
21 let me = ctx.token.ancestors().find_map(ast::FnDef::cast);
21 for node in ctx.token.parent().ancestors() { 22 for node in ctx.token.parent().ancestors() {
22 let items = match_ast! { 23 let items = match_ast! {
23 match node { 24 match node {
@@ -28,25 +29,26 @@ pub(super) fn complete_fn_param(acc: &mut Completions, ctx: &CompletionContext)
28 }; 29 };
29 for item in items { 30 for item in items {
30 if let ast::ModuleItem::FnDef(func) = item { 31 if let ast::ModuleItem::FnDef(func) = item {
32 if Some(&func) == me.as_ref() {
33 continue;
34 }
31 func.param_list().into_iter().flat_map(|it| it.params()).for_each(|param| { 35 func.param_list().into_iter().flat_map(|it| it.params()).for_each(|param| {
32 let text = param.syntax().text().to_string(); 36 let text = param.syntax().text().to_string();
33 params.entry(text).or_insert((0, param)).0 += 1; 37 params.entry(text).or_insert(param);
34 }) 38 })
35 } 39 }
36 } 40 }
37 } 41 }
42
38 params 43 params
39 .into_iter() 44 .into_iter()
40 .filter_map(|(label, (count, param))| { 45 .filter_map(|(label, param)| {
41 let lookup = param.pat()?.syntax().text().to_string(); 46 let lookup = param.pat()?.syntax().text().to_string();
42 if count < 2 { 47 Some((label, lookup))
43 None
44 } else {
45 Some((label, lookup))
46 }
47 }) 48 })
48 .for_each(|(label, lookup)| { 49 .for_each(|(label, lookup)| {
49 CompletionItem::new(CompletionKind::Magic, ctx.source_range(), label) 50 CompletionItem::new(CompletionKind::Magic, ctx.source_range(), label)
51 .kind(crate::CompletionItemKind::Binding)
50 .lookup_by(lookup) 52 .lookup_by(lookup)
51 .add_to(acc) 53 .add_to(acc)
52 }); 54 });
@@ -54,85 +56,70 @@ pub(super) fn complete_fn_param(acc: &mut Completions, ctx: &CompletionContext)
54 56
55#[cfg(test)] 57#[cfg(test)]
56mod tests { 58mod tests {
57 use crate::completion::{test_utils::do_completion, CompletionItem, CompletionKind}; 59 use expect::{expect, Expect};
58 use insta::assert_debug_snapshot;
59 60
60 fn do_magic_completion(code: &str) -> Vec<CompletionItem> { 61 use crate::completion::{test_utils::completion_list, CompletionKind};
61 do_completion(code, CompletionKind::Magic) 62
63 fn check(ra_fixture: &str, expect: Expect) {
64 let actual = completion_list(ra_fixture, CompletionKind::Magic);
65 expect.assert_eq(&actual);
62 } 66 }
63 67
64 #[test] 68 #[test]
65 fn test_param_completion_last_param() { 69 fn test_param_completion_last_param() {
66 assert_debug_snapshot!( 70 check(
67 do_magic_completion( 71 r#"
68 r" 72fn foo(file_id: FileId) {}
69 fn foo(file_id: FileId) {} 73fn bar(file_id: FileId) {}
70 fn bar(file_id: FileId) {} 74fn baz(file<|>) {}
71 fn baz(file<|>) {} 75"#,
72 ", 76 expect![[r#"
73 ), 77 bn file_id: FileId
74 @r###" 78 "#]],
75 [
76 CompletionItem {
77 label: "file_id: FileId",
78 source_range: 110..114,
79 delete: 110..114,
80 insert: "file_id: FileId",
81 lookup: "file_id",
82 },
83 ]
84 "###
85 ); 79 );
86 } 80 }
87 81
88 #[test] 82 #[test]
89 fn test_param_completion_nth_param() { 83 fn test_param_completion_nth_param() {
90 assert_debug_snapshot!( 84 check(
91 do_magic_completion( 85 r#"
92 r" 86fn foo(file_id: FileId) {}
93 fn foo(file_id: FileId) {} 87fn baz(file<|>, x: i32) {}
94 fn bar(file_id: FileId) {} 88"#,
95 fn baz(file<|>, x: i32) {} 89 expect![[r#"
96 ", 90 bn file_id: FileId
97 ), 91 "#]],
98 @r###"
99 [
100 CompletionItem {
101 label: "file_id: FileId",
102 source_range: 110..114,
103 delete: 110..114,
104 insert: "file_id: FileId",
105 lookup: "file_id",
106 },
107 ]
108 "###
109 ); 92 );
110 } 93 }
111 94
112 #[test] 95 #[test]
113 fn test_param_completion_trait_param() { 96 fn test_param_completion_trait_param() {
114 assert_debug_snapshot!( 97 check(
115 do_magic_completion( 98 r#"
116 r" 99pub(crate) trait SourceRoot {
117 pub(crate) trait SourceRoot { 100 pub fn contains(&self, file_id: FileId) -> bool;
118 pub fn contains(&self, file_id: FileId) -> bool; 101 pub fn module_map(&self) -> &ModuleMap;
119 pub fn module_map(&self) -> &ModuleMap; 102 pub fn lines(&self, file_id: FileId) -> &LineIndex;
120 pub fn lines(&self, file_id: FileId) -> &LineIndex; 103 pub fn syntax(&self, file<|>)
121 pub fn syntax(&self, file<|>) 104}
122 } 105"#,
123 ", 106 expect![[r#"
124 ), 107 bn file_id: FileId
125 @r###" 108 "#]],
126 [
127 CompletionItem {
128 label: "file_id: FileId",
129 source_range: 289..293,
130 delete: 289..293,
131 insert: "file_id: FileId",
132 lookup: "file_id",
133 },
134 ]
135 "###
136 ); 109 );
137 } 110 }
111
112 #[test]
113 fn completes_param_in_inner_function() {
114 check(
115 r#"
116fn outer(text: String) {
117 fn inner(<|>)
118}
119"#,
120 expect![[r#"
121 bn text: String
122 "#]],
123 )
124 }
138} 125}
diff --git a/crates/ra_ide/src/completion/complete_keyword.rs b/crates/ra_ide/src/completion/complete_keyword.rs
index fd95bc410..fcdaeef49 100644
--- a/crates/ra_ide/src/completion/complete_keyword.rs
+++ b/crates/ra_ide/src/completion/complete_keyword.rs
@@ -1,11 +1,7 @@
1//! FIXME: write short doc here 1//! FIXME: write short doc here
2 2
3use ra_syntax::{ 3use ra_syntax::{ast, SyntaxKind};
4 ast::{self, LoopBodyOwner}, 4use test_utils::mark;
5 match_ast, AstNode,
6 SyntaxKind::*,
7 SyntaxToken,
8};
9 5
10use crate::completion::{ 6use crate::completion::{
11 CompletionContext, CompletionItem, CompletionItemKind, CompletionKind, Completions, 7 CompletionContext, CompletionItem, CompletionItemKind, CompletionKind, Completions,
@@ -16,14 +12,14 @@ pub(super) fn complete_use_tree_keyword(acc: &mut Completions, ctx: &CompletionC
16 let source_range = ctx.source_range(); 12 let source_range = ctx.source_range();
17 match (ctx.use_item_syntax.as_ref(), ctx.path_prefix.as_ref()) { 13 match (ctx.use_item_syntax.as_ref(), ctx.path_prefix.as_ref()) {
18 (Some(_), None) => { 14 (Some(_), None) => {
19 CompletionItem::new(CompletionKind::Keyword, source_range, "crate") 15 CompletionItem::new(CompletionKind::Keyword, source_range, "crate::")
20 .kind(CompletionItemKind::Keyword) 16 .kind(CompletionItemKind::Keyword)
21 .insert_text("crate::") 17 .insert_text("crate::")
22 .add_to(acc); 18 .add_to(acc);
23 CompletionItem::new(CompletionKind::Keyword, source_range, "self") 19 CompletionItem::new(CompletionKind::Keyword, source_range, "self")
24 .kind(CompletionItemKind::Keyword) 20 .kind(CompletionItemKind::Keyword)
25 .add_to(acc); 21 .add_to(acc);
26 CompletionItem::new(CompletionKind::Keyword, source_range, "super") 22 CompletionItem::new(CompletionKind::Keyword, source_range, "super::")
27 .kind(CompletionItemKind::Keyword) 23 .kind(CompletionItemKind::Keyword)
28 .insert_text("super::") 24 .insert_text("super::")
29 .add_to(acc); 25 .add_to(acc);
@@ -32,77 +28,147 @@ pub(super) fn complete_use_tree_keyword(acc: &mut Completions, ctx: &CompletionC
32 CompletionItem::new(CompletionKind::Keyword, source_range, "self") 28 CompletionItem::new(CompletionKind::Keyword, source_range, "self")
33 .kind(CompletionItemKind::Keyword) 29 .kind(CompletionItemKind::Keyword)
34 .add_to(acc); 30 .add_to(acc);
35 CompletionItem::new(CompletionKind::Keyword, source_range, "super") 31 CompletionItem::new(CompletionKind::Keyword, source_range, "super::")
36 .kind(CompletionItemKind::Keyword) 32 .kind(CompletionItemKind::Keyword)
37 .insert_text("super::") 33 .insert_text("super::")
38 .add_to(acc); 34 .add_to(acc);
39 } 35 }
40 _ => {} 36 _ => {}
41 } 37 }
42}
43 38
44fn keyword(ctx: &CompletionContext, kw: &str, snippet: &str) -> CompletionItem { 39 // Suggest .await syntax for types that implement Future trait
45 let res = CompletionItem::new(CompletionKind::Keyword, ctx.source_range(), kw) 40 if let Some(receiver) = &ctx.dot_receiver {
46 .kind(CompletionItemKind::Keyword); 41 if let Some(ty) = ctx.sema.type_of_expr(receiver) {
47 42 if ty.impls_future(ctx.db) {
48 match ctx.config.snippet_cap { 43 CompletionItem::new(CompletionKind::Keyword, ctx.source_range(), "await")
49 Some(cap) => res.insert_snippet(cap, snippet), 44 .kind(CompletionItemKind::Keyword)
50 _ => res.insert_text(if snippet.contains('$') { kw } else { snippet }), 45 .detail("expr.await")
46 .insert_text("await")
47 .add_to(acc);
48 }
49 };
51 } 50 }
52 .build()
53} 51}
54 52
55pub(super) fn complete_expr_keyword(acc: &mut Completions, ctx: &CompletionContext) { 53pub(super) fn complete_expr_keyword(acc: &mut Completions, ctx: &CompletionContext) {
56 if !ctx.is_trivial_path { 54 if ctx.token.kind() == SyntaxKind::COMMENT {
55 mark::hit!(no_keyword_completion_in_comments);
57 return; 56 return;
58 } 57 }
59 58
60 let fn_def = match &ctx.function_syntax { 59 let has_trait_or_impl_parent = ctx.has_impl_parent || ctx.has_trait_parent;
61 Some(it) => it, 60 if ctx.trait_as_prev_sibling || ctx.impl_as_prev_sibling {
62 None => return, 61 add_keyword(ctx, acc, "where", "where ");
63 }; 62 return;
64 acc.add(keyword(ctx, "if", "if $0 {}")); 63 }
65 acc.add(keyword(ctx, "match", "match $0 {}")); 64 if ctx.unsafe_is_prev {
66 acc.add(keyword(ctx, "while", "while $0 {}")); 65 if ctx.has_item_list_or_source_file_parent || ctx.block_expr_parent {
67 acc.add(keyword(ctx, "loop", "loop {$0}")); 66 add_keyword(ctx, acc, "fn", "fn $0() {}")
67 }
68
69 if (ctx.has_item_list_or_source_file_parent && !has_trait_or_impl_parent)
70 || ctx.block_expr_parent
71 {
72 add_keyword(ctx, acc, "trait", "trait $0 {}");
73 add_keyword(ctx, acc, "impl", "impl $0 {}");
74 }
75
76 return;
77 }
78 if ctx.has_item_list_or_source_file_parent || ctx.block_expr_parent {
79 add_keyword(ctx, acc, "fn", "fn $0() {}");
80 }
81 if (ctx.has_item_list_or_source_file_parent && !has_trait_or_impl_parent)
82 || ctx.block_expr_parent
83 {
84 add_keyword(ctx, acc, "use", "use ");
85 add_keyword(ctx, acc, "impl", "impl $0 {}");
86 add_keyword(ctx, acc, "trait", "trait $0 {}");
87 }
88
89 if ctx.has_item_list_or_source_file_parent && !has_trait_or_impl_parent {
90 add_keyword(ctx, acc, "enum", "enum $0 {}");
91 add_keyword(ctx, acc, "struct", "struct $0");
92 add_keyword(ctx, acc, "union", "union $0 {}");
93 }
94
95 if ctx.is_expr {
96 add_keyword(ctx, acc, "match", "match $0 {}");
97 add_keyword(ctx, acc, "while", "while $0 {}");
98 add_keyword(ctx, acc, "loop", "loop {$0}");
99 add_keyword(ctx, acc, "if", "if ");
100 add_keyword(ctx, acc, "if let", "if let ");
101 }
102
103 if ctx.if_is_prev || ctx.block_expr_parent {
104 add_keyword(ctx, acc, "let", "let ");
105 }
68 106
69 if ctx.after_if { 107 if ctx.after_if {
70 acc.add(keyword(ctx, "else", "else {$0}")); 108 add_keyword(ctx, acc, "else", "else {$0}");
71 acc.add(keyword(ctx, "else if", "else if $0 {}")); 109 add_keyword(ctx, acc, "else if", "else if $0 {}");
110 }
111 if (ctx.has_item_list_or_source_file_parent && !has_trait_or_impl_parent)
112 || ctx.block_expr_parent
113 {
114 add_keyword(ctx, acc, "mod", "mod $0 {}");
115 }
116 if ctx.bind_pat_parent || ctx.ref_pat_parent {
117 add_keyword(ctx, acc, "mut", "mut ");
118 }
119 if ctx.has_item_list_or_source_file_parent || ctx.block_expr_parent {
120 add_keyword(ctx, acc, "const", "const ");
121 add_keyword(ctx, acc, "type", "type ");
122 }
123 if (ctx.has_item_list_or_source_file_parent && !has_trait_or_impl_parent)
124 || ctx.block_expr_parent
125 {
126 add_keyword(ctx, acc, "static", "static ");
127 };
128 if (ctx.has_item_list_or_source_file_parent && !has_trait_or_impl_parent)
129 || ctx.block_expr_parent
130 {
131 add_keyword(ctx, acc, "extern", "extern ");
132 }
133 if ctx.has_item_list_or_source_file_parent || ctx.block_expr_parent || ctx.is_match_arm {
134 add_keyword(ctx, acc, "unsafe", "unsafe ");
72 } 135 }
73 if is_in_loop_body(&ctx.token) { 136 if ctx.in_loop_body {
74 if ctx.can_be_stmt { 137 if ctx.can_be_stmt {
75 acc.add(keyword(ctx, "continue", "continue;")); 138 add_keyword(ctx, acc, "continue", "continue;");
76 acc.add(keyword(ctx, "break", "break;")); 139 add_keyword(ctx, acc, "break", "break;");
77 } else { 140 } else {
78 acc.add(keyword(ctx, "continue", "continue")); 141 add_keyword(ctx, acc, "continue", "continue");
79 acc.add(keyword(ctx, "break", "break")); 142 add_keyword(ctx, acc, "break", "break");
80 } 143 }
81 } 144 }
145 if ctx.has_item_list_or_source_file_parent && !ctx.has_trait_parent {
146 add_keyword(ctx, acc, "pub", "pub ")
147 }
148
149 if !ctx.is_trivial_path {
150 return;
151 }
152 let fn_def = match &ctx.function_syntax {
153 Some(it) => it,
154 None => return,
155 };
82 acc.add_all(complete_return(ctx, &fn_def, ctx.can_be_stmt)); 156 acc.add_all(complete_return(ctx, &fn_def, ctx.can_be_stmt));
83} 157}
84 158
85fn is_in_loop_body(leaf: &SyntaxToken) -> bool { 159fn keyword(ctx: &CompletionContext, kw: &str, snippet: &str) -> CompletionItem {
86 // FIXME move this to CompletionContext and make it handle macros 160 let res = CompletionItem::new(CompletionKind::Keyword, ctx.source_range(), kw)
87 for node in leaf.parent().ancestors() { 161 .kind(CompletionItemKind::Keyword);
88 if node.kind() == FN_DEF || node.kind() == LAMBDA_EXPR { 162
89 break; 163 match ctx.config.snippet_cap {
90 } 164 Some(cap) => res.insert_snippet(cap, snippet),
91 let loop_body = match_ast! { 165 _ => res.insert_text(if snippet.contains('$') { kw } else { snippet }),
92 match node {
93 ast::ForExpr(it) => it.loop_body(),
94 ast::WhileExpr(it) => it.loop_body(),
95 ast::LoopExpr(it) => it.loop_body(),
96 _ => None,
97 }
98 };
99 if let Some(body) = loop_body {
100 if body.syntax().text_range().contains_range(leaf.text_range()) {
101 return true;
102 }
103 }
104 } 166 }
105 false 167 .build()
168}
169
170fn add_keyword(ctx: &CompletionContext, acc: &mut Completions, kw: &str, snippet: &str) {
171 acc.add(keyword(ctx, kw, snippet));
106} 172}
107 173
108fn complete_return( 174fn complete_return(
@@ -121,666 +187,354 @@ fn complete_return(
121 187
122#[cfg(test)] 188#[cfg(test)]
123mod tests { 189mod tests {
124 use crate::completion::{test_utils::do_completion, CompletionItem, CompletionKind}; 190 use expect::{expect, Expect};
125 use insta::assert_debug_snapshot; 191
192 use crate::completion::{
193 test_utils::{check_edit, completion_list},
194 CompletionKind,
195 };
196 use test_utils::mark;
126 197
127 fn do_keyword_completion(code: &str) -> Vec<CompletionItem> { 198 fn check(ra_fixture: &str, expect: Expect) {
128 do_completion(code, CompletionKind::Keyword) 199 let actual = completion_list(ra_fixture, CompletionKind::Keyword);
200 expect.assert_eq(&actual)
129 } 201 }
130 202
131 #[test] 203 #[test]
132 fn completes_keywords_in_use_stmt() { 204 fn test_keywords_in_use_stmt() {
133 assert_debug_snapshot!( 205 check(
134 do_keyword_completion( 206 r"use <|>",
135 r" 207 expect![[r#"
136 use <|> 208 kw crate::
137 ", 209 kw self
138 ), 210 kw super::
139 @r###" 211 "#]],
140 [
141 CompletionItem {
142 label: "crate",
143 source_range: 21..21,
144 delete: 21..21,
145 insert: "crate::",
146 kind: Keyword,
147 },
148 CompletionItem {
149 label: "self",
150 source_range: 21..21,
151 delete: 21..21,
152 insert: "self",
153 kind: Keyword,
154 },
155 CompletionItem {
156 label: "super",
157 source_range: 21..21,
158 delete: 21..21,
159 insert: "super::",
160 kind: Keyword,
161 },
162 ]
163 "###
164 ); 212 );
165 213
166 assert_debug_snapshot!( 214 check(
167 do_keyword_completion( 215 r"use a::<|>",
168 r" 216 expect![[r#"
169 use a::<|> 217 kw self
170 ", 218 kw super::
171 ), 219 "#]],
172 @r###"
173 [
174 CompletionItem {
175 label: "self",
176 source_range: 24..24,
177 delete: 24..24,
178 insert: "self",
179 kind: Keyword,
180 },
181 CompletionItem {
182 label: "super",
183 source_range: 24..24,
184 delete: 24..24,
185 insert: "super::",
186 kind: Keyword,
187 },
188 ]
189 "###
190 ); 220 );
191 221
192 assert_debug_snapshot!( 222 check(
193 do_keyword_completion( 223 r"use a::{b, <|>}",
194 r" 224 expect![[r#"
195 use a::{b, <|>} 225 kw self
196 ", 226 kw super::
197 ), 227 "#]],
198 @r###"
199 [
200 CompletionItem {
201 label: "self",
202 source_range: 28..28,
203 delete: 28..28,
204 insert: "self",
205 kind: Keyword,
206 },
207 CompletionItem {
208 label: "super",
209 source_range: 28..28,
210 delete: 28..28,
211 insert: "super::",
212 kind: Keyword,
213 },
214 ]
215 "###
216 ); 228 );
217 } 229 }
218 230
219 #[test] 231 #[test]
220 fn completes_various_keywords_in_function() { 232 fn test_keywords_at_source_file_level() {
221 assert_debug_snapshot!( 233 check(
222 do_keyword_completion( 234 r"m<|>",
223 r" 235 expect![[r#"
224 fn quux() { 236 kw const
225 <|> 237 kw enum
226 } 238 kw extern
227 ", 239 kw fn
228 ), 240 kw impl
229 @r###" 241 kw mod
230 [ 242 kw pub
231 CompletionItem { 243 kw static
232 label: "if", 244 kw struct
233 source_range: 49..49, 245 kw trait
234 delete: 49..49, 246 kw type
235 insert: "if $0 {}", 247 kw union
236 kind: Keyword, 248 kw unsafe
237 }, 249 kw use
238 CompletionItem { 250 "#]],
239 label: "loop",
240 source_range: 49..49,
241 delete: 49..49,
242 insert: "loop {$0}",
243 kind: Keyword,
244 },
245 CompletionItem {
246 label: "match",
247 source_range: 49..49,
248 delete: 49..49,
249 insert: "match $0 {}",
250 kind: Keyword,
251 },
252 CompletionItem {
253 label: "return",
254 source_range: 49..49,
255 delete: 49..49,
256 insert: "return;",
257 kind: Keyword,
258 },
259 CompletionItem {
260 label: "while",
261 source_range: 49..49,
262 delete: 49..49,
263 insert: "while $0 {}",
264 kind: Keyword,
265 },
266 ]
267 "###
268 ); 251 );
269 } 252 }
270 253
271 #[test] 254 #[test]
272 fn completes_else_after_if() { 255 fn test_keywords_in_function() {
273 assert_debug_snapshot!( 256 check(
274 do_keyword_completion( 257 r"fn quux() { <|> }",
275 r" 258 expect![[r#"
276 fn quux() { 259 kw const
277 if true { 260 kw extern
278 () 261 kw fn
279 } <|> 262 kw if
280 } 263 kw if let
281 ", 264 kw impl
282 ), 265 kw let
283 @r###" 266 kw loop
284 [ 267 kw match
285 CompletionItem { 268 kw mod
286 label: "else", 269 kw return
287 source_range: 108..108, 270 kw static
288 delete: 108..108, 271 kw trait
289 insert: "else {$0}", 272 kw type
290 kind: Keyword, 273 kw unsafe
291 }, 274 kw use
292 CompletionItem { 275 kw while
293 label: "else if", 276 "#]],
294 source_range: 108..108,
295 delete: 108..108,
296 insert: "else if $0 {}",
297 kind: Keyword,
298 },
299 CompletionItem {
300 label: "if",
301 source_range: 108..108,
302 delete: 108..108,
303 insert: "if $0 {}",
304 kind: Keyword,
305 },
306 CompletionItem {
307 label: "loop",
308 source_range: 108..108,
309 delete: 108..108,
310 insert: "loop {$0}",
311 kind: Keyword,
312 },
313 CompletionItem {
314 label: "match",
315 source_range: 108..108,
316 delete: 108..108,
317 insert: "match $0 {}",
318 kind: Keyword,
319 },
320 CompletionItem {
321 label: "return",
322 source_range: 108..108,
323 delete: 108..108,
324 insert: "return;",
325 kind: Keyword,
326 },
327 CompletionItem {
328 label: "while",
329 source_range: 108..108,
330 delete: 108..108,
331 insert: "while $0 {}",
332 kind: Keyword,
333 },
334 ]
335 "###
336 ); 277 );
337 } 278 }
338 279
339 #[test] 280 #[test]
340 fn test_completion_return_value() { 281 fn test_keywords_inside_block() {
341 assert_debug_snapshot!( 282 check(
342 do_keyword_completion( 283 r"fn quux() { if true { <|> } }",
343 r" 284 expect![[r#"
344 fn quux() -> i32 { 285 kw const
345 <|> 286 kw extern
346 92 287 kw fn
347 } 288 kw if
348 ", 289 kw if let
349 ), 290 kw impl
350 @r###" 291 kw let
351 [ 292 kw loop
352 CompletionItem { 293 kw match
353 label: "if", 294 kw mod
354 source_range: 56..56, 295 kw return
355 delete: 56..56, 296 kw static
356 insert: "if $0 {}", 297 kw trait
357 kind: Keyword, 298 kw type
358 }, 299 kw unsafe
359 CompletionItem { 300 kw use
360 label: "loop", 301 kw while
361 source_range: 56..56, 302 "#]],
362 delete: 56..56,
363 insert: "loop {$0}",
364 kind: Keyword,
365 },
366 CompletionItem {
367 label: "match",
368 source_range: 56..56,
369 delete: 56..56,
370 insert: "match $0 {}",
371 kind: Keyword,
372 },
373 CompletionItem {
374 label: "return",
375 source_range: 56..56,
376 delete: 56..56,
377 insert: "return $0;",
378 kind: Keyword,
379 },
380 CompletionItem {
381 label: "while",
382 source_range: 56..56,
383 delete: 56..56,
384 insert: "while $0 {}",
385 kind: Keyword,
386 },
387 ]
388 "###
389 ); 303 );
390 assert_debug_snapshot!( 304 }
391 do_keyword_completion( 305
392 r" 306 #[test]
393 fn quux() { 307 fn test_keywords_after_if() {
394 <|> 308 check(
395 92 309 r#"fn quux() { if true { () } <|> }"#,
396 } 310 expect![[r#"
397 ", 311 kw const
398 ), 312 kw else
399 @r###" 313 kw else if
400 [ 314 kw extern
401 CompletionItem { 315 kw fn
402 label: "if", 316 kw if
403 source_range: 49..49, 317 kw if let
404 delete: 49..49, 318 kw impl
405 insert: "if $0 {}", 319 kw let
406 kind: Keyword, 320 kw loop
407 }, 321 kw match
408 CompletionItem { 322 kw mod
409 label: "loop", 323 kw return
410 source_range: 49..49, 324 kw static
411 delete: 49..49, 325 kw trait
412 insert: "loop {$0}", 326 kw type
413 kind: Keyword, 327 kw unsafe
414 }, 328 kw use
415 CompletionItem { 329 kw while
416 label: "match", 330 "#]],
417 source_range: 49..49, 331 );
418 delete: 49..49, 332 check_edit(
419 insert: "match $0 {}", 333 "else",
420 kind: Keyword, 334 r#"fn quux() { if true { () } <|> }"#,
421 }, 335 r#"fn quux() { if true { () } else {$0} }"#,
422 CompletionItem {
423 label: "return",
424 source_range: 49..49,
425 delete: 49..49,
426 insert: "return;",
427 kind: Keyword,
428 },
429 CompletionItem {
430 label: "while",
431 source_range: 49..49,
432 delete: 49..49,
433 insert: "while $0 {}",
434 kind: Keyword,
435 },
436 ]
437 "###
438 ); 336 );
439 } 337 }
440 338
441 #[test] 339 #[test]
442 fn dont_add_semi_after_return_if_not_a_statement() { 340 fn test_keywords_in_match_arm() {
443 assert_debug_snapshot!( 341 check(
444 do_keyword_completion( 342 r#"
445 r" 343fn quux() -> i32 {
446 fn quux() -> i32 { 344 match () { () => <|> }
447 match () { 345}
448 () => <|> 346"#,
449 } 347 expect![[r#"
450 } 348 kw if
451 ", 349 kw if let
452 ), 350 kw loop
453 @r###" 351 kw match
454 [ 352 kw return
455 CompletionItem { 353 kw unsafe
456 label: "if", 354 kw while
457 source_range: 97..97, 355 "#]],
458 delete: 97..97,
459 insert: "if $0 {}",
460 kind: Keyword,
461 },
462 CompletionItem {
463 label: "loop",
464 source_range: 97..97,
465 delete: 97..97,
466 insert: "loop {$0}",
467 kind: Keyword,
468 },
469 CompletionItem {
470 label: "match",
471 source_range: 97..97,
472 delete: 97..97,
473 insert: "match $0 {}",
474 kind: Keyword,
475 },
476 CompletionItem {
477 label: "return",
478 source_range: 97..97,
479 delete: 97..97,
480 insert: "return $0",
481 kind: Keyword,
482 },
483 CompletionItem {
484 label: "while",
485 source_range: 97..97,
486 delete: 97..97,
487 insert: "while $0 {}",
488 kind: Keyword,
489 },
490 ]
491 "###
492 ); 356 );
493 } 357 }
494 358
495 #[test] 359 #[test]
496 fn last_return_in_block_has_semi() { 360 fn test_keywords_in_trait_def() {
497 assert_debug_snapshot!( 361 check(
498 do_keyword_completion( 362 r"trait My { <|> }",
499 r" 363 expect![[r#"
500 fn quux() -> i32 { 364 kw const
501 if condition { 365 kw fn
502 <|> 366 kw type
503 } 367 kw unsafe
504 } 368 "#]],
505 ",
506 ),
507 @r###"
508 [
509 CompletionItem {
510 label: "if",
511 source_range: 95..95,
512 delete: 95..95,
513 insert: "if $0 {}",
514 kind: Keyword,
515 },
516 CompletionItem {
517 label: "loop",
518 source_range: 95..95,
519 delete: 95..95,
520 insert: "loop {$0}",
521 kind: Keyword,
522 },
523 CompletionItem {
524 label: "match",
525 source_range: 95..95,
526 delete: 95..95,
527 insert: "match $0 {}",
528 kind: Keyword,
529 },
530 CompletionItem {
531 label: "return",
532 source_range: 95..95,
533 delete: 95..95,
534 insert: "return $0;",
535 kind: Keyword,
536 },
537 CompletionItem {
538 label: "while",
539 source_range: 95..95,
540 delete: 95..95,
541 insert: "while $0 {}",
542 kind: Keyword,
543 },
544 ]
545 "###
546 ); 369 );
547 assert_debug_snapshot!( 370 }
548 do_keyword_completion( 371
549 r" 372 #[test]
550 fn quux() -> i32 { 373 fn test_keywords_in_impl_def() {
551 if condition { 374 check(
552 <|> 375 r"impl My { <|> }",
553 } 376 expect![[r#"
554 let x = 92; 377 kw const
555 x 378 kw fn
556 } 379 kw pub
557 ", 380 kw type
558 ), 381 kw unsafe
559 @r###" 382 "#]],
560 [
561 CompletionItem {
562 label: "if",
563 source_range: 95..95,
564 delete: 95..95,
565 insert: "if $0 {}",
566 kind: Keyword,
567 },
568 CompletionItem {
569 label: "loop",
570 source_range: 95..95,
571 delete: 95..95,
572 insert: "loop {$0}",
573 kind: Keyword,
574 },
575 CompletionItem {
576 label: "match",
577 source_range: 95..95,
578 delete: 95..95,
579 insert: "match $0 {}",
580 kind: Keyword,
581 },
582 CompletionItem {
583 label: "return",
584 source_range: 95..95,
585 delete: 95..95,
586 insert: "return $0;",
587 kind: Keyword,
588 },
589 CompletionItem {
590 label: "while",
591 source_range: 95..95,
592 delete: 95..95,
593 insert: "while $0 {}",
594 kind: Keyword,
595 },
596 ]
597 "###
598 ); 383 );
599 } 384 }
600 385
601 #[test] 386 #[test]
602 fn completes_break_and_continue_in_loops() { 387 fn test_keywords_in_loop() {
603 assert_debug_snapshot!( 388 check(
604 do_keyword_completion( 389 r"fn my() { loop { <|> } }",
605 r" 390 expect![[r#"
606 fn quux() -> i32 { 391 kw break
607 loop { <|> } 392 kw const
608 } 393 kw continue
609 ", 394 kw extern
610 ), 395 kw fn
611 @r###" 396 kw if
612 [ 397 kw if let
613 CompletionItem { 398 kw impl
614 label: "break", 399 kw let
615 source_range: 63..63, 400 kw loop
616 delete: 63..63, 401 kw match
617 insert: "break;", 402 kw mod
618 kind: Keyword, 403 kw return
619 }, 404 kw static
620 CompletionItem { 405 kw trait
621 label: "continue", 406 kw type
622 source_range: 63..63, 407 kw unsafe
623 delete: 63..63, 408 kw use
624 insert: "continue;", 409 kw while
625 kind: Keyword, 410 "#]],
626 },
627 CompletionItem {
628 label: "if",
629 source_range: 63..63,
630 delete: 63..63,
631 insert: "if $0 {}",
632 kind: Keyword,
633 },
634 CompletionItem {
635 label: "loop",
636 source_range: 63..63,
637 delete: 63..63,
638 insert: "loop {$0}",
639 kind: Keyword,
640 },
641 CompletionItem {
642 label: "match",
643 source_range: 63..63,
644 delete: 63..63,
645 insert: "match $0 {}",
646 kind: Keyword,
647 },
648 CompletionItem {
649 label: "return",
650 source_range: 63..63,
651 delete: 63..63,
652 insert: "return $0;",
653 kind: Keyword,
654 },
655 CompletionItem {
656 label: "while",
657 source_range: 63..63,
658 delete: 63..63,
659 insert: "while $0 {}",
660 kind: Keyword,
661 },
662 ]
663 "###
664 ); 411 );
412 }
665 413
666 // No completion: lambda isolates control flow 414 #[test]
667 assert_debug_snapshot!( 415 fn test_keywords_after_unsafe_in_item_list() {
668 do_keyword_completion( 416 check(
669 r" 417 r"unsafe <|>",
670 fn quux() -> i32 { 418 expect![[r#"
671 loop { || { <|> } } 419 kw fn
672 } 420 kw impl
673 ", 421 kw trait
674 ), 422 "#]],
675 @r###"
676 [
677 CompletionItem {
678 label: "if",
679 source_range: 68..68,
680 delete: 68..68,
681 insert: "if $0 {}",
682 kind: Keyword,
683 },
684 CompletionItem {
685 label: "loop",
686 source_range: 68..68,
687 delete: 68..68,
688 insert: "loop {$0}",
689 kind: Keyword,
690 },
691 CompletionItem {
692 label: "match",
693 source_range: 68..68,
694 delete: 68..68,
695 insert: "match $0 {}",
696 kind: Keyword,
697 },
698 CompletionItem {
699 label: "return",
700 source_range: 68..68,
701 delete: 68..68,
702 insert: "return $0;",
703 kind: Keyword,
704 },
705 CompletionItem {
706 label: "while",
707 source_range: 68..68,
708 delete: 68..68,
709 insert: "while $0 {}",
710 kind: Keyword,
711 },
712 ]
713 "###
714 ); 423 );
715 } 424 }
716 425
717 #[test] 426 #[test]
718 fn no_semi_after_break_continue_in_expr() { 427 fn test_keywords_after_unsafe_in_block_expr() {
719 assert_debug_snapshot!( 428 check(
720 do_keyword_completion( 429 r"fn my_fn() { unsafe <|> }",
721 r" 430 expect![[r#"
722 fn f() { 431 kw fn
723 loop { 432 kw impl
724 match () { 433 kw trait
725 () => br<|> 434 "#]],
726 } 435 );
727 } 436 }
728 } 437
729 ", 438 #[test]
730 ), 439 fn test_mut_in_ref_and_in_fn_parameters_list() {
731 @r###" 440 check(
732 [ 441 r"fn my_fn(&<|>) {}",
733 CompletionItem { 442 expect![[r#"
734 label: "break", 443 kw mut
735 source_range: 122..124, 444 "#]],
736 delete: 122..124, 445 );
737 insert: "break", 446 check(
738 kind: Keyword, 447 r"fn my_fn(<|>) {}",
739 }, 448 expect![[r#"
740 CompletionItem { 449 kw mut
741 label: "continue", 450 "#]],
742 source_range: 122..124, 451 );
743 delete: 122..124, 452 check(
744 insert: "continue", 453 r"fn my_fn() { let &<|> }",
745 kind: Keyword, 454 expect![[r#"
746 }, 455 kw mut
747 CompletionItem { 456 "#]],
748 label: "if", 457 );
749 source_range: 122..124, 458 }
750 delete: 122..124, 459
751 insert: "if $0 {}", 460 #[test]
752 kind: Keyword, 461 fn test_where_keyword() {
753 }, 462 check(
754 CompletionItem { 463 r"trait A <|>",
755 label: "loop", 464 expect![[r#"
756 source_range: 122..124, 465 kw where
757 delete: 122..124, 466 "#]],
758 insert: "loop {$0}", 467 );
759 kind: Keyword, 468 check(
760 }, 469 r"impl A <|>",
761 CompletionItem { 470 expect![[r#"
762 label: "match", 471 kw where
763 source_range: 122..124, 472 "#]],
764 delete: 122..124, 473 );
765 insert: "match $0 {}", 474 }
766 kind: Keyword, 475
767 }, 476 #[test]
768 CompletionItem { 477 fn no_keyword_completion_in_comments() {
769 label: "return", 478 mark::check!(no_keyword_completion_in_comments);
770 source_range: 122..124, 479 check(
771 delete: 122..124, 480 r#"
772 insert: "return", 481fn test() {
773 kind: Keyword, 482 let x = 2; // A comment<|>
774 }, 483}
775 CompletionItem { 484"#,
776 label: "while", 485 expect![[""]],
777 source_range: 122..124, 486 );
778 delete: 122..124, 487 check(
779 insert: "while $0 {}", 488 r#"
780 kind: Keyword, 489/*
781 }, 490Some multi-line comment<|>
782 ] 491*/
783 "### 492"#,
493 expect![[""]],
494 );
495 check(
496 r#"
497/// Some doc comment
498/// let test<|> = 1
499"#,
500 expect![[""]],
501 );
502 }
503
504 #[test]
505 fn test_completion_await_impls_future() {
506 check(
507 r#"
508//- /main.rs
509use std::future::*;
510struct A {}
511impl Future for A {}
512fn foo(a: A) { a.<|> }
513
514//- /std/lib.rs
515pub mod future {
516 #[lang = "future_trait"]
517 pub trait Future {}
518}
519"#,
520 expect![[r#"
521 kw await expr.await
522 "#]],
523 )
524 }
525
526 #[test]
527 fn after_let() {
528 check(
529 r#"fn main() { let _ = <|> }"#,
530 expect![[r#"
531 kw if
532 kw if let
533 kw loop
534 kw match
535 kw return
536 kw while
537 "#]],
784 ) 538 )
785 } 539 }
786} 540}
diff --git a/crates/ra_ide/src/completion/complete_macro_in_item_position.rs b/crates/ra_ide/src/completion/complete_macro_in_item_position.rs
index d9bb5fd25..0447f0511 100644
--- a/crates/ra_ide/src/completion/complete_macro_in_item_position.rs
+++ b/crates/ra_ide/src/completion/complete_macro_in_item_position.rs
@@ -5,7 +5,7 @@ use crate::completion::{CompletionContext, Completions};
5pub(super) fn complete_macro_in_item_position(acc: &mut Completions, ctx: &CompletionContext) { 5pub(super) fn complete_macro_in_item_position(acc: &mut Completions, ctx: &CompletionContext) {
6 // Show only macros in top level. 6 // Show only macros in top level.
7 if ctx.is_new_item { 7 if ctx.is_new_item {
8 ctx.scope().process_all_names(&mut |name, res| { 8 ctx.scope.process_all_names(&mut |name, res| {
9 if let hir::ScopeDef::MacroDef(mac) = res { 9 if let hir::ScopeDef::MacroDef(mac) = res {
10 acc.add_macro(ctx, Some(name.to_string()), mac); 10 acc.add_macro(ctx, Some(name.to_string()), mac);
11 } 11 }
@@ -15,130 +15,27 @@ pub(super) fn complete_macro_in_item_position(acc: &mut Completions, ctx: &Compl
15 15
16#[cfg(test)] 16#[cfg(test)]
17mod tests { 17mod tests {
18 use insta::assert_debug_snapshot; 18 use expect::{expect, Expect};
19 19
20 use crate::completion::{test_utils::do_completion, CompletionItem, CompletionKind}; 20 use crate::completion::{test_utils::completion_list, CompletionKind};
21 21
22 fn do_reference_completion(code: &str) -> Vec<CompletionItem> { 22 fn check(ra_fixture: &str, expect: Expect) {
23 do_completion(code, CompletionKind::Reference) 23 let actual = completion_list(ra_fixture, CompletionKind::Reference);
24 expect.assert_eq(&actual)
24 } 25 }
25 26
26 #[test] 27 #[test]
27 fn completes_macros_as_item() { 28 fn completes_macros_as_item() {
28 assert_debug_snapshot!( 29 check(
29 do_reference_completion( 30 r#"
30 " 31macro_rules! foo { () => {} }
31 //- /main.rs 32fn foo() {}
32 macro_rules! foo { 33
33 () => {} 34<|>
34 } 35"#,
35 36 expect![[r#"
36 fn foo() {} 37 ma foo!(…) macro_rules! foo
37 38 "#]],
38 <|> 39 )
39 "
40 ),
41 @r###"
42 [
43 CompletionItem {
44 label: "foo!(…)",
45 source_range: 46..46,
46 delete: 46..46,
47 insert: "foo!($0)",
48 kind: Macro,
49 detail: "macro_rules! foo",
50 },
51 ]
52 "###
53 );
54 }
55
56 #[test]
57 fn completes_vec_macros_with_square_brackets() {
58 assert_debug_snapshot!(
59 do_reference_completion(
60 "
61 //- /main.rs
62 /// Creates a [`Vec`] containing the arguments.
63 ///
64 /// - Create a [`Vec`] containing a given list of elements:
65 ///
66 /// ```
67 /// let v = vec![1, 2, 3];
68 /// assert_eq!(v[0], 1);
69 /// assert_eq!(v[1], 2);
70 /// assert_eq!(v[2], 3);
71 /// ```
72 macro_rules! vec {
73 () => {}
74 }
75
76 fn foo() {}
77
78 <|>
79 "
80 ),
81 @r###"
82 [
83 CompletionItem {
84 label: "vec![…]",
85 source_range: 280..280,
86 delete: 280..280,
87 insert: "vec![$0]",
88 kind: Macro,
89 detail: "macro_rules! vec",
90 documentation: Documentation(
91 "Creates a [`Vec`] containing the arguments.\n\n- Create a [`Vec`] containing a given list of elements:\n\n```\nlet v = vec![1, 2, 3];\nassert_eq!(v[0], 1);\nassert_eq!(v[1], 2);\nassert_eq!(v[2], 3);\n```",
92 ),
93 },
94 ]
95 "###
96 );
97 }
98
99 #[test]
100 fn completes_macros_braces_guessing() {
101 assert_debug_snapshot!(
102 do_reference_completion(
103 "
104 //- /main.rs
105 /// Foo
106 ///
107 /// Not call `fooo!()` `fooo!()`, or `_foo![]` `_foo![]`.
108 /// Call as `let _=foo! { hello world };`
109 macro_rules! foo {
110 () => {}
111 }
112
113 fn main() {
114 <|>
115 }
116 "
117 ),
118 @r###"
119 [
120 CompletionItem {
121 label: "foo! {…}",
122 source_range: 163..163,
123 delete: 163..163,
124 insert: "foo! {$0}",
125 kind: Macro,
126 detail: "macro_rules! foo",
127 documentation: Documentation(
128 "Foo\n\nNot call `fooo!()` `fooo!()`, or `_foo![]` `_foo![]`.\nCall as `let _=foo! { hello world };`",
129 ),
130 },
131 CompletionItem {
132 label: "main()",
133 source_range: 163..163,
134 delete: 163..163,
135 insert: "main()$0",
136 kind: Function,
137 lookup: "main",
138 detail: "fn main()",
139 },
140 ]
141 "###
142 );
143 } 40 }
144} 41}
diff --git a/crates/ra_ide/src/completion/complete_pattern.rs b/crates/ra_ide/src/completion/complete_pattern.rs
index fdd9e928b..aceb77cb5 100644
--- a/crates/ra_ide/src/completion/complete_pattern.rs
+++ b/crates/ra_ide/src/completion/complete_pattern.rs
@@ -13,7 +13,7 @@ pub(super) fn complete_pattern(acc: &mut Completions, ctx: &CompletionContext) {
13 13
14 // FIXME: ideally, we should look at the type we are matching against and 14 // FIXME: ideally, we should look at the type we are matching against and
15 // suggest variants + auto-imports 15 // suggest variants + auto-imports
16 ctx.scope().process_all_names(&mut |name, res| { 16 ctx.scope.process_all_names(&mut |name, res| {
17 match &res { 17 match &res {
18 hir::ScopeDef::ModuleDef(def) => match def { 18 hir::ScopeDef::ModuleDef(def) => match def {
19 hir::ModuleDef::Adt(hir::Adt::Enum(..)) 19 hir::ModuleDef::Adt(hir::Adt::Enum(..))
@@ -33,106 +33,56 @@ pub(super) fn complete_pattern(acc: &mut Completions, ctx: &CompletionContext) {
33 33
34#[cfg(test)] 34#[cfg(test)]
35mod tests { 35mod tests {
36 use crate::completion::{test_utils::do_completion, CompletionItem, CompletionKind}; 36 use expect::{expect, Expect};
37 use insta::assert_debug_snapshot;
38 37
39 fn complete(code: &str) -> Vec<CompletionItem> { 38 use crate::completion::{test_utils::completion_list, CompletionKind};
40 do_completion(code, CompletionKind::Reference) 39
40 fn check(ra_fixture: &str, expect: Expect) {
41 let actual = completion_list(ra_fixture, CompletionKind::Reference);
42 expect.assert_eq(&actual)
41 } 43 }
42 44
43 #[test] 45 #[test]
44 fn completes_enum_variants_and_modules() { 46 fn completes_enum_variants_and_modules() {
45 let completions = complete( 47 check(
46 r" 48 r#"
47 enum E { X } 49enum E { X }
48 use self::E::X; 50use self::E::X;
49 const Z: E = E::X; 51const Z: E = E::X;
50 mod m {} 52mod m {}
51 53
52 static FOO: E = E::X; 54static FOO: E = E::X;
53 struct Bar { f: u32 } 55struct Bar { f: u32 }
54 56
55 fn foo() { 57fn foo() {
56 match E::X { 58 match E::X { <|> }
57 <|> 59}
58 } 60"#,
59 } 61 expect![[r#"
60 ", 62 st Bar
63 en E
64 ev X ()
65 ct Z
66 md m
67 "#]],
61 ); 68 );
62 assert_debug_snapshot!(completions, @r###"
63 [
64 CompletionItem {
65 label: "Bar",
66 source_range: 246..246,
67 delete: 246..246,
68 insert: "Bar",
69 kind: Struct,
70 },
71 CompletionItem {
72 label: "E",
73 source_range: 246..246,
74 delete: 246..246,
75 insert: "E",
76 kind: Enum,
77 },
78 CompletionItem {
79 label: "X",
80 source_range: 246..246,
81 delete: 246..246,
82 insert: "X",
83 kind: EnumVariant,
84 detail: "()",
85 },
86 CompletionItem {
87 label: "Z",
88 source_range: 246..246,
89 delete: 246..246,
90 insert: "Z",
91 kind: Const,
92 },
93 CompletionItem {
94 label: "m",
95 source_range: 246..246,
96 delete: 246..246,
97 insert: "m",
98 kind: Module,
99 },
100 ]
101 "###);
102 } 69 }
103 70
104 #[test] 71 #[test]
105 fn completes_in_simple_macro_call() { 72 fn completes_in_simple_macro_call() {
106 let completions = complete( 73 check(
107 r" 74 r#"
108 macro_rules! m { ($e:expr) => { $e } } 75macro_rules! m { ($e:expr) => { $e } }
109 enum E { X } 76enum E { X }
110 77
111 fn foo() { 78fn foo() {
112 m!(match E::X { 79 m!(match E::X { <|> })
113 <|> 80}
114 }) 81"#,
115 } 82 expect![[r#"
116 ", 83 en E
84 ma m!(…) macro_rules! m
85 "#]],
117 ); 86 );
118 assert_debug_snapshot!(completions, @r###"
119 [
120 CompletionItem {
121 label: "E",
122 source_range: 151..151,
123 delete: 151..151,
124 insert: "E",
125 kind: Enum,
126 },
127 CompletionItem {
128 label: "m!(…)",
129 source_range: 151..151,
130 delete: 151..151,
131 insert: "m!($0)",
132 kind: Macro,
133 detail: "macro_rules! m",
134 },
135 ]
136 "###);
137 } 87 }
138} 88}
diff --git a/crates/ra_ide/src/completion/complete_postfix.rs b/crates/ra_ide/src/completion/complete_postfix.rs
index 59b58bf98..8735b9010 100644
--- a/crates/ra_ide/src/completion/complete_postfix.rs
+++ b/crates/ra_ide/src/completion/complete_postfix.rs
@@ -8,14 +8,13 @@ use ra_text_edit::TextEdit;
8 8
9use crate::{ 9use crate::{
10 completion::{ 10 completion::{
11 completion_config::SnippetCap,
11 completion_context::CompletionContext, 12 completion_context::CompletionContext,
12 completion_item::{Builder, CompletionKind, Completions}, 13 completion_item::{Builder, CompletionKind, Completions},
13 }, 14 },
14 CompletionItem, 15 CompletionItem, CompletionItemKind,
15}; 16};
16 17
17use super::completion_config::SnippetCap;
18
19pub(super) fn complete_postfix(acc: &mut Completions, ctx: &CompletionContext) { 18pub(super) fn complete_postfix(acc: &mut Completions, ctx: &CompletionContext) {
20 if !ctx.config.enable_postfix_completions { 19 if !ctx.config.enable_postfix_completions {
21 return; 20 return;
@@ -91,7 +90,7 @@ pub(super) fn complete_postfix(acc: &mut Completions, ctx: &CompletionContext) {
91 &dot_receiver, 90 &dot_receiver,
92 "if", 91 "if",
93 "if expr {}", 92 "if expr {}",
94 &format!("if {} {{$0}}", receiver_text), 93 &format!("if {} {{\n $0\n}}", receiver_text),
95 ) 94 )
96 .add_to(acc); 95 .add_to(acc);
97 postfix_snippet( 96 postfix_snippet(
@@ -100,13 +99,12 @@ pub(super) fn complete_postfix(acc: &mut Completions, ctx: &CompletionContext) {
100 &dot_receiver, 99 &dot_receiver,
101 "while", 100 "while",
102 "while expr {}", 101 "while expr {}",
103 &format!("while {} {{\n$0\n}}", receiver_text), 102 &format!("while {} {{\n $0\n}}", receiver_text),
104 ) 103 )
105 .add_to(acc); 104 .add_to(acc);
105 postfix_snippet(ctx, cap, &dot_receiver, "not", "!expr", &format!("!{}", receiver_text))
106 .add_to(acc);
106 } 107 }
107 // !&&&42 is a compiler error, ergo process it before considering the references
108 postfix_snippet(ctx, cap, &dot_receiver, "not", "!expr", &format!("!{}", receiver_text))
109 .add_to(acc);
110 108
111 postfix_snippet(ctx, cap, &dot_receiver, "ref", "&expr", &format!("&{}", receiver_text)) 109 postfix_snippet(ctx, cap, &dot_receiver, "ref", "&expr", &format!("&{}", receiver_text))
112 .add_to(acc); 110 .add_to(acc);
@@ -125,33 +123,35 @@ pub(super) fn complete_postfix(acc: &mut Completions, ctx: &CompletionContext) {
125 let dot_receiver = include_references(dot_receiver); 123 let dot_receiver = include_references(dot_receiver);
126 let receiver_text = 124 let receiver_text =
127 get_receiver_text(&dot_receiver, ctx.dot_receiver_is_ambiguous_float_literal); 125 get_receiver_text(&dot_receiver, ctx.dot_receiver_is_ambiguous_float_literal);
126
128 match try_enum { 127 match try_enum {
129 Some(try_enum) => { 128 Some(try_enum) => match try_enum {
130 match try_enum { 129 TryEnum::Result => {
131 TryEnum::Result => { 130 postfix_snippet(
132 postfix_snippet(
133 ctx, 131 ctx,
134 cap, 132 cap,
135 &dot_receiver, 133 &dot_receiver,
136 "match", 134 "match",
137 "match expr {}", 135 "match expr {}",
138 &format!("match {} {{\n Ok(${{1:_}}) => {{$2\\}},\n Err(${{3:_}}) => {{$0\\}},\n}}", receiver_text), 136 &format!("match {} {{\n Ok(${{1:_}}) => {{$2}},\n Err(${{3:_}}) => {{$0}},\n}}", receiver_text),
139 ) 137 )
140 .add_to(acc); 138 .add_to(acc);
141 } 139 }
142 TryEnum::Option => { 140 TryEnum::Option => {
143 postfix_snippet( 141 postfix_snippet(
144 ctx, 142 ctx,
145 cap, 143 cap,
146 &dot_receiver, 144 &dot_receiver,
147 "match", 145 "match",
148 "match expr {}", 146 "match expr {}",
149 &format!("match {} {{\n Some(${{1:_}}) => {{$2\\}},\n None => {{$0\\}},\n}}", receiver_text), 147 &format!(
148 "match {} {{\n Some(${{1:_}}) => {{$2}},\n None => {{$0}},\n}}",
149 receiver_text
150 ),
150 ) 151 )
151 .add_to(acc); 152 .add_to(acc);
152 }
153 } 153 }
154 } 154 },
155 None => { 155 None => {
156 postfix_snippet( 156 postfix_snippet(
157 ctx, 157 ctx,
@@ -159,7 +159,7 @@ pub(super) fn complete_postfix(acc: &mut Completions, ctx: &CompletionContext) {
159 &dot_receiver, 159 &dot_receiver,
160 "match", 160 "match",
161 "match expr {}", 161 "match expr {}",
162 &format!("match {} {{\n ${{1:_}} => {{$0\\}},\n}}", receiver_text), 162 &format!("match {} {{\n ${{1:_}} => {{$0}},\n}}", receiver_text),
163 ) 163 )
164 .add_to(acc); 164 .add_to(acc);
165 } 165 }
@@ -232,536 +232,147 @@ fn postfix_snippet(
232 }; 232 };
233 CompletionItem::new(CompletionKind::Postfix, ctx.source_range(), label) 233 CompletionItem::new(CompletionKind::Postfix, ctx.source_range(), label)
234 .detail(detail) 234 .detail(detail)
235 .kind(CompletionItemKind::Snippet)
235 .snippet_edit(cap, edit) 236 .snippet_edit(cap, edit)
236} 237}
237 238
238#[cfg(test)] 239#[cfg(test)]
239mod tests { 240mod tests {
240 use insta::assert_debug_snapshot; 241 use expect::{expect, Expect};
241 242
242 use crate::completion::{test_utils::do_completion, CompletionItem, CompletionKind}; 243 use crate::completion::{
244 test_utils::{check_edit, completion_list},
245 CompletionKind,
246 };
243 247
244 fn do_postfix_completion(code: &str) -> Vec<CompletionItem> { 248 fn check(ra_fixture: &str, expect: Expect) {
245 do_completion(code, CompletionKind::Postfix) 249 let actual = completion_list(ra_fixture, CompletionKind::Postfix);
250 expect.assert_eq(&actual)
246 } 251 }
247 252
248 #[test] 253 #[test]
249 fn postfix_completion_works_for_trivial_path_expression() { 254 fn postfix_completion_works_for_trivial_path_expression() {
250 assert_debug_snapshot!( 255 check(
251 do_postfix_completion( 256 r#"
252 r#" 257fn main() {
253 fn main() { 258 let bar = true;
254 let bar = true; 259 bar.<|>
255 bar.<|> 260}
256 } 261"#,
257 "#, 262 expect![[r#"
258 ), 263 sn box Box::new(expr)
259 @r###" 264 sn call function(expr)
260 [ 265 sn dbg dbg!(expr)
261 CompletionItem { 266 sn if if expr {}
262 label: "box", 267 sn match match expr {}
263 source_range: 89..89, 268 sn not !expr
264 delete: 85..89, 269 sn ref &expr
265 insert: "Box::new(bar)", 270 sn refm &mut expr
266 detail: "Box::new(expr)", 271 sn while while expr {}
267 }, 272 "#]],
268 CompletionItem {
269 label: "call",
270 source_range: 89..89,
271 delete: 85..89,
272 insert: "${1}(bar)",
273 detail: "function(expr)",
274 },
275 CompletionItem {
276 label: "dbg",
277 source_range: 89..89,
278 delete: 85..89,
279 insert: "dbg!(bar)",
280 detail: "dbg!(expr)",
281 },
282 CompletionItem {
283 label: "if",
284 source_range: 89..89,
285 delete: 85..89,
286 insert: "if bar {$0}",
287 detail: "if expr {}",
288 },
289 CompletionItem {
290 label: "match",
291 source_range: 89..89,
292 delete: 85..89,
293 insert: "match bar {\n ${1:_} => {$0\\},\n}",
294 detail: "match expr {}",
295 },
296 CompletionItem {
297 label: "not",
298 source_range: 89..89,
299 delete: 85..89,
300 insert: "!bar",
301 detail: "!expr",
302 },
303 CompletionItem {
304 label: "ref",
305 source_range: 89..89,
306 delete: 85..89,
307 insert: "&bar",
308 detail: "&expr",
309 },
310 CompletionItem {
311 label: "refm",
312 source_range: 89..89,
313 delete: 85..89,
314 insert: "&mut bar",
315 detail: "&mut expr",
316 },
317 CompletionItem {
318 label: "while",
319 source_range: 89..89,
320 delete: 85..89,
321 insert: "while bar {\n$0\n}",
322 detail: "while expr {}",
323 },
324 ]
325 "###
326 ); 273 );
327 } 274 }
328 275
329 #[test] 276 #[test]
330 fn postfix_completion_works_for_option() { 277 fn postfix_type_filtering() {
331 assert_debug_snapshot!( 278 check(
332 do_postfix_completion( 279 r#"
333 r#" 280fn main() {
334 enum Option<T> { 281 let bar: u8 = 12;
335 Some(T), 282 bar.<|>
336 None, 283}
337 } 284"#,
338 285 expect![[r#"
339 fn main() { 286 sn box Box::new(expr)
340 let bar = Option::Some(true); 287 sn call function(expr)
341 bar.<|> 288 sn dbg dbg!(expr)
342 } 289 sn match match expr {}
343 "#, 290 sn ref &expr
344 ), 291 sn refm &mut expr
345 @r###" 292 "#]],
346 [ 293 )
347 CompletionItem {
348 label: "box",
349 source_range: 210..210,
350 delete: 206..210,
351 insert: "Box::new(bar)",
352 detail: "Box::new(expr)",
353 },
354 CompletionItem {
355 label: "call",
356 source_range: 210..210,
357 delete: 206..210,
358 insert: "${1}(bar)",
359 detail: "function(expr)",
360 },
361 CompletionItem {
362 label: "dbg",
363 source_range: 210..210,
364 delete: 206..210,
365 insert: "dbg!(bar)",
366 detail: "dbg!(expr)",
367 },
368 CompletionItem {
369 label: "ifl",
370 source_range: 210..210,
371 delete: 206..210,
372 insert: "if let Some($1) = bar {\n $0\n}",
373 detail: "if let Some {}",
374 },
375 CompletionItem {
376 label: "match",
377 source_range: 210..210,
378 delete: 206..210,
379 insert: "match bar {\n Some(${1:_}) => {$2\\},\n None => {$0\\},\n}",
380 detail: "match expr {}",
381 },
382 CompletionItem {
383 label: "not",
384 source_range: 210..210,
385 delete: 206..210,
386 insert: "!bar",
387 detail: "!expr",
388 },
389 CompletionItem {
390 label: "ref",
391 source_range: 210..210,
392 delete: 206..210,
393 insert: "&bar",
394 detail: "&expr",
395 },
396 CompletionItem {
397 label: "refm",
398 source_range: 210..210,
399 delete: 206..210,
400 insert: "&mut bar",
401 detail: "&mut expr",
402 },
403 CompletionItem {
404 label: "while",
405 source_range: 210..210,
406 delete: 206..210,
407 insert: "while let Some($1) = bar {\n $0\n}",
408 detail: "while let Some {}",
409 },
410 ]
411 "###
412 );
413 } 294 }
414 295
415 #[test] 296 #[test]
416 fn postfix_completion_works_for_result() { 297 fn option_iflet() {
417 assert_debug_snapshot!( 298 check_edit(
418 do_postfix_completion( 299 "ifl",
419 r#" 300 r#"
420 enum Result<T, E> { 301enum Option<T> { Some(T), None }
421 Ok(T), 302
422 Err(E), 303fn main() {
423 } 304 let bar = Option::Some(true);
305 bar.<|>
306}
307"#,
308 r#"
309enum Option<T> { Some(T), None }
424 310
425 fn main() { 311fn main() {
426 let bar = Result::Ok(true); 312 let bar = Option::Some(true);
427 bar.<|> 313 if let Some($1) = bar {
428 } 314 $0
429 "#, 315}
430 ), 316}
431 @r###" 317"#,
432 [
433 CompletionItem {
434 label: "box",
435 source_range: 211..211,
436 delete: 207..211,
437 insert: "Box::new(bar)",
438 detail: "Box::new(expr)",
439 },
440 CompletionItem {
441 label: "call",
442 source_range: 211..211,
443 delete: 207..211,
444 insert: "${1}(bar)",
445 detail: "function(expr)",
446 },
447 CompletionItem {
448 label: "dbg",
449 source_range: 211..211,
450 delete: 207..211,
451 insert: "dbg!(bar)",
452 detail: "dbg!(expr)",
453 },
454 CompletionItem {
455 label: "ifl",
456 source_range: 211..211,
457 delete: 207..211,
458 insert: "if let Ok($1) = bar {\n $0\n}",
459 detail: "if let Ok {}",
460 },
461 CompletionItem {
462 label: "match",
463 source_range: 211..211,
464 delete: 207..211,
465 insert: "match bar {\n Ok(${1:_}) => {$2\\},\n Err(${3:_}) => {$0\\},\n}",
466 detail: "match expr {}",
467 },
468 CompletionItem {
469 label: "not",
470 source_range: 211..211,
471 delete: 207..211,
472 insert: "!bar",
473 detail: "!expr",
474 },
475 CompletionItem {
476 label: "ref",
477 source_range: 211..211,
478 delete: 207..211,
479 insert: "&bar",
480 detail: "&expr",
481 },
482 CompletionItem {
483 label: "refm",
484 source_range: 211..211,
485 delete: 207..211,
486 insert: "&mut bar",
487 detail: "&mut expr",
488 },
489 CompletionItem {
490 label: "while",
491 source_range: 211..211,
492 delete: 207..211,
493 insert: "while let Ok($1) = bar {\n $0\n}",
494 detail: "while let Ok {}",
495 },
496 ]
497 "###
498 ); 318 );
499 } 319 }
500 320
501 #[test] 321 #[test]
502 fn some_postfix_completions_ignored() { 322 fn result_match() {
503 assert_debug_snapshot!( 323 check_edit(
504 do_postfix_completion( 324 "match",
505 r#" 325 r#"
506 fn main() { 326enum Result<T, E> { Ok(T), Err(E) }
507 let bar: u8 = 12; 327
508 bar.<|> 328fn main() {
509 } 329 let bar = Result::Ok(true);
510 "#, 330 bar.<|>
511 ), 331}
512 @r###" 332"#,
513 [ 333 r#"
514 CompletionItem { 334enum Result<T, E> { Ok(T), Err(E) }
515 label: "box", 335
516 source_range: 91..91, 336fn main() {
517 delete: 87..91, 337 let bar = Result::Ok(true);
518 insert: "Box::new(bar)", 338 match bar {
519 detail: "Box::new(expr)", 339 Ok(${1:_}) => {$2},
520 }, 340 Err(${3:_}) => {$0},
521 CompletionItem { 341}
522 label: "call", 342}
523 source_range: 91..91, 343"#,
524 delete: 87..91,
525 insert: "${1}(bar)",
526 detail: "function(expr)",
527 },
528 CompletionItem {
529 label: "dbg",
530 source_range: 91..91,
531 delete: 87..91,
532 insert: "dbg!(bar)",
533 detail: "dbg!(expr)",
534 },
535 CompletionItem {
536 label: "match",
537 source_range: 91..91,
538 delete: 87..91,
539 insert: "match bar {\n ${1:_} => {$0\\},\n}",
540 detail: "match expr {}",
541 },
542 CompletionItem {
543 label: "not",
544 source_range: 91..91,
545 delete: 87..91,
546 insert: "!bar",
547 detail: "!expr",
548 },
549 CompletionItem {
550 label: "ref",
551 source_range: 91..91,
552 delete: 87..91,
553 insert: "&bar",
554 detail: "&expr",
555 },
556 CompletionItem {
557 label: "refm",
558 source_range: 91..91,
559 delete: 87..91,
560 insert: "&mut bar",
561 detail: "&mut expr",
562 },
563 ]
564 "###
565 ); 344 );
566 } 345 }
567 346
568 #[test] 347 #[test]
569 fn postfix_completion_works_for_ambiguous_float_literal() { 348 fn postfix_completion_works_for_ambiguous_float_literal() {
570 assert_debug_snapshot!( 349 check_edit("refm", r#"fn main() { 42.<|> }"#, r#"fn main() { &mut 42 }"#)
571 do_postfix_completion(
572 r#"
573 fn main() {
574 42.<|>
575 }
576 "#,
577 ),
578 @r###"
579 [
580 CompletionItem {
581 label: "box",
582 source_range: 52..52,
583 delete: 49..52,
584 insert: "Box::new(42)",
585 detail: "Box::new(expr)",
586 },
587 CompletionItem {
588 label: "call",
589 source_range: 52..52,
590 delete: 49..52,
591 insert: "${1}(42)",
592 detail: "function(expr)",
593 },
594 CompletionItem {
595 label: "dbg",
596 source_range: 52..52,
597 delete: 49..52,
598 insert: "dbg!(42)",
599 detail: "dbg!(expr)",
600 },
601 CompletionItem {
602 label: "match",
603 source_range: 52..52,
604 delete: 49..52,
605 insert: "match 42 {\n ${1:_} => {$0\\},\n}",
606 detail: "match expr {}",
607 },
608 CompletionItem {
609 label: "not",
610 source_range: 52..52,
611 delete: 49..52,
612 insert: "!42",
613 detail: "!expr",
614 },
615 CompletionItem {
616 label: "ref",
617 source_range: 52..52,
618 delete: 49..52,
619 insert: "&42",
620 detail: "&expr",
621 },
622 CompletionItem {
623 label: "refm",
624 source_range: 52..52,
625 delete: 49..52,
626 insert: "&mut 42",
627 detail: "&mut expr",
628 },
629 ]
630 "###
631 );
632 } 350 }
633 351
634 #[test] 352 #[test]
635 fn works_in_simple_macro() { 353 fn works_in_simple_macro() {
636 assert_debug_snapshot!( 354 check_edit(
637 do_postfix_completion( 355 "dbg",
638 r#" 356 r#"
639 macro_rules! m { ($e:expr) => { $e } } 357macro_rules! m { ($e:expr) => { $e } }
640 fn main() { 358fn main() {
641 let bar: u8 = 12; 359 let bar: u8 = 12;
642 m!(bar.b<|>) 360 m!(bar.d<|>)
643 } 361}
644 "#, 362"#,
645 ), 363 r#"
646 @r###" 364macro_rules! m { ($e:expr) => { $e } }
647 [ 365fn main() {
648 CompletionItem { 366 let bar: u8 = 12;
649 label: "box", 367 m!(dbg!(bar))
650 source_range: 149..150, 368}
651 delete: 145..150, 369"#,
652 insert: "Box::new(bar)",
653 detail: "Box::new(expr)",
654 },
655 CompletionItem {
656 label: "call",
657 source_range: 149..150,
658 delete: 145..150,
659 insert: "${1}(bar)",
660 detail: "function(expr)",
661 },
662 CompletionItem {
663 label: "dbg",
664 source_range: 149..150,
665 delete: 145..150,
666 insert: "dbg!(bar)",
667 detail: "dbg!(expr)",
668 },
669 CompletionItem {
670 label: "match",
671 source_range: 149..150,
672 delete: 145..150,
673 insert: "match bar {\n ${1:_} => {$0\\},\n}",
674 detail: "match expr {}",
675 },
676 CompletionItem {
677 label: "not",
678 source_range: 149..150,
679 delete: 145..150,
680 insert: "!bar",
681 detail: "!expr",
682 },
683 CompletionItem {
684 label: "ref",
685 source_range: 149..150,
686 delete: 145..150,
687 insert: "&bar",
688 detail: "&expr",
689 },
690 CompletionItem {
691 label: "refm",
692 source_range: 149..150,
693 delete: 145..150,
694 insert: "&mut bar",
695 detail: "&mut expr",
696 },
697 ]
698 "###
699 ); 370 );
700 } 371 }
701 372
702 #[test] 373 #[test]
703 fn postfix_completion_for_references() { 374 fn postfix_completion_for_references() {
704 assert_debug_snapshot!( 375 check_edit("dbg", r#"fn main() { &&42.<|> }"#, r#"fn main() { dbg!(&&42) }"#);
705 do_postfix_completion( 376 check_edit("refm", r#"fn main() { &&42.<|> }"#, r#"fn main() { &&&mut 42 }"#);
706 r#"
707 fn main() {
708 &&&&42.<|>
709 }
710 "#,
711 ),
712 @r###"
713 [
714 CompletionItem {
715 label: "box",
716 source_range: 56..56,
717 delete: 49..56,
718 insert: "Box::new(&&&&42)",
719 detail: "Box::new(expr)",
720 },
721 CompletionItem {
722 label: "call",
723 source_range: 56..56,
724 delete: 49..56,
725 insert: "${1}(&&&&42)",
726 detail: "function(expr)",
727 },
728 CompletionItem {
729 label: "dbg",
730 source_range: 56..56,
731 delete: 49..56,
732 insert: "dbg!(&&&&42)",
733 detail: "dbg!(expr)",
734 },
735 CompletionItem {
736 label: "match",
737 source_range: 56..56,
738 delete: 49..56,
739 insert: "match &&&&42 {\n ${1:_} => {$0\\},\n}",
740 detail: "match expr {}",
741 },
742 CompletionItem {
743 label: "not",
744 source_range: 56..56,
745 delete: 53..56,
746 insert: "!42",
747 detail: "!expr",
748 },
749 CompletionItem {
750 label: "ref",
751 source_range: 56..56,
752 delete: 53..56,
753 insert: "&42",
754 detail: "&expr",
755 },
756 CompletionItem {
757 label: "refm",
758 source_range: 56..56,
759 delete: 53..56,
760 insert: "&mut 42",
761 detail: "&mut expr",
762 },
763 ]
764 "###
765 );
766 } 377 }
767} 378}
diff --git a/crates/ra_ide/src/completion/complete_qualified_path.rs b/crates/ra_ide/src/completion/complete_qualified_path.rs
index 02ac0166b..b08f5b9b4 100644
--- a/crates/ra_ide/src/completion/complete_qualified_path.rs
+++ b/crates/ra_ide/src/completion/complete_qualified_path.rs
@@ -17,21 +17,20 @@ pub(super) fn complete_qualified_path(acc: &mut Completions, ctx: &CompletionCon
17 return; 17 return;
18 } 18 }
19 19
20 let scope = ctx.scope(); 20 let context_module = ctx.scope.module();
21 let context_module = scope.module();
22 21
23 let res = match scope.resolve_hir_path_qualifier(&path) { 22 let resolution = match ctx.scope.resolve_hir_path_qualifier(&path) {
24 Some(res) => res, 23 Some(res) => res,
25 None => return, 24 None => return,
26 }; 25 };
27 26
28 // Add associated types on type parameters and `Self`. 27 // Add associated types on type parameters and `Self`.
29 res.assoc_type_shorthand_candidates(ctx.db, |alias| { 28 resolution.assoc_type_shorthand_candidates(ctx.db, |alias| {
30 acc.add_type_alias(ctx, alias); 29 acc.add_type_alias(ctx, alias);
31 None::<()> 30 None::<()>
32 }); 31 });
33 32
34 match res { 33 match resolution {
35 PathResolution::Def(hir::ModuleDef::Module(module)) => { 34 PathResolution::Def(hir::ModuleDef::Module(module)) => {
36 let module_scope = module.scope(ctx.db, context_module); 35 let module_scope = module.scope(ctx.db, context_module);
37 for (name, def) in module_scope { 36 for (name, def) in module_scope {
@@ -68,7 +67,7 @@ pub(super) fn complete_qualified_path(acc: &mut Completions, ctx: &CompletionCon
68 67
69 let krate = ctx.krate; 68 let krate = ctx.krate;
70 if let Some(krate) = krate { 69 if let Some(krate) = krate {
71 let traits_in_scope = ctx.scope().traits_in_scope(); 70 let traits_in_scope = ctx.scope.traits_in_scope();
72 ty.iterate_path_candidates(ctx.db, krate, &traits_in_scope, None, |_ty, item| { 71 ty.iterate_path_candidates(ctx.db, krate, &traits_in_scope, None, |_ty, item| {
73 if context_module.map_or(false, |m| !item.is_visible_from(ctx.db, m)) { 72 if context_module.map_or(false, |m| !item.is_visible_from(ctx.db, m)) {
74 return None; 73 return None;
@@ -113,13 +112,13 @@ pub(super) fn complete_qualified_path(acc: &mut Completions, ctx: &CompletionCon
113 } 112 }
114 PathResolution::TypeParam(_) | PathResolution::SelfType(_) => { 113 PathResolution::TypeParam(_) | PathResolution::SelfType(_) => {
115 if let Some(krate) = ctx.krate { 114 if let Some(krate) = ctx.krate {
116 let ty = match res { 115 let ty = match resolution {
117 PathResolution::TypeParam(param) => param.ty(ctx.db), 116 PathResolution::TypeParam(param) => param.ty(ctx.db),
118 PathResolution::SelfType(impl_def) => impl_def.target_ty(ctx.db), 117 PathResolution::SelfType(impl_def) => impl_def.target_ty(ctx.db),
119 _ => return, 118 _ => return,
120 }; 119 };
121 120
122 let traits_in_scope = ctx.scope().traits_in_scope(); 121 let traits_in_scope = ctx.scope.traits_in_scope();
123 let mut seen = FxHashSet::default(); 122 let mut seen = FxHashSet::default();
124 ty.iterate_path_candidates(ctx.db, krate, &traits_in_scope, None, |_ty, item| { 123 ty.iterate_path_candidates(ctx.db, krate, &traits_in_scope, None, |_ty, item| {
125 if context_module.map_or(false, |m| !item.is_visible_from(ctx.db, m)) { 124 if context_module.map_or(false, |m| !item.is_visible_from(ctx.db, m)) {
@@ -147,1229 +146,588 @@ pub(super) fn complete_qualified_path(acc: &mut Completions, ctx: &CompletionCon
147 146
148#[cfg(test)] 147#[cfg(test)]
149mod tests { 148mod tests {
149 use expect::{expect, Expect};
150 use test_utils::mark; 150 use test_utils::mark;
151 151
152 use crate::completion::{test_utils::do_completion, CompletionItem, CompletionKind}; 152 use crate::completion::{
153 use insta::assert_debug_snapshot; 153 test_utils::{check_edit, completion_list},
154 CompletionKind,
155 };
156
157 fn check(ra_fixture: &str, expect: Expect) {
158 let actual = completion_list(ra_fixture, CompletionKind::Reference);
159 expect.assert_eq(&actual);
160 }
154 161
155 fn do_reference_completion(code: &str) -> Vec<CompletionItem> { 162 fn check_builtin(ra_fixture: &str, expect: Expect) {
156 do_completion(code, CompletionKind::Reference) 163 let actual = completion_list(ra_fixture, CompletionKind::BuiltinType);
164 expect.assert_eq(&actual);
157 } 165 }
158 166
159 #[test] 167 #[test]
160 fn dont_complete_current_use() { 168 fn dont_complete_current_use() {
161 mark::check!(dont_complete_current_use); 169 mark::check!(dont_complete_current_use);
162 let completions = do_completion(r"use self::foo<|>;", CompletionKind::Reference); 170 check(r#"use self::foo<|>;"#, expect![[""]]);
163 assert!(completions.is_empty());
164 } 171 }
165 172
166 #[test] 173 #[test]
167 fn dont_complete_current_use_in_braces_with_glob() { 174 fn dont_complete_current_use_in_braces_with_glob() {
168 let completions = do_completion( 175 check(
169 r" 176 r#"
170 mod foo { pub struct S; } 177mod foo { pub struct S; }
171 use self::{foo::*, bar<|>}; 178use self::{foo::*, bar<|>};
172 ", 179"#,
173 CompletionKind::Reference, 180 expect![[r#"
181 st S
182 md foo
183 "#]],
174 ); 184 );
175 assert_eq!(completions.len(), 2);
176 } 185 }
177 186
178 #[test] 187 #[test]
179 fn dont_complete_primitive_in_use() { 188 fn dont_complete_primitive_in_use() {
180 let completions = do_completion(r"use self::<|>;", CompletionKind::BuiltinType); 189 check_builtin(r#"use self::<|>;"#, expect![[""]]);
181 assert!(completions.is_empty());
182 } 190 }
183 191
184 #[test] 192 #[test]
185 fn dont_complete_primitive_in_module_scope() { 193 fn dont_complete_primitive_in_module_scope() {
186 let completions = do_completion(r"fn foo() { self::<|> }", CompletionKind::BuiltinType); 194 check_builtin(r#"fn foo() { self::<|> }"#, expect![[""]]);
187 assert!(completions.is_empty());
188 } 195 }
189 196
190 #[test] 197 #[test]
191 fn completes_primitives() { 198 fn completes_primitives() {
192 let completions = 199 check_builtin(
193 do_completion(r"fn main() { let _: <|> = 92; }", CompletionKind::BuiltinType); 200 r#"fn main() { let _: <|> = 92; }"#,
194 assert_eq!(completions.len(), 17); 201 expect![[r#"
195 } 202 bt bool
196 203 bt char
197 #[test] 204 bt f32
198 fn completes_mod_with_docs() { 205 bt f64
199 assert_debug_snapshot!( 206 bt i128
200 do_reference_completion( 207 bt i16
201 r" 208 bt i32
202 use self::my<|>; 209 bt i64
203 210 bt i8
204 /// Some simple 211 bt isize
205 /// docs describing `mod my`. 212 bt str
206 mod my { 213 bt u128
207 struct Bar; 214 bt u16
208 } 215 bt u32
209 " 216 bt u64
210 ), 217 bt u8
211 @r###" 218 bt usize
212 [ 219 "#]],
213 CompletionItem {
214 label: "my",
215 source_range: 27..29,
216 delete: 27..29,
217 insert: "my",
218 kind: Module,
219 documentation: Documentation(
220 "Some simple\ndocs describing `mod my`.",
221 ),
222 },
223 ]
224 "###
225 ); 220 );
226 } 221 }
227 222
228 #[test] 223 #[test]
229 fn completes_mod_with_same_name_as_function() { 224 fn completes_mod_with_same_name_as_function() {
230 assert_debug_snapshot!( 225 check(
231 do_reference_completion( 226 r#"
232 r" 227use self::my::<|>;
233 use self::my::<|>; 228
234 229mod my { pub struct Bar; }
235 mod my { 230fn my() {}
236 pub struct Bar; 231"#,
237 } 232 expect![[r#"
238 233 st Bar
239 fn my() {} 234 "#]],
240 "
241 ),
242 @r###"
243 [
244 CompletionItem {
245 label: "Bar",
246 source_range: 31..31,
247 delete: 31..31,
248 insert: "Bar",
249 kind: Struct,
250 },
251 ]
252 "###
253 ); 235 );
254 } 236 }
255 237
256 #[test] 238 #[test]
257 fn path_visibility() { 239 fn filters_visibility() {
258 assert_debug_snapshot!( 240 check(
259 do_reference_completion( 241 r#"
260 r" 242use self::my::<|>;
261 use self::my::<|>; 243
262 244mod my {
263 mod my { 245 struct Bar;
264 struct Bar; 246 pub struct Foo;
265 pub struct Foo; 247 pub use Bar as PublicBar;
266 pub use Bar as PublicBar; 248}
267 } 249"#,
268 " 250 expect![[r#"
269 ), 251 st Foo
270 @r###" 252 st PublicBar
271 [ 253 "#]],
272 CompletionItem {
273 label: "Foo",
274 source_range: 31..31,
275 delete: 31..31,
276 insert: "Foo",
277 kind: Struct,
278 },
279 CompletionItem {
280 label: "PublicBar",
281 source_range: 31..31,
282 delete: 31..31,
283 insert: "PublicBar",
284 kind: Struct,
285 },
286 ]
287 "###
288 ); 254 );
289 } 255 }
290 256
291 #[test] 257 #[test]
292 fn completes_use_item_starting_with_self() { 258 fn completes_use_item_starting_with_self() {
293 assert_debug_snapshot!( 259 check(
294 do_reference_completion( 260 r#"
295 r" 261use self::m::<|>;
296 use self::m::<|>;
297 262
298 mod m { 263mod m { pub struct Bar; }
299 pub struct Bar; 264"#,
300 } 265 expect![[r#"
301 " 266 st Bar
302 ), 267 "#]],
303 @r###"
304 [
305 CompletionItem {
306 label: "Bar",
307 source_range: 30..30,
308 delete: 30..30,
309 insert: "Bar",
310 kind: Struct,
311 },
312 ]
313 "###
314 ); 268 );
315 } 269 }
316 270
317 #[test] 271 #[test]
318 fn completes_use_item_starting_with_crate() { 272 fn completes_use_item_starting_with_crate() {
319 assert_debug_snapshot!( 273 check(
320 do_reference_completion( 274 r#"
321 " 275//- /lib.rs
322 //- /lib.rs 276mod foo;
323 mod foo; 277struct Spam;
324 struct Spam; 278//- /foo.rs
325 //- /foo.rs 279use crate::Sp<|>
326 use crate::Sp<|> 280"#,
327 " 281 expect![[r#"
328 ), 282 st Spam
329 @r###" 283 md foo
330 [ 284 "#]],
331 CompletionItem {
332 label: "Spam",
333 source_range: 11..13,
334 delete: 11..13,
335 insert: "Spam",
336 kind: Struct,
337 },
338 CompletionItem {
339 label: "foo",
340 source_range: 11..13,
341 delete: 11..13,
342 insert: "foo",
343 kind: Module,
344 },
345 ]
346 "###
347 ); 285 );
348 } 286 }
349 287
350 #[test] 288 #[test]
351 fn completes_nested_use_tree() { 289 fn completes_nested_use_tree() {
352 assert_debug_snapshot!( 290 check(
353 do_reference_completion( 291 r#"
354 " 292//- /lib.rs
355 //- /lib.rs 293mod foo;
356 mod foo; 294struct Spam;
357 struct Spam; 295//- /foo.rs
358 //- /foo.rs 296use crate::{Sp<|>};
359 use crate::{Sp<|>}; 297"#,
360 " 298 expect![[r#"
361 ), 299 st Spam
362 @r###" 300 md foo
363 [ 301 "#]],
364 CompletionItem {
365 label: "Spam",
366 source_range: 12..14,
367 delete: 12..14,
368 insert: "Spam",
369 kind: Struct,
370 },
371 CompletionItem {
372 label: "foo",
373 source_range: 12..14,
374 delete: 12..14,
375 insert: "foo",
376 kind: Module,
377 },
378 ]
379 "###
380 ); 302 );
381 } 303 }
382 304
383 #[test] 305 #[test]
384 fn completes_deeply_nested_use_tree() { 306 fn completes_deeply_nested_use_tree() {
385 assert_debug_snapshot!( 307 check(
386 do_reference_completion( 308 r#"
387 " 309//- /lib.rs
388 //- /lib.rs 310mod foo;
389 mod foo; 311pub mod bar {
390 pub mod bar { 312 pub mod baz {
391 pub mod baz { 313 pub struct Spam;
392 pub struct Spam;
393 }
394 }
395 //- /foo.rs
396 use crate::{bar::{baz::Sp<|>}};
397 "
398 ),
399 @r###"
400 [
401 CompletionItem {
402 label: "Spam",
403 source_range: 23..25,
404 delete: 23..25,
405 insert: "Spam",
406 kind: Struct,
407 },
408 ]
409 "###
410 );
411 }
412
413 #[test]
414 fn completes_enum_variant() {
415 assert_debug_snapshot!(
416 do_reference_completion(
417 "
418 //- /lib.rs
419 /// An enum
420 enum E {
421 /// Foo Variant
422 Foo,
423 /// Bar Variant with i32
424 Bar(i32)
425 }
426 fn foo() { let _ = E::<|> }
427 "
428 ),
429 @r###"
430 [
431 CompletionItem {
432 label: "Bar(…)",
433 source_range: 116..116,
434 delete: 116..116,
435 insert: "Bar($0)",
436 kind: EnumVariant,
437 lookup: "Bar",
438 detail: "(i32)",
439 documentation: Documentation(
440 "Bar Variant with i32",
441 ),
442 trigger_call_info: true,
443 },
444 CompletionItem {
445 label: "Foo",
446 source_range: 116..116,
447 delete: 116..116,
448 insert: "Foo",
449 kind: EnumVariant,
450 detail: "()",
451 documentation: Documentation(
452 "Foo Variant",
453 ),
454 },
455 ]
456 "###
457 );
458 }
459
460 #[test]
461 fn completes_enum_variant_with_details() {
462 assert_debug_snapshot!(
463 do_reference_completion(
464 "
465 //- /lib.rs
466 struct S { field: u32 }
467 /// An enum
468 enum E {
469 /// Foo Variant (empty)
470 Foo,
471 /// Bar Variant with i32 and u32
472 Bar(i32, u32),
473 ///
474 S(S),
475 }
476 fn foo() { let _ = E::<|> }
477 "
478 ),
479 @r###"
480 [
481 CompletionItem {
482 label: "Bar(…)",
483 source_range: 180..180,
484 delete: 180..180,
485 insert: "Bar($0)",
486 kind: EnumVariant,
487 lookup: "Bar",
488 detail: "(i32, u32)",
489 documentation: Documentation(
490 "Bar Variant with i32 and u32",
491 ),
492 trigger_call_info: true,
493 },
494 CompletionItem {
495 label: "Foo",
496 source_range: 180..180,
497 delete: 180..180,
498 insert: "Foo",
499 kind: EnumVariant,
500 detail: "()",
501 documentation: Documentation(
502 "Foo Variant (empty)",
503 ),
504 },
505 CompletionItem {
506 label: "S(…)",
507 source_range: 180..180,
508 delete: 180..180,
509 insert: "S($0)",
510 kind: EnumVariant,
511 lookup: "S",
512 detail: "(S)",
513 documentation: Documentation(
514 "",
515 ),
516 trigger_call_info: true,
517 },
518 ]
519 "###
520 );
521 } 314 }
522 315}
523 #[test] 316//- /foo.rs
524 fn completes_struct_associated_method() { 317use crate::{bar::{baz::Sp<|>}};
525 assert_debug_snapshot!( 318"#,
526 do_reference_completion( 319 expect![[r#"
527 " 320 st Spam
528 //- /lib.rs 321 "#]],
529 /// A Struct
530 struct S;
531
532 impl S {
533 /// An associated method
534 fn m() { }
535 }
536
537 fn foo() { let _ = S::<|> }
538 "
539 ),
540 @r###"
541 [
542 CompletionItem {
543 label: "m()",
544 source_range: 100..100,
545 delete: 100..100,
546 insert: "m()$0",
547 kind: Function,
548 lookup: "m",
549 detail: "fn m()",
550 documentation: Documentation(
551 "An associated method",
552 ),
553 },
554 ]
555 "###
556 ); 322 );
557 } 323 }
558 324
559 #[test] 325 #[test]
560 fn completes_struct_associated_method_with_self() { 326 fn completes_enum_variant() {
561 assert_debug_snapshot!( 327 check(
562 do_reference_completion( 328 r#"
563 " 329enum E { Foo, Bar(i32) }
564 //- /lib.rs 330fn foo() { let _ = E::<|> }
565 /// A Struct 331"#,
566 struct S; 332 expect![[r#"
567 333 ev Bar(…) (i32)
568 impl S { 334 ev Foo ()
569 /// An associated method 335 "#]],
570 fn m(&self) { }
571 }
572
573 fn foo() { let _ = S::<|> }
574 "
575 ),
576 @r###"
577 [
578 CompletionItem {
579 label: "m()",
580 source_range: 105..105,
581 delete: 105..105,
582 insert: "m()$0",
583 kind: Method,
584 lookup: "m",
585 detail: "fn m(&self)",
586 documentation: Documentation(
587 "An associated method",
588 ),
589 },
590 ]
591 "###
592 ); 336 );
593 } 337 }
594 338
595 #[test] 339 #[test]
596 fn completes_struct_associated_const() { 340 fn completes_struct_associated_items() {
597 assert_debug_snapshot!( 341 check(
598 do_reference_completion( 342 r#"
599 " 343//- /lib.rs
600 //- /lib.rs 344struct S;
601 /// A Struct 345
602 struct S; 346impl S {
603 347 fn a() {}
604 impl S { 348 fn b(&self) {}
605 /// An associated const 349 const C: i32 = 42;
606 const C: i32 = 42; 350 type T = i32;
607 } 351}
608 352
609 fn foo() { let _ = S::<|> } 353fn foo() { let _ = S::<|> }
610 " 354"#,
611 ), 355 expect![[r#"
612 @r###" 356 ct C const C: i32 = 42;
613 [ 357 ta T type T = i32;
614 CompletionItem { 358 fn a() fn a()
615 label: "C", 359 me b() fn b(&self)
616 source_range: 107..107, 360 "#]],
617 delete: 107..107,
618 insert: "C",
619 kind: Const,
620 detail: "const C: i32 = 42;",
621 documentation: Documentation(
622 "An associated const",
623 ),
624 },
625 ]
626 "###
627 ); 361 );
628 } 362 }
629 363
630 #[test] 364 #[test]
631 fn completes_struct_associated_type() { 365 fn associated_item_visibility() {
632 assert_debug_snapshot!( 366 check(
633 do_reference_completion( 367 r#"
634 " 368struct S;
635 //- /lib.rs
636 /// A Struct
637 struct S;
638
639 impl S {
640 /// An associated type
641 type T = i32;
642 }
643 369
644 fn foo() { let _ = S::<|> } 370mod m {
645 " 371 impl super::S {
646 ), 372 pub(super) fn public_method() { }
647 @r###" 373 fn private_method() { }
648 [ 374 pub(super) type PublicType = u32;
649 CompletionItem { 375 type PrivateType = u32;
650 label: "T", 376 pub(super) const PUBLIC_CONST: u32 = 1;
651 source_range: 101..101, 377 const PRIVATE_CONST: u32 = 1;
652 delete: 101..101,
653 insert: "T",
654 kind: TypeAlias,
655 detail: "type T = i32;",
656 documentation: Documentation(
657 "An associated type",
658 ),
659 },
660 ]
661 "###
662 );
663 } 378 }
379}
664 380
665 #[test] 381fn foo() { let _ = S::<|> }
666 fn associated_item_visibility() { 382"#,
667 assert_debug_snapshot!( 383 expect![[r#"
668 do_reference_completion( 384 ct PUBLIC_CONST pub(super) const PUBLIC_CONST: u32 = 1;
669 " 385 ta PublicType pub(super) type PublicType = u32;
670 //- /lib.rs 386 fn public_method() pub(super) fn public_method()
671 struct S; 387 "#]],
672
673 mod m {
674 impl super::S {
675 pub(super) fn public_method() { }
676 fn private_method() { }
677 pub(super) type PublicType = u32;
678 type PrivateType = u32;
679 pub(super) const PUBLIC_CONST: u32 = 1;
680 const PRIVATE_CONST: u32 = 1;
681 }
682 }
683
684 fn foo() { let _ = S::<|> }
685 "
686 ),
687 @r###"
688 [
689 CompletionItem {
690 label: "PUBLIC_CONST",
691 source_range: 302..302,
692 delete: 302..302,
693 insert: "PUBLIC_CONST",
694 kind: Const,
695 detail: "pub(super) const PUBLIC_CONST: u32 = 1;",
696 },
697 CompletionItem {
698 label: "PublicType",
699 source_range: 302..302,
700 delete: 302..302,
701 insert: "PublicType",
702 kind: TypeAlias,
703 detail: "pub(super) type PublicType = u32;",
704 },
705 CompletionItem {
706 label: "public_method()",
707 source_range: 302..302,
708 delete: 302..302,
709 insert: "public_method()$0",
710 kind: Function,
711 lookup: "public_method",
712 detail: "pub(super) fn public_method()",
713 },
714 ]
715 "###
716 ); 388 );
717 } 389 }
718 390
719 #[test] 391 #[test]
720 fn completes_enum_associated_method() { 392 fn completes_enum_associated_method() {
721 assert_debug_snapshot!( 393 check(
722 do_reference_completion( 394 r#"
723 " 395enum E {};
724 //- /lib.rs 396impl E { fn m() { } }
725 /// An enum 397
726 enum S {}; 398fn foo() { let _ = E::<|> }
727 399 "#,
728 impl S { 400 expect![[r#"
729 /// An associated method 401 fn m() fn m()
730 fn m() { } 402 "#]],
731 }
732
733 fn foo() { let _ = S::<|> }
734 "
735 ),
736 @r###"
737 [
738 CompletionItem {
739 label: "m()",
740 source_range: 100..100,
741 delete: 100..100,
742 insert: "m()$0",
743 kind: Function,
744 lookup: "m",
745 detail: "fn m()",
746 documentation: Documentation(
747 "An associated method",
748 ),
749 },
750 ]
751 "###
752 ); 403 );
753 } 404 }
754 405
755 #[test] 406 #[test]
756 fn completes_union_associated_method() { 407 fn completes_union_associated_method() {
757 assert_debug_snapshot!( 408 check(
758 do_reference_completion( 409 r#"
759 " 410union U {};
760 //- /lib.rs 411impl U { fn m() { } }
761 /// A union 412
762 union U {}; 413fn foo() { let _ = U::<|> }
763 414"#,
764 impl U { 415 expect![[r#"
765 /// An associated method 416 fn m() fn m()
766 fn m() { } 417 "#]],
767 }
768
769 fn foo() { let _ = U::<|> }
770 "
771 ),
772 @r###"
773 [
774 CompletionItem {
775 label: "m()",
776 source_range: 101..101,
777 delete: 101..101,
778 insert: "m()$0",
779 kind: Function,
780 lookup: "m",
781 detail: "fn m()",
782 documentation: Documentation(
783 "An associated method",
784 ),
785 },
786 ]
787 "###
788 ); 418 );
789 } 419 }
790 420
791 #[test] 421 #[test]
792 fn completes_use_paths_across_crates() { 422 fn completes_use_paths_across_crates() {
793 assert_debug_snapshot!( 423 check(
794 do_reference_completion( 424 r#"
795 " 425//- /main.rs
796 //- /main.rs 426use foo::<|>;
797 use foo::<|>; 427
798 428//- /foo/lib.rs
799 //- /foo/lib.rs 429pub mod bar { pub struct S; }
800 pub mod bar { 430"#,
801 pub struct S; 431 expect![[r#"
802 } 432 md bar
803 " 433 "#]],
804 ),
805 @r###"
806 [
807 CompletionItem {
808 label: "bar",
809 source_range: 9..9,
810 delete: 9..9,
811 insert: "bar",
812 kind: Module,
813 },
814 ]
815 "###
816 ); 434 );
817 } 435 }
818 436
819 #[test] 437 #[test]
820 fn completes_trait_associated_method_1() { 438 fn completes_trait_associated_method_1() {
821 assert_debug_snapshot!( 439 check(
822 do_reference_completion( 440 r#"
823 " 441trait Trait { fn m(); }
824 //- /lib.rs
825 trait Trait {
826 /// A trait method
827 fn m();
828 }
829 442
830 fn foo() { let _ = Trait::<|> } 443fn foo() { let _ = Trait::<|> }
831 " 444"#,
832 ), 445 expect![[r#"
833 @r###" 446 fn m() fn m()
834 [ 447 "#]],
835 CompletionItem {
836 label: "m()",
837 source_range: 73..73,
838 delete: 73..73,
839 insert: "m()$0",
840 kind: Function,
841 lookup: "m",
842 detail: "fn m()",
843 documentation: Documentation(
844 "A trait method",
845 ),
846 },
847 ]
848 "###
849 ); 448 );
850 } 449 }
851 450
852 #[test] 451 #[test]
853 fn completes_trait_associated_method_2() { 452 fn completes_trait_associated_method_2() {
854 assert_debug_snapshot!( 453 check(
855 do_reference_completion( 454 r#"
856 " 455trait Trait { fn m(); }
857 //- /lib.rs 456
858 trait Trait { 457struct S;
859 /// A trait method 458impl Trait for S {}
860 fn m();
861 }
862 459
863 struct S; 460fn foo() { let _ = S::<|> }
864 impl Trait for S {} 461"#,
865 462 expect![[r#"
866 fn foo() { let _ = S::<|> } 463 fn m() fn m()
867 " 464 "#]],
868 ),
869 @r###"
870 [
871 CompletionItem {
872 label: "m()",
873 source_range: 99..99,
874 delete: 99..99,
875 insert: "m()$0",
876 kind: Function,
877 lookup: "m",
878 detail: "fn m()",
879 documentation: Documentation(
880 "A trait method",
881 ),
882 },
883 ]
884 "###
885 ); 465 );
886 } 466 }
887 467
888 #[test] 468 #[test]
889 fn completes_trait_associated_method_3() { 469 fn completes_trait_associated_method_3() {
890 assert_debug_snapshot!( 470 check(
891 do_reference_completion( 471 r#"
892 " 472trait Trait { fn m(); }
893 //- /lib.rs
894 trait Trait {
895 /// A trait method
896 fn m();
897 }
898 473
899 struct S; 474struct S;
900 impl Trait for S {} 475impl Trait for S {}
901 476
902 fn foo() { let _ = <S as Trait>::<|> } 477fn foo() { let _ = <S as Trait>::<|> }
903 " 478"#,
904 ), 479 expect![[r#"
905 @r###" 480 fn m() fn m()
906 [ 481 "#]],
907 CompletionItem {
908 label: "m()",
909 source_range: 110..110,
910 delete: 110..110,
911 insert: "m()$0",
912 kind: Function,
913 lookup: "m",
914 detail: "fn m()",
915 documentation: Documentation(
916 "A trait method",
917 ),
918 },
919 ]
920 "###
921 ); 482 );
922 } 483 }
923 484
924 #[test] 485 #[test]
925 fn completes_ty_param_assoc_ty() { 486 fn completes_ty_param_assoc_ty() {
926 assert_debug_snapshot!( 487 check(
927 do_reference_completion( 488 r#"
928 " 489trait Super {
929 //- /lib.rs 490 type Ty;
930 trait Super { 491 const CONST: u8;
931 type Ty; 492 fn func() {}
932 const CONST: u8; 493 fn method(&self) {}
933 fn func() {} 494}
934 fn method(&self) {}
935 }
936 495
937 trait Sub: Super { 496trait Sub: Super {
938 type SubTy; 497 type SubTy;
939 const C2: (); 498 const C2: ();
940 fn subfunc() {} 499 fn subfunc() {}
941 fn submethod(&self) {} 500 fn submethod(&self) {}
942 } 501}
943 502
944 fn foo<T: Sub>() { 503fn foo<T: Sub>() { T::<|> }
945 T::<|> 504"#,
946 } 505 expect![[r#"
947 " 506 ct C2 const C2: ();
948 ), 507 ct CONST const CONST: u8;
949 @r###" 508 ta SubTy type SubTy;
950 [ 509 ta Ty type Ty;
951 CompletionItem { 510 fn func() fn func()
952 label: "C2", 511 me method() fn method(&self)
953 source_range: 219..219, 512 fn subfunc() fn subfunc()
954 delete: 219..219, 513 me submethod() fn submethod(&self)
955 insert: "C2", 514 "#]],
956 kind: Const,
957 detail: "const C2: ();",
958 },
959 CompletionItem {
960 label: "CONST",
961 source_range: 219..219,
962 delete: 219..219,
963 insert: "CONST",
964 kind: Const,
965 detail: "const CONST: u8;",
966 },
967 CompletionItem {
968 label: "SubTy",
969 source_range: 219..219,
970 delete: 219..219,
971 insert: "SubTy",
972 kind: TypeAlias,
973 detail: "type SubTy;",
974 },
975 CompletionItem {
976 label: "Ty",
977 source_range: 219..219,
978 delete: 219..219,
979 insert: "Ty",
980 kind: TypeAlias,
981 detail: "type Ty;",
982 },
983 CompletionItem {
984 label: "func()",
985 source_range: 219..219,
986 delete: 219..219,
987 insert: "func()$0",
988 kind: Function,
989 lookup: "func",
990 detail: "fn func()",
991 },
992 CompletionItem {
993 label: "method()",
994 source_range: 219..219,
995 delete: 219..219,
996 insert: "method()$0",
997 kind: Method,
998 lookup: "method",
999 detail: "fn method(&self)",
1000 },
1001 CompletionItem {
1002 label: "subfunc()",
1003 source_range: 219..219,
1004 delete: 219..219,
1005 insert: "subfunc()$0",
1006 kind: Function,
1007 lookup: "subfunc",
1008 detail: "fn subfunc()",
1009 },
1010 CompletionItem {
1011 label: "submethod()",
1012 source_range: 219..219,
1013 delete: 219..219,
1014 insert: "submethod()$0",
1015 kind: Method,
1016 lookup: "submethod",
1017 detail: "fn submethod(&self)",
1018 },
1019 ]
1020 "###
1021 ); 515 );
1022 } 516 }
1023 517
1024 #[test] 518 #[test]
1025 fn completes_self_param_assoc_ty() { 519 fn completes_self_param_assoc_ty() {
1026 assert_debug_snapshot!( 520 check(
1027 do_reference_completion( 521 r#"
1028 " 522trait Super {
1029 //- /lib.rs 523 type Ty;
1030 trait Super { 524 const CONST: u8 = 0;
1031 type Ty; 525 fn func() {}
1032 const CONST: u8 = 0; 526 fn method(&self) {}
1033 fn func() {} 527}
1034 fn method(&self) {}
1035 }
1036 528
1037 trait Sub: Super { 529trait Sub: Super {
1038 type SubTy; 530 type SubTy;
1039 const C2: () = (); 531 const C2: () = ();
1040 fn subfunc() {} 532 fn subfunc() {}
1041 fn submethod(&self) {} 533 fn submethod(&self) {}
1042 } 534}
1043 535
1044 struct Wrap<T>(T); 536struct Wrap<T>(T);
1045 impl<T> Super for Wrap<T> {} 537impl<T> Super for Wrap<T> {}
1046 impl<T> Sub for Wrap<T> { 538impl<T> Sub for Wrap<T> {
1047 fn subfunc() { 539 fn subfunc() {
1048 // Should be able to assume `Self: Sub + Super` 540 // Should be able to assume `Self: Sub + Super`
1049 Self::<|> 541 Self::<|>
1050 } 542 }
1051 } 543}
1052 " 544"#,
1053 ), 545 expect![[r#"
1054 @r###" 546 ct C2 const C2: () = ();
1055 [ 547 ct CONST const CONST: u8 = 0;
1056 CompletionItem { 548 ta SubTy type SubTy;
1057 label: "C2", 549 ta Ty type Ty;
1058 source_range: 365..365, 550 fn func() fn func()
1059 delete: 365..365, 551 me method() fn method(&self)
1060 insert: "C2", 552 fn subfunc() fn subfunc()
1061 kind: Const, 553 me submethod() fn submethod(&self)
1062 detail: "const C2: () = ();", 554 "#]],
1063 },
1064 CompletionItem {
1065 label: "CONST",
1066 source_range: 365..365,
1067 delete: 365..365,
1068 insert: "CONST",
1069 kind: Const,
1070 detail: "const CONST: u8 = 0;",
1071 },
1072 CompletionItem {
1073 label: "SubTy",
1074 source_range: 365..365,
1075 delete: 365..365,
1076 insert: "SubTy",
1077 kind: TypeAlias,
1078 detail: "type SubTy;",
1079 },
1080 CompletionItem {
1081 label: "Ty",
1082 source_range: 365..365,
1083 delete: 365..365,
1084 insert: "Ty",
1085 kind: TypeAlias,
1086 detail: "type Ty;",
1087 },
1088 CompletionItem {
1089 label: "func()",
1090 source_range: 365..365,
1091 delete: 365..365,
1092 insert: "func()$0",
1093 kind: Function,
1094 lookup: "func",
1095 detail: "fn func()",
1096 },
1097 CompletionItem {
1098 label: "method()",
1099 source_range: 365..365,
1100 delete: 365..365,
1101 insert: "method()$0",
1102 kind: Method,
1103 lookup: "method",
1104 detail: "fn method(&self)",
1105 },
1106 CompletionItem {
1107 label: "subfunc()",
1108 source_range: 365..365,
1109 delete: 365..365,
1110 insert: "subfunc()$0",
1111 kind: Function,
1112 lookup: "subfunc",
1113 detail: "fn subfunc()",
1114 },
1115 CompletionItem {
1116 label: "submethod()",
1117 source_range: 365..365,
1118 delete: 365..365,
1119 insert: "submethod()$0",
1120 kind: Method,
1121 lookup: "submethod",
1122 detail: "fn submethod(&self)",
1123 },
1124 ]
1125 "###
1126 ); 555 );
1127 } 556 }
1128 557
1129 #[test] 558 #[test]
1130 fn completes_type_alias() { 559 fn completes_type_alias() {
1131 assert_debug_snapshot!( 560 check(
1132 do_reference_completion( 561 r#"
1133 " 562struct S;
1134 struct S; 563impl S { fn foo() {} }
1135 impl S { fn foo() {} } 564type T = S;
1136 type T = S; 565impl T { fn bar() {} }
1137 impl T { fn bar() {} } 566
1138 567fn main() { T::<|>; }
1139 fn main() { 568"#,
1140 T::<|>; 569 expect![[r#"
1141 } 570 fn bar() fn bar()
1142 " 571 fn foo() fn foo()
1143 ), 572 "#]],
1144 @r###"
1145 [
1146 CompletionItem {
1147 label: "bar()",
1148 source_range: 185..185,
1149 delete: 185..185,
1150 insert: "bar()$0",
1151 kind: Function,
1152 lookup: "bar",
1153 detail: "fn bar()",
1154 },
1155 CompletionItem {
1156 label: "foo()",
1157 source_range: 185..185,
1158 delete: 185..185,
1159 insert: "foo()$0",
1160 kind: Function,
1161 lookup: "foo",
1162 detail: "fn foo()",
1163 },
1164 ]
1165 "###
1166 ); 573 );
1167 } 574 }
1168 575
1169 #[test] 576 #[test]
1170 fn completes_qualified_macros() { 577 fn completes_qualified_macros() {
1171 assert_debug_snapshot!( 578 check(
1172 do_reference_completion( 579 r#"
1173 " 580#[macro_export]
1174 #[macro_export] 581macro_rules! foo { () => {} }
1175 macro_rules! foo { 582
1176 () => {} 583fn main() { let _ = crate::<|> }
1177 } 584 "#,
585 expect![[r##"
586 ma foo!(…) #[macro_export]
587 macro_rules! foo
588 fn main() fn main()
589 "##]],
590 );
591 }
1178 592
1179 fn main() { 593 #[test]
1180 let _ = crate::<|> 594 fn test_super_super_completion() {
1181 } 595 check(
1182 " 596 r#"
1183 ), 597mod a {
1184 @r###" 598 const A: usize = 0;
1185 [ 599 mod b {
1186 CompletionItem { 600 const B: usize = 0;
1187 label: "foo!(…)", 601 mod c { use super::super::<|> }
1188 source_range: 179..179, 602 }
1189 delete: 179..179, 603}
1190 insert: "foo!($0)", 604"#,
1191 kind: Macro, 605 expect![[r#"
1192 detail: "#[macro_export]\nmacro_rules! foo", 606 ct A
1193 }, 607 md b
1194 CompletionItem { 608 "#]],
1195 label: "main()",
1196 source_range: 179..179,
1197 delete: 179..179,
1198 insert: "main()$0",
1199 kind: Function,
1200 lookup: "main",
1201 detail: "fn main()",
1202 },
1203 ]
1204 "###
1205 ); 609 );
1206 } 610 }
1207 611
1208 #[test] 612 #[test]
1209 fn completes_reexported_items_under_correct_name() { 613 fn completes_reexported_items_under_correct_name() {
1210 assert_debug_snapshot!( 614 check(
1211 do_reference_completion( 615 r#"
1212 r" 616fn foo() { self::m::<|> }
1213 fn foo() {
1214 self::m::<|>
1215 }
1216 617
1217 mod m { 618mod m {
1218 pub use super::p::wrong_fn as right_fn; 619 pub use super::p::wrong_fn as right_fn;
1219 pub use super::p::WRONG_CONST as RIGHT_CONST; 620 pub use super::p::WRONG_CONST as RIGHT_CONST;
1220 pub use super::p::WrongType as RightType; 621 pub use super::p::WrongType as RightType;
1221 } 622}
1222 mod p { 623mod p {
1223 fn wrong_fn() {} 624 fn wrong_fn() {}
1224 const WRONG_CONST: u32 = 1; 625 const WRONG_CONST: u32 = 1;
1225 struct WrongType {}; 626 struct WrongType {};
1226 } 627}
1227 " 628"#,
1228 ), 629 expect![[r#"
1229 @r###" 630 ct RIGHT_CONST
1230 [ 631 st RightType
1231 CompletionItem { 632 fn right_fn() fn wrong_fn()
1232 label: "RIGHT_CONST", 633 "#]],
1233 source_range: 57..57, 634 );
1234 delete: 57..57, 635
1235 insert: "RIGHT_CONST", 636 check_edit(
1236 kind: Const, 637 "RightType",
1237 }, 638 r#"
1238 CompletionItem { 639fn foo() { self::m::<|> }
1239 label: "RightType", 640
1240 source_range: 57..57, 641mod m {
1241 delete: 57..57, 642 pub use super::p::wrong_fn as right_fn;
1242 insert: "RightType", 643 pub use super::p::WRONG_CONST as RIGHT_CONST;
1243 kind: Struct, 644 pub use super::p::WrongType as RightType;
1244 }, 645}
1245 CompletionItem { 646mod p {
1246 label: "right_fn()", 647 fn wrong_fn() {}
1247 source_range: 57..57, 648 const WRONG_CONST: u32 = 1;
1248 delete: 57..57, 649 struct WrongType {};
1249 insert: "right_fn()$0", 650}
1250 kind: Function, 651"#,
1251 lookup: "right_fn", 652 r#"
1252 detail: "fn wrong_fn()", 653fn foo() { self::m::RightType }
1253 }, 654
1254 ] 655mod m {
1255 "### 656 pub use super::p::wrong_fn as right_fn;
657 pub use super::p::WRONG_CONST as RIGHT_CONST;
658 pub use super::p::WrongType as RightType;
659}
660mod p {
661 fn wrong_fn() {}
662 const WRONG_CONST: u32 = 1;
663 struct WrongType {};
664}
665"#,
1256 ); 666 );
1257 } 667 }
1258 668
1259 #[test] 669 #[test]
1260 fn completes_in_simple_macro_call() { 670 fn completes_in_simple_macro_call() {
1261 let completions = do_reference_completion( 671 check(
1262 r#" 672 r#"
1263 macro_rules! m { ($e:expr) => { $e } } 673macro_rules! m { ($e:expr) => { $e } }
1264 fn main() { m!(self::f<|>); } 674fn main() { m!(self::f<|>); }
1265 fn foo() {} 675fn foo() {}
1266 "#, 676"#,
677 expect![[r#"
678 fn foo() fn foo()
679 fn main() fn main()
680 "#]],
1267 ); 681 );
1268 assert_debug_snapshot!(completions, @r###"
1269 [
1270 CompletionItem {
1271 label: "foo()",
1272 source_range: 93..94,
1273 delete: 93..94,
1274 insert: "foo()$0",
1275 kind: Function,
1276 lookup: "foo",
1277 detail: "fn foo()",
1278 },
1279 CompletionItem {
1280 label: "main()",
1281 source_range: 93..94,
1282 delete: 93..94,
1283 insert: "main()$0",
1284 kind: Function,
1285 lookup: "main",
1286 detail: "fn main()",
1287 },
1288 ]
1289 "###);
1290 } 682 }
1291 683
1292 #[test] 684 #[test]
1293 fn function_mod_share_name() { 685 fn function_mod_share_name() {
1294 assert_debug_snapshot!( 686 check(
1295 do_reference_completion( 687 r#"
1296 r" 688fn foo() { self::m::<|> }
1297 fn foo() {
1298 self::m::<|>
1299 }
1300 689
1301 mod m { 690mod m {
1302 pub mod z {} 691 pub mod z {}
1303 pub fn z() {} 692 pub fn z() {}
1304 } 693}
1305 ", 694"#,
1306 ), 695 expect![[r#"
1307 @r###" 696 md z
1308 [ 697 fn z() pub fn z()
1309 CompletionItem { 698 "#]],
1310 label: "z",
1311 source_range: 57..57,
1312 delete: 57..57,
1313 insert: "z",
1314 kind: Module,
1315 },
1316 CompletionItem {
1317 label: "z()",
1318 source_range: 57..57,
1319 delete: 57..57,
1320 insert: "z()$0",
1321 kind: Function,
1322 lookup: "z",
1323 detail: "pub fn z()",
1324 },
1325 ]
1326 "###
1327 ); 699 );
1328 } 700 }
1329 701
1330 #[test] 702 #[test]
1331 fn completes_hashmap_new() { 703 fn completes_hashmap_new() {
1332 assert_debug_snapshot!( 704 check(
1333 do_reference_completion( 705 r#"
1334 r" 706struct RandomState;
1335 struct RandomState; 707struct HashMap<K, V, S = RandomState> {}
1336 struct HashMap<K, V, S = RandomState> {} 708
1337 709impl<K, V> HashMap<K, V, RandomState> {
1338 impl<K, V> HashMap<K, V, RandomState> { 710 pub fn new() -> HashMap<K, V, RandomState> { }
1339 pub fn new() -> HashMap<K, V, RandomState> { } 711}
1340 } 712fn foo() {
1341 fn foo() { 713 HashMap::<|>
1342 HashMap::<|> 714}
1343 } 715"#,
1344 " 716 expect![[r#"
1345 ), 717 fn new() pub fn new() -> HashMap<K, V, RandomState>
1346 @r###" 718 "#]],
1347 [
1348 CompletionItem {
1349 label: "new()",
1350 source_range: 292..292,
1351 delete: 292..292,
1352 insert: "new()$0",
1353 kind: Function,
1354 lookup: "new",
1355 detail: "pub fn new() -> HashMap<K, V, RandomState>",
1356 },
1357 ]
1358 "###
1359 ); 719 );
1360 } 720 }
1361 721
1362 #[test] 722 #[test]
1363 fn dont_complete_attr() { 723 fn dont_complete_attr() {
1364 assert_debug_snapshot!( 724 check(
1365 do_reference_completion( 725 r#"
1366 r" 726mod foo { pub struct Foo; }
1367 mod foo { pub struct Foo; } 727#[foo::<|>]
1368 #[foo::<|>] 728fn f() {}
1369 fn f() {} 729"#,
1370 " 730 expect![[""]],
1371 ), 731 );
1372 @r###"[]"###
1373 )
1374 } 732 }
1375} 733}
diff --git a/crates/ra_ide/src/completion/complete_record.rs b/crates/ra_ide/src/completion/complete_record.rs
index b7ab654c5..74b94594d 100644
--- a/crates/ra_ide/src/completion/complete_record.rs
+++ b/crates/ra_ide/src/completion/complete_record.rs
@@ -18,389 +18,209 @@ pub(super) fn complete_record(acc: &mut Completions, ctx: &CompletionContext) ->
18 18
19#[cfg(test)] 19#[cfg(test)]
20mod tests { 20mod tests {
21 mod record_pat_tests { 21 use expect::{expect, Expect};
22 use insta::assert_debug_snapshot;
23 22
24 use crate::completion::{test_utils::do_completion, CompletionItem, CompletionKind}; 23 use crate::completion::{test_utils::completion_list, CompletionKind};
25 24
26 fn complete(code: &str) -> Vec<CompletionItem> { 25 fn check(ra_fixture: &str, expect: Expect) {
27 do_completion(code, CompletionKind::Reference) 26 let actual = completion_list(ra_fixture, CompletionKind::Reference);
28 } 27 expect.assert_eq(&actual);
29 28 }
30 #[test]
31 fn test_record_pattern_field() {
32 let completions = complete(
33 r"
34 struct S { foo: u32 }
35
36 fn process(f: S) {
37 match f {
38 S { f<|>: 92 } => (),
39 }
40 }
41 ",
42 );
43 assert_debug_snapshot!(completions, @r###"
44 [
45 CompletionItem {
46 label: "foo",
47 source_range: 117..118,
48 delete: 117..118,
49 insert: "foo",
50 kind: Field,
51 detail: "u32",
52 },
53 ]
54 "###);
55 }
56
57 #[test]
58 fn test_record_pattern_enum_variant() {
59 let completions = complete(
60 r"
61 enum E {
62 S { foo: u32, bar: () }
63 }
64
65 fn process(e: E) {
66 match e {
67 E::S { <|> } => (),
68 }
69 }
70 ",
71 );
72 assert_debug_snapshot!(completions, @r###"
73 [
74 CompletionItem {
75 label: "bar",
76 source_range: 161..161,
77 delete: 161..161,
78 insert: "bar",
79 kind: Field,
80 detail: "()",
81 },
82 CompletionItem {
83 label: "foo",
84 source_range: 161..161,
85 delete: 161..161,
86 insert: "foo",
87 kind: Field,
88 detail: "u32",
89 },
90 ]
91 "###);
92 }
93 29
94 #[test] 30 #[test]
95 fn test_record_pattern_field_in_simple_macro() { 31 fn test_record_pattern_field() {
96 let completions = complete( 32 check(
97 r" 33 r#"
98 macro_rules! m { ($e:expr) => { $e } } 34struct S { foo: u32 }
99 struct S { foo: u32 }
100 35
101 fn process(f: S) { 36fn process(f: S) {
102 m!(match f { 37 match f {
103 S { f<|>: 92 } => (), 38 S { f<|>: 92 } => (),
104 }) 39 }
105 } 40}
106 ", 41"#,
107 ); 42 expect![[r#"
108 assert_debug_snapshot!(completions, @r###" 43 fd foo u32
109 [ 44 "#]],
110 CompletionItem { 45 );
111 label: "foo", 46 }
112 source_range: 171..172,
113 delete: 171..172,
114 insert: "foo",
115 kind: Field,
116 detail: "u32",
117 },
118 ]
119 "###);
120 }
121 47
122 #[test] 48 #[test]
123 fn only_missing_fields_are_completed_in_destruct_pats() { 49 fn test_record_pattern_enum_variant() {
124 let completions = complete( 50 check(
125 r" 51 r#"
126 struct S { 52enum E { S { foo: u32, bar: () } }
127 foo1: u32,
128 foo2: u32,
129 bar: u32,
130 baz: u32,
131 }
132 53
133 fn main() { 54fn process(e: E) {
134 let s = S { 55 match e {
135 foo1: 1, 56 E::S { <|> } => (),
136 foo2: 2, 57 }
137 bar: 3, 58}
138 baz: 4, 59"#,
139 }; 60 expect![[r#"
140 if let S { foo1, foo2: a, <|> } = s {} 61 fd bar ()
141 } 62 fd foo u32
142 ", 63 "#]],
143 ); 64 );
144 assert_debug_snapshot!(completions, @r###"
145 [
146 CompletionItem {
147 label: "bar",
148 source_range: 372..372,
149 delete: 372..372,
150 insert: "bar",
151 kind: Field,
152 detail: "u32",
153 },
154 CompletionItem {
155 label: "baz",
156 source_range: 372..372,
157 delete: 372..372,
158 insert: "baz",
159 kind: Field,
160 detail: "u32",
161 },
162 ]
163 "###);
164 }
165 } 65 }
166 66
167 mod record_lit_tests { 67 #[test]
168 use insta::assert_debug_snapshot; 68 fn test_record_pattern_field_in_simple_macro() {
169 69 check(
170 use crate::completion::{test_utils::do_completion, CompletionItem, CompletionKind}; 70 r"
71macro_rules! m { ($e:expr) => { $e } }
72struct S { foo: u32 }
73
74fn process(f: S) {
75 m!(match f {
76 S { f<|>: 92 } => (),
77 })
78}
79",
80 expect![[r#"
81 fd foo u32
82 "#]],
83 );
84 }
171 85
172 fn complete(code: &str) -> Vec<CompletionItem> { 86 #[test]
173 do_completion(code, CompletionKind::Reference) 87 fn only_missing_fields_are_completed_in_destruct_pats() {
174 } 88 check(
89 r#"
90struct S {
91 foo1: u32, foo2: u32,
92 bar: u32, baz: u32,
93}
175 94
176 #[test] 95fn main() {
177 fn test_record_literal_deprecated_field() { 96 let s = S {
178 let completions = complete( 97 foo1: 1, foo2: 2,
179 r" 98 bar: 3, baz: 4,
180 struct A { 99 };
181 #[deprecated] 100 if let S { foo1, foo2: a, <|> } = s {}
182 the_field: u32, 101}
183 } 102"#,
184 fn foo() { 103 expect![[r#"
185 A { the<|> } 104 fd bar u32
186 } 105 fd baz u32
187 ", 106 "#]],
188 ); 107 );
189 assert_debug_snapshot!(completions, @r###" 108 }
190 [
191 CompletionItem {
192 label: "the_field",
193 source_range: 142..145,
194 delete: 142..145,
195 insert: "the_field",
196 kind: Field,
197 detail: "u32",
198 deprecated: true,
199 },
200 ]
201 "###);
202 }
203 109
204 #[test] 110 #[test]
205 fn test_record_literal_field() { 111 fn test_record_literal_field() {
206 let completions = complete( 112 check(
207 r" 113 r#"
208 struct A { the_field: u32 } 114struct A { the_field: u32 }
209 fn foo() { 115fn foo() {
210 A { the<|> } 116 A { the<|> }
211 } 117}
212 ", 118"#,
213 ); 119 expect![[r#"
214 assert_debug_snapshot!(completions, @r###" 120 fd the_field u32
215 [ 121 "#]],
216 CompletionItem { 122 );
217 label: "the_field", 123 }
218 source_range: 83..86,
219 delete: 83..86,
220 insert: "the_field",
221 kind: Field,
222 detail: "u32",
223 },
224 ]
225 "###);
226 }
227 124
228 #[test] 125 #[test]
229 fn test_record_literal_enum_variant() { 126 fn test_record_literal_enum_variant() {
230 let completions = complete( 127 check(
231 r" 128 r#"
232 enum E { 129enum E { A { a: u32 } }
233 A { a: u32 } 130fn foo() {
234 } 131 let _ = E::A { <|> }
235 fn foo() { 132}
236 let _ = E::A { <|> } 133"#,
237 } 134 expect![[r#"
238 ", 135 fd a u32
239 ); 136 "#]],
240 assert_debug_snapshot!(completions, @r###" 137 );
241 [ 138 }
242 CompletionItem {
243 label: "a",
244 source_range: 119..119,
245 delete: 119..119,
246 insert: "a",
247 kind: Field,
248 detail: "u32",
249 },
250 ]
251 "###);
252 }
253 139
254 #[test] 140 #[test]
255 fn test_record_literal_two_structs() { 141 fn test_record_literal_two_structs() {
256 let completions = complete( 142 check(
257 r" 143 r#"
258 struct A { a: u32 } 144struct A { a: u32 }
259 struct B { b: u32 } 145struct B { b: u32 }
260 146
261 fn foo() { 147fn foo() {
262 let _: A = B { <|> } 148 let _: A = B { <|> }
263 } 149}
264 ", 150"#,
265 ); 151 expect![[r#"
266 assert_debug_snapshot!(completions, @r###" 152 fd b u32
267 [ 153 "#]],
268 CompletionItem { 154 );
269 label: "b", 155 }
270 source_range: 119..119,
271 delete: 119..119,
272 insert: "b",
273 kind: Field,
274 detail: "u32",
275 },
276 ]
277 "###);
278 }
279 156
280 #[test] 157 #[test]
281 fn test_record_literal_generic_struct() { 158 fn test_record_literal_generic_struct() {
282 let completions = complete( 159 check(
283 r" 160 r#"
284 struct A<T> { a: T } 161struct A<T> { a: T }
285 162
286 fn foo() { 163fn foo() {
287 let _: A<u32> = A { <|> } 164 let _: A<u32> = A { <|> }
288 } 165}
289 ", 166"#,
290 ); 167 expect![[r#"
291 assert_debug_snapshot!(completions, @r###" 168 fd a u32
292 [ 169 "#]],
293 CompletionItem { 170 );
294 label: "a", 171 }
295 source_range: 93..93,
296 delete: 93..93,
297 insert: "a",
298 kind: Field,
299 detail: "u32",
300 },
301 ]
302 "###);
303 }
304 172
305 #[test] 173 #[test]
306 fn test_record_literal_field_in_simple_macro() { 174 fn test_record_literal_field_in_simple_macro() {
307 let completions = complete( 175 check(
308 r" 176 r#"
309 macro_rules! m { ($e:expr) => { $e } } 177macro_rules! m { ($e:expr) => { $e } }
310 struct A { the_field: u32 } 178struct A { the_field: u32 }
311 fn foo() { 179fn foo() {
312 m!(A { the<|> }) 180 m!(A { the<|> })
313 } 181}
314 ", 182"#,
315 ); 183 expect![[r#"
316 assert_debug_snapshot!(completions, @r###" 184 fd the_field u32
317 [ 185 "#]],
318 CompletionItem { 186 );
319 label: "the_field", 187 }
320 source_range: 137..140,
321 delete: 137..140,
322 insert: "the_field",
323 kind: Field,
324 detail: "u32",
325 },
326 ]
327 "###);
328 }
329 188
330 #[test] 189 #[test]
331 fn only_missing_fields_are_completed() { 190 fn only_missing_fields_are_completed() {
332 let completions = complete( 191 check(
333 r" 192 r#"
334 struct S { 193struct S {
335 foo1: u32, 194 foo1: u32, foo2: u32,
336 foo2: u32, 195 bar: u32, baz: u32,
337 bar: u32, 196}
338 baz: u32,
339 }
340 197
341 fn main() { 198fn main() {
342 let foo1 = 1; 199 let foo1 = 1;
343 let s = S { 200 let s = S { foo1, foo2: 5, <|> }
344 foo1, 201}
345 foo2: 5, 202"#,
346 <|> 203 expect![[r#"
347 } 204 fd bar u32
348 } 205 fd baz u32
349 ", 206 "#]],
350 ); 207 );
351 assert_debug_snapshot!(completions, @r###" 208 }
352 [
353 CompletionItem {
354 label: "bar",
355 source_range: 302..302,
356 delete: 302..302,
357 insert: "bar",
358 kind: Field,
359 detail: "u32",
360 },
361 CompletionItem {
362 label: "baz",
363 source_range: 302..302,
364 delete: 302..302,
365 insert: "baz",
366 kind: Field,
367 detail: "u32",
368 },
369 ]
370 "###);
371 }
372 209
373 #[test] 210 #[test]
374 fn completes_functional_update() { 211 fn completes_functional_update() {
375 let completions = complete( 212 check(
376 r" 213 r#"
377 struct S { 214struct S { foo1: u32, foo2: u32 }
378 foo1: u32,
379 foo2: u32,
380 }
381 215
382 fn main() { 216fn main() {
383 let foo1 = 1; 217 let foo1 = 1;
384 let s = S { 218 let s = S { foo1, <|> .. loop {} }
385 foo1, 219}
386 <|> 220"#,
387 .. loop {} 221 expect![[r#"
388 } 222 fd foo2 u32
389 } 223 "#]],
390 ", 224 );
391 );
392 assert_debug_snapshot!(completions, @r###"
393 [
394 CompletionItem {
395 label: "foo2",
396 source_range: 221..221,
397 delete: 221..221,
398 insert: "foo2",
399 kind: Field,
400 detail: "u32",
401 },
402 ]
403 "###);
404 }
405 } 225 }
406} 226}
diff --git a/crates/ra_ide/src/completion/complete_snippet.rs b/crates/ra_ide/src/completion/complete_snippet.rs
index 0568d9ccf..28d8f7876 100644
--- a/crates/ra_ide/src/completion/complete_snippet.rs
+++ b/crates/ra_ide/src/completion/complete_snippet.rs
@@ -70,95 +70,47 @@ fn ${1:feature}() {
70 70
71#[cfg(test)] 71#[cfg(test)]
72mod tests { 72mod tests {
73 use crate::completion::{test_utils::do_completion, CompletionItem, CompletionKind}; 73 use expect::{expect, Expect};
74 use insta::assert_debug_snapshot;
75 74
76 fn do_snippet_completion(code: &str) -> Vec<CompletionItem> { 75 use crate::completion::{test_utils::completion_list, CompletionKind};
77 do_completion(code, CompletionKind::Snippet) 76
77 fn check(ra_fixture: &str, expect: Expect) {
78 let actual = completion_list(ra_fixture, CompletionKind::Snippet);
79 expect.assert_eq(&actual)
78 } 80 }
79 81
80 #[test] 82 #[test]
81 fn completes_snippets_in_expressions() { 83 fn completes_snippets_in_expressions() {
82 assert_debug_snapshot!( 84 check(
83 do_snippet_completion(r"fn foo(x: i32) { <|> }"), 85 r#"fn foo(x: i32) { <|> }"#,
84 @r###" 86 expect![[r#"
85 [ 87 sn pd
86 CompletionItem { 88 sn ppd
87 label: "pd", 89 "#]],
88 source_range: 17..17, 90 );
89 delete: 17..17,
90 insert: "eprintln!(\"$0 = {:?}\", $0);",
91 kind: Snippet,
92 },
93 CompletionItem {
94 label: "ppd",
95 source_range: 17..17,
96 delete: 17..17,
97 insert: "eprintln!(\"$0 = {:#?}\", $0);",
98 kind: Snippet,
99 },
100 ]
101 "###
102 );
103 } 91 }
104 92
105 #[test] 93 #[test]
106 fn should_not_complete_snippets_in_path() { 94 fn should_not_complete_snippets_in_path() {
107 assert_debug_snapshot!( 95 check(r#"fn foo(x: i32) { ::foo<|> }"#, expect![[""]]);
108 do_snippet_completion(r"fn foo(x: i32) { ::foo<|> }"), 96 check(r#"fn foo(x: i32) { ::<|> }"#, expect![[""]]);
109 @"[]"
110 );
111 assert_debug_snapshot!(
112 do_snippet_completion(r"fn foo(x: i32) { ::<|> }"),
113 @"[]"
114 );
115 } 97 }
116 98
117 #[test] 99 #[test]
118 fn completes_snippets_in_items() { 100 fn completes_snippets_in_items() {
119 assert_debug_snapshot!( 101 check(
120 do_snippet_completion( 102 r#"
121 r" 103#[cfg(test)]
122 #[cfg(test)] 104mod tests {
123 mod tests { 105 <|>
124 <|> 106}
125 } 107"#,
126 " 108 expect![[r#"
127 ), 109 sn Test function
128 @r###" 110 sn Test module
129 [ 111 sn macro_rules
130 CompletionItem { 112 sn pub(crate)
131 label: "Test function", 113 "#]],
132 source_range: 78..78, 114 )
133 delete: 78..78,
134 insert: "#[test]\nfn ${1:feature}() {\n $0\n}",
135 kind: Snippet,
136 lookup: "tfn",
137 },
138 CompletionItem {
139 label: "Test module",
140 source_range: 78..78,
141 delete: 78..78,
142 insert: "#[cfg(test)]\nmod tests {\n use super::*;\n\n #[test]\n fn ${1:test_name}() {\n $0\n }\n}",
143 kind: Snippet,
144 lookup: "tmod",
145 },
146 CompletionItem {
147 label: "macro_rules",
148 source_range: 78..78,
149 delete: 78..78,
150 insert: "macro_rules! $1 {\n\t($2) => {\n\t\t$0\n\t};\n}",
151 kind: Snippet,
152 },
153 CompletionItem {
154 label: "pub(crate)",
155 source_range: 78..78,
156 delete: 78..78,
157 insert: "pub(crate) $0",
158 kind: Snippet,
159 },
160 ]
161 "###
162 );
163 } 115 }
164} 116}
diff --git a/crates/ra_ide/src/completion/complete_trait_impl.rs b/crates/ra_ide/src/completion/complete_trait_impl.rs
index 21c9316e6..a610fd6d1 100644
--- a/crates/ra_ide/src/completion/complete_trait_impl.rs
+++ b/crates/ra_ide/src/completion/complete_trait_impl.rs
@@ -227,330 +227,264 @@ fn make_const_compl_syntax(const_: &ast::ConstDef) -> String {
227 227
228#[cfg(test)] 228#[cfg(test)]
229mod tests { 229mod tests {
230 use insta::assert_debug_snapshot; 230 use expect::{expect, Expect};
231 231
232 use crate::completion::{test_utils::do_completion, CompletionItem, CompletionKind}; 232 use crate::completion::{
233 test_utils::{check_edit, completion_list},
234 CompletionKind,
235 };
233 236
234 fn complete(code: &str) -> Vec<CompletionItem> { 237 fn check(ra_fixture: &str, expect: Expect) {
235 do_completion(code, CompletionKind::Magic) 238 let actual = completion_list(ra_fixture, CompletionKind::Magic);
239 expect.assert_eq(&actual)
236 } 240 }
237 241
238 #[test] 242 #[test]
239 fn name_ref_function_type_const() { 243 fn name_ref_function_type_const() {
240 let completions = complete( 244 check(
241 r" 245 r#"
242 trait Test { 246trait Test {
243 type TestType; 247 type TestType;
244 const TEST_CONST: u16; 248 const TEST_CONST: u16;
245 fn test(); 249 fn test();
246 } 250}
247 251struct T;
248 struct T1;
249 252
250 impl Test for T1 { 253impl Test for T {
251 t<|> 254 t<|>
252 } 255}
253 ", 256"#,
257 expect![["
258ct const TEST_CONST: u16 = \n\
259fn fn test()
260ta type TestType = \n\
261 "]],
254 ); 262 );
255 assert_debug_snapshot!(completions, @r###"
256 [
257 CompletionItem {
258 label: "const TEST_CONST: u16 = ",
259 source_range: 209..210,
260 delete: 209..210,
261 insert: "const TEST_CONST: u16 = ",
262 kind: Const,
263 lookup: "TEST_CONST",
264 },
265 CompletionItem {
266 label: "fn test()",
267 source_range: 209..210,
268 delete: 209..210,
269 insert: "fn test() {\n $0\n}",
270 kind: Function,
271 lookup: "test",
272 },
273 CompletionItem {
274 label: "type TestType = ",
275 source_range: 209..210,
276 delete: 209..210,
277 insert: "type TestType = ",
278 kind: TypeAlias,
279 lookup: "TestType",
280 },
281 ]
282 "###);
283 } 263 }
284 264
285 #[test] 265 #[test]
286 fn no_nested_fn_completions() { 266 fn no_nested_fn_completions() {
287 let completions = complete( 267 check(
288 r" 268 r"
289 trait Test { 269trait Test {
290 fn test(); 270 fn test();
291 fn test2(); 271 fn test2();
292 } 272}
293 273struct T;
294 struct T1;
295 274
296 impl Test for T1 { 275impl Test for T {
297 fn test() { 276 fn test() {
298 t<|> 277 t<|>
299 } 278 }
300 } 279}
301 ", 280",
281 expect![[""]],
302 ); 282 );
303 assert_debug_snapshot!(completions, @r###"[]"###);
304 } 283 }
305 284
306 #[test] 285 #[test]
307 fn name_ref_single_function() { 286 fn name_ref_single_function() {
308 let completions = complete( 287 check_edit(
309 r" 288 "test",
310 trait Test { 289 r#"
311 fn test(); 290trait Test {
312 } 291 fn test();
292}
293struct T;
313 294
314 struct T1; 295impl Test for T {
296 t<|>
297}
298"#,
299 r#"
300trait Test {
301 fn test();
302}
303struct T;
315 304
316 impl Test for T1 { 305impl Test for T {
317 t<|> 306 fn test() {
318 } 307 $0
319 ", 308}
309}
310"#,
320 ); 311 );
321 assert_debug_snapshot!(completions, @r###"
322 [
323 CompletionItem {
324 label: "fn test()",
325 source_range: 139..140,
326 delete: 139..140,
327 insert: "fn test() {\n $0\n}",
328 kind: Function,
329 lookup: "test",
330 },
331 ]
332 "###);
333 } 312 }
334 313
335 #[test] 314 #[test]
336 fn single_function() { 315 fn single_function() {
337 let completions = complete( 316 check_edit(
338 r" 317 "test",
339 trait Test { 318 r#"
340 fn foo(); 319trait Test {
341 } 320 fn test();
321}
322struct T;
342 323
343 struct T1; 324impl Test for T {
325 fn t<|>
326}
327"#,
328 r#"
329trait Test {
330 fn test();
331}
332struct T;
344 333
345 impl Test for T1 { 334impl Test for T {
346 fn f<|> 335 fn test() {
347 } 336 $0
348 ", 337}
338}
339"#,
349 ); 340 );
350 assert_debug_snapshot!(completions, @r###"
351 [
352 CompletionItem {
353 label: "fn foo()",
354 source_range: 141..142,
355 delete: 138..142,
356 insert: "fn foo() {\n $0\n}",
357 kind: Function,
358 lookup: "foo",
359 },
360 ]
361 "###);
362 } 341 }
363 342
364 #[test] 343 #[test]
365 fn hide_implemented_fn() { 344 fn hide_implemented_fn() {
366 let completions = complete( 345 check(
367 r" 346 r#"
368 trait Test { 347trait Test {
369 fn foo(); 348 fn foo();
370 fn foo_bar(); 349 fn foo_bar();
371 } 350}
372 351struct T;
373 struct T1;
374
375 impl Test for T1 {
376 fn foo() {}
377
378 fn f<|>
379 }
380 ",
381 );
382 assert_debug_snapshot!(completions, @r###"
383 [
384 CompletionItem {
385 label: "fn foo_bar()",
386 source_range: 200..201,
387 delete: 197..201,
388 insert: "fn foo_bar() {\n $0\n}",
389 kind: Function,
390 lookup: "foo_bar",
391 },
392 ]
393 "###);
394 }
395
396 #[test]
397 fn completes_only_on_top_level() {
398 let completions = complete(
399 r"
400 trait Test {
401 fn foo();
402
403 fn foo_bar();
404 }
405
406 struct T1;
407 352
408 impl Test for T1 { 353impl Test for T {
409 fn foo() { 354 fn foo() {}
410 <|> 355 fn f<|>
411 } 356}
412 } 357"#,
413 ", 358 expect![[r#"
359 fn fn foo_bar()
360 "#]],
414 ); 361 );
415 assert_debug_snapshot!(completions, @r###"[]"###);
416 } 362 }
417 363
418 #[test] 364 #[test]
419 fn generic_fn() { 365 fn generic_fn() {
420 let completions = complete( 366 check_edit(
421 r" 367 "foo",
422 trait Test { 368 r#"
423 fn foo<T>(); 369trait Test {
424 } 370 fn foo<T>();
371}
372struct T;
425 373
426 struct T1; 374impl Test for T {
375 fn f<|>
376}
377"#,
378 r#"
379trait Test {
380 fn foo<T>();
381}
382struct T;
427 383
428 impl Test for T1 { 384impl Test for T {
429 fn f<|> 385 fn foo<T>() {
430 } 386 $0
431 ", 387}
388}
389"#,
432 ); 390 );
433 assert_debug_snapshot!(completions, @r###" 391 check_edit(
434 [ 392 "foo",
435 CompletionItem { 393 r#"
436 label: "fn foo()", 394trait Test {
437 source_range: 144..145, 395 fn foo<T>() where T: Into<String>;
438 delete: 141..145, 396}
439 insert: "fn foo<T>() {\n $0\n}", 397struct T;
440 kind: Function,
441 lookup: "foo",
442 },
443 ]
444 "###);
445 }
446
447 #[test]
448 fn generic_constrait_fn() {
449 let completions = complete(
450 r"
451 trait Test {
452 fn foo<T>() where T: Into<String>;
453 }
454 398
455 struct T1; 399impl Test for T {
400 fn f<|>
401}
402"#,
403 r#"
404trait Test {
405 fn foo<T>() where T: Into<String>;
406}
407struct T;
456 408
457 impl Test for T1 { 409impl Test for T {
458 fn f<|> 410 fn foo<T>()
459 } 411where T: Into<String> {
460 ", 412 $0
413}
414}
415"#,
461 ); 416 );
462 assert_debug_snapshot!(completions, @r###"
463 [
464 CompletionItem {
465 label: "fn foo()",
466 source_range: 166..167,
467 delete: 163..167,
468 insert: "fn foo<T>()\nwhere T: Into<String> {\n $0\n}",
469 kind: Function,
470 lookup: "foo",
471 },
472 ]
473 "###);
474 } 417 }
475 418
476 #[test] 419 #[test]
477 fn associated_type() { 420 fn associated_type() {
478 let completions = complete( 421 check_edit(
479 r" 422 "SomeType",
480 trait Test { 423 r#"
481 type SomeType; 424trait Test {
482 } 425 type SomeType;
426}
483 427
484 impl Test for () { 428impl Test for () {
485 type S<|> 429 type S<|>
486 } 430}
487 ", 431"#,
432 "
433trait Test {
434 type SomeType;
435}
436
437impl Test for () {
438 type SomeType = \n\
439}
440",
488 ); 441 );
489 assert_debug_snapshot!(completions, @r###"
490 [
491 CompletionItem {
492 label: "type SomeType = ",
493 source_range: 124..125,
494 delete: 119..125,
495 insert: "type SomeType = ",
496 kind: TypeAlias,
497 lookup: "SomeType",
498 },
499 ]
500 "###);
501 } 442 }
502 443
503 #[test] 444 #[test]
504 fn associated_const() { 445 fn associated_const() {
505 let completions = complete( 446 check_edit(
506 r" 447 "SOME_CONST",
507 trait Test { 448 r#"
508 const SOME_CONST: u16; 449trait Test {
509 } 450 const SOME_CONST: u16;
451}
510 452
511 impl Test for () { 453impl Test for () {
512 const S<|> 454 const S<|>
513 } 455}
514 ", 456"#,
457 "
458trait Test {
459 const SOME_CONST: u16;
460}
461
462impl Test for () {
463 const SOME_CONST: u16 = \n\
464}
465",
515 ); 466 );
516 assert_debug_snapshot!(completions, @r###"
517 [
518 CompletionItem {
519 label: "const SOME_CONST: u16 = ",
520 source_range: 133..134,
521 delete: 127..134,
522 insert: "const SOME_CONST: u16 = ",
523 kind: Const,
524 lookup: "SOME_CONST",
525 },
526 ]
527 "###);
528 }
529 467
530 #[test] 468 check_edit(
531 fn associated_const_with_default() { 469 "SOME_CONST",
532 let completions = complete( 470 r#"
533 r" 471trait Test {
534 trait Test { 472 const SOME_CONST: u16 = 92;
535 const SOME_CONST: u16 = 42; 473}
536 }
537 474
538 impl Test for () { 475impl Test for () {
539 const S<|> 476 const S<|>
540 } 477}
541 ", 478"#,
479 "
480trait Test {
481 const SOME_CONST: u16 = 92;
482}
483
484impl Test for () {
485 const SOME_CONST: u16 = \n\
486}
487",
542 ); 488 );
543 assert_debug_snapshot!(completions, @r###"
544 [
545 CompletionItem {
546 label: "const SOME_CONST: u16 = ",
547 source_range: 138..139,
548 delete: 132..139,
549 insert: "const SOME_CONST: u16 = ",
550 kind: Const,
551 lookup: "SOME_CONST",
552 },
553 ]
554 "###);
555 } 489 }
556} 490}
diff --git a/crates/ra_ide/src/completion/complete_unqualified_path.rs b/crates/ra_ide/src/completion/complete_unqualified_path.rs
index 68032c37e..bd9551f35 100644
--- a/crates/ra_ide/src/completion/complete_unqualified_path.rs
+++ b/crates/ra_ide/src/completion/complete_unqualified_path.rs
@@ -1,11 +1,10 @@
1//! Completion of names from the current scope, e.g. locals and imported items. 1//! Completion of names from the current scope, e.g. locals and imported items.
2 2
3use hir::ScopeDef; 3use hir::{Adt, ModuleDef, ScopeDef, Type};
4use ra_syntax::AstNode;
4use test_utils::mark; 5use test_utils::mark;
5 6
6use crate::completion::{CompletionContext, Completions}; 7use crate::completion::{CompletionContext, Completions};
7use hir::{Adt, ModuleDef, Type};
8use ra_syntax::AstNode;
9 8
10pub(super) fn complete_unqualified_path(acc: &mut Completions, ctx: &CompletionContext) { 9pub(super) fn complete_unqualified_path(acc: &mut Completions, ctx: &CompletionContext) {
11 if !(ctx.is_trivial_path || ctx.is_pat_binding_or_const) { 10 if !(ctx.is_trivial_path || ctx.is_pat_binding_or_const) {
@@ -26,7 +25,7 @@ pub(super) fn complete_unqualified_path(acc: &mut Completions, ctx: &CompletionC
26 return; 25 return;
27 } 26 }
28 27
29 ctx.scope().process_all_names(&mut |name, res| { 28 ctx.scope.process_all_names(&mut |name, res| {
30 if ctx.use_item_syntax.is_some() { 29 if ctx.use_item_syntax.is_some() {
31 if let (ScopeDef::Unknown, Some(name_ref)) = (&res, &ctx.name_ref_syntax) { 30 if let (ScopeDef::Unknown, Some(name_ref)) = (&res, &ctx.name_ref_syntax) {
32 if name_ref.syntax().text() == name.to_string().as_str() { 31 if name_ref.syntax().text() == name.to_string().as_str() {
@@ -43,7 +42,7 @@ fn complete_enum_variants(acc: &mut Completions, ctx: &CompletionContext, ty: &T
43 if let Some(Adt::Enum(enum_data)) = ty.as_adt() { 42 if let Some(Adt::Enum(enum_data)) = ty.as_adt() {
44 let variants = enum_data.variants(ctx.db); 43 let variants = enum_data.variants(ctx.db);
45 44
46 let module = if let Some(module) = ctx.scope().module() { 45 let module = if let Some(module) = ctx.scope.module() {
47 // Compute path from the completion site if available. 46 // Compute path from the completion site if available.
48 module 47 module
49 } else { 48 } else {
@@ -65,1361 +64,595 @@ fn complete_enum_variants(acc: &mut Completions, ctx: &CompletionContext, ty: &T
65 64
66#[cfg(test)] 65#[cfg(test)]
67mod tests { 66mod tests {
68 use insta::assert_debug_snapshot; 67 use expect::{expect, Expect};
69 use test_utils::mark; 68 use test_utils::mark;
70 69
71 use crate::completion::{test_utils::do_completion, CompletionItem, CompletionKind}; 70 use crate::completion::{
71 test_utils::{check_edit, completion_list},
72 CompletionKind,
73 };
72 74
73 fn do_reference_completion(ra_fixture: &str) -> Vec<CompletionItem> { 75 fn check(ra_fixture: &str, expect: Expect) {
74 do_completion(ra_fixture, CompletionKind::Reference) 76 let actual = completion_list(ra_fixture, CompletionKind::Reference);
77 expect.assert_eq(&actual)
75 } 78 }
76 79
77 #[test] 80 #[test]
78 fn self_fulfilling_completion() { 81 fn self_fulfilling_completion() {
79 mark::check!(self_fulfilling_completion); 82 mark::check!(self_fulfilling_completion);
80 assert_debug_snapshot!( 83 check(
81 do_reference_completion( 84 r#"
82 r#" 85use foo<|>
83 use foo<|> 86use std::collections;
84 use std::collections; 87"#,
85 "#, 88 expect![[r#"
86 ), 89 ?? collections
87 @r###" 90 "#]],
88 [
89 CompletionItem {
90 label: "collections",
91 source_range: 21..24,
92 delete: 21..24,
93 insert: "collections",
94 },
95 ]
96 "###
97 ); 91 );
98 } 92 }
99 93
100 #[test] 94 #[test]
101 fn bind_pat_and_path_ignore_at() { 95 fn bind_pat_and_path_ignore_at() {
102 assert_debug_snapshot!( 96 check(
103 do_reference_completion( 97 r#"
104 r" 98enum Enum { A, B }
105 enum Enum { 99fn quux(x: Option<Enum>) {
106 A, 100 match x {
107 B, 101 None => (),
108 } 102 Some(en<|> @ Enum::A) => (),
109 fn quux(x: Option<Enum>) { 103 }
110 match x { 104}
111 None => (), 105"#,
112 Some(en<|> @ Enum::A) => (), 106 expect![[""]],
113 }
114 }
115 "
116 ),
117 @"[]"
118 ); 107 );
119 } 108 }
120 109
121 #[test] 110 #[test]
122 fn bind_pat_and_path_ignore_ref() { 111 fn bind_pat_and_path_ignore_ref() {
123 assert_debug_snapshot!( 112 check(
124 do_reference_completion( 113 r#"
125 r" 114enum Enum { A, B }
126 enum Enum { 115fn quux(x: Option<Enum>) {
127 A, 116 match x {
128 B, 117 None => (),
129 } 118 Some(ref en<|>) => (),
130 fn quux(x: Option<Enum>) { 119 }
131 match x { 120}
132 None => (), 121"#,
133 Some(ref en<|>) => (), 122 expect![[""]],
134 }
135 }
136 "
137 ),
138 @r###"[]"###
139 ); 123 );
140 } 124 }
141 125
142 #[test] 126 #[test]
143 fn bind_pat_and_path() { 127 fn bind_pat_and_path() {
144 assert_debug_snapshot!( 128 check(
145 do_reference_completion( 129 r#"
146 r" 130enum Enum { A, B }
147 enum Enum { 131fn quux(x: Option<Enum>) {
148 A, 132 match x {
149 B, 133 None => (),
150 } 134 Some(En<|>) => (),
151 fn quux(x: Option<Enum>) { 135 }
152 match x { 136}
153 None => (), 137"#,
154 Some(En<|>) => (), 138 expect![[r#"
155 } 139 en Enum
156 } 140 "#]],
157 "
158 ),
159 @r###"
160 [
161 CompletionItem {
162 label: "Enum",
163 source_range: 231..233,
164 delete: 231..233,
165 insert: "Enum",
166 kind: Enum,
167 },
168 ]
169 "###
170 ); 141 );
171 } 142 }
172 143
173 #[test] 144 #[test]
174 fn completes_bindings_from_let() { 145 fn completes_bindings_from_let() {
175 assert_debug_snapshot!( 146 check(
176 do_reference_completion( 147 r#"
177 r" 148fn quux(x: i32) {
178 fn quux(x: i32) { 149 let y = 92;
179 let y = 92; 150 1 + <|>;
180 1 + <|>; 151 let z = ();
181 let z = (); 152}
182 } 153"#,
183 " 154 expect![[r#"
184 ), 155 fn quux(…) fn quux(x: i32)
185 @r###" 156 bn x i32
186 [ 157 bn y i32
187 CompletionItem { 158 "#]],
188 label: "quux(…)",
189 source_range: 91..91,
190 delete: 91..91,
191 insert: "quux(${1:x})$0",
192 kind: Function,
193 lookup: "quux",
194 detail: "fn quux(x: i32)",
195 trigger_call_info: true,
196 },
197 CompletionItem {
198 label: "x",
199 source_range: 91..91,
200 delete: 91..91,
201 insert: "x",
202 kind: Binding,
203 detail: "i32",
204 },
205 CompletionItem {
206 label: "y",
207 source_range: 91..91,
208 delete: 91..91,
209 insert: "y",
210 kind: Binding,
211 detail: "i32",
212 },
213 ]
214 "###
215 ); 159 );
216 } 160 }
217 161
218 #[test] 162 #[test]
219 fn completes_bindings_from_if_let() { 163 fn completes_bindings_from_if_let() {
220 assert_debug_snapshot!( 164 check(
221 do_reference_completion( 165 r#"
222 r" 166fn quux() {
223 fn quux() { 167 if let Some(x) = foo() {
224 if let Some(x) = foo() { 168 let y = 92;
225 let y = 92; 169 };
226 }; 170 if let Some(a) = bar() {
227 if let Some(a) = bar() { 171 let b = 62;
228 let b = 62; 172 1 + <|>
229 1 + <|> 173 }
230 } 174}
231 } 175"#,
232 " 176 expect![[r#"
233 ), 177 bn a
234 @r###" 178 bn b i32
235 [ 179 fn quux() fn quux()
236 CompletionItem { 180 "#]],
237 label: "a",
238 source_range: 242..242,
239 delete: 242..242,
240 insert: "a",
241 kind: Binding,
242 },
243 CompletionItem {
244 label: "b",
245 source_range: 242..242,
246 delete: 242..242,
247 insert: "b",
248 kind: Binding,
249 detail: "i32",
250 },
251 CompletionItem {
252 label: "quux()",
253 source_range: 242..242,
254 delete: 242..242,
255 insert: "quux()$0",
256 kind: Function,
257 lookup: "quux",
258 detail: "fn quux()",
259 },
260 ]
261 "###
262 ); 181 );
263 } 182 }
264 183
265 #[test] 184 #[test]
266 fn completes_bindings_from_for() { 185 fn completes_bindings_from_for() {
267 assert_debug_snapshot!( 186 check(
268 do_reference_completion( 187 r#"
269 r" 188fn quux() {
270 fn quux() { 189 for x in &[1, 2, 3] { <|> }
271 for x in &[1, 2, 3] { 190}
272 <|> 191"#,
273 } 192 expect![[r#"
274 } 193 fn quux() fn quux()
275 " 194 bn x
276 ), 195 "#]],
277 @r###"
278 [
279 CompletionItem {
280 label: "quux()",
281 source_range: 95..95,
282 delete: 95..95,
283 insert: "quux()$0",
284 kind: Function,
285 lookup: "quux",
286 detail: "fn quux()",
287 },
288 CompletionItem {
289 label: "x",
290 source_range: 95..95,
291 delete: 95..95,
292 insert: "x",
293 kind: Binding,
294 },
295 ]
296 "###
297 ); 196 );
298 } 197 }
299 198
300 #[test] 199 #[test]
301 fn completes_bindings_from_for_with_in_prefix() { 200 fn completes_if_prefix_is_keyword() {
302 mark::check!(completes_bindings_from_for_with_in_prefix); 201 mark::check!(completes_if_prefix_is_keyword);
303 assert_debug_snapshot!( 202 check_edit(
304 do_reference_completion( 203 "wherewolf",
305 r" 204 r#"
306 fn test() { 205fn main() {
307 for index in &[1, 2, 3] { 206 let wherewolf = 92;
308 let t = in<|> 207 drop(where<|>)
309 } 208}
310 } 209"#,
311 " 210 r#"
312 ), 211fn main() {
313 @r###" 212 let wherewolf = 92;
314 [ 213 drop(wherewolf)
315 CompletionItem { 214}
316 label: "index", 215"#,
317 source_range: 107..107, 216 )
318 delete: 107..107,
319 insert: "index",
320 kind: Binding,
321 },
322 CompletionItem {
323 label: "test()",
324 source_range: 107..107,
325 delete: 107..107,
326 insert: "test()$0",
327 kind: Function,
328 lookup: "test",
329 detail: "fn test()",
330 },
331 ]
332 "###
333 );
334 } 217 }
335 218
336 #[test] 219 #[test]
337 fn completes_generic_params() { 220 fn completes_generic_params() {
338 assert_debug_snapshot!( 221 check(
339 do_reference_completion( 222 r#"fn quux<T>() { <|> }"#,
340 r" 223 expect![[r#"
341 fn quux<T>() { 224 tp T
342 <|> 225 fn quux() fn quux<T>()
343 } 226 "#]],
344 "
345 ),
346 @r###"
347 [
348 CompletionItem {
349 label: "T",
350 source_range: 52..52,
351 delete: 52..52,
352 insert: "T",
353 kind: TypeParam,
354 },
355 CompletionItem {
356 label: "quux()",
357 source_range: 52..52,
358 delete: 52..52,
359 insert: "quux()$0",
360 kind: Function,
361 lookup: "quux",
362 detail: "fn quux<T>()",
363 },
364 ]
365 "###
366 ); 227 );
367 } 228 }
368 229
369 #[test] 230 #[test]
370 fn completes_generic_params_in_struct() { 231 fn completes_generic_params_in_struct() {
371 assert_debug_snapshot!( 232 check(
372 do_reference_completion( 233 r#"struct S<T> { x: <|>}"#,
373 r" 234 expect![[r#"
374 struct X<T> { 235 st S<…>
375 x: <|> 236 tp Self
376 } 237 tp T
377 " 238 "#]],
378 ),
379 @r###"
380 [
381 CompletionItem {
382 label: "Self",
383 source_range: 54..54,
384 delete: 54..54,
385 insert: "Self",
386 kind: TypeParam,
387 },
388 CompletionItem {
389 label: "T",
390 source_range: 54..54,
391 delete: 54..54,
392 insert: "T",
393 kind: TypeParam,
394 },
395 CompletionItem {
396 label: "X<…>",
397 source_range: 54..54,
398 delete: 54..54,
399 insert: "X<$0>",
400 kind: Struct,
401 lookup: "X",
402 },
403 ]
404 "###
405 ); 239 );
406 } 240 }
407 241
408 #[test] 242 #[test]
409 fn completes_self_in_enum() { 243 fn completes_self_in_enum() {
410 assert_debug_snapshot!( 244 check(
411 do_reference_completion( 245 r#"enum X { Y(<|>) }"#,
412 r" 246 expect![[r#"
413 enum X { 247 tp Self
414 Y(<|>) 248 en X
415 } 249 "#]],
416 "
417 ),
418 @r###"
419 [
420 CompletionItem {
421 label: "Self",
422 source_range: 48..48,
423 delete: 48..48,
424 insert: "Self",
425 kind: TypeParam,
426 },
427 CompletionItem {
428 label: "X",
429 source_range: 48..48,
430 delete: 48..48,
431 insert: "X",
432 kind: Enum,
433 },
434 ]
435 "###
436 ); 250 );
437 } 251 }
438 252
439 #[test] 253 #[test]
440 fn completes_module_items() { 254 fn completes_module_items() {
441 assert_debug_snapshot!( 255 check(
442 do_reference_completion( 256 r#"
443 r" 257struct S;
444 struct Foo; 258enum E {}
445 enum Baz {} 259fn quux() { <|> }
446 fn quux() { 260"#,
447 <|> 261 expect![[r#"
448 } 262 en E
449 " 263 st S
450 ), 264 fn quux() fn quux()
451 @r###" 265 "#]],
452 [ 266 );
453 CompletionItem {
454 label: "Baz",
455 source_range: 105..105,
456 delete: 105..105,
457 insert: "Baz",
458 kind: Enum,
459 },
460 CompletionItem {
461 label: "Foo",
462 source_range: 105..105,
463 delete: 105..105,
464 insert: "Foo",
465 kind: Struct,
466 },
467 CompletionItem {
468 label: "quux()",
469 source_range: 105..105,
470 delete: 105..105,
471 insert: "quux()$0",
472 kind: Function,
473 lookup: "quux",
474 detail: "fn quux()",
475 },
476 ]
477 "###
478 );
479 } 267 }
480 268
481 #[test] 269 #[test]
482 fn completes_extern_prelude() { 270 fn completes_extern_prelude() {
483 assert_debug_snapshot!( 271 check(
484 do_reference_completion( 272 r#"
485 r" 273//- /lib.rs
486 //- /lib.rs 274use <|>;
487 use <|>; 275
488 276//- /other_crate/lib.rs
489 //- /other_crate/lib.rs 277// nothing here
490 // nothing here 278"#,
491 " 279 expect![[r#"
492 ), 280 md other_crate
493 @r###" 281 "#]],
494 [
495 CompletionItem {
496 label: "other_crate",
497 source_range: 4..4,
498 delete: 4..4,
499 insert: "other_crate",
500 kind: Module,
501 },
502 ]
503 "###
504 ); 282 );
505 } 283 }
506 284
507 #[test] 285 #[test]
508 fn completes_module_items_in_nested_modules() { 286 fn completes_module_items_in_nested_modules() {
509 assert_debug_snapshot!( 287 check(
510 do_reference_completion( 288 r#"
511 r" 289struct Foo;
512 struct Foo; 290mod m {
513 mod m { 291 struct Bar;
514 struct Bar; 292 fn quux() { <|> }
515 fn quux() { <|> } 293}
516 } 294"#,
517 " 295 expect![[r#"
518 ), 296 st Bar
519 @r###" 297 fn quux() fn quux()
520 [ 298 "#]],
521 CompletionItem {
522 label: "Bar",
523 source_range: 117..117,
524 delete: 117..117,
525 insert: "Bar",
526 kind: Struct,
527 },
528 CompletionItem {
529 label: "quux()",
530 source_range: 117..117,
531 delete: 117..117,
532 insert: "quux()$0",
533 kind: Function,
534 lookup: "quux",
535 detail: "fn quux()",
536 },
537 ]
538 "###
539 ); 299 );
540 } 300 }
541 301
542 #[test] 302 #[test]
543 fn completes_return_type() { 303 fn completes_return_type() {
544 assert_debug_snapshot!( 304 check(
545 do_reference_completion( 305 r#"
546 r" 306struct Foo;
547 struct Foo; 307fn x() -> <|>
548 fn x() -> <|> 308"#,
549 " 309 expect![[r#"
550 ), 310 st Foo
551 @r###" 311 fn x() fn x()
552 [ 312 "#]],
553 CompletionItem {
554 label: "Foo",
555 source_range: 55..55,
556 delete: 55..55,
557 insert: "Foo",
558 kind: Struct,
559 },
560 CompletionItem {
561 label: "x()",
562 source_range: 55..55,
563 delete: 55..55,
564 insert: "x()$0",
565 kind: Function,
566 lookup: "x",
567 detail: "fn x()",
568 },
569 ]
570 "###
571 ); 313 );
572 } 314 }
573 315
574 #[test] 316 #[test]
575 fn dont_show_both_completions_for_shadowing() { 317 fn dont_show_both_completions_for_shadowing() {
576 assert_debug_snapshot!( 318 check(
577 do_reference_completion( 319 r#"
578 r" 320fn foo() {
579 fn foo() { 321 let bar = 92;
580 let bar = 92; 322 {
581 { 323 let bar = 62;
582 let bar = 62; 324 drop(<|>)
583 <|> 325 }
584 } 326}
585 } 327"#,
586 " 328 // FIXME: should be only one bar here
587 ), 329 expect![[r#"
588 @r###" 330 bn bar i32
589 [ 331 bn bar i32
590 CompletionItem { 332 fn foo() fn foo()
591 label: "bar", 333 "#]],
592 source_range: 146..146,
593 delete: 146..146,
594 insert: "bar",
595 kind: Binding,
596 detail: "i32",
597 },
598 CompletionItem {
599 label: "foo()",
600 source_range: 146..146,
601 delete: 146..146,
602 insert: "foo()$0",
603 kind: Function,
604 lookup: "foo",
605 detail: "fn foo()",
606 },
607 ]
608 "###
609 ); 334 );
610 } 335 }
611 336
612 #[test] 337 #[test]
613 fn completes_self_in_methods() { 338 fn completes_self_in_methods() {
614 assert_debug_snapshot!( 339 check(
615 do_reference_completion(r"impl S { fn foo(&self) { <|> } }"), 340 r#"impl S { fn foo(&self) { <|> } }"#,
616 @r###" 341 expect![[r#"
617 [ 342 tp Self
618 CompletionItem { 343 bn self &{unknown}
619 label: "Self", 344 "#]],
620 source_range: 25..25,
621 delete: 25..25,
622 insert: "Self",
623 kind: TypeParam,
624 },
625 CompletionItem {
626 label: "self",
627 source_range: 25..25,
628 delete: 25..25,
629 insert: "self",
630 kind: Binding,
631 detail: "&{unknown}",
632 },
633 ]
634 "###
635 ); 345 );
636 } 346 }
637 347
638 #[test] 348 #[test]
639 fn completes_prelude() { 349 fn completes_prelude() {
640 assert_debug_snapshot!( 350 check(
641 do_reference_completion( 351 r#"
642 " 352//- /main.rs
643 //- /main.rs 353fn foo() { let x: <|> }
644 fn foo() { let x: <|> } 354
645 355//- /std/lib.rs
646 //- /std/lib.rs 356#[prelude_import]
647 #[prelude_import] 357use prelude::*;
648 use prelude::*; 358
649 359mod prelude { struct Option; }
650 mod prelude { 360"#,
651 struct Option; 361 expect![[r#"
652 } 362 st Option
653 " 363 fn foo() fn foo()
654 ), 364 md std
655 @r###" 365 "#]],
656 [
657 CompletionItem {
658 label: "Option",
659 source_range: 18..18,
660 delete: 18..18,
661 insert: "Option",
662 kind: Struct,
663 },
664 CompletionItem {
665 label: "foo()",
666 source_range: 18..18,
667 delete: 18..18,
668 insert: "foo()$0",
669 kind: Function,
670 lookup: "foo",
671 detail: "fn foo()",
672 },
673 CompletionItem {
674 label: "std",
675 source_range: 18..18,
676 delete: 18..18,
677 insert: "std",
678 kind: Module,
679 },
680 ]
681 "###
682 ); 366 );
683 } 367 }
684 368
685 #[test] 369 #[test]
686 fn completes_std_prelude_if_core_is_defined() { 370 fn completes_std_prelude_if_core_is_defined() {
687 assert_debug_snapshot!( 371 check(
688 do_reference_completion( 372 r#"
689 " 373//- /main.rs
690 //- /main.rs 374fn foo() { let x: <|> }
691 fn foo() { let x: <|> } 375
692 376//- /core/lib.rs
693 //- /core/lib.rs 377#[prelude_import]
694 #[prelude_import] 378use prelude::*;
695 use prelude::*; 379
696 380mod prelude { struct Option; }
697 mod prelude { 381
698 struct Option; 382//- /std/lib.rs
699 } 383#[prelude_import]
700 384use prelude::*;
701 //- /std/lib.rs 385
702 #[prelude_import] 386mod prelude { struct String; }
703 use prelude::*; 387"#,
704 388 expect![[r#"
705 mod prelude { 389 st String
706 struct String; 390 md core
707 } 391 fn foo() fn foo()
708 " 392 md std
709 ), 393 "#]],
710 @r###"
711 [
712 CompletionItem {
713 label: "String",
714 source_range: 18..18,
715 delete: 18..18,
716 insert: "String",
717 kind: Struct,
718 },
719 CompletionItem {
720 label: "core",
721 source_range: 18..18,
722 delete: 18..18,
723 insert: "core",
724 kind: Module,
725 },
726 CompletionItem {
727 label: "foo()",
728 source_range: 18..18,
729 delete: 18..18,
730 insert: "foo()$0",
731 kind: Function,
732 lookup: "foo",
733 detail: "fn foo()",
734 },
735 CompletionItem {
736 label: "std",
737 source_range: 18..18,
738 delete: 18..18,
739 insert: "std",
740 kind: Module,
741 },
742 ]
743 "###
744 ); 394 );
745 } 395 }
746 396
747 #[test] 397 #[test]
748 fn completes_macros_as_value() { 398 fn completes_macros_as_value() {
749 assert_debug_snapshot!( 399 check(
750 do_reference_completion( 400 r#"
751 " 401macro_rules! foo { () => {} }
752 //- /main.rs
753 macro_rules! foo {
754 () => {}
755 }
756 402
757 #[macro_use] 403#[macro_use]
758 mod m1 { 404mod m1 {
759 macro_rules! bar { 405 macro_rules! bar { () => {} }
760 () => {} 406}
761 }
762 }
763 407
764 mod m2 { 408mod m2 {
765 macro_rules! nope { 409 macro_rules! nope { () => {} }
766 () => {}
767 }
768 410
769 #[macro_export] 411 #[macro_export]
770 macro_rules! baz { 412 macro_rules! baz { () => {} }
771 () => {} 413}
772 }
773 }
774 414
775 fn main() { 415fn main() { let v = <|> }
776 let v = <|> 416"#,
777 } 417 expect![[r##"
778 " 418 ma bar!(…) macro_rules! bar
779 ), 419 ma baz!(…) #[macro_export]
780 @r###" 420 macro_rules! baz
781 [ 421 ma foo!(…) macro_rules! foo
782 CompletionItem { 422 md m1
783 label: "bar!(…)", 423 md m2
784 source_range: 252..252, 424 fn main() fn main()
785 delete: 252..252, 425 "##]],
786 insert: "bar!($0)",
787 kind: Macro,
788 detail: "macro_rules! bar",
789 },
790 CompletionItem {
791 label: "baz!(…)",
792 source_range: 252..252,
793 delete: 252..252,
794 insert: "baz!($0)",
795 kind: Macro,
796 detail: "#[macro_export]\nmacro_rules! baz",
797 },
798 CompletionItem {
799 label: "foo!(…)",
800 source_range: 252..252,
801 delete: 252..252,
802 insert: "foo!($0)",
803 kind: Macro,
804 detail: "macro_rules! foo",
805 },
806 CompletionItem {
807 label: "m1",
808 source_range: 252..252,
809 delete: 252..252,
810 insert: "m1",
811 kind: Module,
812 },
813 CompletionItem {
814 label: "m2",
815 source_range: 252..252,
816 delete: 252..252,
817 insert: "m2",
818 kind: Module,
819 },
820 CompletionItem {
821 label: "main()",
822 source_range: 252..252,
823 delete: 252..252,
824 insert: "main()$0",
825 kind: Function,
826 lookup: "main",
827 detail: "fn main()",
828 },
829 ]
830 "###
831 ); 426 );
832 } 427 }
833 428
834 #[test] 429 #[test]
835 fn completes_both_macro_and_value() { 430 fn completes_both_macro_and_value() {
836 assert_debug_snapshot!( 431 check(
837 do_reference_completion( 432 r#"
838 " 433macro_rules! foo { () => {} }
839 //- /main.rs 434fn foo() { <|> }
840 macro_rules! foo { 435"#,
841 () => {} 436 expect![[r#"
842 } 437 ma foo!(…) macro_rules! foo
843 438 fn foo() fn foo()
844 fn foo() { 439 "#]],
845 <|>
846 }
847 "
848 ),
849 @r###"
850 [
851 CompletionItem {
852 label: "foo!(…)",
853 source_range: 49..49,
854 delete: 49..49,
855 insert: "foo!($0)",
856 kind: Macro,
857 detail: "macro_rules! foo",
858 },
859 CompletionItem {
860 label: "foo()",
861 source_range: 49..49,
862 delete: 49..49,
863 insert: "foo()$0",
864 kind: Function,
865 lookup: "foo",
866 detail: "fn foo()",
867 },
868 ]
869 "###
870 ); 440 );
871 } 441 }
872 442
873 #[test] 443 #[test]
874 fn completes_macros_as_type() { 444 fn completes_macros_as_type() {
875 assert_debug_snapshot!( 445 check(
876 do_reference_completion( 446 r#"
877 " 447macro_rules! foo { () => {} }
878 //- /main.rs 448fn main() { let x: <|> }
879 macro_rules! foo { 449"#,
880 () => {} 450 expect![[r#"
881 } 451 ma foo!(…) macro_rules! foo
882 452 fn main() fn main()
883 fn main() { 453 "#]],
884 let x: <|>
885 }
886 "
887 ),
888 @r###"
889 [
890 CompletionItem {
891 label: "foo!(…)",
892 source_range: 57..57,
893 delete: 57..57,
894 insert: "foo!($0)",
895 kind: Macro,
896 detail: "macro_rules! foo",
897 },
898 CompletionItem {
899 label: "main()",
900 source_range: 57..57,
901 delete: 57..57,
902 insert: "main()$0",
903 kind: Function,
904 lookup: "main",
905 detail: "fn main()",
906 },
907 ]
908 "###
909 ); 454 );
910 } 455 }
911 456
912 #[test] 457 #[test]
913 fn completes_macros_as_stmt() { 458 fn completes_macros_as_stmt() {
914 assert_debug_snapshot!( 459 check(
915 do_reference_completion( 460 r#"
916 " 461macro_rules! foo { () => {} }
917 //- /main.rs 462fn main() { <|> }
918 macro_rules! foo { 463"#,
919 () => {} 464 expect![[r#"
920 } 465 ma foo!(…) macro_rules! foo
921 466 fn main() fn main()
922 fn main() { 467 "#]],
923 <|>
924 }
925 "
926 ),
927 @r###"
928 [
929 CompletionItem {
930 label: "foo!(…)",
931 source_range: 50..50,
932 delete: 50..50,
933 insert: "foo!($0)",
934 kind: Macro,
935 detail: "macro_rules! foo",
936 },
937 CompletionItem {
938 label: "main()",
939 source_range: 50..50,
940 delete: 50..50,
941 insert: "main()$0",
942 kind: Function,
943 lookup: "main",
944 detail: "fn main()",
945 },
946 ]
947 "###
948 ); 468 );
949 } 469 }
950 470
951 #[test] 471 #[test]
952 fn completes_local_item() { 472 fn completes_local_item() {
953 assert_debug_snapshot!( 473 check(
954 do_reference_completion( 474 r#"
955 " 475fn main() {
956 //- /main.rs 476 return f<|>;
957 fn main() { 477 fn frobnicate() {}
958 return f<|>; 478}
959 fn frobnicate() {} 479"#,
960 } 480 expect![[r#"
961 " 481 fn frobnicate() fn frobnicate()
962 ), 482 fn main() fn main()
963 @r###" 483 "#]],
964 [ 484 );
965 CompletionItem {
966 label: "frobnicate()",
967 source_range: 23..24,
968 delete: 23..24,
969 insert: "frobnicate()$0",
970 kind: Function,
971 lookup: "frobnicate",
972 detail: "fn frobnicate()",
973 },
974 CompletionItem {
975 label: "main()",
976 source_range: 23..24,
977 delete: 23..24,
978 insert: "main()$0",
979 kind: Function,
980 lookup: "main",
981 detail: "fn main()",
982 },
983 ]
984 "###
985 )
986 } 485 }
987 486
988 #[test] 487 #[test]
989 fn completes_in_simple_macro_1() { 488 fn completes_in_simple_macro_1() {
990 assert_debug_snapshot!( 489 check(
991 do_reference_completion( 490 r#"
992 r" 491macro_rules! m { ($e:expr) => { $e } }
993 macro_rules! m { ($e:expr) => { $e } } 492fn quux(x: i32) {
994 fn quux(x: i32) { 493 let y = 92;
995 let y = 92; 494 m!(<|>);
996 m!(<|>); 495}
997 } 496"#,
998 " 497 expect![[r#"
999 ), 498 ma m!(…) macro_rules! m
1000 @r###" 499 fn quux(…) fn quux(x: i32)
1001 [ 500 bn x i32
1002 CompletionItem { 501 bn y i32
1003 label: "m!(…)", 502 "#]],
1004 source_range: 145..145,
1005 delete: 145..145,
1006 insert: "m!($0)",
1007 kind: Macro,
1008 detail: "macro_rules! m",
1009 },
1010 CompletionItem {
1011 label: "quux(…)",
1012 source_range: 145..145,
1013 delete: 145..145,
1014 insert: "quux(${1:x})$0",
1015 kind: Function,
1016 lookup: "quux",
1017 detail: "fn quux(x: i32)",
1018 trigger_call_info: true,
1019 },
1020 CompletionItem {
1021 label: "x",
1022 source_range: 145..145,
1023 delete: 145..145,
1024 insert: "x",
1025 kind: Binding,
1026 detail: "i32",
1027 },
1028 CompletionItem {
1029 label: "y",
1030 source_range: 145..145,
1031 delete: 145..145,
1032 insert: "y",
1033 kind: Binding,
1034 detail: "i32",
1035 },
1036 ]
1037 "###
1038 ); 503 );
1039 } 504 }
1040 505
1041 #[test] 506 #[test]
1042 fn completes_in_simple_macro_2() { 507 fn completes_in_simple_macro_2() {
1043 assert_debug_snapshot!( 508 check(
1044 do_reference_completion( 509 r"
1045 r" 510macro_rules! m { ($e:expr) => { $e } }
1046 macro_rules! m { ($e:expr) => { $e } } 511fn quux(x: i32) {
1047 fn quux(x: i32) { 512 let y = 92;
1048 let y = 92; 513 m!(x<|>);
1049 m!(x<|>); 514}
1050 } 515",
1051 " 516 expect![[r#"
1052 ), 517 ma m!(…) macro_rules! m
1053 @r###" 518 fn quux(…) fn quux(x: i32)
1054 [ 519 bn x i32
1055 CompletionItem { 520 bn y i32
1056 label: "m!(…)", 521 "#]],
1057 source_range: 145..146,
1058 delete: 145..146,
1059 insert: "m!($0)",
1060 kind: Macro,
1061 detail: "macro_rules! m",
1062 },
1063 CompletionItem {
1064 label: "quux(…)",
1065 source_range: 145..146,
1066 delete: 145..146,
1067 insert: "quux(${1:x})$0",
1068 kind: Function,
1069 lookup: "quux",
1070 detail: "fn quux(x: i32)",
1071 trigger_call_info: true,
1072 },
1073 CompletionItem {
1074 label: "x",
1075 source_range: 145..146,
1076 delete: 145..146,
1077 insert: "x",
1078 kind: Binding,
1079 detail: "i32",
1080 },
1081 CompletionItem {
1082 label: "y",
1083 source_range: 145..146,
1084 delete: 145..146,
1085 insert: "y",
1086 kind: Binding,
1087 detail: "i32",
1088 },
1089 ]
1090 "###
1091 ); 522 );
1092 } 523 }
1093 524
1094 #[test] 525 #[test]
1095 fn completes_in_simple_macro_without_closing_parens() { 526 fn completes_in_simple_macro_without_closing_parens() {
1096 assert_debug_snapshot!( 527 check(
1097 do_reference_completion( 528 r#"
1098 r" 529macro_rules! m { ($e:expr) => { $e } }
1099 macro_rules! m { ($e:expr) => { $e } } 530fn quux(x: i32) {
1100 fn quux(x: i32) { 531 let y = 92;
1101 let y = 92; 532 m!(x<|>
1102 m!(x<|> 533}
1103 } 534"#,
1104 " 535 expect![[r#"
1105 ), 536 ma m!(…) macro_rules! m
1106 @r###" 537 fn quux(…) fn quux(x: i32)
1107 [ 538 bn x i32
1108 CompletionItem { 539 bn y i32
1109 label: "m!(…)", 540 "#]],
1110 source_range: 145..146,
1111 delete: 145..146,
1112 insert: "m!($0)",
1113 kind: Macro,
1114 detail: "macro_rules! m",
1115 },
1116 CompletionItem {
1117 label: "quux(…)",
1118 source_range: 145..146,
1119 delete: 145..146,
1120 insert: "quux(${1:x})$0",
1121 kind: Function,
1122 lookup: "quux",
1123 detail: "fn quux(x: i32)",
1124 trigger_call_info: true,
1125 },
1126 CompletionItem {
1127 label: "x",
1128 source_range: 145..146,
1129 delete: 145..146,
1130 insert: "x",
1131 kind: Binding,
1132 detail: "i32",
1133 },
1134 CompletionItem {
1135 label: "y",
1136 source_range: 145..146,
1137 delete: 145..146,
1138 insert: "y",
1139 kind: Binding,
1140 detail: "i32",
1141 },
1142 ]
1143 "###
1144 ); 541 );
1145 } 542 }
1146 543
1147 #[test] 544 #[test]
1148 fn completes_unresolved_uses() { 545 fn completes_unresolved_uses() {
1149 assert_debug_snapshot!( 546 check(
1150 do_reference_completion( 547 r#"
1151 r" 548use spam::Quux;
1152 use spam::Quux; 549
1153 550fn main() { <|> }
1154 fn main() { 551"#,
1155 <|> 552 expect![[r#"
1156 } 553 ?? Quux
1157 " 554 fn main() fn main()
1158 ), 555 "#]],
1159 @r###"
1160 [
1161 CompletionItem {
1162 label: "Quux",
1163 source_range: 82..82,
1164 delete: 82..82,
1165 insert: "Quux",
1166 },
1167 CompletionItem {
1168 label: "main()",
1169 source_range: 82..82,
1170 delete: 82..82,
1171 insert: "main()$0",
1172 kind: Function,
1173 lookup: "main",
1174 detail: "fn main()",
1175 },
1176 ]
1177 "###
1178 ); 556 );
1179 } 557 }
1180 #[test] 558 #[test]
1181 fn completes_enum_variant_matcharm() { 559 fn completes_enum_variant_matcharm() {
1182 assert_debug_snapshot!( 560 check(
1183 do_reference_completion( 561 r#"
1184 r" 562enum Foo { Bar, Baz, Quux }
1185 enum Foo {
1186 Bar,
1187 Baz,
1188 Quux
1189 }
1190
1191 fn main() {
1192 let foo = Foo::Quux;
1193 563
1194 match foo { 564fn main() {
1195 Qu<|> 565 let foo = Foo::Quux;
1196 } 566 match foo { Qu<|> }
1197 } 567}
1198 " 568"#,
1199 ), 569 expect![[r#"
1200 @r###" 570 en Foo
1201 [ 571 ev Foo::Bar ()
1202 CompletionItem { 572 ev Foo::Baz ()
1203 label: "Foo", 573 ev Foo::Quux ()
1204 source_range: 248..250, 574 "#]],
1205 delete: 248..250,
1206 insert: "Foo",
1207 kind: Enum,
1208 },
1209 CompletionItem {
1210 label: "Foo::Bar",
1211 source_range: 248..250,
1212 delete: 248..250,
1213 insert: "Foo::Bar",
1214 kind: EnumVariant,
1215 lookup: "Bar",
1216 detail: "()",
1217 },
1218 CompletionItem {
1219 label: "Foo::Baz",
1220 source_range: 248..250,
1221 delete: 248..250,
1222 insert: "Foo::Baz",
1223 kind: EnumVariant,
1224 lookup: "Baz",
1225 detail: "()",
1226 },
1227 CompletionItem {
1228 label: "Foo::Quux",
1229 source_range: 248..250,
1230 delete: 248..250,
1231 insert: "Foo::Quux",
1232 kind: EnumVariant,
1233 lookup: "Quux",
1234 detail: "()",
1235 },
1236 ]
1237 "###
1238 ) 575 )
1239 } 576 }
1240 577
1241 #[test] 578 #[test]
1242 fn completes_enum_variant_iflet() { 579 fn completes_enum_variant_iflet() {
1243 assert_debug_snapshot!( 580 check(
1244 do_reference_completion( 581 r#"
1245 r" 582enum Foo { Bar, Baz, Quux }
1246 enum Foo {
1247 Bar,
1248 Baz,
1249 Quux
1250 }
1251 583
1252 fn main() { 584fn main() {
1253 let foo = Foo::Quux; 585 let foo = Foo::Quux;
1254 586 if let Qu<|> = foo { }
1255 if let Qu<|> = foo { 587}
1256 588"#,
1257 } 589 expect![[r#"
1258 } 590 en Foo
1259 " 591 ev Foo::Bar ()
1260 ), 592 ev Foo::Baz ()
1261 @r###" 593 ev Foo::Quux ()
1262 [ 594 "#]],
1263 CompletionItem {
1264 label: "Foo",
1265 source_range: 219..221,
1266 delete: 219..221,
1267 insert: "Foo",
1268 kind: Enum,
1269 },
1270 CompletionItem {
1271 label: "Foo::Bar",
1272 source_range: 219..221,
1273 delete: 219..221,
1274 insert: "Foo::Bar",
1275 kind: EnumVariant,
1276 lookup: "Bar",
1277 detail: "()",
1278 },
1279 CompletionItem {
1280 label: "Foo::Baz",
1281 source_range: 219..221,
1282 delete: 219..221,
1283 insert: "Foo::Baz",
1284 kind: EnumVariant,
1285 lookup: "Baz",
1286 detail: "()",
1287 },
1288 CompletionItem {
1289 label: "Foo::Quux",
1290 source_range: 219..221,
1291 delete: 219..221,
1292 insert: "Foo::Quux",
1293 kind: EnumVariant,
1294 lookup: "Quux",
1295 detail: "()",
1296 },
1297 ]
1298 "###
1299 ) 595 )
1300 } 596 }
1301 597
1302 #[test] 598 #[test]
1303 fn completes_enum_variant_basic_expr() { 599 fn completes_enum_variant_basic_expr() {
1304 assert_debug_snapshot!( 600 check(
1305 do_reference_completion( 601 r#"
1306 r" 602enum Foo { Bar, Baz, Quux }
1307 enum Foo { 603fn main() { let foo: Foo = Q<|> }
1308 Bar, 604"#,
1309 Baz, 605 expect![[r#"
1310 Quux 606 en Foo
1311 } 607 ev Foo::Bar ()
1312 608 ev Foo::Baz ()
1313 fn main() { 609 ev Foo::Quux ()
1314 let foo: Foo = Q<|> 610 fn main() fn main()
1315 } 611 "#]],
1316 "
1317 ),
1318 @r###"
1319 [
1320 CompletionItem {
1321 label: "Foo",
1322 source_range: 185..186,
1323 delete: 185..186,
1324 insert: "Foo",
1325 kind: Enum,
1326 },
1327 CompletionItem {
1328 label: "Foo::Bar",
1329 source_range: 185..186,
1330 delete: 185..186,
1331 insert: "Foo::Bar",
1332 kind: EnumVariant,
1333 lookup: "Bar",
1334 detail: "()",
1335 },
1336 CompletionItem {
1337 label: "Foo::Baz",
1338 source_range: 185..186,
1339 delete: 185..186,
1340 insert: "Foo::Baz",
1341 kind: EnumVariant,
1342 lookup: "Baz",
1343 detail: "()",
1344 },
1345 CompletionItem {
1346 label: "Foo::Quux",
1347 source_range: 185..186,
1348 delete: 185..186,
1349 insert: "Foo::Quux",
1350 kind: EnumVariant,
1351 lookup: "Quux",
1352 detail: "()",
1353 },
1354 CompletionItem {
1355 label: "main()",
1356 source_range: 185..186,
1357 delete: 185..186,
1358 insert: "main()$0",
1359 kind: Function,
1360 lookup: "main",
1361 detail: "fn main()",
1362 },
1363 ]
1364 "###
1365 ) 612 )
1366 } 613 }
1367 614
1368 #[test] 615 #[test]
1369 fn completes_enum_variant_from_module() { 616 fn completes_enum_variant_from_module() {
1370 assert_debug_snapshot!( 617 check(
1371 do_reference_completion( 618 r#"
1372 r" 619mod m { pub enum E { V } }
1373 mod m { pub enum E { V } } 620fn f() -> m::E { V<|> }
1374 621"#,
1375 fn f() -> m::E { 622 expect![[r#"
1376 V<|> 623 fn f() fn f() -> m::E
1377 } 624 md m
1378 " 625 ev m::E::V ()
1379 ), 626 "#]],
1380 @r###"
1381 [
1382 CompletionItem {
1383 label: "f()",
1384 source_range: 98..99,
1385 delete: 98..99,
1386 insert: "f()$0",
1387 kind: Function,
1388 lookup: "f",
1389 detail: "fn f() -> m::E",
1390 },
1391 CompletionItem {
1392 label: "m",
1393 source_range: 98..99,
1394 delete: 98..99,
1395 insert: "m",
1396 kind: Module,
1397 },
1398 CompletionItem {
1399 label: "m::E::V",
1400 source_range: 98..99,
1401 delete: 98..99,
1402 insert: "m::E::V",
1403 kind: EnumVariant,
1404 lookup: "V",
1405 detail: "()",
1406 },
1407 ]
1408 "###
1409 ) 627 )
1410 } 628 }
1411 629
1412 #[test] 630 #[test]
1413 fn dont_complete_attr() { 631 fn dont_complete_attr() {
1414 assert_debug_snapshot!( 632 check(
1415 do_reference_completion( 633 r#"
1416 r" 634struct Foo;
1417 struct Foo; 635#[<|>]
1418 #[<|>] 636fn f() {}
1419 fn f() {} 637"#,
1420 " 638 expect![[""]],
1421 ), 639 )
1422 @r###"[]"### 640 }
641
642 #[test]
643 fn completes_type_or_trait_in_impl_block() {
644 check(
645 r#"
646trait MyTrait {}
647struct MyStruct {}
648
649impl My<|>
650"#,
651 expect![[r#"
652 st MyStruct
653 tt MyTrait
654 tp Self
655 "#]],
1423 ) 656 )
1424 } 657 }
1425} 658}
diff --git a/crates/ra_ide/src/completion/completion_context.rs b/crates/ra_ide/src/completion/completion_context.rs
index c4646b727..9e82d6854 100644
--- a/crates/ra_ide/src/completion/completion_context.rs
+++ b/crates/ra_ide/src/completion/completion_context.rs
@@ -5,12 +5,17 @@ use ra_db::SourceDatabase;
5use ra_ide_db::RootDatabase; 5use ra_ide_db::RootDatabase;
6use ra_syntax::{ 6use ra_syntax::{
7 algo::{find_covering_element, find_node_at_offset}, 7 algo::{find_covering_element, find_node_at_offset},
8 ast, match_ast, AstNode, 8 ast, match_ast, AstNode, NodeOrToken,
9 SyntaxKind::*, 9 SyntaxKind::*,
10 SyntaxNode, SyntaxToken, TextRange, TextSize, 10 SyntaxNode, SyntaxToken, TextRange, TextSize,
11}; 11};
12use ra_text_edit::Indel; 12use ra_text_edit::Indel;
13 13
14use super::patterns::{
15 has_bind_pat_parent, has_block_expr_parent, has_impl_as_prev_sibling, has_impl_parent,
16 has_item_list_or_source_file_parent, has_ref_parent, has_trait_as_prev_sibling,
17 has_trait_parent, if_is_prev, is_in_loop_body, is_match_arm, unsafe_is_prev,
18};
14use crate::{call_info::ActiveParameter, completion::CompletionConfig, FilePosition}; 19use crate::{call_info::ActiveParameter, completion::CompletionConfig, FilePosition};
15use test_utils::mark; 20use test_utils::mark;
16 21
@@ -19,6 +24,7 @@ use test_utils::mark;
19#[derive(Debug)] 24#[derive(Debug)]
20pub(crate) struct CompletionContext<'a> { 25pub(crate) struct CompletionContext<'a> {
21 pub(super) sema: Semantics<'a, RootDatabase>, 26 pub(super) sema: Semantics<'a, RootDatabase>,
27 pub(super) scope: SemanticsScope<'a>,
22 pub(super) db: &'a RootDatabase, 28 pub(super) db: &'a RootDatabase,
23 pub(super) config: &'a CompletionConfig, 29 pub(super) config: &'a CompletionConfig,
24 pub(super) offset: TextSize, 30 pub(super) offset: TextSize,
@@ -48,6 +54,8 @@ pub(crate) struct CompletionContext<'a> {
48 pub(super) after_if: bool, 54 pub(super) after_if: bool,
49 /// `true` if we are a statement or a last expr in the block. 55 /// `true` if we are a statement or a last expr in the block.
50 pub(super) can_be_stmt: bool, 56 pub(super) can_be_stmt: bool,
57 /// `true` if we expect an expression at the cursor position.
58 pub(super) is_expr: bool,
51 /// Something is typed at the "top" level, in module or impl/trait. 59 /// Something is typed at the "top" level, in module or impl/trait.
52 pub(super) is_new_item: bool, 60 pub(super) is_new_item: bool,
53 /// The receiver if this is a field or method access, i.e. writing something.<|> 61 /// The receiver if this is a field or method access, i.e. writing something.<|>
@@ -55,11 +63,25 @@ pub(crate) struct CompletionContext<'a> {
55 pub(super) dot_receiver_is_ambiguous_float_literal: bool, 63 pub(super) dot_receiver_is_ambiguous_float_literal: bool,
56 /// If this is a call (method or function) in particular, i.e. the () are already there. 64 /// If this is a call (method or function) in particular, i.e. the () are already there.
57 pub(super) is_call: bool, 65 pub(super) is_call: bool,
66 /// Like `is_call`, but for tuple patterns.
67 pub(super) is_pattern_call: bool,
58 /// If this is a macro call, i.e. the () are already there. 68 /// If this is a macro call, i.e. the () are already there.
59 pub(super) is_macro_call: bool, 69 pub(super) is_macro_call: bool,
60 pub(super) is_path_type: bool, 70 pub(super) is_path_type: bool,
61 pub(super) has_type_args: bool, 71 pub(super) has_type_args: bool,
62 pub(super) attribute_under_caret: Option<ast::Attr>, 72 pub(super) attribute_under_caret: Option<ast::Attr>,
73 pub(super) unsafe_is_prev: bool,
74 pub(super) if_is_prev: bool,
75 pub(super) block_expr_parent: bool,
76 pub(super) bind_pat_parent: bool,
77 pub(super) ref_pat_parent: bool,
78 pub(super) in_loop_body: bool,
79 pub(super) has_trait_parent: bool,
80 pub(super) has_impl_parent: bool,
81 pub(super) trait_as_prev_sibling: bool,
82 pub(super) impl_as_prev_sibling: bool,
83 pub(super) is_match_arm: bool,
84 pub(super) has_item_list_or_source_file_parent: bool,
63} 85}
64 86
65impl<'a> CompletionContext<'a> { 87impl<'a> CompletionContext<'a> {
@@ -87,8 +109,10 @@ impl<'a> CompletionContext<'a> {
87 let original_token = 109 let original_token =
88 original_file.syntax().token_at_offset(position.offset).left_biased()?; 110 original_file.syntax().token_at_offset(position.offset).left_biased()?;
89 let token = sema.descend_into_macros(original_token.clone()); 111 let token = sema.descend_into_macros(original_token.clone());
112 let scope = sema.scope_at_offset(&token.parent(), position.offset);
90 let mut ctx = CompletionContext { 113 let mut ctx = CompletionContext {
91 sema, 114 sema,
115 scope,
92 db, 116 db,
93 config, 117 config,
94 original_token, 118 original_token,
@@ -110,14 +134,28 @@ impl<'a> CompletionContext<'a> {
110 path_prefix: None, 134 path_prefix: None,
111 after_if: false, 135 after_if: false,
112 can_be_stmt: false, 136 can_be_stmt: false,
137 is_expr: false,
113 is_new_item: false, 138 is_new_item: false,
114 dot_receiver: None, 139 dot_receiver: None,
115 is_call: false, 140 is_call: false,
141 is_pattern_call: false,
116 is_macro_call: false, 142 is_macro_call: false,
117 is_path_type: false, 143 is_path_type: false,
118 has_type_args: false, 144 has_type_args: false,
119 dot_receiver_is_ambiguous_float_literal: false, 145 dot_receiver_is_ambiguous_float_literal: false,
120 attribute_under_caret: None, 146 attribute_under_caret: None,
147 unsafe_is_prev: false,
148 in_loop_body: false,
149 ref_pat_parent: false,
150 bind_pat_parent: false,
151 block_expr_parent: false,
152 has_trait_parent: false,
153 has_impl_parent: false,
154 trait_as_prev_sibling: false,
155 impl_as_prev_sibling: false,
156 if_is_prev: false,
157 is_match_arm: false,
158 has_item_list_or_source_file_parent: false,
121 }; 159 };
122 160
123 let mut original_file = original_file.syntax().clone(); 161 let mut original_file = original_file.syntax().clone();
@@ -159,7 +197,7 @@ impl<'a> CompletionContext<'a> {
159 break; 197 break;
160 } 198 }
161 } 199 }
162 200 ctx.fill_keyword_patterns(&hypothetical_file, offset);
163 ctx.fill(&original_file, hypothetical_file, offset); 201 ctx.fill(&original_file, hypothetical_file, offset);
164 Some(ctx) 202 Some(ctx)
165 } 203 }
@@ -167,25 +205,30 @@ impl<'a> CompletionContext<'a> {
167 // The range of the identifier that is being completed. 205 // The range of the identifier that is being completed.
168 pub(crate) fn source_range(&self) -> TextRange { 206 pub(crate) fn source_range(&self) -> TextRange {
169 // check kind of macro-expanded token, but use range of original token 207 // check kind of macro-expanded token, but use range of original token
170 match self.token.kind() { 208 if self.token.kind() == IDENT || self.token.kind().is_keyword() {
171 // workaroud when completion is triggered by trigger characters. 209 mark::hit!(completes_if_prefix_is_keyword);
172 IDENT => self.original_token.text_range(), 210 self.original_token.text_range()
173 _ => { 211 } else {
174 // If we haven't characters between keyword and our cursor we take the keyword start range to edit 212 TextRange::empty(self.offset)
175 if self.token.kind().is_keyword()
176 && self.offset == self.original_token.text_range().end()
177 {
178 mark::hit!(completes_bindings_from_for_with_in_prefix);
179 TextRange::empty(self.original_token.text_range().start())
180 } else {
181 TextRange::empty(self.offset)
182 }
183 }
184 } 213 }
185 } 214 }
186 215
187 pub(crate) fn scope(&self) -> SemanticsScope<'_, RootDatabase> { 216 fn fill_keyword_patterns(&mut self, file_with_fake_ident: &SyntaxNode, offset: TextSize) {
188 self.sema.scope_at_offset(&self.token.parent(), self.offset) 217 let fake_ident_token = file_with_fake_ident.token_at_offset(offset).right_biased().unwrap();
218 let syntax_element = NodeOrToken::Token(fake_ident_token.clone());
219 self.block_expr_parent = has_block_expr_parent(syntax_element.clone());
220 self.unsafe_is_prev = unsafe_is_prev(syntax_element.clone());
221 self.if_is_prev = if_is_prev(syntax_element.clone());
222 self.bind_pat_parent = has_bind_pat_parent(syntax_element.clone());
223 self.ref_pat_parent = has_ref_parent(syntax_element.clone());
224 self.in_loop_body = is_in_loop_body(syntax_element.clone());
225 self.has_trait_parent = has_trait_parent(syntax_element.clone());
226 self.has_impl_parent = has_impl_parent(syntax_element.clone());
227 self.impl_as_prev_sibling = has_impl_as_prev_sibling(syntax_element.clone());
228 self.trait_as_prev_sibling = has_trait_as_prev_sibling(syntax_element.clone());
229 self.is_match_arm = is_match_arm(syntax_element.clone());
230 self.has_item_list_or_source_file_parent =
231 has_item_list_or_source_file_parent(syntax_element.clone());
189 } 232 }
190 233
191 fn fill( 234 fn fill(
@@ -330,10 +373,13 @@ impl<'a> CompletionContext<'a> {
330 .and_then(|it| it.syntax().parent().and_then(ast::CallExpr::cast)) 373 .and_then(|it| it.syntax().parent().and_then(ast::CallExpr::cast))
331 .is_some(); 374 .is_some();
332 self.is_macro_call = path.syntax().parent().and_then(ast::MacroCall::cast).is_some(); 375 self.is_macro_call = path.syntax().parent().and_then(ast::MacroCall::cast).is_some();
376 self.is_pattern_call =
377 path.syntax().parent().and_then(ast::TupleStructPat::cast).is_some();
333 378
334 self.is_path_type = path.syntax().parent().and_then(ast::PathType::cast).is_some(); 379 self.is_path_type = path.syntax().parent().and_then(ast::PathType::cast).is_some();
335 self.has_type_args = segment.type_arg_list().is_some(); 380 self.has_type_args = segment.type_arg_list().is_some();
336 381
382 #[allow(deprecated)]
337 if let Some(path) = hir::Path::from_ast(path.clone()) { 383 if let Some(path) = hir::Path::from_ast(path.clone()) {
338 if let Some(path_prefix) = path.qualifier() { 384 if let Some(path_prefix) = path.qualifier() {
339 self.path_prefix = Some(path_prefix); 385 self.path_prefix = Some(path_prefix);
@@ -364,6 +410,7 @@ impl<'a> CompletionContext<'a> {
364 None 410 None
365 }) 411 })
366 .unwrap_or(false); 412 .unwrap_or(false);
413 self.is_expr = path.syntax().parent().and_then(ast::PathExpr::cast).is_some();
367 414
368 if let Some(off) = name_ref.syntax().text_range().start().checked_sub(2.into()) { 415 if let Some(off) = name_ref.syntax().text_range().start().checked_sub(2.into()) {
369 if let Some(if_expr) = 416 if let Some(if_expr) =
diff --git a/crates/ra_ide/src/completion/completion_item.rs b/crates/ra_ide/src/completion/completion_item.rs
index cfb7c1e38..7bdda316c 100644
--- a/crates/ra_ide/src/completion/completion_item.rs
+++ b/crates/ra_ide/src/completion/completion_item.rs
@@ -58,7 +58,7 @@ pub struct CompletionItem {
58 score: Option<CompletionScore>, 58 score: Option<CompletionScore>,
59} 59}
60 60
61// We use custom debug for CompletionItem to make `insta`'s diffs more readable. 61// We use custom debug for CompletionItem to make snapshot tests more readable.
62impl fmt::Debug for CompletionItem { 62impl fmt::Debug for CompletionItem {
63 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 63 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
64 let mut s = f.debug_struct("CompletionItem"); 64 let mut s = f.debug_struct("CompletionItem");
@@ -95,7 +95,7 @@ impl fmt::Debug for CompletionItem {
95 } 95 }
96} 96}
97 97
98#[derive(Debug, Clone, Copy)] 98#[derive(Debug, Clone, Copy, Ord, PartialOrd, Eq, PartialEq)]
99pub enum CompletionScore { 99pub enum CompletionScore {
100 /// If only type match 100 /// If only type match
101 TypeMatch, 101 TypeMatch,
@@ -123,6 +123,34 @@ pub enum CompletionItemKind {
123 TypeParam, 123 TypeParam,
124 Macro, 124 Macro,
125 Attribute, 125 Attribute,
126 UnresolvedReference,
127}
128
129impl CompletionItemKind {
130 #[cfg(test)]
131 pub(crate) fn tag(&self) -> &'static str {
132 match self {
133 CompletionItemKind::Attribute => "at",
134 CompletionItemKind::Binding => "bn",
135 CompletionItemKind::BuiltinType => "bt",
136 CompletionItemKind::Const => "ct",
137 CompletionItemKind::Enum => "en",
138 CompletionItemKind::EnumVariant => "ev",
139 CompletionItemKind::Field => "fd",
140 CompletionItemKind::Function => "fn",
141 CompletionItemKind::Keyword => "kw",
142 CompletionItemKind::Macro => "ma",
143 CompletionItemKind::Method => "me",
144 CompletionItemKind::Module => "md",
145 CompletionItemKind::Snippet => "sn",
146 CompletionItemKind::Static => "sc",
147 CompletionItemKind::Struct => "st",
148 CompletionItemKind::Trait => "tt",
149 CompletionItemKind::TypeAlias => "ta",
150 CompletionItemKind::TypeParam => "tp",
151 CompletionItemKind::UnresolvedReference => "??",
152 }
153 }
126} 154}
127 155
128#[derive(Debug, PartialEq, Eq, Copy, Clone)] 156#[derive(Debug, PartialEq, Eq, Copy, Clone)]
diff --git a/crates/ra_ide/src/completion/patterns.rs b/crates/ra_ide/src/completion/patterns.rs
new file mode 100644
index 000000000..b2fe13280
--- /dev/null
+++ b/crates/ra_ide/src/completion/patterns.rs
@@ -0,0 +1,194 @@
1//! Patterns telling us certain facts about current syntax element, they are used in completion context
2
3use ra_syntax::{
4 algo::non_trivia_sibling,
5 ast::{self, LoopBodyOwner},
6 match_ast, AstNode, Direction, NodeOrToken, SyntaxElement,
7 SyntaxKind::*,
8 SyntaxNode, SyntaxToken,
9};
10
11#[cfg(test)]
12use crate::completion::test_utils::check_pattern_is_applicable;
13
14pub(crate) fn has_trait_parent(element: SyntaxElement) -> bool {
15 not_same_range_ancestor(element)
16 .filter(|it| it.kind() == ITEM_LIST)
17 .and_then(|it| it.parent())
18 .filter(|it| it.kind() == TRAIT_DEF)
19 .is_some()
20}
21#[test]
22fn test_has_trait_parent() {
23 check_pattern_is_applicable(r"trait A { f<|> }", has_trait_parent);
24}
25
26pub(crate) fn has_impl_parent(element: SyntaxElement) -> bool {
27 not_same_range_ancestor(element)
28 .filter(|it| it.kind() == ITEM_LIST)
29 .and_then(|it| it.parent())
30 .filter(|it| it.kind() == IMPL_DEF)
31 .is_some()
32}
33#[test]
34fn test_has_impl_parent() {
35 check_pattern_is_applicable(r"impl A { f<|> }", has_impl_parent);
36}
37
38pub(crate) fn has_block_expr_parent(element: SyntaxElement) -> bool {
39 not_same_range_ancestor(element).filter(|it| it.kind() == BLOCK_EXPR).is_some()
40}
41#[test]
42fn test_has_block_expr_parent() {
43 check_pattern_is_applicable(r"fn my_fn() { let a = 2; f<|> }", has_block_expr_parent);
44}
45
46pub(crate) fn has_bind_pat_parent(element: SyntaxElement) -> bool {
47 element.ancestors().find(|it| it.kind() == BIND_PAT).is_some()
48}
49#[test]
50fn test_has_bind_pat_parent() {
51 check_pattern_is_applicable(r"fn my_fn(m<|>) {}", has_bind_pat_parent);
52 check_pattern_is_applicable(r"fn my_fn() { let m<|> }", has_bind_pat_parent);
53}
54
55pub(crate) fn has_ref_parent(element: SyntaxElement) -> bool {
56 not_same_range_ancestor(element)
57 .filter(|it| it.kind() == REF_PAT || it.kind() == REF_EXPR)
58 .is_some()
59}
60#[test]
61fn test_has_ref_parent() {
62 check_pattern_is_applicable(r"fn my_fn(&m<|>) {}", has_ref_parent);
63 check_pattern_is_applicable(r"fn my() { let &m<|> }", has_ref_parent);
64}
65
66pub(crate) fn has_item_list_or_source_file_parent(element: SyntaxElement) -> bool {
67 let ancestor = not_same_range_ancestor(element);
68 if !ancestor.is_some() {
69 return true;
70 }
71 ancestor.filter(|it| it.kind() == SOURCE_FILE || it.kind() == ITEM_LIST).is_some()
72}
73#[test]
74fn test_has_item_list_or_source_file_parent() {
75 check_pattern_is_applicable(r"i<|>", has_item_list_or_source_file_parent);
76 check_pattern_is_applicable(r"impl { f<|> }", has_item_list_or_source_file_parent);
77}
78
79pub(crate) fn is_match_arm(element: SyntaxElement) -> bool {
80 not_same_range_ancestor(element.clone()).filter(|it| it.kind() == MATCH_ARM).is_some()
81 && previous_sibling_or_ancestor_sibling(element)
82 .and_then(|it| it.into_token())
83 .filter(|it| it.kind() == FAT_ARROW)
84 .is_some()
85}
86#[test]
87fn test_is_match_arm() {
88 check_pattern_is_applicable(r"fn my_fn() { match () { () => m<|> } }", is_match_arm);
89}
90
91pub(crate) fn unsafe_is_prev(element: SyntaxElement) -> bool {
92 element
93 .into_token()
94 .and_then(|it| previous_non_trivia_token(it))
95 .filter(|it| it.kind() == UNSAFE_KW)
96 .is_some()
97}
98#[test]
99fn test_unsafe_is_prev() {
100 check_pattern_is_applicable(r"unsafe i<|>", unsafe_is_prev);
101}
102
103pub(crate) fn if_is_prev(element: SyntaxElement) -> bool {
104 element
105 .into_token()
106 .and_then(|it| previous_non_trivia_token(it))
107 .filter(|it| it.kind() == IF_KW)
108 .is_some()
109}
110#[test]
111fn test_if_is_prev() {
112 check_pattern_is_applicable(r"if l<|>", if_is_prev);
113}
114
115pub(crate) fn has_trait_as_prev_sibling(element: SyntaxElement) -> bool {
116 previous_sibling_or_ancestor_sibling(element).filter(|it| it.kind() == TRAIT_DEF).is_some()
117}
118#[test]
119fn test_has_trait_as_prev_sibling() {
120 check_pattern_is_applicable(r"trait A w<|> {}", has_trait_as_prev_sibling);
121}
122
123pub(crate) fn has_impl_as_prev_sibling(element: SyntaxElement) -> bool {
124 previous_sibling_or_ancestor_sibling(element).filter(|it| it.kind() == IMPL_DEF).is_some()
125}
126#[test]
127fn test_has_impl_as_prev_sibling() {
128 check_pattern_is_applicable(r"impl A w<|> {}", has_impl_as_prev_sibling);
129}
130
131pub(crate) fn is_in_loop_body(element: SyntaxElement) -> bool {
132 let leaf = match element {
133 NodeOrToken::Node(node) => node,
134 NodeOrToken::Token(token) => token.parent(),
135 };
136 for node in leaf.ancestors() {
137 if node.kind() == FN_DEF || node.kind() == LAMBDA_EXPR {
138 break;
139 }
140 let loop_body = match_ast! {
141 match node {
142 ast::ForExpr(it) => it.loop_body(),
143 ast::WhileExpr(it) => it.loop_body(),
144 ast::LoopExpr(it) => it.loop_body(),
145 _ => None,
146 }
147 };
148 if let Some(body) = loop_body {
149 if body.syntax().text_range().contains_range(leaf.text_range()) {
150 return true;
151 }
152 }
153 }
154 false
155}
156
157fn not_same_range_ancestor(element: SyntaxElement) -> Option<SyntaxNode> {
158 element
159 .ancestors()
160 .take_while(|it| it.text_range() == element.text_range())
161 .last()
162 .and_then(|it| it.parent())
163}
164
165fn previous_non_trivia_token(token: SyntaxToken) -> Option<SyntaxToken> {
166 let mut token = token.prev_token();
167 while let Some(inner) = token.clone() {
168 if !inner.kind().is_trivia() {
169 return Some(inner);
170 } else {
171 token = inner.prev_token();
172 }
173 }
174 None
175}
176
177fn previous_sibling_or_ancestor_sibling(element: SyntaxElement) -> Option<SyntaxElement> {
178 let token_sibling = non_trivia_sibling(element.clone(), Direction::Prev);
179 if let Some(sibling) = token_sibling {
180 Some(sibling)
181 } else {
182 // if not trying to find first ancestor which has such a sibling
183 let node = match element {
184 NodeOrToken::Node(node) => node,
185 NodeOrToken::Token(token) => token.parent(),
186 };
187 let range = node.text_range();
188 let top_node = node.ancestors().take_while(|it| it.text_range() == range).last()?;
189 let prev_sibling_node = top_node.ancestors().find(|it| {
190 non_trivia_sibling(NodeOrToken::Node(it.to_owned()), Direction::Prev).is_some()
191 })?;
192 non_trivia_sibling(NodeOrToken::Node(prev_sibling_node), Direction::Prev)
193 }
194}
diff --git a/crates/ra_ide/src/completion/presentation.rs b/crates/ra_ide/src/completion/presentation.rs
index 61565c84f..64349dcb8 100644
--- a/crates/ra_ide/src/completion/presentation.rs
+++ b/crates/ra_ide/src/completion/presentation.rs
@@ -1,4 +1,5 @@
1//! This modules takes care of rendering various definitions as completion items. 1//! This modules takes care of rendering various definitions as completion items.
2//! It also handles scoring (sorting) completions.
2 3
3use hir::{Docs, HasAttrs, HasSource, HirDisplay, ModPath, ScopeDef, StructKind, Type}; 4use hir::{Docs, HasAttrs, HasSource, HirDisplay, ModPath, ScopeDef, StructKind, Type};
4use ra_syntax::ast::NameOwner; 5use ra_syntax::ast::NameOwner;
@@ -78,11 +79,10 @@ impl Completions {
78 return self.add_macro(ctx, Some(local_name), *mac); 79 return self.add_macro(ctx, Some(local_name), *mac);
79 } 80 }
80 ScopeDef::Unknown => { 81 ScopeDef::Unknown => {
81 return self.add(CompletionItem::new( 82 return self.add(
82 CompletionKind::Reference, 83 CompletionItem::new(CompletionKind::Reference, ctx.source_range(), local_name)
83 ctx.source_range(), 84 .kind(CompletionItemKind::UnresolvedReference),
84 local_name, 85 );
85 ));
86 } 86 }
87 }; 87 };
88 88
@@ -173,6 +173,7 @@ impl Completions {
173 builder 173 builder
174 .insert_snippet(cap, format!("{}!{}$0{}", name, bra, ket)) 174 .insert_snippet(cap, format!("{}!{}$0{}", name, bra, ket))
175 .label(format!("{}!{}…{}", name, bra, ket)) 175 .label(format!("{}!{}…{}", name, bra, ket))
176 .lookup_by(format!("{}!", name))
176 } 177 }
177 None if needs_bang => builder.insert_text(format!("{}!", name)), 178 None if needs_bang => builder.insert_text(format!("{}!", name)),
178 _ => { 179 _ => {
@@ -314,6 +315,7 @@ impl Completions {
314 } 315 }
315 316
316 if variant_kind == StructKind::Tuple { 317 if variant_kind == StructKind::Tuple {
318 mark::hit!(inserts_parens_for_tuple_enums);
317 let params = Params::Anonymous(variant.fields(ctx.db).len()); 319 let params = Params::Anonymous(variant.fields(ctx.db).len());
318 res = res.add_call_parens(ctx, qualified_name, params) 320 res = res.add_call_parens(ctx, qualified_name, params)
319 } 321 }
@@ -330,14 +332,14 @@ pub(crate) fn compute_score(
330 // FIXME: this should not fall back to string equality. 332 // FIXME: this should not fall back to string equality.
331 let ty = &ty.display(ctx.db).to_string(); 333 let ty = &ty.display(ctx.db).to_string();
332 let (active_name, active_type) = if let Some(record_field) = &ctx.record_field_syntax { 334 let (active_name, active_type) = if let Some(record_field) = &ctx.record_field_syntax {
333 mark::hit!(test_struct_field_completion_in_record_lit); 335 mark::hit!(record_field_type_match);
334 let (struct_field, _local) = ctx.sema.resolve_record_field(record_field)?; 336 let (struct_field, _local) = ctx.sema.resolve_record_field(record_field)?;
335 ( 337 (
336 struct_field.name(ctx.db).to_string(), 338 struct_field.name(ctx.db).to_string(),
337 struct_field.signature_ty(ctx.db).display(ctx.db).to_string(), 339 struct_field.signature_ty(ctx.db).display(ctx.db).to_string(),
338 ) 340 )
339 } else if let Some(active_parameter) = &ctx.active_parameter { 341 } else if let Some(active_parameter) = &ctx.active_parameter {
340 mark::hit!(test_struct_field_completion_in_func_call); 342 mark::hit!(active_param_type_match);
341 (active_parameter.name.clone(), active_parameter.ty.clone()) 343 (active_parameter.name.clone(), active_parameter.ty.clone())
342 } else { 344 } else {
343 return None; 345 return None;
@@ -382,13 +384,22 @@ impl Builder {
382 if !ctx.config.add_call_parenthesis { 384 if !ctx.config.add_call_parenthesis {
383 return self; 385 return self;
384 } 386 }
385 if ctx.use_item_syntax.is_some() || ctx.is_call { 387 if ctx.use_item_syntax.is_some() {
388 mark::hit!(no_parens_in_use_item);
389 return self;
390 }
391 if ctx.is_pattern_call {
392 mark::hit!(dont_duplicate_pattern_parens);
393 return self;
394 }
395 if ctx.is_call {
386 return self; 396 return self;
387 } 397 }
388 398
389 // Don't add parentheses if the expected type is some function reference. 399 // Don't add parentheses if the expected type is some function reference.
390 if let Some(ty) = &ctx.expected_type { 400 if let Some(ty) = &ctx.expected_type {
391 if ty.is_fn() { 401 if ty.is_fn() {
402 mark::hit!(no_call_parens_if_fn_ptr_needed);
392 return self; 403 return self;
393 } 404 }
394 } 405 }
@@ -413,7 +424,10 @@ impl Builder {
413 .sep_by(", "); 424 .sep_by(", ");
414 format!("{}({})$0", name, function_params_snippet) 425 format!("{}({})$0", name, function_params_snippet)
415 } 426 }
416 _ => format!("{}($0)", name), 427 _ => {
428 mark::hit!(suppress_arg_snippets);
429 format!("{}($0)", name)
430 }
417 }; 431 };
418 432
419 (snippet, format!("{}(…)", name)) 433 (snippet, format!("{}(…)", name))
@@ -456,1061 +470,750 @@ fn guess_macro_braces(macro_name: &str, docs: &str) -> (&'static str, &'static s
456 470
457#[cfg(test)] 471#[cfg(test)]
458mod tests { 472mod tests {
459 use insta::assert_debug_snapshot; 473 use std::cmp::Reverse;
474
475 use expect::{expect, Expect};
460 use test_utils::mark; 476 use test_utils::mark;
461 477
462 use crate::completion::{ 478 use crate::{
463 test_utils::{do_completion, do_completion_with_options}, 479 completion::{
464 CompletionConfig, CompletionItem, CompletionKind, 480 test_utils::{
481 check_edit, check_edit_with_config, do_completion, get_all_completion_items,
482 },
483 CompletionConfig, CompletionKind,
484 },
485 CompletionScore,
465 }; 486 };
466 487
467 fn do_reference_completion(ra_fixture: &str) -> Vec<CompletionItem> { 488 fn check(ra_fixture: &str, expect: Expect) {
468 do_completion(ra_fixture, CompletionKind::Reference) 489 let actual = do_completion(ra_fixture, CompletionKind::Reference);
490 expect.assert_debug_eq(&actual);
469 } 491 }
470 492
471 fn do_reference_completion_with_options( 493 fn check_scores(ra_fixture: &str, expect: Expect) {
472 ra_fixture: &str, 494 fn display_score(score: Option<CompletionScore>) -> &'static str {
473 options: CompletionConfig, 495 match score {
474 ) -> Vec<CompletionItem> { 496 Some(CompletionScore::TypeMatch) => "[type]",
475 do_completion_with_options(ra_fixture, CompletionKind::Reference, &options) 497 Some(CompletionScore::TypeAndNameMatch) => "[type+name]",
498 None => "[]".into(),
499 }
500 }
501
502 let mut completions = get_all_completion_items(CompletionConfig::default(), ra_fixture);
503 completions.sort_by_key(|it| (Reverse(it.score()), it.label().to_string()));
504 let actual = completions
505 .into_iter()
506 .filter(|it| it.completion_kind == CompletionKind::Reference)
507 .map(|it| {
508 let tag = it.kind().unwrap().tag();
509 let score = display_score(it.score());
510 format!("{} {} {}\n", tag, it.label(), score)
511 })
512 .collect::<String>();
513 expect.assert_eq(&actual);
476 } 514 }
477 515
478 #[test] 516 #[test]
479 fn enum_detail_includes_names_for_record() { 517 fn enum_detail_includes_record_fields() {
480 assert_debug_snapshot!( 518 check(
481 do_reference_completion(
482 r#" 519 r#"
483 enum Foo { 520enum Foo { Foo { x: i32, y: i32 } }
484 Foo {x: i32, y: i32} 521
485 } 522fn main() { Foo::Fo<|> }
486 523"#,
487 fn main() { Foo::Fo<|> } 524 expect![[r#"
488 "#, 525 [
489 ), 526 CompletionItem {
490 @r###" 527 label: "Foo",
491 [ 528 source_range: 54..56,
492 CompletionItem { 529 delete: 54..56,
493 label: "Foo", 530 insert: "Foo",
494 source_range: 121..123, 531 kind: EnumVariant,
495 delete: 121..123, 532 detail: "{ x: i32, y: i32 }",
496 insert: "Foo", 533 },
497 kind: EnumVariant, 534 ]
498 detail: "{ x: i32, y: i32 }", 535 "#]],
499 },
500 ]"###
501 ); 536 );
502 } 537 }
503 538
504 #[test] 539 #[test]
505 fn enum_detail_doesnt_include_names_for_tuple() { 540 fn enum_detail_doesnt_include_tuple_fields() {
506 assert_debug_snapshot!( 541 check(
507 do_reference_completion(
508 r#" 542 r#"
509 enum Foo { 543enum Foo { Foo (i32, i32) }
510 Foo (i32, i32) 544
511 } 545fn main() { Foo::Fo<|> }
512 546"#,
513 fn main() { Foo::Fo<|> } 547 expect![[r#"
514 "#, 548 [
515 ), 549 CompletionItem {
516 @r###" 550 label: "Foo(…)",
517 [ 551 source_range: 46..48,
518 CompletionItem { 552 delete: 46..48,
519 label: "Foo(…)", 553 insert: "Foo($0)",
520 source_range: 115..117, 554 kind: EnumVariant,
521 delete: 115..117, 555 lookup: "Foo",
522 insert: "Foo($0)", 556 detail: "(i32, i32)",
523 kind: EnumVariant, 557 trigger_call_info: true,
524 lookup: "Foo", 558 },
525 detail: "(i32, i32)", 559 ]
526 trigger_call_info: true, 560 "#]],
527 },
528 ]"###
529 ); 561 );
530 } 562 }
531 563
532 #[test] 564 #[test]
533 fn enum_detail_just_parentheses_for_unit() { 565 fn enum_detail_just_parentheses_for_unit() {
534 assert_debug_snapshot!( 566 check(
535 do_reference_completion(
536 r#" 567 r#"
537 enum Foo { 568enum Foo { Foo }
538 Foo 569
539 } 570fn main() { Foo::Fo<|> }
540 571"#,
541 fn main() { Foo::Fo<|> } 572 expect![[r#"
542 "#, 573 [
543 ), 574 CompletionItem {
544 @r###" 575 label: "Foo",
545 [ 576 source_range: 35..37,
546 CompletionItem { 577 delete: 35..37,
547 label: "Foo", 578 insert: "Foo",
548 source_range: 104..106, 579 kind: EnumVariant,
549 delete: 104..106, 580 detail: "()",
550 insert: "Foo", 581 },
551 kind: EnumVariant, 582 ]
552 detail: "()", 583 "#]],
553 },
554 ]"###
555 ); 584 );
556 } 585 }
557 586
558 #[test] 587 #[test]
559 fn sets_deprecated_flag_in_completion_items() { 588 fn sets_deprecated_flag_in_completion_items() {
560 assert_debug_snapshot!( 589 check(
561 do_reference_completion( 590 r#"
562 r#" 591#[deprecated]
563 #[deprecated] 592fn something_deprecated() {}
564 fn something_deprecated() {} 593#[deprecated(since = "1.0.0")]
565 594fn something_else_deprecated() {}
566 #[deprecated(since = "1.0.0")] 595
567 fn something_else_deprecated() {} 596fn main() { som<|> }
568 597"#,
569 fn main() { som<|> } 598 expect![[r#"
570 "#, 599 [
571 ), 600 CompletionItem {
572 @r###" 601 label: "main()",
573 [ 602 source_range: 121..124,
574 CompletionItem { 603 delete: 121..124,
575 label: "main()", 604 insert: "main()$0",
576 source_range: 203..206, 605 kind: Function,
577 delete: 203..206, 606 lookup: "main",
578 insert: "main()$0", 607 detail: "fn main()",
579 kind: Function, 608 },
580 lookup: "main", 609 CompletionItem {
581 detail: "fn main()", 610 label: "something_deprecated()",
582 }, 611 source_range: 121..124,
583 CompletionItem { 612 delete: 121..124,
584 label: "something_deprecated()", 613 insert: "something_deprecated()$0",
585 source_range: 203..206, 614 kind: Function,
586 delete: 203..206, 615 lookup: "something_deprecated",
587 insert: "something_deprecated()$0", 616 detail: "fn something_deprecated()",
588 kind: Function, 617 deprecated: true,
589 lookup: "something_deprecated", 618 },
590 detail: "fn something_deprecated()", 619 CompletionItem {
591 deprecated: true, 620 label: "something_else_deprecated()",
592 }, 621 source_range: 121..124,
593 CompletionItem { 622 delete: 121..124,
594 label: "something_else_deprecated()", 623 insert: "something_else_deprecated()$0",
595 source_range: 203..206, 624 kind: Function,
596 delete: 203..206, 625 lookup: "something_else_deprecated",
597 insert: "something_else_deprecated()$0", 626 detail: "fn something_else_deprecated()",
598 kind: Function, 627 deprecated: true,
599 lookup: "something_else_deprecated", 628 },
600 detail: "fn something_else_deprecated()", 629 ]
601 deprecated: true, 630 "#]],
602 }, 631 );
603 ] 632
604 "### 633 check(
634 r#"
635struct A { #[deprecated] the_field: u32 }
636fn foo() { A { the<|> } }
637"#,
638 expect![[r#"
639 [
640 CompletionItem {
641 label: "the_field",
642 source_range: 57..60,
643 delete: 57..60,
644 insert: "the_field",
645 kind: Field,
646 detail: "u32",
647 deprecated: true,
648 },
649 ]
650 "#]],
605 ); 651 );
606 } 652 }
607 653
608 #[test] 654 #[test]
655 fn renders_docs() {
656 check(
657 r#"
658struct S {
659 /// Field docs
660 foo:
661}
662impl S {
663 /// Method docs
664 fn bar(self) { self.<|> }
665}"#,
666 expect![[r#"
667 [
668 CompletionItem {
669 label: "bar()",
670 source_range: 94..94,
671 delete: 94..94,
672 insert: "bar()$0",
673 kind: Method,
674 lookup: "bar",
675 detail: "fn bar(self)",
676 documentation: Documentation(
677 "Method docs",
678 ),
679 },
680 CompletionItem {
681 label: "foo",
682 source_range: 94..94,
683 delete: 94..94,
684 insert: "foo",
685 kind: Field,
686 detail: "{unknown}",
687 documentation: Documentation(
688 "Field docs",
689 ),
690 },
691 ]
692 "#]],
693 );
694
695 check(
696 r#"
697use self::my<|>;
698
699/// mod docs
700mod my { }
701
702/// enum docs
703enum E {
704 /// variant docs
705 V
706}
707use self::E::*;
708"#,
709 expect![[r#"
710 [
711 CompletionItem {
712 label: "E",
713 source_range: 10..12,
714 delete: 10..12,
715 insert: "E",
716 kind: Enum,
717 documentation: Documentation(
718 "enum docs",
719 ),
720 },
721 CompletionItem {
722 label: "V",
723 source_range: 10..12,
724 delete: 10..12,
725 insert: "V",
726 kind: EnumVariant,
727 detail: "()",
728 documentation: Documentation(
729 "variant docs",
730 ),
731 },
732 CompletionItem {
733 label: "my",
734 source_range: 10..12,
735 delete: 10..12,
736 insert: "my",
737 kind: Module,
738 documentation: Documentation(
739 "mod docs",
740 ),
741 },
742 ]
743 "#]],
744 )
745 }
746
747 #[test]
748 fn dont_render_attrs() {
749 check(
750 r#"
751struct S;
752impl S {
753 #[inline]
754 fn the_method(&self) { }
755}
756fn foo(s: S) { s.<|> }
757"#,
758 expect![[r#"
759 [
760 CompletionItem {
761 label: "the_method()",
762 source_range: 81..81,
763 delete: 81..81,
764 insert: "the_method()$0",
765 kind: Method,
766 lookup: "the_method",
767 detail: "fn the_method(&self)",
768 },
769 ]
770 "#]],
771 )
772 }
773
774 #[test]
609 fn inserts_parens_for_function_calls() { 775 fn inserts_parens_for_function_calls() {
610 mark::check!(inserts_parens_for_function_calls); 776 mark::check!(inserts_parens_for_function_calls);
611 assert_debug_snapshot!( 777 check_edit(
612 do_reference_completion( 778 "no_args",
613 r" 779 r#"
614 fn no_args() {} 780fn no_args() {}
615 fn main() { no_<|> } 781fn main() { no_<|> }
616 " 782"#,
617 ), 783 r#"
618 @r###" 784fn no_args() {}
619 [ 785fn main() { no_args()$0 }
620 CompletionItem { 786"#,
621 label: "main()",
622 source_range: 61..64,
623 delete: 61..64,
624 insert: "main()$0",
625 kind: Function,
626 lookup: "main",
627 detail: "fn main()",
628 },
629 CompletionItem {
630 label: "no_args()",
631 source_range: 61..64,
632 delete: 61..64,
633 insert: "no_args()$0",
634 kind: Function,
635 lookup: "no_args",
636 detail: "fn no_args()",
637 },
638 ]
639 "###
640 );
641 assert_debug_snapshot!(
642 do_reference_completion(
643 r"
644 fn with_args(x: i32, y: String) {}
645 fn main() { with_<|> }
646 "
647 ),
648 @r###"
649 [
650 CompletionItem {
651 label: "main()",
652 source_range: 80..85,
653 delete: 80..85,
654 insert: "main()$0",
655 kind: Function,
656 lookup: "main",
657 detail: "fn main()",
658 },
659 CompletionItem {
660 label: "with_args(…)",
661 source_range: 80..85,
662 delete: 80..85,
663 insert: "with_args(${1:x}, ${2:y})$0",
664 kind: Function,
665 lookup: "with_args",
666 detail: "fn with_args(x: i32, y: String)",
667 trigger_call_info: true,
668 },
669 ]
670 "###
671 ); 787 );
672 assert_debug_snapshot!( 788
673 do_reference_completion( 789 check_edit(
674 r" 790 "with_args",
675 fn with_ignored_args(_foo: i32, ___bar: bool, ho_ge_: String) {} 791 r#"
676 fn main() { with_<|> } 792fn with_args(x: i32, y: String) {}
677 " 793fn main() { with_<|> }
678 ), 794"#,
679 @r###" 795 r#"
680 [ 796fn with_args(x: i32, y: String) {}
681 CompletionItem { 797fn main() { with_args(${1:x}, ${2:y})$0 }
682 label: "main()", 798"#,
683 source_range: 110..115,
684 delete: 110..115,
685 insert: "main()$0",
686 kind: Function,
687 lookup: "main",
688 detail: "fn main()",
689 },
690 CompletionItem {
691 label: "with_ignored_args(…)",
692 source_range: 110..115,
693 delete: 110..115,
694 insert: "with_ignored_args(${1:foo}, ${2:bar}, ${3:ho_ge_})$0",
695 kind: Function,
696 lookup: "with_ignored_args",
697 detail: "fn with_ignored_args(_foo: i32, ___bar: bool, ho_ge_: String)",
698 trigger_call_info: true,
699 },
700 ]
701 "###
702 ); 799 );
703 assert_debug_snapshot!( 800
704 do_reference_completion( 801 check_edit(
705 r" 802 "foo",
706 struct S {} 803 r#"
707 impl S { 804struct S;
708 fn foo(&self) {} 805impl S {
709 } 806 fn foo(&self) {}
710 fn bar(s: &S) { 807}
711 s.f<|> 808fn bar(s: &S) { s.f<|> }
712 } 809"#,
713 " 810 r#"
714 ), 811struct S;
715 @r###" 812impl S {
716 [ 813 fn foo(&self) {}
717 CompletionItem { 814}
718 label: "foo()", 815fn bar(s: &S) { s.foo()$0 }
719 source_range: 163..164, 816"#,
720 delete: 163..164,
721 insert: "foo()$0",
722 kind: Method,
723 lookup: "foo",
724 detail: "fn foo(&self)",
725 },
726 ]
727 "###
728 ); 817 );
729 assert_debug_snapshot!( 818
730 do_reference_completion( 819 check_edit(
731 r" 820 "foo",
732 struct S {} 821 r#"
733 impl S { 822struct S {}
734 fn foo_ignored_args(&self, _a: bool, b: i32) {} 823impl S {
735 } 824 fn foo(&self, x: i32) {}
736 fn bar(s: &S) { 825}
737 s.f<|> 826fn bar(s: &S) {
738 } 827 s.f<|>
739 " 828}
740 ), 829"#,
741 @r###" 830 r#"
742 [ 831struct S {}
743 CompletionItem { 832impl S {
744 label: "foo_ignored_args(…)", 833 fn foo(&self, x: i32) {}
745 source_range: 194..195, 834}
746 delete: 194..195, 835fn bar(s: &S) {
747 insert: "foo_ignored_args(${1:a}, ${2:b})$0", 836 s.foo(${1:x})$0
748 kind: Method, 837}
749 lookup: "foo_ignored_args", 838"#,
750 detail: "fn foo_ignored_args(&self, _a: bool, b: i32)",
751 trigger_call_info: true,
752 },
753 ]
754 "###
755 ); 839 );
756 } 840 }
757 841
758 #[test] 842 #[test]
759 fn inserts_parens_for_tuple_enums() { 843 fn suppress_arg_snippets() {
760 assert_debug_snapshot!( 844 mark::check!(suppress_arg_snippets);
761 do_reference_completion( 845 check_edit_with_config(
762 r" 846 CompletionConfig { add_call_argument_snippets: false, ..CompletionConfig::default() },
763 enum Option<T> { Some(T), None } 847 "with_args",
764 use Option::*; 848 r#"
765 fn main() -> Option<i32> { 849fn with_args(x: i32, y: String) {}
766 Som<|> 850fn main() { with_<|> }
767 } 851"#,
768 " 852 r#"
769 ), 853fn with_args(x: i32, y: String) {}
770 @r###" 854fn main() { with_args($0) }
771 [ 855"#,
772 CompletionItem {
773 label: "None",
774 source_range: 144..147,
775 delete: 144..147,
776 insert: "None",
777 kind: EnumVariant,
778 detail: "()",
779 },
780 CompletionItem {
781 label: "Option",
782 source_range: 144..147,
783 delete: 144..147,
784 insert: "Option",
785 kind: Enum,
786 },
787 CompletionItem {
788 label: "Some(…)",
789 source_range: 144..147,
790 delete: 144..147,
791 insert: "Some($0)",
792 kind: EnumVariant,
793 lookup: "Some",
794 detail: "(T)",
795 trigger_call_info: true,
796 },
797 CompletionItem {
798 label: "main()",
799 source_range: 144..147,
800 delete: 144..147,
801 insert: "main()$0",
802 kind: Function,
803 lookup: "main",
804 detail: "fn main() -> Option<i32>",
805 },
806 ]
807 "###
808 );
809 assert_debug_snapshot!(
810 do_reference_completion(
811 r"
812 enum Option<T> { Some(T), None }
813 use Option::*;
814 fn main(value: Option<i32>) {
815 match value {
816 Som<|>
817 }
818 }
819 "
820 ),
821 @r###"
822 [
823 CompletionItem {
824 label: "None",
825 source_range: 185..188,
826 delete: 185..188,
827 insert: "None",
828 kind: EnumVariant,
829 detail: "()",
830 },
831 CompletionItem {
832 label: "Option",
833 source_range: 185..188,
834 delete: 185..188,
835 insert: "Option",
836 kind: Enum,
837 },
838 CompletionItem {
839 label: "Some(…)",
840 source_range: 185..188,
841 delete: 185..188,
842 insert: "Some($0)",
843 kind: EnumVariant,
844 lookup: "Some",
845 detail: "(T)",
846 trigger_call_info: true,
847 },
848 ]
849 "###
850 ); 856 );
851 } 857 }
852 858
853 #[test] 859 #[test]
854 fn no_call_parens_if_fn_ptr_needed() { 860 fn strips_underscores_from_args() {
855 assert_debug_snapshot!( 861 check_edit(
856 do_reference_completion( 862 "foo",
857 r" 863 r#"
858 fn somefn(with: u8, a: u8, lot: u8, of: u8, args: u8) {} 864fn foo(_foo: i32, ___bar: bool, ho_ge_: String) {}
859 865fn main() { f<|> }
860 struct ManualVtable { 866"#,
861 method: fn(u8, u8, u8, u8, u8), 867 r#"
862 } 868fn foo(_foo: i32, ___bar: bool, ho_ge_: String) {}
869fn main() { foo(${1:foo}, ${2:bar}, ${3:ho_ge_})$0 }
870"#,
871 );
872 }
863 873
864 fn main() -> ManualVtable { 874 #[test]
865 ManualVtable { 875 fn inserts_parens_for_tuple_enums() {
866 method: some<|> 876 mark::check!(inserts_parens_for_tuple_enums);
867 } 877 check_edit(
868 } 878 "Some",
869 " 879 r#"
870 ), 880enum Option<T> { Some(T), None }
871 @r###" 881use Option::*;
872 [ 882fn main() -> Option<i32> {
873 CompletionItem { 883 Som<|>
874 label: "ManualVtable", 884}
875 source_range: 295..299, 885"#,
876 delete: 295..299, 886 r#"
877 insert: "ManualVtable", 887enum Option<T> { Some(T), None }
878 kind: Struct, 888use Option::*;
879 }, 889fn main() -> Option<i32> {
880 CompletionItem { 890 Some($0)
881 label: "main", 891}
882 source_range: 295..299, 892"#,
883 delete: 295..299, 893 );
884 insert: "main", 894 check_edit(
885 kind: Function, 895 "Some",
886 detail: "fn main() -> ManualVtable", 896 r#"
887 }, 897enum Option<T> { Some(T), None }
888 CompletionItem { 898use Option::*;
889 label: "somefn", 899fn main(value: Option<i32>) {
890 source_range: 295..299, 900 match value {
891 delete: 295..299, 901 Som<|>
892 insert: "somefn", 902 }
893 kind: Function, 903}
894 detail: "fn somefn(with: u8, a: u8, lot: u8, of: u8, args: u8)", 904"#,
895 }, 905 r#"
896 ] 906enum Option<T> { Some(T), None }
897 "### 907use Option::*;
908fn main(value: Option<i32>) {
909 match value {
910 Some($0)
911 }
912}
913"#,
898 ); 914 );
899 } 915 }
900 916
901 #[test] 917 #[test]
902 fn arg_snippets_for_method_call() { 918 fn dont_duplicate_pattern_parens() {
903 assert_debug_snapshot!( 919 mark::check!(dont_duplicate_pattern_parens);
904 do_reference_completion( 920 check_edit(
905 r" 921 "Var",
906 struct S {} 922 r#"
907 impl S { 923enum E { Var(i32) }
908 fn foo(&self, x: i32) {} 924fn main() {
909 } 925 match E::Var(92) {
910 fn bar(s: &S) { 926 E::<|>(92) => (),
911 s.f<|> 927 }
912 } 928}
913 " 929"#,
914 ), 930 r#"
915 @r###" 931enum E { Var(i32) }
916 [ 932fn main() {
917 CompletionItem { 933 match E::Var(92) {
918 label: "foo(…)", 934 E::Var(92) => (),
919 source_range: 171..172, 935 }
920 delete: 171..172, 936}
921 insert: "foo(${1:x})$0", 937"#,
922 kind: Method, 938 );
923 lookup: "foo",
924 detail: "fn foo(&self, x: i32)",
925 trigger_call_info: true,
926 },
927 ]
928 "###
929 )
930 } 939 }
931 940
932 #[test] 941 #[test]
933 fn no_arg_snippets_for_method_call() { 942 fn no_call_parens_if_fn_ptr_needed() {
934 assert_debug_snapshot!( 943 mark::check!(no_call_parens_if_fn_ptr_needed);
935 do_reference_completion_with_options( 944 check_edit(
936 r" 945 "foo",
937 struct S {} 946 r#"
938 impl S { 947fn foo(foo: u8, bar: u8) {}
939 fn foo(&self, x: i32) {} 948struct ManualVtable { f: fn(u8, u8) }
940 } 949
941 fn bar(s: &S) { 950fn main() -> ManualVtable {
942 s.f<|> 951 ManualVtable { f: f<|> }
943 } 952}
944 ", 953"#,
945 CompletionConfig { 954 r#"
946 add_call_argument_snippets: false, 955fn foo(foo: u8, bar: u8) {}
947 .. Default::default() 956struct ManualVtable { f: fn(u8, u8) }
948 } 957
949 ), 958fn main() -> ManualVtable {
950 @r###" 959 ManualVtable { f: foo }
951 [ 960}
952 CompletionItem { 961"#,
953 label: "foo(…)", 962 );
954 source_range: 171..172,
955 delete: 171..172,
956 insert: "foo($0)",
957 kind: Method,
958 lookup: "foo",
959 detail: "fn foo(&self, x: i32)",
960 trigger_call_info: true,
961 },
962 ]
963 "###
964 )
965 } 963 }
966 964
967 #[test] 965 #[test]
968 fn dont_render_function_parens_in_use_item() { 966 fn no_parens_in_use_item() {
969 assert_debug_snapshot!( 967 mark::check!(no_parens_in_use_item);
970 do_reference_completion( 968 check_edit(
971 " 969 "foo",
972 //- /lib.rs 970 r#"
973 mod m { pub fn foo() {} } 971mod m { pub fn foo() {} }
974 use crate::m::f<|>; 972use crate::m::f<|>;
975 " 973"#,
976 ), 974 r#"
977 @r###" 975mod m { pub fn foo() {} }
978 [ 976use crate::m::foo;
979 CompletionItem { 977"#,
980 label: "foo",
981 source_range: 40..41,
982 delete: 40..41,
983 insert: "foo",
984 kind: Function,
985 detail: "pub fn foo()",
986 },
987 ]
988 "###
989 ); 978 );
990 } 979 }
991 980
992 #[test] 981 #[test]
993 fn dont_render_function_parens_if_already_call() { 982 fn no_parens_in_call() {
994 assert_debug_snapshot!( 983 check_edit(
995 do_reference_completion( 984 "foo",
996 " 985 r#"
997 //- /lib.rs 986fn foo(x: i32) {}
998 fn frobnicate() {} 987fn main() { f<|>(); }
999 fn main() { 988"#,
1000 frob<|>(); 989 r#"
1001 } 990fn foo(x: i32) {}
1002 " 991fn main() { foo(); }
1003 ), 992"#,
1004 @r###"
1005 [
1006 CompletionItem {
1007 label: "frobnicate",
1008 source_range: 35..39,
1009 delete: 35..39,
1010 insert: "frobnicate",
1011 kind: Function,
1012 detail: "fn frobnicate()",
1013 },
1014 CompletionItem {
1015 label: "main",
1016 source_range: 35..39,
1017 delete: 35..39,
1018 insert: "main",
1019 kind: Function,
1020 detail: "fn main()",
1021 },
1022 ]
1023 "###
1024 ); 993 );
1025 assert_debug_snapshot!( 994 check_edit(
1026 do_reference_completion( 995 "foo",
1027 " 996 r#"
1028 //- /lib.rs 997struct Foo;
1029 struct Foo {} 998impl Foo { fn foo(&self){} }
1030 impl Foo { fn new() -> Foo {} } 999fn f(foo: &Foo) { foo.f<|>(); }
1031 fn main() { 1000"#,
1032 Foo::ne<|>(); 1001 r#"
1033 } 1002struct Foo;
1034 " 1003impl Foo { fn foo(&self){} }
1035 ), 1004fn f(foo: &Foo) { foo.foo(); }
1036 @r###" 1005"#,
1037 [
1038 CompletionItem {
1039 label: "new",
1040 source_range: 67..69,
1041 delete: 67..69,
1042 insert: "new",
1043 kind: Function,
1044 detail: "fn new() -> Foo",
1045 },
1046 ]
1047 "###
1048 ); 1006 );
1049 } 1007 }
1050 1008
1051 #[test] 1009 #[test]
1052 fn inserts_angle_brackets_for_generics() { 1010 fn inserts_angle_brackets_for_generics() {
1053 mark::check!(inserts_angle_brackets_for_generics); 1011 mark::check!(inserts_angle_brackets_for_generics);
1054 assert_debug_snapshot!( 1012 check_edit(
1055 do_reference_completion( 1013 "Vec",
1056 r" 1014 r#"
1057 struct Vec<T> {} 1015struct Vec<T> {}
1058 fn foo(xs: Ve<|>) 1016fn foo(xs: Ve<|>)
1059 " 1017"#,
1060 ), 1018 r#"
1061 @r###" 1019struct Vec<T> {}
1062 [ 1020fn foo(xs: Vec<$0>)
1063 CompletionItem { 1021"#,
1064 label: "Vec<…>",
1065 source_range: 61..63,
1066 delete: 61..63,
1067 insert: "Vec<$0>",
1068 kind: Struct,
1069 lookup: "Vec",
1070 },
1071 CompletionItem {
1072 label: "foo(…)",
1073 source_range: 61..63,
1074 delete: 61..63,
1075 insert: "foo(${1:xs})$0",
1076 kind: Function,
1077 lookup: "foo",
1078 detail: "fn foo(xs: Ve)",
1079 trigger_call_info: true,
1080 },
1081 ]
1082 "###
1083 ); 1022 );
1084 assert_debug_snapshot!( 1023 check_edit(
1085 do_reference_completion( 1024 "Vec",
1086 r" 1025 r#"
1087 type Vec<T> = (T,); 1026type Vec<T> = (T,);
1088 fn foo(xs: Ve<|>) 1027fn foo(xs: Ve<|>)
1089 " 1028"#,
1090 ), 1029 r#"
1091 @r###" 1030type Vec<T> = (T,);
1092 [ 1031fn foo(xs: Vec<$0>)
1093 CompletionItem { 1032"#,
1094 label: "Vec<…>",
1095 source_range: 64..66,
1096 delete: 64..66,
1097 insert: "Vec<$0>",
1098 kind: TypeAlias,
1099 lookup: "Vec",
1100 },
1101 CompletionItem {
1102 label: "foo(…)",
1103 source_range: 64..66,
1104 delete: 64..66,
1105 insert: "foo(${1:xs})$0",
1106 kind: Function,
1107 lookup: "foo",
1108 detail: "fn foo(xs: Ve)",
1109 trigger_call_info: true,
1110 },
1111 ]
1112 "###
1113 ); 1033 );
1114 assert_debug_snapshot!( 1034 check_edit(
1115 do_reference_completion( 1035 "Vec",
1116 r" 1036 r#"
1117 struct Vec<T = i128> {} 1037struct Vec<T = i128> {}
1118 fn foo(xs: Ve<|>) 1038fn foo(xs: Ve<|>)
1119 " 1039"#,
1120 ), 1040 r#"
1121 @r###" 1041struct Vec<T = i128> {}
1122 [ 1042fn foo(xs: Vec)
1123 CompletionItem { 1043"#,
1124 label: "Vec",
1125 source_range: 68..70,
1126 delete: 68..70,
1127 insert: "Vec",
1128 kind: Struct,
1129 },
1130 CompletionItem {
1131 label: "foo(…)",
1132 source_range: 68..70,
1133 delete: 68..70,
1134 insert: "foo(${1:xs})$0",
1135 kind: Function,
1136 lookup: "foo",
1137 detail: "fn foo(xs: Ve)",
1138 trigger_call_info: true,
1139 },
1140 ]
1141 "###
1142 ); 1044 );
1143 assert_debug_snapshot!( 1045 check_edit(
1144 do_reference_completion( 1046 "Vec",
1145 r" 1047 r#"
1146 struct Vec<T> {} 1048struct Vec<T> {}
1147 fn foo(xs: Ve<|><i128>) 1049fn foo(xs: Ve<|><i128>)
1148 " 1050"#,
1149 ), 1051 r#"
1150 @r###" 1052struct Vec<T> {}
1151 [ 1053fn foo(xs: Vec<i128>)
1152 CompletionItem { 1054"#,
1153 label: "Vec",
1154 source_range: 61..63,
1155 delete: 61..63,
1156 insert: "Vec",
1157 kind: Struct,
1158 },
1159 CompletionItem {
1160 label: "foo(…)",
1161 source_range: 61..63,
1162 delete: 61..63,
1163 insert: "foo(${1:xs})$0",
1164 kind: Function,
1165 lookup: "foo",
1166 detail: "fn foo(xs: Ve<i128>)",
1167 trigger_call_info: true,
1168 },
1169 ]
1170 "###
1171 ); 1055 );
1172 } 1056 }
1173 1057
1174 #[test] 1058 #[test]
1175 fn dont_insert_macro_call_parens_unncessary() { 1059 fn dont_insert_macro_call_parens_unncessary() {
1176 mark::check!(dont_insert_macro_call_parens_unncessary); 1060 mark::check!(dont_insert_macro_call_parens_unncessary);
1177 assert_debug_snapshot!( 1061 check_edit(
1178 do_reference_completion( 1062 "frobnicate!",
1179 r" 1063 r#"
1180 //- /main.rs 1064//- /main.rs
1181 use foo::<|>; 1065use foo::<|>;
1182 1066//- /foo/lib.rs
1183 //- /foo/lib.rs 1067#[macro_export]
1184 #[macro_export] 1068macro_rules frobnicate { () => () }
1185 macro_rules frobnicate { 1069"#,
1186 () => () 1070 r#"
1187 } 1071use foo::frobnicate;
1188 " 1072"#,
1189 ),
1190 @r###"
1191 [
1192 CompletionItem {
1193 label: "frobnicate!",
1194 source_range: 9..9,
1195 delete: 9..9,
1196 insert: "frobnicate",
1197 kind: Macro,
1198 detail: "#[macro_export]\nmacro_rules! frobnicate",
1199 },
1200 ]
1201 "###
1202 ); 1073 );
1203 1074
1204 assert_debug_snapshot!( 1075 check_edit(
1205 do_reference_completion( 1076 "frobnicate!",
1206 r" 1077 r#"
1207 //- /main.rs 1078macro_rules frobnicate { () => () }
1208 macro_rules frobnicate { 1079fn main() { frob<|>!(); }
1209 () => () 1080"#,
1210 } 1081 r#"
1211 fn main() { 1082macro_rules frobnicate { () => () }
1212 frob<|>!(); 1083fn main() { frobnicate!(); }
1213 } 1084"#,
1214 "
1215 ),
1216 @r###"
1217 [
1218 CompletionItem {
1219 label: "frobnicate!",
1220 source_range: 56..60,
1221 delete: 56..60,
1222 insert: "frobnicate",
1223 kind: Macro,
1224 detail: "macro_rules! frobnicate",
1225 },
1226 CompletionItem {
1227 label: "main()",
1228 source_range: 56..60,
1229 delete: 56..60,
1230 insert: "main()$0",
1231 kind: Function,
1232 lookup: "main",
1233 detail: "fn main()",
1234 },
1235 ]
1236 "###
1237 ); 1085 );
1238 } 1086 }
1239 1087
1240 #[test] 1088 #[test]
1241 fn test_struct_field_completion_in_func_call() { 1089 fn active_param_score() {
1242 mark::check!(test_struct_field_completion_in_func_call); 1090 mark::check!(active_param_type_match);
1243 assert_debug_snapshot!( 1091 check_scores(
1244 do_reference_completion( 1092 r#"
1245 r" 1093struct S { foo: i64, bar: u32, baz: u32 }
1246 struct A { another_field: i64, the_field: u32, my_string: String } 1094fn test(bar: u32) { }
1247 fn test(my_param: u32) -> u32 { my_param } 1095fn foo(s: S) { test(s.<|>) }
1248 fn foo(a: A) { 1096"#,
1249 test(a.<|>) 1097 expect![[r#"
1250 } 1098 fd bar [type+name]
1251 ", 1099 fd baz [type]
1252 ), 1100 fd foo []
1253 @r###" 1101 "#]],
1254 [
1255 CompletionItem {
1256 label: "another_field",
1257 source_range: 201..201,
1258 delete: 201..201,
1259 insert: "another_field",
1260 kind: Field,
1261 detail: "i64",
1262 },
1263 CompletionItem {
1264 label: "my_string",
1265 source_range: 201..201,
1266 delete: 201..201,
1267 insert: "my_string",
1268 kind: Field,
1269 detail: "{unknown}",
1270 },
1271 CompletionItem {
1272 label: "the_field",
1273 source_range: 201..201,
1274 delete: 201..201,
1275 insert: "the_field",
1276 kind: Field,
1277 detail: "u32",
1278 score: TypeMatch,
1279 },
1280 ]
1281 "###
1282 ); 1102 );
1283 } 1103 }
1284 1104
1285 #[test] 1105 #[test]
1286 fn test_struct_field_completion_in_func_call_with_type_and_name() { 1106 fn record_field_scores() {
1287 assert_debug_snapshot!( 1107 mark::check!(record_field_type_match);
1288 do_reference_completion( 1108 check_scores(
1289 r" 1109 r#"
1290 struct A { another_field: i64, another_good_type: u32, the_field: u32 } 1110struct A { foo: i64, bar: u32, baz: u32 }
1291 fn test(the_field: u32) -> u32 { the_field } 1111struct B { x: (), y: f32, bar: u32 }
1292 fn foo(a: A) { 1112fn foo(a: A) { B { bar: a.<|> }; }
1293 test(a.<|>) 1113"#,
1294 } 1114 expect![[r#"
1295 ", 1115 fd bar [type+name]
1296 ), 1116 fd baz [type]
1297 @r###" 1117 fd foo []
1298 [ 1118 "#]],
1299 CompletionItem { 1119 )
1300 label: "another_field",
1301 source_range: 208..208,
1302 delete: 208..208,
1303 insert: "another_field",
1304 kind: Field,
1305 detail: "i64",
1306 },
1307 CompletionItem {
1308 label: "another_good_type",
1309 source_range: 208..208,
1310 delete: 208..208,
1311 insert: "another_good_type",
1312 kind: Field,
1313 detail: "u32",
1314 score: TypeMatch,
1315 },
1316 CompletionItem {
1317 label: "the_field",
1318 source_range: 208..208,
1319 delete: 208..208,
1320 insert: "the_field",
1321 kind: Field,
1322 detail: "u32",
1323 score: TypeAndNameMatch,
1324 },
1325 ]
1326 "###
1327 );
1328 } 1120 }
1329 1121
1330 #[test] 1122 #[test]
1331 fn test_struct_field_completion_in_record_lit() { 1123 fn record_field_and_call_scores() {
1332 mark::check!(test_struct_field_completion_in_record_lit); 1124 check_scores(
1333 assert_debug_snapshot!( 1125 r#"
1334 do_reference_completion( 1126struct A { foo: i64, bar: u32, baz: u32 }
1335 r" 1127struct B { x: (), y: f32, bar: u32 }
1336 struct A { another_field: i64, another_good_type: u32, the_field: u32 } 1128fn f(foo: i64) { }
1337 struct B { my_string: String, my_vec: Vec<u32>, the_field: u32 } 1129fn foo(a: A) { B { bar: f(a.<|>) }; }
1338 fn foo(a: A) { 1130"#,
1339 let b = B { 1131 expect![[r#"
1340 the_field: a.<|> 1132 fd foo [type+name]
1341 }; 1133 fd bar []
1342 } 1134 fd baz []
1343 ", 1135 "#]],
1344 ),
1345 @r###"
1346 [
1347 CompletionItem {
1348 label: "another_field",
1349 source_range: 270..270,
1350 delete: 270..270,
1351 insert: "another_field",
1352 kind: Field,
1353 detail: "i64",
1354 },
1355 CompletionItem {
1356 label: "another_good_type",
1357 source_range: 270..270,
1358 delete: 270..270,
1359 insert: "another_good_type",
1360 kind: Field,
1361 detail: "u32",
1362 score: TypeMatch,
1363 },
1364 CompletionItem {
1365 label: "the_field",
1366 source_range: 270..270,
1367 delete: 270..270,
1368 insert: "the_field",
1369 kind: Field,
1370 detail: "u32",
1371 score: TypeAndNameMatch,
1372 },
1373 ]
1374 "###
1375 ); 1136 );
1376 } 1137 check_scores(
1377 1138 r#"
1378 #[test] 1139struct A { foo: i64, bar: u32, baz: u32 }
1379 fn test_struct_field_completion_in_record_lit_and_fn_call() { 1140struct B { x: (), y: f32, bar: u32 }
1380 assert_debug_snapshot!( 1141fn f(foo: i64) { }
1381 do_reference_completion( 1142fn foo(a: A) { f(B { bar: a.<|> }); }
1382 r" 1143"#,
1383 struct A { another_field: i64, another_good_type: u32, the_field: u32 } 1144 expect![[r#"
1384 struct B { my_string: String, my_vec: Vec<u32>, the_field: u32 } 1145 fd bar [type+name]
1385 fn test(the_field: i64) -> i64 { the_field } 1146 fd baz [type]
1386 fn foo(a: A) { 1147 fd foo []
1387 let b = B { 1148 "#]],
1388 the_field: test(a.<|>)
1389 };
1390 }
1391 ",
1392 ),
1393 @r###"
1394 [
1395 CompletionItem {
1396 label: "another_field",
1397 source_range: 336..336,
1398 delete: 336..336,
1399 insert: "another_field",
1400 kind: Field,
1401 detail: "i64",
1402 score: TypeMatch,
1403 },
1404 CompletionItem {
1405 label: "another_good_type",
1406 source_range: 336..336,
1407 delete: 336..336,
1408 insert: "another_good_type",
1409 kind: Field,
1410 detail: "u32",
1411 },
1412 CompletionItem {
1413 label: "the_field",
1414 source_range: 336..336,
1415 delete: 336..336,
1416 insert: "the_field",
1417 kind: Field,
1418 detail: "u32",
1419 },
1420 ]
1421 "###
1422 ); 1149 );
1423 } 1150 }
1424 1151
1425 #[test] 1152 #[test]
1426 fn test_struct_field_completion_in_fn_call_and_record_lit() { 1153 fn prioritize_exact_ref_match() {
1427 assert_debug_snapshot!( 1154 check_scores(
1428 do_reference_completion( 1155 r#"
1429 r" 1156struct WorldSnapshot { _f: () };
1430 struct A { another_field: i64, another_good_type: u32, the_field: u32 } 1157fn go(world: &WorldSnapshot) { go(w<|>) }
1431 struct B { my_string: String, my_vec: Vec<u32>, the_field: u32 } 1158"#,
1432 fn test(the_field: i64) -> i64 { the_field } 1159 expect![[r#"
1433 fn foo(a: A) { 1160 bn world [type+name]
1434 test(B { 1161 st WorldSnapshot []
1435 the_field: a.<|> 1162 fn go(…) []
1436 }); 1163 "#]],
1437 }
1438 ",
1439 ),
1440 @r###"
1441 [
1442 CompletionItem {
1443 label: "another_field",
1444 source_range: 328..328,
1445 delete: 328..328,
1446 insert: "another_field",
1447 kind: Field,
1448 detail: "i64",
1449 },
1450 CompletionItem {
1451 label: "another_good_type",
1452 source_range: 328..328,
1453 delete: 328..328,
1454 insert: "another_good_type",
1455 kind: Field,
1456 detail: "u32",
1457 score: TypeMatch,
1458 },
1459 CompletionItem {
1460 label: "the_field",
1461 source_range: 328..328,
1462 delete: 328..328,
1463 insert: "the_field",
1464 kind: Field,
1465 detail: "u32",
1466 score: TypeAndNameMatch,
1467 },
1468 ]
1469 "###
1470 ); 1164 );
1471 } 1165 }
1472 1166
1473 #[test] 1167 #[test]
1474 fn prioritize_exact_ref_match() { 1168 fn guesses_macro_braces() {
1475 assert_debug_snapshot!( 1169 check_edit(
1476 do_reference_completion( 1170 "vec!",
1477 r" 1171 r#"
1478 struct WorldSnapshot { _f: () }; 1172/// Creates a [`Vec`] containing the arguments.
1479 fn go(world: &WorldSnapshot) { 1173///
1480 go(w<|>) 1174/// ```
1481 } 1175/// let v = vec![1, 2, 3];
1482 ", 1176/// assert_eq!(v[0], 1);
1483 ), 1177/// assert_eq!(v[1], 2);
1484 @r###" 1178/// assert_eq!(v[2], 3);
1485 [ 1179/// ```
1486 CompletionItem { 1180macro_rules! vec { () => {} }
1487 label: "WorldSnapshot", 1181
1488 source_range: 132..133, 1182fn fn main() { v<|> }
1489 delete: 132..133, 1183"#,
1490 insert: "WorldSnapshot", 1184 r#"
1491 kind: Struct, 1185/// Creates a [`Vec`] containing the arguments.
1492 }, 1186///
1493 CompletionItem { 1187/// ```
1494 label: "go(…)", 1188/// let v = vec![1, 2, 3];
1495 source_range: 132..133, 1189/// assert_eq!(v[0], 1);
1496 delete: 132..133, 1190/// assert_eq!(v[1], 2);
1497 insert: "go(${1:world})$0", 1191/// assert_eq!(v[2], 3);
1498 kind: Function, 1192/// ```
1499 lookup: "go", 1193macro_rules! vec { () => {} }
1500 detail: "fn go(world: &WorldSnapshot)", 1194
1501 trigger_call_info: true, 1195fn fn main() { vec![$0] }
1502 }, 1196"#,
1503 CompletionItem {
1504 label: "world",
1505 source_range: 132..133,
1506 delete: 132..133,
1507 insert: "world",
1508 kind: Binding,
1509 detail: "&WorldSnapshot",
1510 score: TypeAndNameMatch,
1511 },
1512 ]
1513 "###
1514 ); 1197 );
1198
1199 check_edit(
1200 "foo!",
1201 r#"
1202/// Foo
1203///
1204/// Don't call `fooo!()` `fooo!()`, or `_foo![]` `_foo![]`,
1205/// call as `let _=foo! { hello world };`
1206macro_rules! foo { () => {} }
1207fn main() { <|> }
1208"#,
1209 r#"
1210/// Foo
1211///
1212/// Don't call `fooo!()` `fooo!()`, or `_foo![]` `_foo![]`,
1213/// call as `let _=foo! { hello world };`
1214macro_rules! foo { () => {} }
1215fn main() { foo! {$0} }
1216"#,
1217 )
1515 } 1218 }
1516} 1219}
diff --git a/crates/ra_ide/src/completion/test_utils.rs b/crates/ra_ide/src/completion/test_utils.rs
index bf22452a2..919177745 100644
--- a/crates/ra_ide/src/completion/test_utils.rs
+++ b/crates/ra_ide/src/completion/test_utils.rs
@@ -1,29 +1,114 @@
1//! Runs completion for testing purposes. 1//! Runs completion for testing purposes.
2 2
3use hir::Semantics;
4use itertools::Itertools;
5use ra_syntax::{AstNode, NodeOrToken, SyntaxElement};
6use stdx::{format_to, trim_indent};
7use test_utils::assert_eq_text;
8
3use crate::{ 9use crate::{
4 completion::{completion_item::CompletionKind, CompletionConfig}, 10 completion::{completion_item::CompletionKind, CompletionConfig},
5 mock_analysis::{analysis_and_position, single_file_with_position}, 11 mock_analysis::analysis_and_position,
6 CompletionItem, 12 CompletionItem,
7}; 13};
8 14
9pub(crate) fn do_completion(code: &str, kind: CompletionKind) -> Vec<CompletionItem> { 15pub(crate) fn do_completion(code: &str, kind: CompletionKind) -> Vec<CompletionItem> {
10 do_completion_with_options(code, kind, &CompletionConfig::default()) 16 do_completion_with_config(CompletionConfig::default(), code, kind)
11} 17}
12 18
13pub(crate) fn do_completion_with_options( 19pub(crate) fn do_completion_with_config(
20 config: CompletionConfig,
14 code: &str, 21 code: &str,
15 kind: CompletionKind, 22 kind: CompletionKind,
16 options: &CompletionConfig,
17) -> Vec<CompletionItem> { 23) -> Vec<CompletionItem> {
18 let (analysis, position) = if code.contains("//-") { 24 let mut kind_completions: Vec<CompletionItem> = get_all_completion_items(config, code)
19 analysis_and_position(code) 25 .into_iter()
20 } else { 26 .filter(|c| c.completion_kind == kind)
21 single_file_with_position(code) 27 .collect();
22 }; 28 kind_completions.sort_by(|l, r| l.label().cmp(r.label()));
23 let completions = analysis.completions(options, position).unwrap().unwrap(); 29 kind_completions
24 let completion_items: Vec<CompletionItem> = completions.into(); 30}
25 let mut kind_completions: Vec<CompletionItem> = 31
26 completion_items.into_iter().filter(|c| c.completion_kind == kind).collect(); 32pub(crate) fn completion_list(code: &str, kind: CompletionKind) -> String {
33 completion_list_with_config(CompletionConfig::default(), code, kind)
34}
35
36pub(crate) fn completion_list_with_config(
37 config: CompletionConfig,
38 code: &str,
39 kind: CompletionKind,
40) -> String {
41 let mut kind_completions: Vec<CompletionItem> = get_all_completion_items(config, code)
42 .into_iter()
43 .filter(|c| c.completion_kind == kind)
44 .collect();
27 kind_completions.sort_by_key(|c| c.label().to_owned()); 45 kind_completions.sort_by_key(|c| c.label().to_owned());
46 let label_width = kind_completions
47 .iter()
48 .map(|it| monospace_width(it.label()))
49 .max()
50 .unwrap_or_default()
51 .min(16);
28 kind_completions 52 kind_completions
53 .into_iter()
54 .map(|it| {
55 let tag = it.kind().unwrap().tag();
56 let var_name = format!("{} {}", tag, it.label());
57 let mut buf = var_name;
58 if let Some(detail) = it.detail() {
59 let width = label_width.saturating_sub(monospace_width(it.label()));
60 format_to!(buf, "{:width$} {}", "", detail, width = width);
61 }
62 format_to!(buf, "\n");
63 buf
64 })
65 .collect()
66}
67
68fn monospace_width(s: &str) -> usize {
69 s.chars().count()
70}
71
72pub(crate) fn check_edit(what: &str, ra_fixture_before: &str, ra_fixture_after: &str) {
73 check_edit_with_config(CompletionConfig::default(), what, ra_fixture_before, ra_fixture_after)
74}
75
76pub(crate) fn check_edit_with_config(
77 config: CompletionConfig,
78 what: &str,
79 ra_fixture_before: &str,
80 ra_fixture_after: &str,
81) {
82 let ra_fixture_after = trim_indent(ra_fixture_after);
83 let (analysis, position) = analysis_and_position(ra_fixture_before);
84 let completions: Vec<CompletionItem> =
85 analysis.completions(&config, position).unwrap().unwrap().into();
86 let (completion,) = completions
87 .iter()
88 .filter(|it| it.lookup() == what)
89 .collect_tuple()
90 .unwrap_or_else(|| panic!("can't find {:?} completion in {:#?}", what, completions));
91 let mut actual = analysis.file_text(position.file_id).unwrap().to_string();
92 completion.text_edit().apply(&mut actual);
93 assert_eq_text!(&ra_fixture_after, &actual)
94}
95
96pub(crate) fn check_pattern_is_applicable(code: &str, check: fn(SyntaxElement) -> bool) {
97 let (analysis, pos) = analysis_and_position(code);
98 analysis
99 .with_db(|db| {
100 let sema = Semantics::new(db);
101 let original_file = sema.parse(pos.file_id);
102 let token = original_file.syntax().token_at_offset(pos.offset).left_biased().unwrap();
103 assert!(check(NodeOrToken::Token(token)));
104 })
105 .unwrap();
106}
107
108pub(crate) fn get_all_completion_items(
109 config: CompletionConfig,
110 code: &str,
111) -> Vec<CompletionItem> {
112 let (analysis, position) = analysis_and_position(code);
113 analysis.completions(&config, position).unwrap().unwrap().into()
29} 114}