aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_ide/src
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_ide/src')
-rw-r--r--crates/ra_ide/src/completion/complete_attribute.rs973
-rw-r--r--crates/ra_ide/src/completion/complete_keyword.rs445
-rw-r--r--crates/ra_ide/src/completion/complete_record.rs546
-rw-r--r--crates/ra_ide/src/completion/completion_item.rs20
-rw-r--r--crates/ra_ide/src/completion/presentation.rs680
-rw-r--r--crates/ra_ide/src/completion/test_utils.rs36
-rw-r--r--crates/ra_ide/src/lib.rs2
-rw-r--r--crates/ra_ide/src/references/rename.rs1043
8 files changed, 1344 insertions, 2401 deletions
diff --git a/crates/ra_ide/src/completion/complete_attribute.rs b/crates/ra_ide/src/completion/complete_attribute.rs
index 6beeca457..9db317509 100644
--- a/crates/ra_ide/src/completion/complete_attribute.rs
+++ b/crates/ra_ide/src/completion/complete_attribute.rs
@@ -46,7 +46,7 @@ fn complete_attribute_start(acc: &mut Completions, ctx: &CompletionContext, attr
46 _ => {} 46 _ => {}
47 } 47 }
48 48
49 if attribute.kind() == ast::AttrKind::Inner || !attr_completion.should_be_inner { 49 if attribute.kind() == ast::AttrKind::Inner || !attr_completion.prefer_inner {
50 acc.add(item); 50 acc.add(item);
51 } 51 }
52 } 52 }
@@ -56,159 +56,72 @@ struct AttrCompletion {
56 label: &'static str, 56 label: &'static str,
57 lookup: Option<&'static str>, 57 lookup: Option<&'static str>,
58 snippet: Option<&'static str>, 58 snippet: Option<&'static str>,
59 should_be_inner: bool, 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>,
71 snippet: Option<&'static str>,
72) -> AttrCompletion {
73 AttrCompletion { label, lookup, snippet, prefer_inner: false }
60} 74}
61 75
62const ATTRIBUTES: &[AttrCompletion] = &[ 76const ATTRIBUTES: &[AttrCompletion] = &[
63 AttrCompletion { 77 attr("allow(…)", Some("allow"), Some("allow(${0:lint})")),
64 label: "allow(…)", 78 attr("cfg_attr(…)", Some("cfg_attr"), Some("cfg_attr(${1:predicate}, ${0:attr})")),
65 snippet: Some("allow(${0:lint})"), 79 attr("cfg(…)", Some("cfg"), Some("cfg(${0:predicate})")),
66 should_be_inner: false, 80 attr("deny(…)", Some("deny"), Some("deny(${0:lint})")),
67 lookup: Some("allow"), 81 attr(r#"deprecated = "…""#, Some("deprecated"), Some(r#"deprecated = "${0:reason}""#)),
68 }, 82 attr("derive(…)", Some("derive"), Some(r#"derive(${0:Debug})"#)),
69 AttrCompletion { 83 attr(r#"doc = "…""#, Some("doc"), Some(r#"doc = "${0:docs}""#)),
70 label: "cfg_attr(…)", 84 attr("feature(…)", Some("feature"), Some("feature(${0:flag})")).prefer_inner(),
71 snippet: Some("cfg_attr(${1:predicate}, ${0:attr})"), 85 attr("forbid(…)", Some("forbid"), Some("forbid(${0:lint})")),
72 should_be_inner: false,
73 lookup: Some("cfg_attr"),
74 },
75 AttrCompletion {
76 label: "cfg(…)",
77 snippet: Some("cfg(${0:predicate})"),
78 should_be_inner: false,
79 lookup: Some("cfg"),
80 },
81 AttrCompletion {
82 label: "deny(…)",
83 snippet: Some("deny(${0:lint})"),
84 should_be_inner: false,
85 lookup: Some("deny"),
86 },
87 AttrCompletion {
88 label: r#"deprecated = "…""#,
89 snippet: Some(r#"deprecated = "${0:reason}""#),
90 should_be_inner: false,
91 lookup: Some("deprecated"),
92 },
93 AttrCompletion {
94 label: "derive(…)",
95 snippet: Some(r#"derive(${0:Debug})"#),
96 should_be_inner: false,
97 lookup: Some("derive"),
98 },
99 AttrCompletion {
100 label: r#"doc = "…""#,
101 snippet: Some(r#"doc = "${0:docs}""#),
102 should_be_inner: false,
103 lookup: Some("doc"),
104 },
105 AttrCompletion {
106 label: "feature(…)",
107 snippet: Some("feature(${0:flag})"),
108 should_be_inner: true,
109 lookup: Some("feature"),
110 },
111 AttrCompletion {
112 label: "forbid(…)",
113 snippet: Some("forbid(${0:lint})"),
114 should_be_inner: false,
115 lookup: Some("forbid"),
116 },
117 // FIXME: resolve through macro resolution? 86 // FIXME: resolve through macro resolution?
118 AttrCompletion { 87 attr("global_allocator", None, None).prefer_inner(),
119 label: "global_allocator", 88 attr("ignore(…)", Some("ignore"), Some("ignore(${0:lint})")),
120 snippet: None, 89 attr("inline(…)", Some("inline"), Some("inline(${0:lint})")),
121 should_be_inner: true, 90 attr(r#"link_name = "…""#, Some("link_name"), Some(r#"link_name = "${0:symbol_name}""#)),
122 lookup: None, 91 attr("link", None, None),
123 }, 92 attr("macro_export", None, None),
124 AttrCompletion { 93 attr("macro_use", None, None),
125 label: "ignore(…)", 94 attr(r#"must_use = "…""#, Some("must_use"), Some(r#"must_use = "${0:reason}""#)),
126 snippet: Some("ignore(${0:lint})"), 95 attr("no_mangle", None, None),
127 should_be_inner: false, 96 attr("no_std", None, None).prefer_inner(),
128 lookup: Some("ignore"), 97 attr("non_exhaustive", None, None),
129 }, 98 attr("panic_handler", None, None).prefer_inner(),
130 AttrCompletion { 99 attr("path = \"…\"", Some("path"), Some("path =\"${0:path}\"")),
131 label: "inline(…)", 100 attr("proc_macro", None, None),
132 snippet: Some("inline(${0:lint})"), 101 attr("proc_macro_attribute", None, None),
133 should_be_inner: false, 102 attr("proc_macro_derive(…)", Some("proc_macro_derive"), Some("proc_macro_derive(${0:Trait})")),
134 lookup: Some("inline"), 103 attr("recursion_limit = …", Some("recursion_limit"), Some("recursion_limit = ${0:128}"))
135 }, 104 .prefer_inner(),
136 AttrCompletion { 105 attr("repr(…)", Some("repr"), Some("repr(${0:C})")),
137 label: r#"link_name = "…""#, 106 attr(
138 snippet: Some(r#"link_name = "${0:symbol_name}""#), 107 "should_panic(…)",
139 should_be_inner: false, 108 Some("should_panic"),
140 lookup: Some("link_name"), 109 Some(r#"should_panic(expected = "${0:reason}")"#),
141 }, 110 ),
142 AttrCompletion { label: "link", snippet: None, should_be_inner: false, lookup: None }, 111 attr(
143 AttrCompletion { label: "macro_export", snippet: None, should_be_inner: false, lookup: None }, 112 r#"target_feature = "…""#,
144 AttrCompletion { label: "macro_use", snippet: None, should_be_inner: false, lookup: None }, 113 Some("target_feature"),
145 AttrCompletion { 114 Some("target_feature = \"${0:feature}\""),
146 label: r#"must_use = "…""#, 115 ),
147 snippet: Some(r#"must_use = "${0:reason}""#), 116 attr("test", None, None),
148 should_be_inner: false, 117 attr("used", None, None),
149 lookup: Some("must_use"), 118 attr("warn(…)", Some("warn"), Some("warn(${0:lint})")),
150 }, 119 attr(
151 AttrCompletion { label: "no_mangle", snippet: None, should_be_inner: false, lookup: None }, 120 r#"windows_subsystem = "…""#,
152 AttrCompletion { label: "no_std", snippet: None, should_be_inner: true, lookup: None }, 121 Some("windows_subsystem"),
153 AttrCompletion { label: "non_exhaustive", snippet: None, should_be_inner: false, lookup: None }, 122 Some(r#"windows_subsystem = "${0:subsystem}""#),
154 AttrCompletion { label: "panic_handler", snippet: None, should_be_inner: true, lookup: None }, 123 )
155 AttrCompletion { 124 .prefer_inner(),
156 label: "path = \"…\"",
157 snippet: Some("path =\"${0:path}\""),
158 should_be_inner: false,
159 lookup: Some("path"),
160 },
161 AttrCompletion { label: "proc_macro", snippet: None, should_be_inner: false, lookup: None },
162 AttrCompletion {
163 label: "proc_macro_attribute",
164 snippet: None,
165 should_be_inner: false,
166 lookup: None,
167 },
168 AttrCompletion {
169 label: "proc_macro_derive(…)",
170 snippet: Some("proc_macro_derive(${0:Trait})"),
171 should_be_inner: false,
172 lookup: Some("proc_macro_derive"),
173 },
174 AttrCompletion {
175 label: "recursion_limit = …",
176 snippet: Some("recursion_limit = ${0:128}"),
177 should_be_inner: true,
178 lookup: Some("recursion_limit"),
179 },
180 AttrCompletion {
181 label: "repr(…)",
182 snippet: Some("repr(${0:C})"),
183 should_be_inner: false,
184 lookup: Some("repr"),
185 },
186 AttrCompletion {
187 label: "should_panic(…)",
188 snippet: Some(r#"should_panic(expected = "${0:reason}")"#),
189 should_be_inner: false,
190 lookup: Some("should_panic"),
191 },
192 AttrCompletion {
193 label: r#"target_feature = "…""#,
194 snippet: Some("target_feature = \"${0:feature}\""),
195 should_be_inner: false,
196 lookup: Some("target_feature"),
197 },
198 AttrCompletion { label: "test", snippet: None, should_be_inner: false, lookup: None },
199 AttrCompletion { label: "used", snippet: None, should_be_inner: false, lookup: None },
200 AttrCompletion {
201 label: "warn(…)",
202 snippet: Some("warn(${0:lint})"),
203 should_be_inner: false,
204 lookup: Some("warn"),
205 },
206 AttrCompletion {
207 label: r#"windows_subsystem = "…""#,
208 snippet: Some(r#"windows_subsystem = "${0:subsystem}""#),
209 should_be_inner: true,
210 lookup: Some("windows_subsystem"),
211 },
212]; 125];
213 126
214fn complete_derive(acc: &mut Completions, ctx: &CompletionContext, derive_input: ast::TokenTree) { 127fn complete_derive(acc: &mut Completions, ctx: &CompletionContext, derive_input: ast::TokenTree) {
@@ -313,677 +226,147 @@ const DEFAULT_DERIVE_COMPLETIONS: &[DeriveCompletion] = &[
313 226
314#[cfg(test)] 227#[cfg(test)]
315mod tests { 228mod tests {
316 use crate::completion::{test_utils::do_completion, CompletionItem, CompletionKind}; 229 use expect::{expect, Expect};
317 use insta::assert_debug_snapshot;
318 230
319 fn do_attr_completion(code: &str) -> Vec<CompletionItem> { 231 use crate::completion::{test_utils::completion_list, CompletionKind};
320 do_completion(code, CompletionKind::Attribute) 232
233 fn check(ra_fixture: &str, expect: Expect) {
234 let actual = completion_list(ra_fixture, CompletionKind::Attribute);
235 expect.assert_eq(&actual);
321 } 236 }
322 237
323 #[test] 238 #[test]
324 fn empty_derive_completion() { 239 fn empty_derive_completion() {
325 assert_debug_snapshot!( 240 check(
326 do_attr_completion( 241 r#"
327 r" 242#[derive(<|>)]
328 #[derive(<|>)] 243struct Test {}
329 struct Test {} 244 "#,
330 ", 245 expect![[r#"
331 ), 246 at Clone
332 @r###" 247 at Copy, Clone
333 [ 248 at Debug
334 CompletionItem { 249 at Default
335 label: "Clone", 250 at Eq, PartialEq
336 source_range: 9..9, 251 at Hash
337 delete: 9..9, 252 at Ord, PartialOrd, Eq, PartialEq
338 insert: "Clone", 253 at PartialEq
339 kind: Attribute, 254 at PartialOrd, PartialEq
340 }, 255 "#]],
341 CompletionItem {
342 label: "Copy, Clone",
343 source_range: 9..9,
344 delete: 9..9,
345 insert: "Copy, Clone",
346 kind: Attribute,
347 },
348 CompletionItem {
349 label: "Debug",
350 source_range: 9..9,
351 delete: 9..9,
352 insert: "Debug",
353 kind: Attribute,
354 },
355 CompletionItem {
356 label: "Default",
357 source_range: 9..9,
358 delete: 9..9,
359 insert: "Default",
360 kind: Attribute,
361 },
362 CompletionItem {
363 label: "Eq, PartialEq",
364 source_range: 9..9,
365 delete: 9..9,
366 insert: "Eq, PartialEq",
367 kind: Attribute,
368 },
369 CompletionItem {
370 label: "Hash",
371 source_range: 9..9,
372 delete: 9..9,
373 insert: "Hash",
374 kind: Attribute,
375 },
376 CompletionItem {
377 label: "Ord, PartialOrd, Eq, PartialEq",
378 source_range: 9..9,
379 delete: 9..9,
380 insert: "Ord, PartialOrd, Eq, PartialEq",
381 kind: Attribute,
382 },
383 CompletionItem {
384 label: "PartialEq",
385 source_range: 9..9,
386 delete: 9..9,
387 insert: "PartialEq",
388 kind: Attribute,
389 },
390 CompletionItem {
391 label: "PartialOrd, PartialEq",
392 source_range: 9..9,
393 delete: 9..9,
394 insert: "PartialOrd, PartialEq",
395 kind: Attribute,
396 },
397 ]
398 "###
399 ); 256 );
400 } 257 }
401 258
402 #[test] 259 #[test]
403 fn no_completion_for_incorrect_derive() { 260 fn no_completion_for_incorrect_derive() {
404 assert_debug_snapshot!( 261 check(
405 do_attr_completion( 262 r#"
406 r" 263#[derive{<|>)]
407 #[derive{<|>)] 264struct Test {}
408 struct Test {} 265"#,
409 ", 266 expect![[r#""#]],
410 ), 267 )
411 @"[]"
412 );
413 } 268 }
414 269
415 #[test] 270 #[test]
416 fn derive_with_input_completion() { 271 fn derive_with_input_completion() {
417 assert_debug_snapshot!( 272 check(
418 do_attr_completion( 273 r#"
419 r" 274#[derive(serde::Serialize, PartialEq, <|>)]
420 #[derive(serde::Serialize, PartialEq, <|>)] 275struct Test {}
421 struct Test {} 276"#,
422 ", 277 expect![[r#"
423 ), 278 at Clone
424 @r###" 279 at Copy, Clone
425 [ 280 at Debug
426 CompletionItem { 281 at Default
427 label: "Clone", 282 at Eq
428 source_range: 38..38, 283 at Hash
429 delete: 38..38, 284 at Ord, PartialOrd, Eq
430 insert: "Clone", 285 at PartialOrd
431 kind: Attribute, 286 "#]],
432 }, 287 )
433 CompletionItem {
434 label: "Copy, Clone",
435 source_range: 38..38,
436 delete: 38..38,
437 insert: "Copy, Clone",
438 kind: Attribute,
439 },
440 CompletionItem {
441 label: "Debug",
442 source_range: 38..38,
443 delete: 38..38,
444 insert: "Debug",
445 kind: Attribute,
446 },
447 CompletionItem {
448 label: "Default",
449 source_range: 38..38,
450 delete: 38..38,
451 insert: "Default",
452 kind: Attribute,
453 },
454 CompletionItem {
455 label: "Eq",
456 source_range: 38..38,
457 delete: 38..38,
458 insert: "Eq",
459 kind: Attribute,
460 },
461 CompletionItem {
462 label: "Hash",
463 source_range: 38..38,
464 delete: 38..38,
465 insert: "Hash",
466 kind: Attribute,
467 },
468 CompletionItem {
469 label: "Ord, PartialOrd, Eq",
470 source_range: 38..38,
471 delete: 38..38,
472 insert: "Ord, PartialOrd, Eq",
473 kind: Attribute,
474 },
475 CompletionItem {
476 label: "PartialOrd",
477 source_range: 38..38,
478 delete: 38..38,
479 insert: "PartialOrd",
480 kind: Attribute,
481 },
482 ]
483 "###
484 );
485 } 288 }
486 289
487 #[test] 290 #[test]
488 fn test_attribute_completion() { 291 fn test_attribute_completion() {
489 assert_debug_snapshot!( 292 check(
490 do_attr_completion( 293 r#"#[<|>]"#,
491 r" 294 expect![[r#"
492 #[<|>] 295 at allow(…)
493 ", 296 at cfg(…)
494 ), 297 at cfg_attr(…)
495 @r###" 298 at deny(…)
496 [ 299 at deprecated = "…"
497 CompletionItem { 300 at derive(…)
498 label: "allow(…)", 301 at doc = "…"
499 source_range: 2..2, 302 at forbid(…)
500 delete: 2..2, 303 at ignore(…)
501 insert: "allow(${0:lint})", 304 at inline(…)
502 kind: Attribute, 305 at link
503 lookup: "allow", 306 at link_name = "…"
504 }, 307 at macro_export
505 CompletionItem { 308 at macro_use
506 label: "cfg(…)", 309 at must_use = "…"
507 source_range: 2..2, 310 at no_mangle
508 delete: 2..2, 311 at non_exhaustive
509 insert: "cfg(${0:predicate})", 312 at path = "…"
510 kind: Attribute, 313 at proc_macro
511 lookup: "cfg", 314 at proc_macro_attribute
512 }, 315 at proc_macro_derive(…)
513 CompletionItem { 316 at repr(…)
514 label: "cfg_attr(…)", 317 at should_panic(…)
515 source_range: 2..2, 318 at target_feature = "…"
516 delete: 2..2, 319 at test
517 insert: "cfg_attr(${1:predicate}, ${0:attr})", 320 at used
518 kind: Attribute, 321 at warn(…)
519 lookup: "cfg_attr", 322 "#]],
520 }, 323 )
521 CompletionItem {
522 label: "deny(…)",
523 source_range: 2..2,
524 delete: 2..2,
525 insert: "deny(${0:lint})",
526 kind: Attribute,
527 lookup: "deny",
528 },
529 CompletionItem {
530 label: "deprecated = \"…\"",
531 source_range: 2..2,
532 delete: 2..2,
533 insert: "deprecated = \"${0:reason}\"",
534 kind: Attribute,
535 lookup: "deprecated",
536 },
537 CompletionItem {
538 label: "derive(…)",
539 source_range: 2..2,
540 delete: 2..2,
541 insert: "derive(${0:Debug})",
542 kind: Attribute,
543 lookup: "derive",
544 },
545 CompletionItem {
546 label: "doc = \"…\"",
547 source_range: 2..2,
548 delete: 2..2,
549 insert: "doc = \"${0:docs}\"",
550 kind: Attribute,
551 lookup: "doc",
552 },
553 CompletionItem {
554 label: "forbid(…)",
555 source_range: 2..2,
556 delete: 2..2,
557 insert: "forbid(${0:lint})",
558 kind: Attribute,
559 lookup: "forbid",
560 },
561 CompletionItem {
562 label: "ignore(…)",
563 source_range: 2..2,
564 delete: 2..2,
565 insert: "ignore(${0:lint})",
566 kind: Attribute,
567 lookup: "ignore",
568 },
569 CompletionItem {
570 label: "inline(…)",
571 source_range: 2..2,
572 delete: 2..2,
573 insert: "inline(${0:lint})",
574 kind: Attribute,
575 lookup: "inline",
576 },
577 CompletionItem {
578 label: "link",
579 source_range: 2..2,
580 delete: 2..2,
581 insert: "link",
582 kind: Attribute,
583 },
584 CompletionItem {
585 label: "link_name = \"…\"",
586 source_range: 2..2,
587 delete: 2..2,
588 insert: "link_name = \"${0:symbol_name}\"",
589 kind: Attribute,
590 lookup: "link_name",
591 },
592 CompletionItem {
593 label: "macro_export",
594 source_range: 2..2,
595 delete: 2..2,
596 insert: "macro_export",
597 kind: Attribute,
598 },
599 CompletionItem {
600 label: "macro_use",
601 source_range: 2..2,
602 delete: 2..2,
603 insert: "macro_use",
604 kind: Attribute,
605 },
606 CompletionItem {
607 label: "must_use = \"…\"",
608 source_range: 2..2,
609 delete: 2..2,
610 insert: "must_use = \"${0:reason}\"",
611 kind: Attribute,
612 lookup: "must_use",
613 },
614 CompletionItem {
615 label: "no_mangle",
616 source_range: 2..2,
617 delete: 2..2,
618 insert: "no_mangle",
619 kind: Attribute,
620 },
621 CompletionItem {
622 label: "non_exhaustive",
623 source_range: 2..2,
624 delete: 2..2,
625 insert: "non_exhaustive",
626 kind: Attribute,
627 },
628 CompletionItem {
629 label: "path = \"…\"",
630 source_range: 2..2,
631 delete: 2..2,
632 insert: "path =\"${0:path}\"",
633 kind: Attribute,
634 lookup: "path",
635 },
636 CompletionItem {
637 label: "proc_macro",
638 source_range: 2..2,
639 delete: 2..2,
640 insert: "proc_macro",
641 kind: Attribute,
642 },
643 CompletionItem {
644 label: "proc_macro_attribute",
645 source_range: 2..2,
646 delete: 2..2,
647 insert: "proc_macro_attribute",
648 kind: Attribute,
649 },
650 CompletionItem {
651 label: "proc_macro_derive(…)",
652 source_range: 2..2,
653 delete: 2..2,
654 insert: "proc_macro_derive(${0:Trait})",
655 kind: Attribute,
656 lookup: "proc_macro_derive",
657 },
658 CompletionItem {
659 label: "repr(…)",
660 source_range: 2..2,
661 delete: 2..2,
662 insert: "repr(${0:C})",
663 kind: Attribute,
664 lookup: "repr",
665 },
666 CompletionItem {
667 label: "should_panic(…)",
668 source_range: 2..2,
669 delete: 2..2,
670 insert: "should_panic(expected = \"${0:reason}\")",
671 kind: Attribute,
672 lookup: "should_panic",
673 },
674 CompletionItem {
675 label: "target_feature = \"…\"",
676 source_range: 2..2,
677 delete: 2..2,
678 insert: "target_feature = \"${0:feature}\"",
679 kind: Attribute,
680 lookup: "target_feature",
681 },
682 CompletionItem {
683 label: "test",
684 source_range: 2..2,
685 delete: 2..2,
686 insert: "test",
687 kind: Attribute,
688 },
689 CompletionItem {
690 label: "used",
691 source_range: 2..2,
692 delete: 2..2,
693 insert: "used",
694 kind: Attribute,
695 },
696 CompletionItem {
697 label: "warn(…)",
698 source_range: 2..2,
699 delete: 2..2,
700 insert: "warn(${0:lint})",
701 kind: Attribute,
702 lookup: "warn",
703 },
704 ]
705 "###
706 );
707 } 324 }
708 325
709 #[test] 326 #[test]
710 fn test_attribute_completion_inside_nested_attr() { 327 fn test_attribute_completion_inside_nested_attr() {
711 assert_debug_snapshot!( 328 check(r#"#[allow(<|>)]"#, expect![[]])
712 do_attr_completion(
713 r"
714 #[allow(<|>)]
715 ",
716 ),
717 @r###"
718 []
719 "###
720 );
721 } 329 }
722 330
723 #[test] 331 #[test]
724 fn test_inner_attribute_completion() { 332 fn test_inner_attribute_completion() {
725 assert_debug_snapshot!( 333 check(
726 do_attr_completion( 334 r"#![<|>]",
727 r" 335 expect![[r#"
728 #![<|>] 336 at allow(…)
729 ", 337 at cfg(…)
730 ), 338 at cfg_attr(…)
731 @r###" 339 at deny(…)
732 [ 340 at deprecated = "…"
733 CompletionItem { 341 at derive(…)
734 label: "allow(…)", 342 at doc = "…"
735 source_range: 3..3, 343 at feature(…)
736 delete: 3..3, 344 at forbid(…)
737 insert: "allow(${0:lint})", 345 at global_allocator
738 kind: Attribute, 346 at ignore(…)
739 lookup: "allow", 347 at inline(…)
740 }, 348 at link
741 CompletionItem { 349 at link_name = "…"
742 label: "cfg(…)", 350 at macro_export
743 source_range: 3..3, 351 at macro_use
744 delete: 3..3, 352 at must_use = "…"
745 insert: "cfg(${0:predicate})", 353 at no_mangle
746 kind: Attribute, 354 at no_std
747 lookup: "cfg", 355 at non_exhaustive
748 }, 356 at panic_handler
749 CompletionItem { 357 at path = "…"
750 label: "cfg_attr(…)", 358 at proc_macro
751 source_range: 3..3, 359 at proc_macro_attribute
752 delete: 3..3, 360 at proc_macro_derive(…)
753 insert: "cfg_attr(${1:predicate}, ${0:attr})", 361 at recursion_limit = …
754 kind: Attribute, 362 at repr(…)
755 lookup: "cfg_attr", 363 at should_panic(…)
756 }, 364 at target_feature = "…"
757 CompletionItem { 365 at test
758 label: "deny(…)", 366 at used
759 source_range: 3..3, 367 at warn(…)
760 delete: 3..3, 368 at windows_subsystem = "…"
761 insert: "deny(${0:lint})", 369 "#]],
762 kind: Attribute,
763 lookup: "deny",
764 },
765 CompletionItem {
766 label: "deprecated = \"…\"",
767 source_range: 3..3,
768 delete: 3..3,
769 insert: "deprecated = \"${0:reason}\"",
770 kind: Attribute,
771 lookup: "deprecated",
772 },
773 CompletionItem {
774 label: "derive(…)",
775 source_range: 3..3,
776 delete: 3..3,
777 insert: "derive(${0:Debug})",
778 kind: Attribute,
779 lookup: "derive",
780 },
781 CompletionItem {
782 label: "doc = \"…\"",
783 source_range: 3..3,
784 delete: 3..3,
785 insert: "doc = \"${0:docs}\"",
786 kind: Attribute,
787 lookup: "doc",
788 },
789 CompletionItem {
790 label: "feature(…)",
791 source_range: 3..3,
792 delete: 3..3,
793 insert: "feature(${0:flag})",
794 kind: Attribute,
795 lookup: "feature",
796 },
797 CompletionItem {
798 label: "forbid(…)",
799 source_range: 3..3,
800 delete: 3..3,
801 insert: "forbid(${0:lint})",
802 kind: Attribute,
803 lookup: "forbid",
804 },
805 CompletionItem {
806 label: "global_allocator",
807 source_range: 3..3,
808 delete: 3..3,
809 insert: "global_allocator",
810 kind: Attribute,
811 },
812 CompletionItem {
813 label: "ignore(…)",
814 source_range: 3..3,
815 delete: 3..3,
816 insert: "ignore(${0:lint})",
817 kind: Attribute,
818 lookup: "ignore",
819 },
820 CompletionItem {
821 label: "inline(…)",
822 source_range: 3..3,
823 delete: 3..3,
824 insert: "inline(${0:lint})",
825 kind: Attribute,
826 lookup: "inline",
827 },
828 CompletionItem {
829 label: "link",
830 source_range: 3..3,
831 delete: 3..3,
832 insert: "link",
833 kind: Attribute,
834 },
835 CompletionItem {
836 label: "link_name = \"…\"",
837 source_range: 3..3,
838 delete: 3..3,
839 insert: "link_name = \"${0:symbol_name}\"",
840 kind: Attribute,
841 lookup: "link_name",
842 },
843 CompletionItem {
844 label: "macro_export",
845 source_range: 3..3,
846 delete: 3..3,
847 insert: "macro_export",
848 kind: Attribute,
849 },
850 CompletionItem {
851 label: "macro_use",
852 source_range: 3..3,
853 delete: 3..3,
854 insert: "macro_use",
855 kind: Attribute,
856 },
857 CompletionItem {
858 label: "must_use = \"…\"",
859 source_range: 3..3,
860 delete: 3..3,
861 insert: "must_use = \"${0:reason}\"",
862 kind: Attribute,
863 lookup: "must_use",
864 },
865 CompletionItem {
866 label: "no_mangle",
867 source_range: 3..3,
868 delete: 3..3,
869 insert: "no_mangle",
870 kind: Attribute,
871 },
872 CompletionItem {
873 label: "no_std",
874 source_range: 3..3,
875 delete: 3..3,
876 insert: "no_std",
877 kind: Attribute,
878 },
879 CompletionItem {
880 label: "non_exhaustive",
881 source_range: 3..3,
882 delete: 3..3,
883 insert: "non_exhaustive",
884 kind: Attribute,
885 },
886 CompletionItem {
887 label: "panic_handler",
888 source_range: 3..3,
889 delete: 3..3,
890 insert: "panic_handler",
891 kind: Attribute,
892 },
893 CompletionItem {
894 label: "path = \"…\"",
895 source_range: 3..3,
896 delete: 3..3,
897 insert: "path =\"${0:path}\"",
898 kind: Attribute,
899 lookup: "path",
900 },
901 CompletionItem {
902 label: "proc_macro",
903 source_range: 3..3,
904 delete: 3..3,
905 insert: "proc_macro",
906 kind: Attribute,
907 },
908 CompletionItem {
909 label: "proc_macro_attribute",
910 source_range: 3..3,
911 delete: 3..3,
912 insert: "proc_macro_attribute",
913 kind: Attribute,
914 },
915 CompletionItem {
916 label: "proc_macro_derive(…)",
917 source_range: 3..3,
918 delete: 3..3,
919 insert: "proc_macro_derive(${0:Trait})",
920 kind: Attribute,
921 lookup: "proc_macro_derive",
922 },
923 CompletionItem {
924 label: "recursion_limit = …",
925 source_range: 3..3,
926 delete: 3..3,
927 insert: "recursion_limit = ${0:128}",
928 kind: Attribute,
929 lookup: "recursion_limit",
930 },
931 CompletionItem {
932 label: "repr(…)",
933 source_range: 3..3,
934 delete: 3..3,
935 insert: "repr(${0:C})",
936 kind: Attribute,
937 lookup: "repr",
938 },
939 CompletionItem {
940 label: "should_panic(…)",
941 source_range: 3..3,
942 delete: 3..3,
943 insert: "should_panic(expected = \"${0:reason}\")",
944 kind: Attribute,
945 lookup: "should_panic",
946 },
947 CompletionItem {
948 label: "target_feature = \"…\"",
949 source_range: 3..3,
950 delete: 3..3,
951 insert: "target_feature = \"${0:feature}\"",
952 kind: Attribute,
953 lookup: "target_feature",
954 },
955 CompletionItem {
956 label: "test",
957 source_range: 3..3,
958 delete: 3..3,
959 insert: "test",
960 kind: Attribute,
961 },
962 CompletionItem {
963 label: "used",
964 source_range: 3..3,
965 delete: 3..3,
966 insert: "used",
967 kind: Attribute,
968 },
969 CompletionItem {
970 label: "warn(…)",
971 source_range: 3..3,
972 delete: 3..3,
973 insert: "warn(${0:lint})",
974 kind: Attribute,
975 lookup: "warn",
976 },
977 CompletionItem {
978 label: "windows_subsystem = \"…\"",
979 source_range: 3..3,
980 delete: 3..3,
981 insert: "windows_subsystem = \"${0:subsystem}\"",
982 kind: Attribute,
983 lookup: "windows_subsystem",
984 },
985 ]
986 "###
987 ); 370 );
988 } 371 }
989} 372}
diff --git a/crates/ra_ide/src/completion/complete_keyword.rs b/crates/ra_ide/src/completion/complete_keyword.rs
index e599cc3d1..086b917ce 100644
--- a/crates/ra_ide/src/completion/complete_keyword.rs
+++ b/crates/ra_ide/src/completion/complete_keyword.rs
@@ -1,6 +1,7 @@
1//! FIXME: write short doc here 1//! FIXME: write short doc here
2 2
3use ra_syntax::{ast, SyntaxKind}; 3use ra_syntax::{ast, SyntaxKind};
4use test_utils::mark;
4 5
5use crate::completion::{ 6use crate::completion::{
6 CompletionContext, CompletionItem, CompletionItemKind, CompletionKind, Completions, 7 CompletionContext, CompletionItem, CompletionItemKind, CompletionKind, Completions,
@@ -38,6 +39,7 @@ pub(super) fn complete_use_tree_keyword(acc: &mut Completions, ctx: &CompletionC
38 39
39pub(super) fn complete_expr_keyword(acc: &mut Completions, ctx: &CompletionContext) { 40pub(super) fn complete_expr_keyword(acc: &mut Completions, ctx: &CompletionContext) {
40 if ctx.token.kind() == SyntaxKind::COMMENT { 41 if ctx.token.kind() == SyntaxKind::COMMENT {
42 mark::hit!(no_keyword_completion_in_comments);
41 return; 43 return;
42 } 44 }
43 45
@@ -174,289 +176,318 @@ fn complete_return(
174 176
175#[cfg(test)] 177#[cfg(test)]
176mod tests { 178mod tests {
177 use crate::completion::{test_utils::completion_list, CompletionKind}; 179 use expect::{expect, Expect};
178 use insta::assert_snapshot;
179 180
180 fn get_keyword_completions(code: &str) -> String { 181 use crate::completion::{
181 completion_list(code, CompletionKind::Keyword) 182 test_utils::{check_edit, completion_list},
183 CompletionKind,
184 };
185 use test_utils::mark;
186
187 fn check(ra_fixture: &str, expect: Expect) {
188 let actual = completion_list(ra_fixture, CompletionKind::Keyword);
189 expect.assert_eq(&actual)
182 } 190 }
183 191
184 #[test] 192 #[test]
185 fn test_keywords_in_use_stmt() { 193 fn test_keywords_in_use_stmt() {
186 assert_snapshot!( 194 check(
187 get_keyword_completions(r"use <|>"), 195 r"use <|>",
188 @r###" 196 expect![[r#"
189 kw crate:: 197 kw crate::
190 kw self 198 kw self
191 kw super:: 199 kw super::
192 "### 200 "#]],
193 ); 201 );
194 202
195 assert_snapshot!( 203 check(
196 get_keyword_completions(r"use a::<|>"), 204 r"use a::<|>",
197 @r###" 205 expect![[r#"
198 kw self 206 kw self
199 kw super:: 207 kw super::
200 "### 208 "#]],
201 ); 209 );
202 210
203 assert_snapshot!( 211 check(
204 get_keyword_completions(r"use a::{b, <|>}"), 212 r"use a::{b, <|>}",
205 @r###" 213 expect![[r#"
206 kw self 214 kw self
207 kw super:: 215 kw super::
208 "### 216 "#]],
209 ); 217 );
210 } 218 }
211 219
212 #[test] 220 #[test]
213 fn test_keywords_at_source_file_level() { 221 fn test_keywords_at_source_file_level() {
214 assert_snapshot!( 222 check(
215 get_keyword_completions(r"m<|>"), 223 r"m<|>",
216 @r###" 224 expect![[r#"
217 kw const 225 kw const
218 kw enum 226 kw enum
219 kw extern 227 kw extern
220 kw fn 228 kw fn
221 kw impl 229 kw impl
222 kw mod 230 kw mod
223 kw pub 231 kw pub
224 kw static 232 kw static
225 kw struct 233 kw struct
226 kw trait 234 kw trait
227 kw type 235 kw type
228 kw union 236 kw union
229 kw unsafe 237 kw unsafe
230 kw use 238 kw use
231 "### 239 "#]],
232 ); 240 );
233 } 241 }
234 242
235 #[test] 243 #[test]
236 fn test_keywords_in_function() { 244 fn test_keywords_in_function() {
237 assert_snapshot!( 245 check(
238 get_keyword_completions(r"fn quux() { <|> }"), 246 r"fn quux() { <|> }",
239 @r###" 247 expect![[r#"
240 kw const 248 kw const
241 kw extern 249 kw extern
242 kw fn 250 kw fn
243 kw if 251 kw if
244 kw if let 252 kw if let
245 kw impl 253 kw impl
246 kw let 254 kw let
247 kw loop 255 kw loop
248 kw match 256 kw match
249 kw mod 257 kw mod
250 kw return 258 kw return
251 kw static 259 kw static
252 kw trait 260 kw trait
253 kw type 261 kw type
254 kw unsafe 262 kw unsafe
255 kw use 263 kw use
256 kw while 264 kw while
257 "### 265 "#]],
258 ); 266 );
259 } 267 }
260 268
261 #[test] 269 #[test]
262 fn test_keywords_inside_block() { 270 fn test_keywords_inside_block() {
263 assert_snapshot!( 271 check(
264 get_keyword_completions(r"fn quux() { if true { <|> } }"), 272 r"fn quux() { if true { <|> } }",
265 @r###" 273 expect![[r#"
266 kw const 274 kw const
267 kw extern 275 kw extern
268 kw fn 276 kw fn
269 kw if 277 kw if
270 kw if let 278 kw if let
271 kw impl 279 kw impl
272 kw let 280 kw let
273 kw loop 281 kw loop
274 kw match 282 kw match
275 kw mod 283 kw mod
276 kw return 284 kw return
277 kw static 285 kw static
278 kw trait 286 kw trait
279 kw type 287 kw type
280 kw unsafe 288 kw unsafe
281 kw use 289 kw use
282 kw while 290 kw while
283 "### 291 "#]],
284 ); 292 );
285 } 293 }
286 294
287 #[test] 295 #[test]
288 fn test_keywords_after_if() { 296 fn test_keywords_after_if() {
289 assert_snapshot!( 297 check(
290 get_keyword_completions( 298 r#"fn quux() { if true { () } <|> }"#,
291 r" 299 expect![[r#"
292 fn quux() { 300 kw const
293 if true { 301 kw else
294 () 302 kw else if
295 } <|> 303 kw extern
296 } 304 kw fn
297 ", 305 kw if
298 ), 306 kw if let
299 @r###" 307 kw impl
300 kw const 308 kw let
301 kw else 309 kw loop
302 kw else if 310 kw match
303 kw extern 311 kw mod
304 kw fn 312 kw return
305 kw if 313 kw static
306 kw if let 314 kw trait
307 kw impl 315 kw type
308 kw let 316 kw unsafe
309 kw loop 317 kw use
310 kw match 318 kw while
311 kw mod 319 "#]],
312 kw return 320 );
313 kw static 321 check_edit(
314 kw trait 322 "else",
315 kw type 323 r#"fn quux() { if true { () } <|> }"#,
316 kw unsafe 324 r#"fn quux() { if true { () } else {$0} }"#,
317 kw use
318 kw while
319 "###
320 ); 325 );
321 } 326 }
322 327
323 #[test] 328 #[test]
324 fn test_keywords_in_match_arm() { 329 fn test_keywords_in_match_arm() {
325 assert_snapshot!( 330 check(
326 get_keyword_completions( 331 r#"
327 r" 332fn quux() -> i32 {
328 fn quux() -> i32 { 333 match () {
329 match () { 334 () => <|>
330 () => <|> 335 }
331 } 336}
332 } 337"#,
333 ", 338 expect![[r#"
334 ), 339 kw if
335 @r###" 340 kw if let
336 kw if 341 kw loop
337 kw if let 342 kw match
338 kw loop 343 kw return
339 kw match 344 kw unsafe
340 kw return 345 "#]],
341 kw unsafe
342 "###
343 ); 346 );
344 } 347 }
345 348
346 #[test] 349 #[test]
347 fn test_keywords_in_trait_def() { 350 fn test_keywords_in_trait_def() {
348 assert_snapshot!( 351 check(
349 get_keyword_completions(r"trait My { <|> }"), 352 r"trait My { <|> }",
350 @r###" 353 expect![[r#"
351 kw const 354 kw const
352 kw fn 355 kw fn
353 kw type 356 kw type
354 kw unsafe 357 kw unsafe
355 "### 358 "#]],
356 ); 359 );
357 } 360 }
358 361
359 #[test] 362 #[test]
360 fn test_keywords_in_impl_def() { 363 fn test_keywords_in_impl_def() {
361 assert_snapshot!( 364 check(
362 get_keyword_completions(r"impl My { <|> }"), 365 r"impl My { <|> }",
363 @r###" 366 expect![[r#"
364 kw const 367 kw const
365 kw fn 368 kw fn
366 kw pub 369 kw pub
367 kw type 370 kw type
368 kw unsafe 371 kw unsafe
369 "### 372 "#]],
370 ); 373 );
371 } 374 }
372 375
373 #[test] 376 #[test]
374 fn test_keywords_in_loop() { 377 fn test_keywords_in_loop() {
375 assert_snapshot!( 378 check(
376 get_keyword_completions(r"fn my() { loop { <|> } }"), 379 r"fn my() { loop { <|> } }",
377 @r###" 380 expect![[r#"
378 kw break 381 kw break
379 kw const 382 kw const
380 kw continue 383 kw continue
381 kw extern 384 kw extern
382 kw fn 385 kw fn
383 kw if 386 kw if
384 kw if let 387 kw if let
385 kw impl 388 kw impl
386 kw let 389 kw let
387 kw loop 390 kw loop
388 kw match 391 kw match
389 kw mod 392 kw mod
390 kw return 393 kw return
391 kw static 394 kw static
392 kw trait 395 kw trait
393 kw type 396 kw type
394 kw unsafe 397 kw unsafe
395 kw use 398 kw use
396 kw while 399 kw while
397 "### 400 "#]],
398 ); 401 );
399 } 402 }
400 403
401 #[test] 404 #[test]
402 fn test_keywords_after_unsafe_in_item_list() { 405 fn test_keywords_after_unsafe_in_item_list() {
403 assert_snapshot!( 406 check(
404 get_keyword_completions(r"unsafe <|>"), 407 r"unsafe <|>",
405 @r###" 408 expect![[r#"
406 kw fn 409 kw fn
407 kw impl 410 kw impl
408 kw trait 411 kw trait
409 "### 412 "#]],
410 ); 413 );
411 } 414 }
412 415
413 #[test] 416 #[test]
414 fn test_keywords_after_unsafe_in_block_expr() { 417 fn test_keywords_after_unsafe_in_block_expr() {
415 assert_snapshot!( 418 check(
416 get_keyword_completions(r"fn my_fn() { unsafe <|> }"), 419 r"fn my_fn() { unsafe <|> }",
417 @r###" 420 expect![[r#"
418 kw fn 421 kw fn
419 kw impl 422 kw impl
420 kw trait 423 kw trait
421 "### 424 "#]],
422 ); 425 );
423 } 426 }
424 427
425 #[test] 428 #[test]
426 fn test_mut_in_ref_and_in_fn_parameters_list() { 429 fn test_mut_in_ref_and_in_fn_parameters_list() {
427 assert_snapshot!( 430 check(
428 get_keyword_completions(r"fn my_fn(&<|>) {}"), 431 r"fn my_fn(&<|>) {}",
429 @r###" 432 expect![[r#"
430 kw mut 433 kw mut
431 "### 434 "#]],
432 ); 435 );
433 assert_snapshot!( 436 check(
434 get_keyword_completions(r"fn my_fn(<|>) {}"), 437 r"fn my_fn(<|>) {}",
435 @r###" 438 expect![[r#"
436 kw mut 439 kw mut
437 "### 440 "#]],
438 ); 441 );
439 assert_snapshot!( 442 check(
440 get_keyword_completions(r"fn my_fn() { let &<|> }"), 443 r"fn my_fn() { let &<|> }",
441 @r###" 444 expect![[r#"
442 kw mut 445 kw mut
443 "### 446 "#]],
444 ); 447 );
445 } 448 }
446 449
447 #[test] 450 #[test]
448 fn test_where_keyword() { 451 fn test_where_keyword() {
449 assert_snapshot!( 452 check(
450 get_keyword_completions(r"trait A <|>"), 453 r"trait A <|>",
451 @r###" 454 expect![[r#"
452 kw where 455 kw where
453 "### 456 "#]],
457 );
458 check(
459 r"impl A <|>",
460 expect![[r#"
461 kw where
462 "#]],
463 );
464 }
465
466 #[test]
467 fn no_keyword_completion_in_comments() {
468 mark::check!(no_keyword_completion_in_comments);
469 check(
470 r#"
471fn test() {
472 let x = 2; // A comment<|>
473}
474"#,
475 expect![[""]],
476 );
477 check(
478 r#"
479/*
480Some multi-line comment<|>
481*/
482"#,
483 expect![[""]],
454 ); 484 );
455 assert_snapshot!( 485 check(
456 get_keyword_completions(r"impl A <|>"), 486 r#"
457 @r###" 487/// Some doc comment
458 kw where 488/// let test<|> = 1
459 "### 489"#,
490 expect![[""]],
460 ); 491 );
461 } 492 }
462} 493}
diff --git a/crates/ra_ide/src/completion/complete_record.rs b/crates/ra_ide/src/completion/complete_record.rs
index 13eb2f79f..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: 68..69,
48 delete: 68..69,
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: 88..88,
77 delete: 88..88,
78 insert: "bar",
79 kind: Field,
80 detail: "()",
81 },
82 CompletionItem {
83 label: "foo",
84 source_range: 88..88,
85 delete: 88..88,
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: 110..111,
113 delete: 110..111,
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: 203..203,
149 delete: 203..203,
150 insert: "bar",
151 kind: Field,
152 detail: "u32",
153 },
154 CompletionItem {
155 label: "baz",
156 source_range: 203..203,
157 delete: 203..203,
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: 69..72,
194 delete: 69..72,
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: 46..49,
219 delete: 46..49,
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: 58..58,
245 delete: 58..58,
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: 70..70,
271 delete: 70..70,
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: 56..56,
296 delete: 56..56,
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: 88..91,
321 delete: 88..91,
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: 157..157,
356 delete: 157..157,
357 insert: "bar",
358 kind: Field,
359 detail: "u32",
360 },
361 CompletionItem {
362 label: "baz",
363 source_range: 157..157,
364 delete: 157..157,
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: 112..112,
397 delete: 112..112,
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/completion_item.rs b/crates/ra_ide/src/completion/completion_item.rs
index 98348b349..4db371d57 100644
--- a/crates/ra_ide/src/completion/completion_item.rs
+++ b/crates/ra_ide/src/completion/completion_item.rs
@@ -129,24 +129,24 @@ impl CompletionItemKind {
129 #[cfg(test)] 129 #[cfg(test)]
130 pub(crate) fn tag(&self) -> &'static str { 130 pub(crate) fn tag(&self) -> &'static str {
131 match self { 131 match self {
132 CompletionItemKind::Snippet => "sn", 132 CompletionItemKind::Attribute => "at",
133 CompletionItemKind::Keyword => "kw", 133 CompletionItemKind::Binding => "bn",
134 CompletionItemKind::Module => "md",
135 CompletionItemKind::Function => "fn",
136 CompletionItemKind::BuiltinType => "bt", 134 CompletionItemKind::BuiltinType => "bt",
137 CompletionItemKind::Struct => "st", 135 CompletionItemKind::Const => "ct",
138 CompletionItemKind::Enum => "en", 136 CompletionItemKind::Enum => "en",
139 CompletionItemKind::EnumVariant => "ev", 137 CompletionItemKind::EnumVariant => "ev",
140 CompletionItemKind::Binding => "bn",
141 CompletionItemKind::Field => "fd", 138 CompletionItemKind::Field => "fd",
139 CompletionItemKind::Function => "fn",
140 CompletionItemKind::Keyword => "kw",
141 CompletionItemKind::Macro => "ma",
142 CompletionItemKind::Method => "me",
143 CompletionItemKind::Module => "md",
144 CompletionItemKind::Snippet => "sn",
142 CompletionItemKind::Static => "sc", 145 CompletionItemKind::Static => "sc",
143 CompletionItemKind::Const => "ct", 146 CompletionItemKind::Struct => "st",
144 CompletionItemKind::Trait => "tt", 147 CompletionItemKind::Trait => "tt",
145 CompletionItemKind::TypeAlias => "ta", 148 CompletionItemKind::TypeAlias => "ta",
146 CompletionItemKind::Method => "me",
147 CompletionItemKind::TypeParam => "tp", 149 CompletionItemKind::TypeParam => "tp",
148 CompletionItemKind::Macro => "ma",
149 CompletionItemKind::Attribute => "at",
150 } 150 }
151 } 151 }
152} 152}
diff --git a/crates/ra_ide/src/completion/presentation.rs b/crates/ra_ide/src/completion/presentation.rs
index b18279746..fd12673b2 100644
--- a/crates/ra_ide/src/completion/presentation.rs
+++ b/crates/ra_ide/src/completion/presentation.rs
@@ -383,12 +383,14 @@ impl Builder {
383 return self; 383 return self;
384 } 384 }
385 if ctx.use_item_syntax.is_some() || ctx.is_call { 385 if ctx.use_item_syntax.is_some() || ctx.is_call {
386 mark::hit!(no_parens_in_use_item);
386 return self; 387 return self;
387 } 388 }
388 389
389 // Don't add parentheses if the expected type is some function reference. 390 // Don't add parentheses if the expected type is some function reference.
390 if let Some(ty) = &ctx.expected_type { 391 if let Some(ty) = &ctx.expected_type {
391 if ty.is_fn() { 392 if ty.is_fn() {
393 mark::hit!(no_call_parens_if_fn_ptr_needed);
392 return self; 394 return self;
393 } 395 }
394 } 396 }
@@ -413,7 +415,10 @@ impl Builder {
413 .sep_by(", "); 415 .sep_by(", ");
414 format!("{}({})$0", name, function_params_snippet) 416 format!("{}({})$0", name, function_params_snippet)
415 } 417 }
416 _ => format!("{}($0)", name), 418 _ => {
419 mark::hit!(suppress_arg_snippets);
420 format!("{}($0)", name)
421 }
417 }; 422 };
418 423
419 (snippet, format!("{}(…)", name)) 424 (snippet, format!("{}(…)", name))
@@ -460,7 +465,7 @@ mod tests {
460 use test_utils::mark; 465 use test_utils::mark;
461 466
462 use crate::completion::{ 467 use crate::completion::{
463 test_utils::{do_completion, do_completion_with_options}, 468 test_utils::{check_edit, check_edit_with_config, do_completion},
464 CompletionConfig, CompletionItem, CompletionKind, 469 CompletionConfig, CompletionItem, CompletionKind,
465 }; 470 };
466 471
@@ -468,13 +473,6 @@ mod tests {
468 do_completion(ra_fixture, CompletionKind::Reference) 473 do_completion(ra_fixture, CompletionKind::Reference)
469 } 474 }
470 475
471 fn do_reference_completion_with_options(
472 ra_fixture: &str,
473 options: CompletionConfig,
474 ) -> Vec<CompletionItem> {
475 do_completion_with_options(ra_fixture, CompletionKind::Reference, &options)
476 }
477
478 #[test] 476 #[test]
479 fn enum_detail_includes_names_for_record() { 477 fn enum_detail_includes_names_for_record() {
480 assert_debug_snapshot!( 478 assert_debug_snapshot!(
@@ -606,448 +604,240 @@ mod tests {
606 ] 604 ]
607 "### 605 "###
608 ); 606 );
609 }
610 607
611 #[test] 608 assert_debug_snapshot!(do_reference_completion(
612 fn inserts_parens_for_function_calls() { 609 r#"
613 mark::check!(inserts_parens_for_function_calls); 610struct A {
614 assert_debug_snapshot!( 611 #[deprecated]
615 do_reference_completion( 612 the_field: u32,
616 r" 613}
617 fn no_args() {} 614fn foo() {
618 fn main() { no_<|> } 615 A { the<|> }
619 " 616}
620 ), 617"#,
621 @r###" 618 ),
622 [ 619 @r###"
623 CompletionItem {
624 label: "main()",
625 source_range: 28..31,
626 delete: 28..31,
627 insert: "main()$0",
628 kind: Function,
629 lookup: "main",
630 detail: "fn main()",
631 },
632 CompletionItem {
633 label: "no_args()",
634 source_range: 28..31,
635 delete: 28..31,
636 insert: "no_args()$0",
637 kind: Function,
638 lookup: "no_args",
639 detail: "fn no_args()",
640 },
641 ]
642 "###
643 );
644 assert_debug_snapshot!(
645 do_reference_completion(
646 r"
647 fn with_args(x: i32, y: String) {}
648 fn main() { with_<|> }
649 "
650 ),
651 @r###"
652 [ 620 [
653 CompletionItem { 621 CompletionItem {
654 label: "main()", 622 label: "the_field",
655 source_range: 47..52, 623 source_range: 69..72,
656 delete: 47..52, 624 delete: 69..72,
657 insert: "main()$0", 625 insert: "the_field",
658 kind: Function, 626 kind: Field,
659 lookup: "main", 627 detail: "u32",
660 detail: "fn main()", 628 deprecated: true,
661 },
662 CompletionItem {
663 label: "with_args(…)",
664 source_range: 47..52,
665 delete: 47..52,
666 insert: "with_args(${1:x}, ${2:y})$0",
667 kind: Function,
668 lookup: "with_args",
669 detail: "fn with_args(x: i32, y: String)",
670 trigger_call_info: true,
671 }, 629 },
672 ] 630 ]
673 "### 631 "###);
632 }
633
634 #[test]
635 fn inserts_parens_for_function_calls() {
636 mark::check!(inserts_parens_for_function_calls);
637 check_edit(
638 "no_args",
639 r#"
640fn no_args() {}
641fn main() { no_<|> }
642"#,
643 r#"
644fn no_args() {}
645fn main() { no_args()$0 }
646"#,
674 ); 647 );
675 assert_debug_snapshot!( 648
676 do_reference_completion( 649 check_edit(
677 r" 650 "with_args",
678 fn with_ignored_args(_foo: i32, ___bar: bool, ho_ge_: String) {} 651 r#"
679 fn main() { with_<|> } 652fn with_args(x: i32, y: String) {}
680 " 653fn main() { with_<|> }
681 ), 654"#,
682 @r###" 655 r#"
683 [ 656fn with_args(x: i32, y: String) {}
684 CompletionItem { 657fn main() { with_args(${1:x}, ${2:y})$0 }
685 label: "main()", 658"#,
686 source_range: 77..82,
687 delete: 77..82,
688 insert: "main()$0",
689 kind: Function,
690 lookup: "main",
691 detail: "fn main()",
692 },
693 CompletionItem {
694 label: "with_ignored_args(…)",
695 source_range: 77..82,
696 delete: 77..82,
697 insert: "with_ignored_args(${1:foo}, ${2:bar}, ${3:ho_ge_})$0",
698 kind: Function,
699 lookup: "with_ignored_args",
700 detail: "fn with_ignored_args(_foo: i32, ___bar: bool, ho_ge_: String)",
701 trigger_call_info: true,
702 },
703 ]
704 "###
705 ); 659 );
706 assert_debug_snapshot!( 660
707 do_reference_completion( 661 check_edit(
708 r" 662 "foo",
709 struct S {} 663 r#"
710 impl S { 664struct S;
711 fn foo(&self) {} 665impl S {
712 } 666 fn foo(&self) {}
713 fn bar(s: &S) { 667}
714 s.f<|> 668fn bar(s: &S) { s.f<|> }
715 } 669"#,
716 " 670 r#"
717 ), 671struct S;
718 @r###" 672impl S {
719 [ 673 fn foo(&self) {}
720 CompletionItem { 674}
721 label: "foo()", 675fn bar(s: &S) { s.foo()$0 }
722 source_range: 66..67, 676"#,
723 delete: 66..67,
724 insert: "foo()$0",
725 kind: Method,
726 lookup: "foo",
727 detail: "fn foo(&self)",
728 },
729 ]
730 "###
731 ); 677 );
732 assert_debug_snapshot!( 678
733 do_reference_completion( 679 check_edit(
734 r" 680 "foo",
735 struct S {} 681 r#"
736 impl S { 682struct S {}
737 fn foo_ignored_args(&self, _a: bool, b: i32) {} 683impl S {
738 } 684 fn foo(&self, x: i32) {}
739 fn bar(s: &S) { 685}
740 s.f<|> 686fn bar(s: &S) {
741 } 687 s.f<|>
742 " 688}
743 ), 689"#,
744 @r###" 690 r#"
745 [ 691struct S {}
746 CompletionItem { 692impl S {
747 label: "foo_ignored_args(…)", 693 fn foo(&self, x: i32) {}
748 source_range: 97..98, 694}
749 delete: 97..98, 695fn bar(s: &S) {
750 insert: "foo_ignored_args(${1:a}, ${2:b})$0", 696 s.foo(${1:x})$0
751 kind: Method, 697}
752 lookup: "foo_ignored_args", 698"#,
753 detail: "fn foo_ignored_args(&self, _a: bool, b: i32)",
754 trigger_call_info: true,
755 },
756 ]
757 "###
758 ); 699 );
759 } 700 }
760 701
761 #[test] 702 #[test]
762 fn inserts_parens_for_tuple_enums() { 703 fn suppress_arg_snippets() {
763 assert_debug_snapshot!( 704 mark::check!(suppress_arg_snippets);
764 do_reference_completion( 705 check_edit_with_config(
765 r" 706 "with_args",
766 enum Option<T> { Some(T), None } 707 r#"
767 use Option::*; 708fn with_args(x: i32, y: String) {}
768 fn main() -> Option<i32> { 709fn main() { with_<|> }
769 Som<|> 710"#,
770 } 711 r#"
771 " 712fn with_args(x: i32, y: String) {}
772 ), 713fn main() { with_args($0) }
773 @r###" 714"#,
774 [ 715 &CompletionConfig { add_call_argument_snippets: false, ..CompletionConfig::default() },
775 CompletionItem {
776 label: "None",
777 source_range: 79..82,
778 delete: 79..82,
779 insert: "None",
780 kind: EnumVariant,
781 detail: "()",
782 },
783 CompletionItem {
784 label: "Option",
785 source_range: 79..82,
786 delete: 79..82,
787 insert: "Option",
788 kind: Enum,
789 },
790 CompletionItem {
791 label: "Some(…)",
792 source_range: 79..82,
793 delete: 79..82,
794 insert: "Some($0)",
795 kind: EnumVariant,
796 lookup: "Some",
797 detail: "(T)",
798 trigger_call_info: true,
799 },
800 CompletionItem {
801 label: "main()",
802 source_range: 79..82,
803 delete: 79..82,
804 insert: "main()$0",
805 kind: Function,
806 lookup: "main",
807 detail: "fn main() -> Option<i32>",
808 },
809 ]
810 "###
811 );
812 assert_debug_snapshot!(
813 do_reference_completion(
814 r"
815 enum Option<T> { Some(T), None }
816 use Option::*;
817 fn main(value: Option<i32>) {
818 match value {
819 Som<|>
820 }
821 }
822 "
823 ),
824 @r###"
825 [
826 CompletionItem {
827 label: "None",
828 source_range: 104..107,
829 delete: 104..107,
830 insert: "None",
831 kind: EnumVariant,
832 detail: "()",
833 },
834 CompletionItem {
835 label: "Option",
836 source_range: 104..107,
837 delete: 104..107,
838 insert: "Option",
839 kind: Enum,
840 },
841 CompletionItem {
842 label: "Some(…)",
843 source_range: 104..107,
844 delete: 104..107,
845 insert: "Some($0)",
846 kind: EnumVariant,
847 lookup: "Some",
848 detail: "(T)",
849 trigger_call_info: true,
850 },
851 ]
852 "###
853 ); 716 );
854 } 717 }
855 718
856 #[test] 719 #[test]
857 fn no_call_parens_if_fn_ptr_needed() { 720 fn strips_underscores_from_args() {
858 assert_debug_snapshot!( 721 check_edit(
859 do_reference_completion( 722 "foo",
860 r" 723 r#"
861 fn somefn(with: u8, a: u8, lot: u8, of: u8, args: u8) {} 724fn foo(_foo: i32, ___bar: bool, ho_ge_: String) {}
862 725fn main() { f<|> }
863 struct ManualVtable { 726"#,
864 method: fn(u8, u8, u8, u8, u8), 727 r#"
865 } 728fn foo(_foo: i32, ___bar: bool, ho_ge_: String) {}
866 729fn main() { foo(${1:foo}, ${2:bar}, ${3:ho_ge_})$0 }
867 fn main() -> ManualVtable { 730"#,
868 ManualVtable {
869 method: some<|>
870 }
871 }
872 "
873 ),
874 @r###"
875 [
876 CompletionItem {
877 label: "ManualVtable",
878 source_range: 182..186,
879 delete: 182..186,
880 insert: "ManualVtable",
881 kind: Struct,
882 },
883 CompletionItem {
884 label: "main",
885 source_range: 182..186,
886 delete: 182..186,
887 insert: "main",
888 kind: Function,
889 detail: "fn main() -> ManualVtable",
890 },
891 CompletionItem {
892 label: "somefn",
893 source_range: 182..186,
894 delete: 182..186,
895 insert: "somefn",
896 kind: Function,
897 detail: "fn somefn(with: u8, a: u8, lot: u8, of: u8, args: u8)",
898 },
899 ]
900 "###
901 ); 731 );
902 } 732 }
903 733
904 #[test] 734 #[test]
905 fn arg_snippets_for_method_call() { 735 fn inserts_parens_for_tuple_enums() {
906 assert_debug_snapshot!( 736 check_edit(
907 do_reference_completion( 737 "Some",
908 r" 738 r#"
909 struct S {} 739enum Option<T> { Some(T), None }
910 impl S { 740use Option::*;
911 fn foo(&self, x: i32) {} 741fn main() -> Option<i32> {
912 } 742 Som<|>
913 fn bar(s: &S) { 743}
914 s.f<|> 744"#,
915 } 745 r#"
916 " 746enum Option<T> { Some(T), None }
917 ), 747use Option::*;
918 @r###" 748fn main() -> Option<i32> {
919 [ 749 Some($0)
920 CompletionItem { 750}
921 label: "foo(…)", 751"#,
922 source_range: 74..75, 752 );
923 delete: 74..75, 753 check_edit(
924 insert: "foo(${1:x})$0", 754 "Some",
925 kind: Method, 755 r#"
926 lookup: "foo", 756enum Option<T> { Some(T), None }
927 detail: "fn foo(&self, x: i32)", 757use Option::*;
928 trigger_call_info: true, 758fn main(value: Option<i32>) {
929 }, 759 match value {
930 ] 760 Som<|>
931 "### 761 }
932 ) 762}
763"#,
764 r#"
765enum Option<T> { Some(T), None }
766use Option::*;
767fn main(value: Option<i32>) {
768 match value {
769 Some($0)
770 }
771}
772"#,
773 );
933 } 774 }
934 775
935 #[test] 776 #[test]
936 fn no_arg_snippets_for_method_call() { 777 fn no_call_parens_if_fn_ptr_needed() {
937 assert_debug_snapshot!( 778 mark::check!(no_call_parens_if_fn_ptr_needed);
938 do_reference_completion_with_options( 779 check_edit(
939 r" 780 "foo",
940 struct S {} 781 r#"
941 impl S { 782fn foo(foo: u8, bar: u8) {}
942 fn foo(&self, x: i32) {} 783struct ManualVtable { f: fn(u8, u8) }
943 } 784
944 fn bar(s: &S) { 785fn main() -> ManualVtable {
945 s.f<|> 786 ManualVtable { f: f<|> }
946 } 787}
947 ", 788"#,
948 CompletionConfig { 789 r#"
949 add_call_argument_snippets: false, 790fn foo(foo: u8, bar: u8) {}
950 .. Default::default() 791struct ManualVtable { f: fn(u8, u8) }
951 } 792
952 ), 793fn main() -> ManualVtable {
953 @r###" 794 ManualVtable { f: foo }
954 [ 795}
955 CompletionItem { 796"#,
956 label: "foo(…)", 797 );
957 source_range: 74..75,
958 delete: 74..75,
959 insert: "foo($0)",
960 kind: Method,
961 lookup: "foo",
962 detail: "fn foo(&self, x: i32)",
963 trigger_call_info: true,
964 },
965 ]
966 "###
967 )
968 } 798 }
969 799
970 #[test] 800 #[test]
971 fn dont_render_function_parens_in_use_item() { 801 fn no_parens_in_use_item() {
972 assert_debug_snapshot!( 802 mark::check!(no_parens_in_use_item);
973 do_reference_completion( 803 check_edit(
974 " 804 "foo",
975 //- /lib.rs 805 r#"
976 mod m { pub fn foo() {} } 806mod m { pub fn foo() {} }
977 use crate::m::f<|>; 807use crate::m::f<|>;
978 " 808"#,
979 ), 809 r#"
980 @r###" 810mod m { pub fn foo() {} }
981 [ 811use crate::m::foo;
982 CompletionItem { 812"#,
983 label: "foo",
984 source_range: 40..41,
985 delete: 40..41,
986 insert: "foo",
987 kind: Function,
988 detail: "pub fn foo()",
989 },
990 ]
991 "###
992 ); 813 );
993 } 814 }
994 815
995 #[test] 816 #[test]
996 fn dont_render_function_parens_if_already_call() { 817 fn no_parens_in_call() {
997 assert_debug_snapshot!( 818 check_edit(
998 do_reference_completion( 819 "foo",
999 " 820 r#"
1000 //- /lib.rs 821fn foo(x: i32) {}
1001 fn frobnicate() {} 822fn main() { f<|>(); }
1002 fn main() { 823"#,
1003 frob<|>(); 824 r#"
1004 } 825fn foo(x: i32) {}
1005 " 826fn main() { foo(); }
1006 ), 827"#,
1007 @r###"
1008 [
1009 CompletionItem {
1010 label: "frobnicate",
1011 source_range: 35..39,
1012 delete: 35..39,
1013 insert: "frobnicate",
1014 kind: Function,
1015 detail: "fn frobnicate()",
1016 },
1017 CompletionItem {
1018 label: "main",
1019 source_range: 35..39,
1020 delete: 35..39,
1021 insert: "main",
1022 kind: Function,
1023 detail: "fn main()",
1024 },
1025 ]
1026 "###
1027 ); 828 );
1028 assert_debug_snapshot!( 829 check_edit(
1029 do_reference_completion( 830 "foo",
1030 " 831 r#"
1031 //- /lib.rs 832struct Foo;
1032 struct Foo {} 833impl Foo { fn foo(&self){} }
1033 impl Foo { fn new() -> Foo {} } 834fn f(foo: &Foo) { foo.f<|>(); }
1034 fn main() { 835"#,
1035 Foo::ne<|>(); 836 r#"
1036 } 837struct Foo;
1037 " 838impl Foo { fn foo(&self){} }
1038 ), 839fn f(foo: &Foo) { foo.foo(); }
1039 @r###" 840"#,
1040 [
1041 CompletionItem {
1042 label: "new",
1043 source_range: 67..69,
1044 delete: 67..69,
1045 insert: "new",
1046 kind: Function,
1047 detail: "fn new() -> Foo",
1048 },
1049 ]
1050 "###
1051 ); 841 );
1052 } 842 }
1053 843
@@ -1516,54 +1306,4 @@ mod tests {
1516 "### 1306 "###
1517 ); 1307 );
1518 } 1308 }
1519
1520 #[test]
1521 fn no_keyword_autocompletion_on_line_comments() {
1522 assert_debug_snapshot!(
1523 do_completion(
1524 r"
1525 fn test() {
1526 let x = 2; // A comment<|>
1527 }
1528 ",
1529 CompletionKind::Keyword
1530 ),
1531 @r###"
1532 []
1533 "###
1534 );
1535 }
1536
1537 #[test]
1538 fn no_keyword_autocompletion_on_multi_line_comments() {
1539 assert_debug_snapshot!(
1540 do_completion(
1541 r"
1542 /*
1543 Some multi-line comment<|>
1544 */
1545 ",
1546 CompletionKind::Keyword
1547 ),
1548 @r###"
1549 []
1550 "###
1551 );
1552 }
1553
1554 #[test]
1555 fn no_keyword_autocompletion_on_doc_comments() {
1556 assert_debug_snapshot!(
1557 do_completion(
1558 r"
1559 /// Some doc comment
1560 /// let test<|> = 1
1561 ",
1562 CompletionKind::Keyword
1563 ),
1564 @r###"
1565 []
1566 "###
1567 );
1568 }
1569} 1309}
diff --git a/crates/ra_ide/src/completion/test_utils.rs b/crates/ra_ide/src/completion/test_utils.rs
index 5c01654cc..145d36c98 100644
--- a/crates/ra_ide/src/completion/test_utils.rs
+++ b/crates/ra_ide/src/completion/test_utils.rs
@@ -1,7 +1,10 @@
1//! Runs completion for testing purposes. 1//! Runs completion for testing purposes.
2 2
3use hir::Semantics; 3use hir::Semantics;
4use itertools::Itertools;
4use ra_syntax::{AstNode, NodeOrToken, SyntaxElement}; 5use ra_syntax::{AstNode, NodeOrToken, SyntaxElement};
6use stdx::{format_to, trim_indent};
7use test_utils::assert_eq_text;
5 8
6use crate::{ 9use crate::{
7 completion::{completion_item::CompletionKind, CompletionConfig}, 10 completion::{completion_item::CompletionKind, CompletionConfig},
@@ -42,10 +45,41 @@ pub(crate) fn completion_list_with_options(
42 kind_completions.sort_by_key(|c| c.label().to_owned()); 45 kind_completions.sort_by_key(|c| c.label().to_owned());
43 kind_completions 46 kind_completions
44 .into_iter() 47 .into_iter()
45 .map(|it| format!("{} {}\n", it.kind().unwrap().tag(), it.label())) 48 .map(|it| {
49 let mut buf = format!("{} {}", it.kind().unwrap().tag(), it.label());
50 if let Some(detail) = it.detail() {
51 format_to!(buf, " {}", detail);
52 }
53 format_to!(buf, "\n");
54 buf
55 })
46 .collect() 56 .collect()
47} 57}
48 58
59pub(crate) fn check_edit(what: &str, ra_fixture_before: &str, ra_fixture_after: &str) {
60 check_edit_with_config(what, ra_fixture_before, ra_fixture_after, &CompletionConfig::default())
61}
62
63pub(crate) fn check_edit_with_config(
64 what: &str,
65 ra_fixture_before: &str,
66 ra_fixture_after: &str,
67 config: &CompletionConfig,
68) {
69 let ra_fixture_after = trim_indent(ra_fixture_after);
70 let (analysis, position) = analysis_and_position(ra_fixture_before);
71 let completions: Vec<CompletionItem> =
72 analysis.completions(config, position).unwrap().unwrap().into();
73 let (completion,) = completions
74 .iter()
75 .filter(|it| it.lookup() == what)
76 .collect_tuple()
77 .unwrap_or_else(|| panic!("can't find {:?} completion in {:#?}", what, completions));
78 let mut actual = analysis.file_text(position.file_id).unwrap().to_string();
79 completion.text_edit().apply(&mut actual);
80 assert_eq_text!(&ra_fixture_after, &actual)
81}
82
49pub(crate) fn check_pattern_is_applicable(code: &str, check: fn(SyntaxElement) -> bool) { 83pub(crate) fn check_pattern_is_applicable(code: &str, check: fn(SyntaxElement) -> bool) {
50 let (analysis, pos) = analysis_and_position(code); 84 let (analysis, pos) = analysis_and_position(code);
51 analysis 85 analysis
diff --git a/crates/ra_ide/src/lib.rs b/crates/ra_ide/src/lib.rs
index 8660278f1..dcfa186dc 100644
--- a/crates/ra_ide/src/lib.rs
+++ b/crates/ra_ide/src/lib.rs
@@ -76,7 +76,7 @@ pub use crate::{
76}; 76};
77 77
78pub use hir::{Documentation, Semantics}; 78pub use hir::{Documentation, Semantics};
79pub use ra_assists::{Assist, AssistConfig, AssistId, ResolvedAssist}; 79pub use ra_assists::{Assist, AssistConfig, AssistId, AssistKind, ResolvedAssist};
80pub use ra_db::{ 80pub use ra_db::{
81 Canceled, CrateGraph, CrateId, Edition, FileId, FilePosition, FileRange, SourceRoot, 81 Canceled, CrateGraph, CrateId, Edition, FileId, FilePosition, FileRange, SourceRoot,
82 SourceRootId, 82 SourceRootId,
diff --git a/crates/ra_ide/src/references/rename.rs b/crates/ra_ide/src/references/rename.rs
index b6a2266b4..8735ec53c 100644
--- a/crates/ra_ide/src/references/rename.rs
+++ b/crates/ra_ide/src/references/rename.rs
@@ -116,8 +116,7 @@ fn rename_mod(
116 } else { 116 } else {
117 format!("{}.rs", new_name) 117 format!("{}.rs", new_name)
118 }; 118 };
119 let move_file = 119 let move_file = FileSystemEdit::MoveFile { src: file_id, anchor: file_id, dst };
120 FileSystemEdit::MoveFile { src: file_id, anchor: position.file_id, dst };
121 file_system_edits.push(move_file); 120 file_system_edits.push(move_file);
122 } 121 }
123 ModuleSource::Module(..) => {} 122 ModuleSource::Module(..) => {}
@@ -271,51 +270,51 @@ fn rename_reference(
271 270
272#[cfg(test)] 271#[cfg(test)]
273mod tests { 272mod tests {
274 use insta::assert_debug_snapshot; 273 use expect::{expect, Expect};
275 use ra_text_edit::TextEditBuilder; 274 use ra_text_edit::TextEditBuilder;
276 use stdx::trim_indent; 275 use stdx::trim_indent;
277 use test_utils::{assert_eq_text, mark}; 276 use test_utils::{assert_eq_text, mark};
278 277
279 use crate::{mock_analysis::analysis_and_position, FileId}; 278 use crate::{mock_analysis::analysis_and_position, FileId};
280 279
280 fn check(new_name: &str, ra_fixture_before: &str, ra_fixture_after: &str) {
281 let ra_fixture_after = &trim_indent(ra_fixture_after);
282 let (analysis, position) = analysis_and_position(ra_fixture_before);
283 let source_change = analysis.rename(position, new_name).unwrap();
284 let mut text_edit_builder = TextEditBuilder::default();
285 let mut file_id: Option<FileId> = None;
286 if let Some(change) = source_change {
287 for edit in change.info.source_file_edits {
288 file_id = Some(edit.file_id);
289 for indel in edit.edit.into_iter() {
290 text_edit_builder.replace(indel.delete, indel.insert);
291 }
292 }
293 }
294 let mut result = analysis.file_text(file_id.unwrap()).unwrap().to_string();
295 text_edit_builder.finish().apply(&mut result);
296 assert_eq_text!(ra_fixture_after, &*result);
297 }
298
299 fn check_expect(new_name: &str, ra_fixture: &str, expect: Expect) {
300 let (analysis, position) = analysis_and_position(ra_fixture);
301 let source_change = analysis.rename(position, new_name).unwrap().unwrap();
302 expect.assert_debug_eq(&source_change)
303 }
304
281 #[test] 305 #[test]
282 fn test_rename_to_underscore() { 306 fn test_rename_to_underscore() {
283 test_rename( 307 check("_", r#"fn main() { let i<|> = 1; }"#, r#"fn main() { let _ = 1; }"#);
284 r#"
285 fn main() {
286 let i<|> = 1;
287 }"#,
288 "_",
289 r#"
290 fn main() {
291 let _ = 1;
292 }"#,
293 );
294 } 308 }
295 309
296 #[test] 310 #[test]
297 fn test_rename_to_raw_identifier() { 311 fn test_rename_to_raw_identifier() {
298 test_rename( 312 check("r#fn", r#"fn main() { let i<|> = 1; }"#, r#"fn main() { let r#fn = 1; }"#);
299 r#"
300 fn main() {
301 let i<|> = 1;
302 }"#,
303 "r#fn",
304 r#"
305 fn main() {
306 let r#fn = 1;
307 }"#,
308 );
309 } 313 }
310 314
311 #[test] 315 #[test]
312 fn test_rename_to_invalid_identifier() { 316 fn test_rename_to_invalid_identifier() {
313 let (analysis, position) = analysis_and_position( 317 let (analysis, position) = analysis_and_position(r#"fn main() { let i<|> = 1; }"#);
314 "
315 fn main() {
316 let i<|> = 1;
317 }",
318 );
319 let new_name = "invalid!"; 318 let new_name = "invalid!";
320 let source_change = analysis.rename(position, new_name).unwrap(); 319 let source_change = analysis.rename(position, new_name).unwrap();
321 assert!(source_change.is_none()); 320 assert!(source_change.is_none());
@@ -323,318 +322,269 @@ mod tests {
323 322
324 #[test] 323 #[test]
325 fn test_rename_for_local() { 324 fn test_rename_for_local() {
326 test_rename( 325 check(
326 "k",
327 r#" 327 r#"
328 fn main() { 328fn main() {
329 let mut i = 1; 329 let mut i = 1;
330 let j = 1; 330 let j = 1;
331 i = i<|> + j; 331 i = i<|> + j;
332 332
333 { 333 { i = 0; }
334 i = 0;
335 }
336 334
337 i = 5; 335 i = 5;
338 }"#, 336}
339 "k", 337"#,
340 r#" 338 r#"
341 fn main() { 339fn main() {
342 let mut k = 1; 340 let mut k = 1;
343 let j = 1; 341 let j = 1;
344 k = k + j; 342 k = k + j;
345 343
346 { 344 { k = 0; }
347 k = 0;
348 }
349 345
350 k = 5; 346 k = 5;
351 }"#, 347}
348"#,
352 ); 349 );
353 } 350 }
354 351
355 #[test] 352 #[test]
356 fn test_rename_for_macro_args() { 353 fn test_rename_for_macro_args() {
357 test_rename( 354 check(
358 r#"
359 macro_rules! foo {($i:ident) => {$i} }
360 fn main() {
361 let a<|> = "test";
362 foo!(a);
363 }"#,
364 "b", 355 "b",
365 r#" 356 r#"
366 macro_rules! foo {($i:ident) => {$i} } 357macro_rules! foo {($i:ident) => {$i} }
367 fn main() { 358fn main() {
368 let b = "test"; 359 let a<|> = "test";
369 foo!(b); 360 foo!(a);
370 }"#, 361}
362"#,
363 r#"
364macro_rules! foo {($i:ident) => {$i} }
365fn main() {
366 let b = "test";
367 foo!(b);
368}
369"#,
371 ); 370 );
372 } 371 }
373 372
374 #[test] 373 #[test]
375 fn test_rename_for_macro_args_rev() { 374 fn test_rename_for_macro_args_rev() {
376 test_rename( 375 check(
377 r#"
378 macro_rules! foo {($i:ident) => {$i} }
379 fn main() {
380 let a = "test";
381 foo!(a<|>);
382 }"#,
383 "b", 376 "b",
384 r#" 377 r#"
385 macro_rules! foo {($i:ident) => {$i} } 378macro_rules! foo {($i:ident) => {$i} }
386 fn main() { 379fn main() {
387 let b = "test"; 380 let a = "test";
388 foo!(b); 381 foo!(a<|>);
389 }"#, 382}
383"#,
384 r#"
385macro_rules! foo {($i:ident) => {$i} }
386fn main() {
387 let b = "test";
388 foo!(b);
389}
390"#,
390 ); 391 );
391 } 392 }
392 393
393 #[test] 394 #[test]
394 fn test_rename_for_macro_define_fn() { 395 fn test_rename_for_macro_define_fn() {
395 test_rename( 396 check(
396 r#"
397 macro_rules! define_fn {($id:ident) => { fn $id{} }}
398 define_fn!(foo);
399 fn main() {
400 fo<|>o();
401 }"#,
402 "bar", 397 "bar",
403 r#" 398 r#"
404 macro_rules! define_fn {($id:ident) => { fn $id{} }} 399macro_rules! define_fn {($id:ident) => { fn $id{} }}
405 define_fn!(bar); 400define_fn!(foo);
406 fn main() { 401fn main() {
407 bar(); 402 fo<|>o();
408 }"#, 403}
404"#,
405 r#"
406macro_rules! define_fn {($id:ident) => { fn $id{} }}
407define_fn!(bar);
408fn main() {
409 bar();
410}
411"#,
409 ); 412 );
410 } 413 }
411 414
412 #[test] 415 #[test]
413 fn test_rename_for_macro_define_fn_rev() { 416 fn test_rename_for_macro_define_fn_rev() {
414 test_rename( 417 check(
415 r#"
416 macro_rules! define_fn {($id:ident) => { fn $id{} }}
417 define_fn!(fo<|>o);
418 fn main() {
419 foo();
420 }"#,
421 "bar", 418 "bar",
422 r#" 419 r#"
423 macro_rules! define_fn {($id:ident) => { fn $id{} }} 420macro_rules! define_fn {($id:ident) => { fn $id{} }}
424 define_fn!(bar); 421define_fn!(fo<|>o);
425 fn main() { 422fn main() {
426 bar(); 423 foo();
427 }"#, 424}
425"#,
426 r#"
427macro_rules! define_fn {($id:ident) => { fn $id{} }}
428define_fn!(bar);
429fn main() {
430 bar();
431}
432"#,
428 ); 433 );
429 } 434 }
430 435
431 #[test] 436 #[test]
432 fn test_rename_for_param_inside() { 437 fn test_rename_for_param_inside() {
433 test_rename( 438 check("j", r#"fn foo(i : u32) -> u32 { i<|> }"#, r#"fn foo(j : u32) -> u32 { j }"#);
434 r#"
435 fn foo(i : u32) -> u32 {
436 i<|>
437 }"#,
438 "j",
439 r#"
440 fn foo(j : u32) -> u32 {
441 j
442 }"#,
443 );
444 } 439 }
445 440
446 #[test] 441 #[test]
447 fn test_rename_refs_for_fn_param() { 442 fn test_rename_refs_for_fn_param() {
448 test_rename( 443 check("j", r#"fn foo(i<|> : u32) -> u32 { i }"#, r#"fn foo(j : u32) -> u32 { j }"#);
449 r#"
450 fn foo(i<|> : u32) -> u32 {
451 i
452 }"#,
453 "new_name",
454 r#"
455 fn foo(new_name : u32) -> u32 {
456 new_name
457 }"#,
458 );
459 } 444 }
460 445
461 #[test] 446 #[test]
462 fn test_rename_for_mut_param() { 447 fn test_rename_for_mut_param() {
463 test_rename( 448 check("j", r#"fn foo(mut i<|> : u32) -> u32 { i }"#, r#"fn foo(mut j : u32) -> u32 { j }"#);
464 r#"
465 fn foo(mut i<|> : u32) -> u32 {
466 i
467 }"#,
468 "new_name",
469 r#"
470 fn foo(mut new_name : u32) -> u32 {
471 new_name
472 }"#,
473 );
474 } 449 }
475 450
476 #[test] 451 #[test]
477 fn test_rename_struct_field() { 452 fn test_rename_struct_field() {
478 test_rename( 453 check(
454 "j",
479 r#" 455 r#"
480 struct Foo { 456struct Foo { i<|>: i32 }
481 i<|>: i32,
482 }
483 457
484 impl Foo { 458impl Foo {
485 fn new(i: i32) -> Self { 459 fn new(i: i32) -> Self {
486 Self { i: i } 460 Self { i: i }
487 }
488 } 461 }
489 "#, 462}
490 "j", 463"#,
491 r#" 464 r#"
492 struct Foo { 465struct Foo { j: i32 }
493 j: i32,
494 }
495 466
496 impl Foo { 467impl Foo {
497 fn new(i: i32) -> Self { 468 fn new(i: i32) -> Self {
498 Self { j: i } 469 Self { j: i }
499 }
500 } 470 }
501 "#, 471}
472"#,
502 ); 473 );
503 } 474 }
504 475
505 #[test] 476 #[test]
506 fn test_rename_struct_field_for_shorthand() { 477 fn test_rename_struct_field_for_shorthand() {
507 mark::check!(test_rename_struct_field_for_shorthand); 478 mark::check!(test_rename_struct_field_for_shorthand);
508 test_rename( 479 check(
480 "j",
509 r#" 481 r#"
510 struct Foo { 482struct Foo { i<|>: i32 }
511 i<|>: i32,
512 }
513 483
514 impl Foo { 484impl Foo {
515 fn new(i: i32) -> Self { 485 fn new(i: i32) -> Self {
516 Self { i } 486 Self { i }
517 }
518 } 487 }
519 "#, 488}
520 "j", 489"#,
521 r#" 490 r#"
522 struct Foo { 491struct Foo { j: i32 }
523 j: i32,
524 }
525 492
526 impl Foo { 493impl Foo {
527 fn new(i: i32) -> Self { 494 fn new(i: i32) -> Self {
528 Self { j: i } 495 Self { j: i }
529 }
530 } 496 }
531 "#, 497}
498"#,
532 ); 499 );
533 } 500 }
534 501
535 #[test] 502 #[test]
536 fn test_rename_local_for_field_shorthand() { 503 fn test_rename_local_for_field_shorthand() {
537 mark::check!(test_rename_local_for_field_shorthand); 504 mark::check!(test_rename_local_for_field_shorthand);
538 test_rename( 505 check(
506 "j",
539 r#" 507 r#"
540 struct Foo { 508struct Foo { i: i32 }
541 i: i32,
542 }
543 509
544 impl Foo { 510impl Foo {
545 fn new(i<|>: i32) -> Self { 511 fn new(i<|>: i32) -> Self {
546 Self { i } 512 Self { i }
547 }
548 } 513 }
549 "#, 514}
550 "j", 515"#,
551 r#" 516 r#"
552 struct Foo { 517struct Foo { i: i32 }
553 i: i32,
554 }
555 518
556 impl Foo { 519impl Foo {
557 fn new(j: i32) -> Self { 520 fn new(j: i32) -> Self {
558 Self { i: j } 521 Self { i: j }
559 }
560 } 522 }
561 "#, 523}
524"#,
562 ); 525 );
563 } 526 }
564 527
565 #[test] 528 #[test]
566 fn test_field_shorthand_correct_struct() { 529 fn test_field_shorthand_correct_struct() {
567 test_rename( 530 check(
568 r#"
569 struct Foo {
570 i<|>: i32,
571 }
572
573 struct Bar {
574 i: i32,
575 }
576
577 impl Bar {
578 fn new(i: i32) -> Self {
579 Self { i }
580 }
581 }
582 "#,
583 "j", 531 "j",
584 r#" 532 r#"
585 struct Foo { 533struct Foo { i<|>: i32 }
586 j: i32, 534struct Bar { i: i32 }
587 }
588 535
589 struct Bar { 536impl Bar {
590 i: i32, 537 fn new(i: i32) -> Self {
538 Self { i }
591 } 539 }
540}
541"#,
542 r#"
543struct Foo { j: i32 }
544struct Bar { i: i32 }
592 545
593 impl Bar { 546impl Bar {
594 fn new(i: i32) -> Self { 547 fn new(i: i32) -> Self {
595 Self { i } 548 Self { i }
596 }
597 } 549 }
598 "#, 550}
551"#,
599 ); 552 );
600 } 553 }
601 554
602 #[test] 555 #[test]
603 fn test_shadow_local_for_struct_shorthand() { 556 fn test_shadow_local_for_struct_shorthand() {
604 test_rename( 557 check(
558 "j",
605 r#" 559 r#"
606 struct Foo { 560struct Foo { i: i32 }
607 i: i32,
608 }
609 561
610 fn baz(i<|>: i32) -> Self { 562fn baz(i<|>: i32) -> Self {
611 let x = Foo { i }; 563 let x = Foo { i };
612 { 564 {
613 let i = 0; 565 let i = 0;
614 Foo { i } 566 Foo { i }
615 }
616 } 567 }
617 "#, 568}
618 "j", 569"#,
619 r#" 570 r#"
620 struct Foo { 571struct Foo { i: i32 }
621 i: i32,
622 }
623 572
624 fn baz(j: i32) -> Self { 573fn baz(j: i32) -> Self {
625 let x = Foo { i: j }; 574 let x = Foo { i: j };
626 { 575 {
627 let i = 0; 576 let i = 0;
628 Foo { i } 577 Foo { i }
629 }
630 } 578 }
631 "#, 579}
580"#,
632 ); 581 );
633 } 582 }
634 583
635 #[test] 584 #[test]
636 fn test_rename_mod() { 585 fn test_rename_mod() {
637 let (analysis, position) = analysis_and_position( 586 check_expect(
587 "foo2",
638 r#" 588 r#"
639//- /lib.rs 589//- /lib.rs
640mod bar; 590mod bar;
@@ -643,53 +593,49 @@ mod bar;
643mod foo<|>; 593mod foo<|>;
644 594
645//- /bar/foo.rs 595//- /bar/foo.rs
646// emtpy 596// empty
647 "#, 597"#,
648 ); 598 expect![[r#"
649 let new_name = "foo2"; 599 RangeInfo {
650 let source_change = analysis.rename(position, new_name).unwrap(); 600 range: 4..7,
651 assert_debug_snapshot!(&source_change, 601 info: SourceChange {
652@r###" 602 source_file_edits: [
653 Some( 603 SourceFileEdit {
654 RangeInfo { 604 file_id: FileId(
655 range: 4..7, 605 2,
656 info: SourceChange { 606 ),
657 source_file_edits: [ 607 edit: TextEdit {
658 SourceFileEdit { 608 indels: [
659 file_id: FileId( 609 Indel {
660 2, 610 insert: "foo2",
661 ), 611 delete: 4..7,
662 edit: TextEdit { 612 },
663 indels: [ 613 ],
664 Indel { 614 },
665 insert: "foo2",
666 delete: 4..7,
667 },
668 ],
669 }, 615 },
670 }, 616 ],
671 ], 617 file_system_edits: [
672 file_system_edits: [ 618 MoveFile {
673 MoveFile { 619 src: FileId(
674 src: FileId( 620 3,
675 3, 621 ),
676 ), 622 anchor: FileId(
677 anchor: FileId( 623 3,
678 2, 624 ),
679 ), 625 dst: "foo2.rs",
680 dst: "foo2.rs", 626 },
681 }, 627 ],
682 ], 628 is_snippet: false,
683 is_snippet: false, 629 },
684 }, 630 }
685 }, 631 "#]],
686 ) 632 );
687 "###);
688 } 633 }
689 634
690 #[test] 635 #[test]
691 fn test_rename_mod_in_use_tree() { 636 fn test_rename_mod_in_use_tree() {
692 let (analysis, position) = analysis_and_position( 637 check_expect(
638 "quux",
693 r#" 639 r#"
694//- /main.rs 640//- /main.rs
695pub mod foo; 641pub mod foo;
@@ -701,140 +647,173 @@ pub struct FooContent;
701 647
702//- /bar.rs 648//- /bar.rs
703use crate::foo<|>::FooContent; 649use crate::foo<|>::FooContent;
704 "#, 650"#,
705 ); 651 expect![[r#"
706 let new_name = "qux"; 652 RangeInfo {
707 let source_change = analysis.rename(position, new_name).unwrap(); 653 range: 11..14,
708 assert_debug_snapshot!(&source_change, 654 info: SourceChange {
709@r###" 655 source_file_edits: [
710 Some( 656 SourceFileEdit {
711 RangeInfo { 657 file_id: FileId(
712 range: 11..14, 658 1,
713 info: SourceChange { 659 ),
714 source_file_edits: [ 660 edit: TextEdit {
715 SourceFileEdit { 661 indels: [
716 file_id: FileId( 662 Indel {
717 1, 663 insert: "quux",
718 ), 664 delete: 8..11,
719 edit: TextEdit { 665 },
720 indels: [ 666 ],
721 Indel { 667 },
722 insert: "qux",
723 delete: 8..11,
724 },
725 ],
726 }, 668 },
727 }, 669 SourceFileEdit {
728 SourceFileEdit { 670 file_id: FileId(
729 file_id: FileId( 671 3,
730 3, 672 ),
731 ), 673 edit: TextEdit {
732 edit: TextEdit { 674 indels: [
733 indels: [ 675 Indel {
734 Indel { 676 insert: "quux",
735 insert: "qux", 677 delete: 11..14,
736 delete: 11..14, 678 },
737 }, 679 ],
738 ], 680 },
739 }, 681 },
740 }, 682 ],
741 ], 683 file_system_edits: [
742 file_system_edits: [ 684 MoveFile {
743 MoveFile { 685 src: FileId(
744 src: FileId( 686 2,
745 2, 687 ),
746 ), 688 anchor: FileId(
747 anchor: FileId( 689 2,
748 3, 690 ),
749 ), 691 dst: "quux.rs",
750 dst: "qux.rs", 692 },
751 }, 693 ],
752 ], 694 is_snippet: false,
753 is_snippet: false, 695 },
754 }, 696 }
755 }, 697 "#]],
756 ) 698 );
757 "###);
758 } 699 }
759 700
760 #[test] 701 #[test]
761 fn test_rename_mod_in_dir() { 702 fn test_rename_mod_in_dir() {
762 let (analysis, position) = analysis_and_position( 703 check_expect(
704 "foo2",
763 r#" 705 r#"
764//- /lib.rs 706//- /lib.rs
765mod fo<|>o; 707mod fo<|>o;
766//- /foo/mod.rs 708//- /foo/mod.rs
767// emtpy 709// emtpy
768 "#, 710"#,
769 ); 711 expect![[r#"
770 let new_name = "foo2"; 712 RangeInfo {
771 let source_change = analysis.rename(position, new_name).unwrap(); 713 range: 4..7,
772 assert_debug_snapshot!(&source_change, 714 info: SourceChange {
773 @r###" 715 source_file_edits: [
774 Some( 716 SourceFileEdit {
775 RangeInfo { 717 file_id: FileId(
776 range: 4..7, 718 1,
777 info: SourceChange { 719 ),
778 source_file_edits: [ 720 edit: TextEdit {
779 SourceFileEdit { 721 indels: [
780 file_id: FileId( 722 Indel {
781 1, 723 insert: "foo2",
782 ), 724 delete: 4..7,
783 edit: TextEdit { 725 },
784 indels: [ 726 ],
785 Indel { 727 },
786 insert: "foo2",
787 delete: 4..7,
788 },
789 ],
790 }, 728 },
791 }, 729 ],
792 ], 730 file_system_edits: [
793 file_system_edits: [ 731 MoveFile {
794 MoveFile { 732 src: FileId(
795 src: FileId( 733 2,
796 2, 734 ),
797 ), 735 anchor: FileId(
798 anchor: FileId( 736 2,
799 1, 737 ),
800 ), 738 dst: "../foo2/mod.rs",
801 dst: "../foo2/mod.rs", 739 },
802 }, 740 ],
803 ], 741 is_snippet: false,
804 is_snippet: false, 742 },
805 }, 743 }
806 }, 744 "#]],
807 ) 745 );
808 "###
809 );
810 } 746 }
811 747
812 #[test] 748 #[test]
813 fn test_module_rename_in_path() { 749 fn test_rename_unusually_nested_mod() {
814 test_rename( 750 check_expect(
751 "bar",
815 r#" 752 r#"
816 mod <|>foo { 753//- /lib.rs
817 pub fn bar() {} 754mod outer { mod fo<|>o; }
755
756//- /outer/foo.rs
757// emtpy
758"#,
759 expect![[r#"
760 RangeInfo {
761 range: 16..19,
762 info: SourceChange {
763 source_file_edits: [
764 SourceFileEdit {
765 file_id: FileId(
766 1,
767 ),
768 edit: TextEdit {
769 indels: [
770 Indel {
771 insert: "bar",
772 delete: 16..19,
773 },
774 ],
775 },
776 },
777 ],
778 file_system_edits: [
779 MoveFile {
780 src: FileId(
781 2,
782 ),
783 anchor: FileId(
784 2,
785 ),
786 dst: "bar.rs",
787 },
788 ],
789 is_snippet: false,
790 },
791 }
792 "#]],
793 );
818 } 794 }
819 795
820 fn main() { 796 #[test]
821 foo::bar(); 797 fn test_module_rename_in_path() {
822 }"#, 798 check(
823 "baz", 799 "baz",
824 r#" 800 r#"
825 mod baz { 801mod <|>foo { pub fn bar() {} }
826 pub fn bar() {}
827 }
828 802
829 fn main() { 803fn main() { foo::bar(); }
830 baz::bar(); 804"#,
831 }"#, 805 r#"
806mod baz { pub fn bar() {} }
807
808fn main() { baz::bar(); }
809"#,
832 ); 810 );
833 } 811 }
834 812
835 #[test] 813 #[test]
836 fn test_rename_mod_filename_and_path() { 814 fn test_rename_mod_filename_and_path() {
837 let (analysis, position) = analysis_and_position( 815 check_expect(
816 "foo2",
838 r#" 817 r#"
839//- /lib.rs 818//- /lib.rs
840mod bar; 819mod bar;
@@ -847,229 +826,185 @@ pub mod foo<|>;
847 826
848//- /bar/foo.rs 827//- /bar/foo.rs
849// pub fn fun() {} 828// pub fn fun() {}
850 "#, 829"#,
851 ); 830 expect![[r#"
852 let new_name = "foo2"; 831 RangeInfo {
853 let source_change = analysis.rename(position, new_name).unwrap(); 832 range: 8..11,
854 assert_debug_snapshot!(&source_change, 833 info: SourceChange {
855@r###" 834 source_file_edits: [
856 Some( 835 SourceFileEdit {
857 RangeInfo { 836 file_id: FileId(
858 range: 8..11, 837 2,
859 info: SourceChange { 838 ),
860 source_file_edits: [ 839 edit: TextEdit {
861 SourceFileEdit { 840 indels: [
862 file_id: FileId( 841 Indel {
863 2, 842 insert: "foo2",
864 ), 843 delete: 8..11,
865 edit: TextEdit { 844 },
866 indels: [ 845 ],
867 Indel { 846 },
868 insert: "foo2",
869 delete: 8..11,
870 },
871 ],
872 }, 847 },
873 }, 848 SourceFileEdit {
874 SourceFileEdit { 849 file_id: FileId(
875 file_id: FileId( 850 1,
876 1, 851 ),
877 ), 852 edit: TextEdit {
878 edit: TextEdit { 853 indels: [
879 indels: [ 854 Indel {
880 Indel { 855 insert: "foo2",
881 insert: "foo2", 856 delete: 27..30,
882 delete: 27..30, 857 },
883 }, 858 ],
884 ], 859 },
885 }, 860 },
886 }, 861 ],
887 ], 862 file_system_edits: [
888 file_system_edits: [ 863 MoveFile {
889 MoveFile { 864 src: FileId(
890 src: FileId( 865 3,
891 3, 866 ),
892 ), 867 anchor: FileId(
893 anchor: FileId( 868 3,
894 2, 869 ),
895 ), 870 dst: "foo2.rs",
896 dst: "foo2.rs", 871 },
897 }, 872 ],
898 ], 873 is_snippet: false,
899 is_snippet: false, 874 },
900 }, 875 }
901 }, 876 "#]],
902 ) 877 );
903 "###);
904 } 878 }
905 879
906 #[test] 880 #[test]
907 fn test_enum_variant_from_module_1() { 881 fn test_enum_variant_from_module_1() {
908 test_rename( 882 check(
883 "Baz",
909 r#" 884 r#"
910 mod foo { 885mod foo {
911 pub enum Foo { 886 pub enum Foo { Bar<|> }
912 Bar<|>, 887}
913 }
914 }
915 888
916 fn func(f: foo::Foo) { 889fn func(f: foo::Foo) {
917 match f { 890 match f {
918 foo::Foo::Bar => {} 891 foo::Foo::Bar => {}
919 }
920 } 892 }
921 "#, 893}
922 "Baz", 894"#,
923 r#" 895 r#"
924 mod foo { 896mod foo {
925 pub enum Foo { 897 pub enum Foo { Baz }
926 Baz, 898}
927 }
928 }
929 899
930 fn func(f: foo::Foo) { 900fn func(f: foo::Foo) {
931 match f { 901 match f {
932 foo::Foo::Baz => {} 902 foo::Foo::Baz => {}
933 }
934 } 903 }
935 "#, 904}
905"#,
936 ); 906 );
937 } 907 }
938 908
939 #[test] 909 #[test]
940 fn test_enum_variant_from_module_2() { 910 fn test_enum_variant_from_module_2() {
941 test_rename( 911 check(
912 "baz",
942 r#" 913 r#"
943 mod foo { 914mod foo {
944 pub struct Foo { 915 pub struct Foo { pub bar<|>: uint }
945 pub bar<|>: uint, 916}
946 }
947 }
948 917
949 fn foo(f: foo::Foo) { 918fn foo(f: foo::Foo) {
950 let _ = f.bar; 919 let _ = f.bar;
951 } 920}
952 "#, 921"#,
953 "baz",
954 r#" 922 r#"
955 mod foo { 923mod foo {
956 pub struct Foo { 924 pub struct Foo { pub baz: uint }
957 pub baz: uint, 925}
958 }
959 }
960 926
961 fn foo(f: foo::Foo) { 927fn foo(f: foo::Foo) {
962 let _ = f.baz; 928 let _ = f.baz;
963 } 929}
964 "#, 930"#,
965 ); 931 );
966 } 932 }
967 933
968 #[test] 934 #[test]
969 fn test_parameter_to_self() { 935 fn test_parameter_to_self() {
970 test_rename( 936 check(
937 "self",
971 r#" 938 r#"
972 struct Foo { 939struct Foo { i: i32 }
973 i: i32,
974 }
975 940
976 impl Foo { 941impl Foo {
977 fn f(foo<|>: &mut Foo) -> i32 { 942 fn f(foo<|>: &mut Foo) -> i32 {
978 foo.i 943 foo.i
979 }
980 } 944 }
981 "#, 945}
982 "self", 946"#,
983 r#" 947 r#"
984 struct Foo { 948struct Foo { i: i32 }
985 i: i32,
986 }
987 949
988 impl Foo { 950impl Foo {
989 fn f(&mut self) -> i32 { 951 fn f(&mut self) -> i32 {
990 self.i 952 self.i
991 }
992 } 953 }
993 "#, 954}
955"#,
994 ); 956 );
995 } 957 }
996 958
997 #[test] 959 #[test]
998 fn test_self_to_parameter() { 960 fn test_self_to_parameter() {
999 test_rename( 961 check(
962 "foo",
1000 r#" 963 r#"
1001 struct Foo { 964struct Foo { i: i32 }
1002 i: i32,
1003 }
1004 965
1005 impl Foo { 966impl Foo {
1006 fn f(&mut <|>self) -> i32 { 967 fn f(&mut <|>self) -> i32 {
1007 self.i 968 self.i
1008 }
1009 } 969 }
1010 "#, 970}
1011 "foo", 971"#,
1012 r#" 972 r#"
1013 struct Foo { 973struct Foo { i: i32 }
1014 i: i32,
1015 }
1016 974
1017 impl Foo { 975impl Foo {
1018 fn f(foo: &mut Foo) -> i32 { 976 fn f(foo: &mut Foo) -> i32 {
1019 foo.i 977 foo.i
1020 }
1021 } 978 }
1022 "#, 979}
980"#,
1023 ); 981 );
1024 } 982 }
1025 983
1026 #[test] 984 #[test]
1027 fn test_self_in_path_to_parameter() { 985 fn test_self_in_path_to_parameter() {
1028 test_rename( 986 check(
987 "foo",
1029 r#" 988 r#"
1030 struct Foo { 989struct Foo { i: i32 }
1031 i: i32,
1032 }
1033 990
1034 impl Foo { 991impl Foo {
1035 fn f(&self) -> i32 { 992 fn f(&self) -> i32 {
1036 let self_var = 1; 993 let self_var = 1;
1037 self<|>.i 994 self<|>.i
1038 }
1039 } 995 }
1040 "#, 996}
1041 "foo", 997"#,
1042 r#" 998 r#"
1043 struct Foo { 999struct Foo { i: i32 }
1044 i: i32,
1045 }
1046 1000
1047 impl Foo { 1001impl Foo {
1048 fn f(foo: &Foo) -> i32 { 1002 fn f(foo: &Foo) -> i32 {
1049 let self_var = 1; 1003 let self_var = 1;
1050 foo.i 1004 foo.i
1051 }
1052 } 1005 }
1053 "#, 1006}
1007"#,
1054 ); 1008 );
1055 } 1009 }
1056
1057 fn test_rename(ra_fixture_before: &str, new_name: &str, ra_fixture_after: &str) {
1058 let ra_fixture_after = &trim_indent(ra_fixture_after);
1059 let (analysis, position) = analysis_and_position(ra_fixture_before);
1060 let source_change = analysis.rename(position, new_name).unwrap();
1061 let mut text_edit_builder = TextEditBuilder::default();
1062 let mut file_id: Option<FileId> = None;
1063 if let Some(change) = source_change {
1064 for edit in change.info.source_file_edits {
1065 file_id = Some(edit.file_id);
1066 for indel in edit.edit.into_iter() {
1067 text_edit_builder.replace(indel.delete, indel.insert);
1068 }
1069 }
1070 }
1071 let mut result = analysis.file_text(file_id.unwrap()).unwrap().to_string();
1072 text_edit_builder.finish().apply(&mut result);
1073 assert_eq_text!(ra_fixture_after, &*result);
1074 }
1075} 1010}