diff options
Diffstat (limited to 'crates/ide_db')
-rw-r--r-- | crates/ide_db/src/call_info.rs | 527 | ||||
-rw-r--r-- | crates/ide_db/src/call_info/tests.rs | 523 | ||||
-rw-r--r-- | crates/ide_db/src/defs.rs | 2 | ||||
-rw-r--r-- | crates/ide_db/src/helpers/insert_use.rs | 639 | ||||
-rw-r--r-- | crates/ide_db/src/helpers/insert_use/tests.rs | 620 | ||||
-rw-r--r-- | crates/ide_db/src/line_index.rs | 131 | ||||
-rw-r--r-- | crates/ide_db/src/line_index/tests.rs | 128 | ||||
-rw-r--r-- | crates/ide_db/src/traits.rs | 148 | ||||
-rw-r--r-- | crates/ide_db/src/traits/tests.rs | 144 |
9 files changed, 1420 insertions, 1442 deletions
diff --git a/crates/ide_db/src/call_info.rs b/crates/ide_db/src/call_info.rs index 83a602b9a..615fa7b0e 100644 --- a/crates/ide_db/src/call_info.rs +++ b/crates/ide_db/src/call_info.rs | |||
@@ -228,529 +228,4 @@ impl FnCallNode { | |||
228 | } | 228 | } |
229 | 229 | ||
230 | #[cfg(test)] | 230 | #[cfg(test)] |
231 | mod tests { | 231 | mod tests; |
232 | use crate::RootDatabase; | ||
233 | use base_db::{fixture::ChangeFixture, FilePosition}; | ||
234 | use expect_test::{expect, Expect}; | ||
235 | use test_utils::{mark, RangeOrOffset}; | ||
236 | |||
237 | /// Creates analysis from a multi-file fixture, returns positions marked with <|>. | ||
238 | pub(crate) fn position(ra_fixture: &str) -> (RootDatabase, FilePosition) { | ||
239 | let change_fixture = ChangeFixture::parse(ra_fixture); | ||
240 | let mut database = RootDatabase::default(); | ||
241 | database.apply_change(change_fixture.change); | ||
242 | let (file_id, range_or_offset) = | ||
243 | change_fixture.file_position.expect("expected a marker (<|>)"); | ||
244 | let offset = match range_or_offset { | ||
245 | RangeOrOffset::Range(_) => panic!(), | ||
246 | RangeOrOffset::Offset(it) => it, | ||
247 | }; | ||
248 | (database, FilePosition { file_id, offset }) | ||
249 | } | ||
250 | |||
251 | fn check(ra_fixture: &str, expect: Expect) { | ||
252 | let (db, position) = position(ra_fixture); | ||
253 | let call_info = crate::call_info::call_info(&db, position); | ||
254 | let actual = match call_info { | ||
255 | Some(call_info) => { | ||
256 | let docs = match &call_info.doc { | ||
257 | None => "".to_string(), | ||
258 | Some(docs) => format!("{}\n------\n", docs.as_str()), | ||
259 | }; | ||
260 | let params = call_info | ||
261 | .parameter_labels() | ||
262 | .enumerate() | ||
263 | .map(|(i, param)| { | ||
264 | if Some(i) == call_info.active_parameter { | ||
265 | format!("<{}>", param) | ||
266 | } else { | ||
267 | param.to_string() | ||
268 | } | ||
269 | }) | ||
270 | .collect::<Vec<_>>() | ||
271 | .join(", "); | ||
272 | format!("{}{}\n({})\n", docs, call_info.signature, params) | ||
273 | } | ||
274 | None => String::new(), | ||
275 | }; | ||
276 | expect.assert_eq(&actual); | ||
277 | } | ||
278 | |||
279 | #[test] | ||
280 | fn test_fn_signature_two_args() { | ||
281 | check( | ||
282 | r#" | ||
283 | fn foo(x: u32, y: u32) -> u32 {x + y} | ||
284 | fn bar() { foo(<|>3, ); } | ||
285 | "#, | ||
286 | expect![[r#" | ||
287 | fn foo(x: u32, y: u32) -> u32 | ||
288 | (<x: u32>, y: u32) | ||
289 | "#]], | ||
290 | ); | ||
291 | check( | ||
292 | r#" | ||
293 | fn foo(x: u32, y: u32) -> u32 {x + y} | ||
294 | fn bar() { foo(3<|>, ); } | ||
295 | "#, | ||
296 | expect![[r#" | ||
297 | fn foo(x: u32, y: u32) -> u32 | ||
298 | (<x: u32>, y: u32) | ||
299 | "#]], | ||
300 | ); | ||
301 | check( | ||
302 | r#" | ||
303 | fn foo(x: u32, y: u32) -> u32 {x + y} | ||
304 | fn bar() { foo(3,<|> ); } | ||
305 | "#, | ||
306 | expect![[r#" | ||
307 | fn foo(x: u32, y: u32) -> u32 | ||
308 | (x: u32, <y: u32>) | ||
309 | "#]], | ||
310 | ); | ||
311 | check( | ||
312 | r#" | ||
313 | fn foo(x: u32, y: u32) -> u32 {x + y} | ||
314 | fn bar() { foo(3, <|>); } | ||
315 | "#, | ||
316 | expect![[r#" | ||
317 | fn foo(x: u32, y: u32) -> u32 | ||
318 | (x: u32, <y: u32>) | ||
319 | "#]], | ||
320 | ); | ||
321 | } | ||
322 | |||
323 | #[test] | ||
324 | fn test_fn_signature_two_args_empty() { | ||
325 | check( | ||
326 | r#" | ||
327 | fn foo(x: u32, y: u32) -> u32 {x + y} | ||
328 | fn bar() { foo(<|>); } | ||
329 | "#, | ||
330 | expect![[r#" | ||
331 | fn foo(x: u32, y: u32) -> u32 | ||
332 | (<x: u32>, y: u32) | ||
333 | "#]], | ||
334 | ); | ||
335 | } | ||
336 | |||
337 | #[test] | ||
338 | fn test_fn_signature_two_args_first_generics() { | ||
339 | check( | ||
340 | r#" | ||
341 | fn foo<T, U: Copy + Display>(x: T, y: U) -> u32 | ||
342 | where T: Copy + Display, U: Debug | ||
343 | { x + y } | ||
344 | |||
345 | fn bar() { foo(<|>3, ); } | ||
346 | "#, | ||
347 | expect![[r#" | ||
348 | fn foo(x: i32, y: {unknown}) -> u32 | ||
349 | (<x: i32>, y: {unknown}) | ||
350 | "#]], | ||
351 | ); | ||
352 | } | ||
353 | |||
354 | #[test] | ||
355 | fn test_fn_signature_no_params() { | ||
356 | check( | ||
357 | r#" | ||
358 | fn foo<T>() -> T where T: Copy + Display {} | ||
359 | fn bar() { foo(<|>); } | ||
360 | "#, | ||
361 | expect![[r#" | ||
362 | fn foo() -> {unknown} | ||
363 | () | ||
364 | "#]], | ||
365 | ); | ||
366 | } | ||
367 | |||
368 | #[test] | ||
369 | fn test_fn_signature_for_impl() { | ||
370 | check( | ||
371 | r#" | ||
372 | struct F; | ||
373 | impl F { pub fn new() { } } | ||
374 | fn bar() { | ||
375 | let _ : F = F::new(<|>); | ||
376 | } | ||
377 | "#, | ||
378 | expect![[r#" | ||
379 | fn new() | ||
380 | () | ||
381 | "#]], | ||
382 | ); | ||
383 | } | ||
384 | |||
385 | #[test] | ||
386 | fn test_fn_signature_for_method_self() { | ||
387 | check( | ||
388 | r#" | ||
389 | struct S; | ||
390 | impl S { pub fn do_it(&self) {} } | ||
391 | |||
392 | fn bar() { | ||
393 | let s: S = S; | ||
394 | s.do_it(<|>); | ||
395 | } | ||
396 | "#, | ||
397 | expect![[r#" | ||
398 | fn do_it(&self) | ||
399 | () | ||
400 | "#]], | ||
401 | ); | ||
402 | } | ||
403 | |||
404 | #[test] | ||
405 | fn test_fn_signature_for_method_with_arg() { | ||
406 | check( | ||
407 | r#" | ||
408 | struct S; | ||
409 | impl S { | ||
410 | fn foo(&self, x: i32) {} | ||
411 | } | ||
412 | |||
413 | fn main() { S.foo(<|>); } | ||
414 | "#, | ||
415 | expect![[r#" | ||
416 | fn foo(&self, x: i32) | ||
417 | (<x: i32>) | ||
418 | "#]], | ||
419 | ); | ||
420 | } | ||
421 | |||
422 | #[test] | ||
423 | fn test_fn_signature_for_method_with_arg_as_assoc_fn() { | ||
424 | check( | ||
425 | r#" | ||
426 | struct S; | ||
427 | impl S { | ||
428 | fn foo(&self, x: i32) {} | ||
429 | } | ||
430 | |||
431 | fn main() { S::foo(<|>); } | ||
432 | "#, | ||
433 | expect![[r#" | ||
434 | fn foo(self: &S, x: i32) | ||
435 | (<self: &S>, x: i32) | ||
436 | "#]], | ||
437 | ); | ||
438 | } | ||
439 | |||
440 | #[test] | ||
441 | fn test_fn_signature_with_docs_simple() { | ||
442 | check( | ||
443 | r#" | ||
444 | /// test | ||
445 | // non-doc-comment | ||
446 | fn foo(j: u32) -> u32 { | ||
447 | j | ||
448 | } | ||
449 | |||
450 | fn bar() { | ||
451 | let _ = foo(<|>); | ||
452 | } | ||
453 | "#, | ||
454 | expect![[r#" | ||
455 | test | ||
456 | ------ | ||
457 | fn foo(j: u32) -> u32 | ||
458 | (<j: u32>) | ||
459 | "#]], | ||
460 | ); | ||
461 | } | ||
462 | |||
463 | #[test] | ||
464 | fn test_fn_signature_with_docs() { | ||
465 | check( | ||
466 | r#" | ||
467 | /// Adds one to the number given. | ||
468 | /// | ||
469 | /// # Examples | ||
470 | /// | ||
471 | /// ``` | ||
472 | /// let five = 5; | ||
473 | /// | ||
474 | /// assert_eq!(6, my_crate::add_one(5)); | ||
475 | /// ``` | ||
476 | pub fn add_one(x: i32) -> i32 { | ||
477 | x + 1 | ||
478 | } | ||
479 | |||
480 | pub fn do() { | ||
481 | add_one(<|> | ||
482 | }"#, | ||
483 | expect![[r##" | ||
484 | Adds one to the number given. | ||
485 | |||
486 | # Examples | ||
487 | |||
488 | ``` | ||
489 | let five = 5; | ||
490 | |||
491 | assert_eq!(6, my_crate::add_one(5)); | ||
492 | ``` | ||
493 | ------ | ||
494 | fn add_one(x: i32) -> i32 | ||
495 | (<x: i32>) | ||
496 | "##]], | ||
497 | ); | ||
498 | } | ||
499 | |||
500 | #[test] | ||
501 | fn test_fn_signature_with_docs_impl() { | ||
502 | check( | ||
503 | r#" | ||
504 | struct addr; | ||
505 | impl addr { | ||
506 | /// Adds one to the number given. | ||
507 | /// | ||
508 | /// # Examples | ||
509 | /// | ||
510 | /// ``` | ||
511 | /// let five = 5; | ||
512 | /// | ||
513 | /// assert_eq!(6, my_crate::add_one(5)); | ||
514 | /// ``` | ||
515 | pub fn add_one(x: i32) -> i32 { | ||
516 | x + 1 | ||
517 | } | ||
518 | } | ||
519 | |||
520 | pub fn do_it() { | ||
521 | addr {}; | ||
522 | addr::add_one(<|>); | ||
523 | } | ||
524 | "#, | ||
525 | expect![[r##" | ||
526 | Adds one to the number given. | ||
527 | |||
528 | # Examples | ||
529 | |||
530 | ``` | ||
531 | let five = 5; | ||
532 | |||
533 | assert_eq!(6, my_crate::add_one(5)); | ||
534 | ``` | ||
535 | ------ | ||
536 | fn add_one(x: i32) -> i32 | ||
537 | (<x: i32>) | ||
538 | "##]], | ||
539 | ); | ||
540 | } | ||
541 | |||
542 | #[test] | ||
543 | fn test_fn_signature_with_docs_from_actix() { | ||
544 | check( | ||
545 | r#" | ||
546 | struct WriteHandler<E>; | ||
547 | |||
548 | impl<E> WriteHandler<E> { | ||
549 | /// Method is called when writer emits error. | ||
550 | /// | ||
551 | /// If this method returns `ErrorAction::Continue` writer processing | ||
552 | /// continues otherwise stream processing stops. | ||
553 | fn error(&mut self, err: E, ctx: &mut Self::Context) -> Running { | ||
554 | Running::Stop | ||
555 | } | ||
556 | |||
557 | /// Method is called when writer finishes. | ||
558 | /// | ||
559 | /// By default this method stops actor's `Context`. | ||
560 | fn finished(&mut self, ctx: &mut Self::Context) { | ||
561 | ctx.stop() | ||
562 | } | ||
563 | } | ||
564 | |||
565 | pub fn foo(mut r: WriteHandler<()>) { | ||
566 | r.finished(<|>); | ||
567 | } | ||
568 | "#, | ||
569 | expect![[r#" | ||
570 | Method is called when writer finishes. | ||
571 | |||
572 | By default this method stops actor's `Context`. | ||
573 | ------ | ||
574 | fn finished(&mut self, ctx: &mut {unknown}) | ||
575 | (<ctx: &mut {unknown}>) | ||
576 | "#]], | ||
577 | ); | ||
578 | } | ||
579 | |||
580 | #[test] | ||
581 | fn call_info_bad_offset() { | ||
582 | mark::check!(call_info_bad_offset); | ||
583 | check( | ||
584 | r#" | ||
585 | fn foo(x: u32, y: u32) -> u32 {x + y} | ||
586 | fn bar() { foo <|> (3, ); } | ||
587 | "#, | ||
588 | expect![[""]], | ||
589 | ); | ||
590 | } | ||
591 | |||
592 | #[test] | ||
593 | fn test_nested_method_in_lambda() { | ||
594 | check( | ||
595 | r#" | ||
596 | struct Foo; | ||
597 | impl Foo { fn bar(&self, _: u32) { } } | ||
598 | |||
599 | fn bar(_: u32) { } | ||
600 | |||
601 | fn main() { | ||
602 | let foo = Foo; | ||
603 | std::thread::spawn(move || foo.bar(<|>)); | ||
604 | } | ||
605 | "#, | ||
606 | expect![[r#" | ||
607 | fn bar(&self, _: u32) | ||
608 | (<_: u32>) | ||
609 | "#]], | ||
610 | ); | ||
611 | } | ||
612 | |||
613 | #[test] | ||
614 | fn works_for_tuple_structs() { | ||
615 | check( | ||
616 | r#" | ||
617 | /// A cool tuple struct | ||
618 | struct S(u32, i32); | ||
619 | fn main() { | ||
620 | let s = S(0, <|>); | ||
621 | } | ||
622 | "#, | ||
623 | expect![[r#" | ||
624 | A cool tuple struct | ||
625 | ------ | ||
626 | struct S(u32, i32) | ||
627 | (u32, <i32>) | ||
628 | "#]], | ||
629 | ); | ||
630 | } | ||
631 | |||
632 | #[test] | ||
633 | fn generic_struct() { | ||
634 | check( | ||
635 | r#" | ||
636 | struct S<T>(T); | ||
637 | fn main() { | ||
638 | let s = S(<|>); | ||
639 | } | ||
640 | "#, | ||
641 | expect![[r#" | ||
642 | struct S({unknown}) | ||
643 | (<{unknown}>) | ||
644 | "#]], | ||
645 | ); | ||
646 | } | ||
647 | |||
648 | #[test] | ||
649 | fn works_for_enum_variants() { | ||
650 | check( | ||
651 | r#" | ||
652 | enum E { | ||
653 | /// A Variant | ||
654 | A(i32), | ||
655 | /// Another | ||
656 | B, | ||
657 | /// And C | ||
658 | C { a: i32, b: i32 } | ||
659 | } | ||
660 | |||
661 | fn main() { | ||
662 | let a = E::A(<|>); | ||
663 | } | ||
664 | "#, | ||
665 | expect![[r#" | ||
666 | A Variant | ||
667 | ------ | ||
668 | enum E::A(i32) | ||
669 | (<i32>) | ||
670 | "#]], | ||
671 | ); | ||
672 | } | ||
673 | |||
674 | #[test] | ||
675 | fn cant_call_struct_record() { | ||
676 | check( | ||
677 | r#" | ||
678 | struct S { x: u32, y: i32 } | ||
679 | fn main() { | ||
680 | let s = S(<|>); | ||
681 | } | ||
682 | "#, | ||
683 | expect![[""]], | ||
684 | ); | ||
685 | } | ||
686 | |||
687 | #[test] | ||
688 | fn cant_call_enum_record() { | ||
689 | check( | ||
690 | r#" | ||
691 | enum E { | ||
692 | /// A Variant | ||
693 | A(i32), | ||
694 | /// Another | ||
695 | B, | ||
696 | /// And C | ||
697 | C { a: i32, b: i32 } | ||
698 | } | ||
699 | |||
700 | fn main() { | ||
701 | let a = E::C(<|>); | ||
702 | } | ||
703 | "#, | ||
704 | expect![[""]], | ||
705 | ); | ||
706 | } | ||
707 | |||
708 | #[test] | ||
709 | fn fn_signature_for_call_in_macro() { | ||
710 | check( | ||
711 | r#" | ||
712 | macro_rules! id { ($($tt:tt)*) => { $($tt)* } } | ||
713 | fn foo() { } | ||
714 | id! { | ||
715 | fn bar() { foo(<|>); } | ||
716 | } | ||
717 | "#, | ||
718 | expect![[r#" | ||
719 | fn foo() | ||
720 | () | ||
721 | "#]], | ||
722 | ); | ||
723 | } | ||
724 | |||
725 | #[test] | ||
726 | fn call_info_for_lambdas() { | ||
727 | check( | ||
728 | r#" | ||
729 | struct S; | ||
730 | fn foo(s: S) -> i32 { 92 } | ||
731 | fn main() { | ||
732 | (|s| foo(s))(<|>) | ||
733 | } | ||
734 | "#, | ||
735 | expect![[r#" | ||
736 | (S) -> i32 | ||
737 | (<S>) | ||
738 | "#]], | ||
739 | ) | ||
740 | } | ||
741 | |||
742 | #[test] | ||
743 | fn call_info_for_fn_ptr() { | ||
744 | check( | ||
745 | r#" | ||
746 | fn main(f: fn(i32, f64) -> char) { | ||
747 | f(0, <|>) | ||
748 | } | ||
749 | "#, | ||
750 | expect![[r#" | ||
751 | (i32, f64) -> char | ||
752 | (i32, <f64>) | ||
753 | "#]], | ||
754 | ) | ||
755 | } | ||
756 | } | ||
diff --git a/crates/ide_db/src/call_info/tests.rs b/crates/ide_db/src/call_info/tests.rs new file mode 100644 index 000000000..9335aeaa5 --- /dev/null +++ b/crates/ide_db/src/call_info/tests.rs | |||
@@ -0,0 +1,523 @@ | |||
1 | use crate::RootDatabase; | ||
2 | use base_db::{fixture::ChangeFixture, FilePosition}; | ||
3 | use expect_test::{expect, Expect}; | ||
4 | use test_utils::{mark, RangeOrOffset}; | ||
5 | |||
6 | /// Creates analysis from a multi-file fixture, returns positions marked with <|>. | ||
7 | pub(crate) fn position(ra_fixture: &str) -> (RootDatabase, FilePosition) { | ||
8 | let change_fixture = ChangeFixture::parse(ra_fixture); | ||
9 | let mut database = RootDatabase::default(); | ||
10 | database.apply_change(change_fixture.change); | ||
11 | let (file_id, range_or_offset) = change_fixture.file_position.expect("expected a marker (<|>)"); | ||
12 | let offset = match range_or_offset { | ||
13 | RangeOrOffset::Range(_) => panic!(), | ||
14 | RangeOrOffset::Offset(it) => it, | ||
15 | }; | ||
16 | (database, FilePosition { file_id, offset }) | ||
17 | } | ||
18 | |||
19 | fn check(ra_fixture: &str, expect: Expect) { | ||
20 | let (db, position) = position(ra_fixture); | ||
21 | let call_info = crate::call_info::call_info(&db, position); | ||
22 | let actual = match call_info { | ||
23 | Some(call_info) => { | ||
24 | let docs = match &call_info.doc { | ||
25 | None => "".to_string(), | ||
26 | Some(docs) => format!("{}\n------\n", docs.as_str()), | ||
27 | }; | ||
28 | let params = call_info | ||
29 | .parameter_labels() | ||
30 | .enumerate() | ||
31 | .map(|(i, param)| { | ||
32 | if Some(i) == call_info.active_parameter { | ||
33 | format!("<{}>", param) | ||
34 | } else { | ||
35 | param.to_string() | ||
36 | } | ||
37 | }) | ||
38 | .collect::<Vec<_>>() | ||
39 | .join(", "); | ||
40 | format!("{}{}\n({})\n", docs, call_info.signature, params) | ||
41 | } | ||
42 | None => String::new(), | ||
43 | }; | ||
44 | expect.assert_eq(&actual); | ||
45 | } | ||
46 | |||
47 | #[test] | ||
48 | fn test_fn_signature_two_args() { | ||
49 | check( | ||
50 | r#" | ||
51 | fn foo(x: u32, y: u32) -> u32 {x + y} | ||
52 | fn bar() { foo(<|>3, ); } | ||
53 | "#, | ||
54 | expect![[r#" | ||
55 | fn foo(x: u32, y: u32) -> u32 | ||
56 | (<x: u32>, y: u32) | ||
57 | "#]], | ||
58 | ); | ||
59 | check( | ||
60 | r#" | ||
61 | fn foo(x: u32, y: u32) -> u32 {x + y} | ||
62 | fn bar() { foo(3<|>, ); } | ||
63 | "#, | ||
64 | expect![[r#" | ||
65 | fn foo(x: u32, y: u32) -> u32 | ||
66 | (<x: u32>, y: u32) | ||
67 | "#]], | ||
68 | ); | ||
69 | check( | ||
70 | r#" | ||
71 | fn foo(x: u32, y: u32) -> u32 {x + y} | ||
72 | fn bar() { foo(3,<|> ); } | ||
73 | "#, | ||
74 | expect![[r#" | ||
75 | fn foo(x: u32, y: u32) -> u32 | ||
76 | (x: u32, <y: u32>) | ||
77 | "#]], | ||
78 | ); | ||
79 | check( | ||
80 | r#" | ||
81 | fn foo(x: u32, y: u32) -> u32 {x + y} | ||
82 | fn bar() { foo(3, <|>); } | ||
83 | "#, | ||
84 | expect![[r#" | ||
85 | fn foo(x: u32, y: u32) -> u32 | ||
86 | (x: u32, <y: u32>) | ||
87 | "#]], | ||
88 | ); | ||
89 | } | ||
90 | |||
91 | #[test] | ||
92 | fn test_fn_signature_two_args_empty() { | ||
93 | check( | ||
94 | r#" | ||
95 | fn foo(x: u32, y: u32) -> u32 {x + y} | ||
96 | fn bar() { foo(<|>); } | ||
97 | "#, | ||
98 | expect![[r#" | ||
99 | fn foo(x: u32, y: u32) -> u32 | ||
100 | (<x: u32>, y: u32) | ||
101 | "#]], | ||
102 | ); | ||
103 | } | ||
104 | |||
105 | #[test] | ||
106 | fn test_fn_signature_two_args_first_generics() { | ||
107 | check( | ||
108 | r#" | ||
109 | fn foo<T, U: Copy + Display>(x: T, y: U) -> u32 | ||
110 | where T: Copy + Display, U: Debug | ||
111 | { x + y } | ||
112 | |||
113 | fn bar() { foo(<|>3, ); } | ||
114 | "#, | ||
115 | expect![[r#" | ||
116 | fn foo(x: i32, y: {unknown}) -> u32 | ||
117 | (<x: i32>, y: {unknown}) | ||
118 | "#]], | ||
119 | ); | ||
120 | } | ||
121 | |||
122 | #[test] | ||
123 | fn test_fn_signature_no_params() { | ||
124 | check( | ||
125 | r#" | ||
126 | fn foo<T>() -> T where T: Copy + Display {} | ||
127 | fn bar() { foo(<|>); } | ||
128 | "#, | ||
129 | expect![[r#" | ||
130 | fn foo() -> {unknown} | ||
131 | () | ||
132 | "#]], | ||
133 | ); | ||
134 | } | ||
135 | |||
136 | #[test] | ||
137 | fn test_fn_signature_for_impl() { | ||
138 | check( | ||
139 | r#" | ||
140 | struct F; | ||
141 | impl F { pub fn new() { } } | ||
142 | fn bar() { | ||
143 | let _ : F = F::new(<|>); | ||
144 | } | ||
145 | "#, | ||
146 | expect![[r#" | ||
147 | fn new() | ||
148 | () | ||
149 | "#]], | ||
150 | ); | ||
151 | } | ||
152 | |||
153 | #[test] | ||
154 | fn test_fn_signature_for_method_self() { | ||
155 | check( | ||
156 | r#" | ||
157 | struct S; | ||
158 | impl S { pub fn do_it(&self) {} } | ||
159 | |||
160 | fn bar() { | ||
161 | let s: S = S; | ||
162 | s.do_it(<|>); | ||
163 | } | ||
164 | "#, | ||
165 | expect![[r#" | ||
166 | fn do_it(&self) | ||
167 | () | ||
168 | "#]], | ||
169 | ); | ||
170 | } | ||
171 | |||
172 | #[test] | ||
173 | fn test_fn_signature_for_method_with_arg() { | ||
174 | check( | ||
175 | r#" | ||
176 | struct S; | ||
177 | impl S { | ||
178 | fn foo(&self, x: i32) {} | ||
179 | } | ||
180 | |||
181 | fn main() { S.foo(<|>); } | ||
182 | "#, | ||
183 | expect![[r#" | ||
184 | fn foo(&self, x: i32) | ||
185 | (<x: i32>) | ||
186 | "#]], | ||
187 | ); | ||
188 | } | ||
189 | |||
190 | #[test] | ||
191 | fn test_fn_signature_for_method_with_arg_as_assoc_fn() { | ||
192 | check( | ||
193 | r#" | ||
194 | struct S; | ||
195 | impl S { | ||
196 | fn foo(&self, x: i32) {} | ||
197 | } | ||
198 | |||
199 | fn main() { S::foo(<|>); } | ||
200 | "#, | ||
201 | expect![[r#" | ||
202 | fn foo(self: &S, x: i32) | ||
203 | (<self: &S>, x: i32) | ||
204 | "#]], | ||
205 | ); | ||
206 | } | ||
207 | |||
208 | #[test] | ||
209 | fn test_fn_signature_with_docs_simple() { | ||
210 | check( | ||
211 | r#" | ||
212 | /// test | ||
213 | // non-doc-comment | ||
214 | fn foo(j: u32) -> u32 { | ||
215 | j | ||
216 | } | ||
217 | |||
218 | fn bar() { | ||
219 | let _ = foo(<|>); | ||
220 | } | ||
221 | "#, | ||
222 | expect![[r#" | ||
223 | test | ||
224 | ------ | ||
225 | fn foo(j: u32) -> u32 | ||
226 | (<j: u32>) | ||
227 | "#]], | ||
228 | ); | ||
229 | } | ||
230 | |||
231 | #[test] | ||
232 | fn test_fn_signature_with_docs() { | ||
233 | check( | ||
234 | r#" | ||
235 | /// Adds one to the number given. | ||
236 | /// | ||
237 | /// # Examples | ||
238 | /// | ||
239 | /// ``` | ||
240 | /// let five = 5; | ||
241 | /// | ||
242 | /// assert_eq!(6, my_crate::add_one(5)); | ||
243 | /// ``` | ||
244 | pub fn add_one(x: i32) -> i32 { | ||
245 | x + 1 | ||
246 | } | ||
247 | |||
248 | pub fn do() { | ||
249 | add_one(<|> | ||
250 | }"#, | ||
251 | expect![[r##" | ||
252 | Adds one to the number given. | ||
253 | |||
254 | # Examples | ||
255 | |||
256 | ``` | ||
257 | let five = 5; | ||
258 | |||
259 | assert_eq!(6, my_crate::add_one(5)); | ||
260 | ``` | ||
261 | ------ | ||
262 | fn add_one(x: i32) -> i32 | ||
263 | (<x: i32>) | ||
264 | "##]], | ||
265 | ); | ||
266 | } | ||
267 | |||
268 | #[test] | ||
269 | fn test_fn_signature_with_docs_impl() { | ||
270 | check( | ||
271 | r#" | ||
272 | struct addr; | ||
273 | impl addr { | ||
274 | /// Adds one to the number given. | ||
275 | /// | ||
276 | /// # Examples | ||
277 | /// | ||
278 | /// ``` | ||
279 | /// let five = 5; | ||
280 | /// | ||
281 | /// assert_eq!(6, my_crate::add_one(5)); | ||
282 | /// ``` | ||
283 | pub fn add_one(x: i32) -> i32 { | ||
284 | x + 1 | ||
285 | } | ||
286 | } | ||
287 | |||
288 | pub fn do_it() { | ||
289 | addr {}; | ||
290 | addr::add_one(<|>); | ||
291 | } | ||
292 | "#, | ||
293 | expect![[r##" | ||
294 | Adds one to the number given. | ||
295 | |||
296 | # Examples | ||
297 | |||
298 | ``` | ||
299 | let five = 5; | ||
300 | |||
301 | assert_eq!(6, my_crate::add_one(5)); | ||
302 | ``` | ||
303 | ------ | ||
304 | fn add_one(x: i32) -> i32 | ||
305 | (<x: i32>) | ||
306 | "##]], | ||
307 | ); | ||
308 | } | ||
309 | |||
310 | #[test] | ||
311 | fn test_fn_signature_with_docs_from_actix() { | ||
312 | check( | ||
313 | r#" | ||
314 | struct WriteHandler<E>; | ||
315 | |||
316 | impl<E> WriteHandler<E> { | ||
317 | /// Method is called when writer emits error. | ||
318 | /// | ||
319 | /// If this method returns `ErrorAction::Continue` writer processing | ||
320 | /// continues otherwise stream processing stops. | ||
321 | fn error(&mut self, err: E, ctx: &mut Self::Context) -> Running { | ||
322 | Running::Stop | ||
323 | } | ||
324 | |||
325 | /// Method is called when writer finishes. | ||
326 | /// | ||
327 | /// By default this method stops actor's `Context`. | ||
328 | fn finished(&mut self, ctx: &mut Self::Context) { | ||
329 | ctx.stop() | ||
330 | } | ||
331 | } | ||
332 | |||
333 | pub fn foo(mut r: WriteHandler<()>) { | ||
334 | r.finished(<|>); | ||
335 | } | ||
336 | "#, | ||
337 | expect![[r#" | ||
338 | Method is called when writer finishes. | ||
339 | |||
340 | By default this method stops actor's `Context`. | ||
341 | ------ | ||
342 | fn finished(&mut self, ctx: &mut {unknown}) | ||
343 | (<ctx: &mut {unknown}>) | ||
344 | "#]], | ||
345 | ); | ||
346 | } | ||
347 | |||
348 | #[test] | ||
349 | fn call_info_bad_offset() { | ||
350 | mark::check!(call_info_bad_offset); | ||
351 | check( | ||
352 | r#" | ||
353 | fn foo(x: u32, y: u32) -> u32 {x + y} | ||
354 | fn bar() { foo <|> (3, ); } | ||
355 | "#, | ||
356 | expect![[""]], | ||
357 | ); | ||
358 | } | ||
359 | |||
360 | #[test] | ||
361 | fn test_nested_method_in_lambda() { | ||
362 | check( | ||
363 | r#" | ||
364 | struct Foo; | ||
365 | impl Foo { fn bar(&self, _: u32) { } } | ||
366 | |||
367 | fn bar(_: u32) { } | ||
368 | |||
369 | fn main() { | ||
370 | let foo = Foo; | ||
371 | std::thread::spawn(move || foo.bar(<|>)); | ||
372 | } | ||
373 | "#, | ||
374 | expect![[r#" | ||
375 | fn bar(&self, _: u32) | ||
376 | (<_: u32>) | ||
377 | "#]], | ||
378 | ); | ||
379 | } | ||
380 | |||
381 | #[test] | ||
382 | fn works_for_tuple_structs() { | ||
383 | check( | ||
384 | r#" | ||
385 | /// A cool tuple struct | ||
386 | struct S(u32, i32); | ||
387 | fn main() { | ||
388 | let s = S(0, <|>); | ||
389 | } | ||
390 | "#, | ||
391 | expect![[r#" | ||
392 | A cool tuple struct | ||
393 | ------ | ||
394 | struct S(u32, i32) | ||
395 | (u32, <i32>) | ||
396 | "#]], | ||
397 | ); | ||
398 | } | ||
399 | |||
400 | #[test] | ||
401 | fn generic_struct() { | ||
402 | check( | ||
403 | r#" | ||
404 | struct S<T>(T); | ||
405 | fn main() { | ||
406 | let s = S(<|>); | ||
407 | } | ||
408 | "#, | ||
409 | expect![[r#" | ||
410 | struct S({unknown}) | ||
411 | (<{unknown}>) | ||
412 | "#]], | ||
413 | ); | ||
414 | } | ||
415 | |||
416 | #[test] | ||
417 | fn works_for_enum_variants() { | ||
418 | check( | ||
419 | r#" | ||
420 | enum E { | ||
421 | /// A Variant | ||
422 | A(i32), | ||
423 | /// Another | ||
424 | B, | ||
425 | /// And C | ||
426 | C { a: i32, b: i32 } | ||
427 | } | ||
428 | |||
429 | fn main() { | ||
430 | let a = E::A(<|>); | ||
431 | } | ||
432 | "#, | ||
433 | expect![[r#" | ||
434 | A Variant | ||
435 | ------ | ||
436 | enum E::A(i32) | ||
437 | (<i32>) | ||
438 | "#]], | ||
439 | ); | ||
440 | } | ||
441 | |||
442 | #[test] | ||
443 | fn cant_call_struct_record() { | ||
444 | check( | ||
445 | r#" | ||
446 | struct S { x: u32, y: i32 } | ||
447 | fn main() { | ||
448 | let s = S(<|>); | ||
449 | } | ||
450 | "#, | ||
451 | expect![[""]], | ||
452 | ); | ||
453 | } | ||
454 | |||
455 | #[test] | ||
456 | fn cant_call_enum_record() { | ||
457 | check( | ||
458 | r#" | ||
459 | enum E { | ||
460 | /// A Variant | ||
461 | A(i32), | ||
462 | /// Another | ||
463 | B, | ||
464 | /// And C | ||
465 | C { a: i32, b: i32 } | ||
466 | } | ||
467 | |||
468 | fn main() { | ||
469 | let a = E::C(<|>); | ||
470 | } | ||
471 | "#, | ||
472 | expect![[""]], | ||
473 | ); | ||
474 | } | ||
475 | |||
476 | #[test] | ||
477 | fn fn_signature_for_call_in_macro() { | ||
478 | check( | ||
479 | r#" | ||
480 | macro_rules! id { ($($tt:tt)*) => { $($tt)* } } | ||
481 | fn foo() { } | ||
482 | id! { | ||
483 | fn bar() { foo(<|>); } | ||
484 | } | ||
485 | "#, | ||
486 | expect![[r#" | ||
487 | fn foo() | ||
488 | () | ||
489 | "#]], | ||
490 | ); | ||
491 | } | ||
492 | |||
493 | #[test] | ||
494 | fn call_info_for_lambdas() { | ||
495 | check( | ||
496 | r#" | ||
497 | struct S; | ||
498 | fn foo(s: S) -> i32 { 92 } | ||
499 | fn main() { | ||
500 | (|s| foo(s))(<|>) | ||
501 | } | ||
502 | "#, | ||
503 | expect![[r#" | ||
504 | (S) -> i32 | ||
505 | (<S>) | ||
506 | "#]], | ||
507 | ) | ||
508 | } | ||
509 | |||
510 | #[test] | ||
511 | fn call_info_for_fn_ptr() { | ||
512 | check( | ||
513 | r#" | ||
514 | fn main(f: fn(i32, f64) -> char) { | ||
515 | f(0, <|>) | ||
516 | } | ||
517 | "#, | ||
518 | expect![[r#" | ||
519 | (i32, f64) -> char | ||
520 | (i32, <f64>) | ||
521 | "#]], | ||
522 | ) | ||
523 | } | ||
diff --git a/crates/ide_db/src/defs.rs b/crates/ide_db/src/defs.rs index 201a3d6fa..5d2cd30d1 100644 --- a/crates/ide_db/src/defs.rs +++ b/crates/ide_db/src/defs.rs | |||
@@ -258,7 +258,7 @@ impl NameRefClass { | |||
258 | sema: &Semantics<RootDatabase>, | 258 | sema: &Semantics<RootDatabase>, |
259 | name_ref: &ast::NameRef, | 259 | name_ref: &ast::NameRef, |
260 | ) -> Option<NameRefClass> { | 260 | ) -> Option<NameRefClass> { |
261 | let _p = profile::span("classify_name_ref"); | 261 | let _p = profile::span("classify_name_ref").detail(|| name_ref.to_string()); |
262 | 262 | ||
263 | let parent = name_ref.syntax().parent()?; | 263 | let parent = name_ref.syntax().parent()?; |
264 | 264 | ||
diff --git a/crates/ide_db/src/helpers/insert_use.rs b/crates/ide_db/src/helpers/insert_use.rs index 08d246c16..040843990 100644 --- a/crates/ide_db/src/helpers/insert_use.rs +++ b/crates/ide_db/src/helpers/insert_use.rs | |||
@@ -573,641 +573,4 @@ fn find_insert_position( | |||
573 | } | 573 | } |
574 | 574 | ||
575 | #[cfg(test)] | 575 | #[cfg(test)] |
576 | mod tests { | 576 | mod tests; |
577 | use super::*; | ||
578 | |||
579 | use test_utils::assert_eq_text; | ||
580 | |||
581 | #[test] | ||
582 | fn insert_existing() { | ||
583 | check_full("std::fs", "use std::fs;", "use std::fs;") | ||
584 | } | ||
585 | |||
586 | #[test] | ||
587 | fn insert_start() { | ||
588 | check_none( | ||
589 | "std::bar::AA", | ||
590 | r" | ||
591 | use std::bar::B; | ||
592 | use std::bar::D; | ||
593 | use std::bar::F; | ||
594 | use std::bar::G;", | ||
595 | r" | ||
596 | use std::bar::AA; | ||
597 | use std::bar::B; | ||
598 | use std::bar::D; | ||
599 | use std::bar::F; | ||
600 | use std::bar::G;", | ||
601 | ) | ||
602 | } | ||
603 | |||
604 | #[test] | ||
605 | fn insert_start_indent() { | ||
606 | mark::check!(insert_use_indent_after); | ||
607 | check_none( | ||
608 | "std::bar::AA", | ||
609 | r" | ||
610 | use std::bar::B; | ||
611 | use std::bar::D;", | ||
612 | r" | ||
613 | use std::bar::AA; | ||
614 | use std::bar::B; | ||
615 | use std::bar::D;", | ||
616 | ) | ||
617 | } | ||
618 | |||
619 | #[test] | ||
620 | fn insert_middle() { | ||
621 | check_none( | ||
622 | "std::bar::EE", | ||
623 | r" | ||
624 | use std::bar::A; | ||
625 | use std::bar::D; | ||
626 | use std::bar::F; | ||
627 | use std::bar::G;", | ||
628 | r" | ||
629 | use std::bar::A; | ||
630 | use std::bar::D; | ||
631 | use std::bar::EE; | ||
632 | use std::bar::F; | ||
633 | use std::bar::G;", | ||
634 | ) | ||
635 | } | ||
636 | |||
637 | #[test] | ||
638 | fn insert_middle_indent() { | ||
639 | check_none( | ||
640 | "std::bar::EE", | ||
641 | r" | ||
642 | use std::bar::A; | ||
643 | use std::bar::D; | ||
644 | use std::bar::F; | ||
645 | use std::bar::G;", | ||
646 | r" | ||
647 | use std::bar::A; | ||
648 | use std::bar::D; | ||
649 | use std::bar::EE; | ||
650 | use std::bar::F; | ||
651 | use std::bar::G;", | ||
652 | ) | ||
653 | } | ||
654 | |||
655 | #[test] | ||
656 | fn insert_end() { | ||
657 | check_none( | ||
658 | "std::bar::ZZ", | ||
659 | r" | ||
660 | use std::bar::A; | ||
661 | use std::bar::D; | ||
662 | use std::bar::F; | ||
663 | use std::bar::G;", | ||
664 | r" | ||
665 | use std::bar::A; | ||
666 | use std::bar::D; | ||
667 | use std::bar::F; | ||
668 | use std::bar::G; | ||
669 | use std::bar::ZZ;", | ||
670 | ) | ||
671 | } | ||
672 | |||
673 | #[test] | ||
674 | fn insert_end_indent() { | ||
675 | mark::check!(insert_use_indent_before); | ||
676 | check_none( | ||
677 | "std::bar::ZZ", | ||
678 | r" | ||
679 | use std::bar::A; | ||
680 | use std::bar::D; | ||
681 | use std::bar::F; | ||
682 | use std::bar::G;", | ||
683 | r" | ||
684 | use std::bar::A; | ||
685 | use std::bar::D; | ||
686 | use std::bar::F; | ||
687 | use std::bar::G; | ||
688 | use std::bar::ZZ;", | ||
689 | ) | ||
690 | } | ||
691 | |||
692 | #[test] | ||
693 | fn insert_middle_nested() { | ||
694 | check_none( | ||
695 | "std::bar::EE", | ||
696 | r" | ||
697 | use std::bar::A; | ||
698 | use std::bar::{D, Z}; // example of weird imports due to user | ||
699 | use std::bar::F; | ||
700 | use std::bar::G;", | ||
701 | r" | ||
702 | use std::bar::A; | ||
703 | use std::bar::EE; | ||
704 | use std::bar::{D, Z}; // example of weird imports due to user | ||
705 | use std::bar::F; | ||
706 | use std::bar::G;", | ||
707 | ) | ||
708 | } | ||
709 | |||
710 | #[test] | ||
711 | fn insert_middle_groups() { | ||
712 | check_none( | ||
713 | "foo::bar::GG", | ||
714 | r" | ||
715 | use std::bar::A; | ||
716 | use std::bar::D; | ||
717 | |||
718 | use foo::bar::F; | ||
719 | use foo::bar::H;", | ||
720 | r" | ||
721 | use std::bar::A; | ||
722 | use std::bar::D; | ||
723 | |||
724 | use foo::bar::F; | ||
725 | use foo::bar::GG; | ||
726 | use foo::bar::H;", | ||
727 | ) | ||
728 | } | ||
729 | |||
730 | #[test] | ||
731 | fn insert_first_matching_group() { | ||
732 | check_none( | ||
733 | "foo::bar::GG", | ||
734 | r" | ||
735 | use foo::bar::A; | ||
736 | use foo::bar::D; | ||
737 | |||
738 | use std; | ||
739 | |||
740 | use foo::bar::F; | ||
741 | use foo::bar::H;", | ||
742 | r" | ||
743 | use foo::bar::A; | ||
744 | use foo::bar::D; | ||
745 | use foo::bar::GG; | ||
746 | |||
747 | use std; | ||
748 | |||
749 | use foo::bar::F; | ||
750 | use foo::bar::H;", | ||
751 | ) | ||
752 | } | ||
753 | |||
754 | #[test] | ||
755 | fn insert_missing_group_std() { | ||
756 | check_none( | ||
757 | "std::fmt", | ||
758 | r" | ||
759 | use foo::bar::A; | ||
760 | use foo::bar::D;", | ||
761 | r" | ||
762 | use std::fmt; | ||
763 | |||
764 | use foo::bar::A; | ||
765 | use foo::bar::D;", | ||
766 | ) | ||
767 | } | ||
768 | |||
769 | #[test] | ||
770 | fn insert_missing_group_self() { | ||
771 | check_none( | ||
772 | "self::fmt", | ||
773 | r" | ||
774 | use foo::bar::A; | ||
775 | use foo::bar::D;", | ||
776 | r" | ||
777 | use foo::bar::A; | ||
778 | use foo::bar::D; | ||
779 | |||
780 | use self::fmt;", | ||
781 | ) | ||
782 | } | ||
783 | |||
784 | #[test] | ||
785 | fn insert_no_imports() { | ||
786 | check_full( | ||
787 | "foo::bar", | ||
788 | "fn main() {}", | ||
789 | r"use foo::bar; | ||
790 | |||
791 | fn main() {}", | ||
792 | ) | ||
793 | } | ||
794 | |||
795 | #[test] | ||
796 | fn insert_empty_file() { | ||
797 | // empty files will get two trailing newlines | ||
798 | // this is due to the test case insert_no_imports above | ||
799 | check_full( | ||
800 | "foo::bar", | ||
801 | "", | ||
802 | r"use foo::bar; | ||
803 | |||
804 | ", | ||
805 | ) | ||
806 | } | ||
807 | |||
808 | #[test] | ||
809 | fn insert_empty_module() { | ||
810 | mark::check!(insert_use_no_indent_after); | ||
811 | check( | ||
812 | "foo::bar", | ||
813 | "mod x {}", | ||
814 | r"{ | ||
815 | use foo::bar; | ||
816 | }", | ||
817 | None, | ||
818 | true, | ||
819 | ) | ||
820 | } | ||
821 | |||
822 | #[test] | ||
823 | fn insert_after_inner_attr() { | ||
824 | check_full( | ||
825 | "foo::bar", | ||
826 | r"#![allow(unused_imports)]", | ||
827 | r"#![allow(unused_imports)] | ||
828 | |||
829 | use foo::bar;", | ||
830 | ) | ||
831 | } | ||
832 | |||
833 | #[test] | ||
834 | fn insert_after_inner_attr2() { | ||
835 | check_full( | ||
836 | "foo::bar", | ||
837 | r"#![allow(unused_imports)] | ||
838 | |||
839 | #![no_std] | ||
840 | fn main() {}", | ||
841 | r"#![allow(unused_imports)] | ||
842 | |||
843 | #![no_std] | ||
844 | |||
845 | use foo::bar; | ||
846 | fn main() {}", | ||
847 | ); | ||
848 | } | ||
849 | |||
850 | #[test] | ||
851 | fn inserts_after_single_line_inner_comments() { | ||
852 | check_none( | ||
853 | "foo::bar::Baz", | ||
854 | "//! Single line inner comments do not allow any code before them.", | ||
855 | r#"//! Single line inner comments do not allow any code before them. | ||
856 | |||
857 | use foo::bar::Baz;"#, | ||
858 | ); | ||
859 | } | ||
860 | |||
861 | #[test] | ||
862 | fn inserts_after_multiline_inner_comments() { | ||
863 | check_none( | ||
864 | "foo::bar::Baz", | ||
865 | r#"/*! Multiline inner comments do not allow any code before them. */ | ||
866 | |||
867 | /*! Still an inner comment, cannot place any code before. */ | ||
868 | fn main() {}"#, | ||
869 | r#"/*! Multiline inner comments do not allow any code before them. */ | ||
870 | |||
871 | /*! Still an inner comment, cannot place any code before. */ | ||
872 | |||
873 | use foo::bar::Baz; | ||
874 | fn main() {}"#, | ||
875 | ) | ||
876 | } | ||
877 | |||
878 | #[test] | ||
879 | fn inserts_after_all_inner_items() { | ||
880 | check_none( | ||
881 | "foo::bar::Baz", | ||
882 | r#"#![allow(unused_imports)] | ||
883 | /*! Multiline line comment 2 */ | ||
884 | |||
885 | |||
886 | //! Single line comment 1 | ||
887 | #![no_std] | ||
888 | //! Single line comment 2 | ||
889 | fn main() {}"#, | ||
890 | r#"#![allow(unused_imports)] | ||
891 | /*! Multiline line comment 2 */ | ||
892 | |||
893 | |||
894 | //! Single line comment 1 | ||
895 | #![no_std] | ||
896 | //! Single line comment 2 | ||
897 | |||
898 | use foo::bar::Baz; | ||
899 | fn main() {}"#, | ||
900 | ) | ||
901 | } | ||
902 | |||
903 | #[test] | ||
904 | fn merge_groups() { | ||
905 | check_last("std::io", r"use std::fmt;", r"use std::{fmt, io};") | ||
906 | } | ||
907 | |||
908 | #[test] | ||
909 | fn merge_groups_last() { | ||
910 | check_last( | ||
911 | "std::io", | ||
912 | r"use std::fmt::{Result, Display};", | ||
913 | r"use std::fmt::{Result, Display}; | ||
914 | use std::io;", | ||
915 | ) | ||
916 | } | ||
917 | |||
918 | #[test] | ||
919 | fn merge_last_into_self() { | ||
920 | check_last("foo::bar::baz", r"use foo::bar;", r"use foo::bar::{self, baz};"); | ||
921 | } | ||
922 | |||
923 | #[test] | ||
924 | fn merge_groups_full() { | ||
925 | check_full( | ||
926 | "std::io", | ||
927 | r"use std::fmt::{Result, Display};", | ||
928 | r"use std::{fmt::{Result, Display}, io};", | ||
929 | ) | ||
930 | } | ||
931 | |||
932 | #[test] | ||
933 | fn merge_groups_long_full() { | ||
934 | check_full( | ||
935 | "std::foo::bar::Baz", | ||
936 | r"use std::foo::bar::Qux;", | ||
937 | r"use std::foo::bar::{Baz, Qux};", | ||
938 | ) | ||
939 | } | ||
940 | |||
941 | #[test] | ||
942 | fn merge_groups_long_last() { | ||
943 | check_last( | ||
944 | "std::foo::bar::Baz", | ||
945 | r"use std::foo::bar::Qux;", | ||
946 | r"use std::foo::bar::{Baz, Qux};", | ||
947 | ) | ||
948 | } | ||
949 | |||
950 | #[test] | ||
951 | fn merge_groups_long_full_list() { | ||
952 | check_full( | ||
953 | "std::foo::bar::Baz", | ||
954 | r"use std::foo::bar::{Qux, Quux};", | ||
955 | r"use std::foo::bar::{Baz, Quux, Qux};", | ||
956 | ) | ||
957 | } | ||
958 | |||
959 | #[test] | ||
960 | fn merge_groups_long_last_list() { | ||
961 | check_last( | ||
962 | "std::foo::bar::Baz", | ||
963 | r"use std::foo::bar::{Qux, Quux};", | ||
964 | r"use std::foo::bar::{Baz, Quux, Qux};", | ||
965 | ) | ||
966 | } | ||
967 | |||
968 | #[test] | ||
969 | fn merge_groups_long_full_nested() { | ||
970 | check_full( | ||
971 | "std::foo::bar::Baz", | ||
972 | r"use std::foo::bar::{Qux, quux::{Fez, Fizz}};", | ||
973 | r"use std::foo::bar::{Baz, Qux, quux::{Fez, Fizz}};", | ||
974 | ) | ||
975 | } | ||
976 | |||
977 | #[test] | ||
978 | fn merge_groups_long_last_nested() { | ||
979 | check_last( | ||
980 | "std::foo::bar::Baz", | ||
981 | r"use std::foo::bar::{Qux, quux::{Fez, Fizz}};", | ||
982 | r"use std::foo::bar::Baz; | ||
983 | use std::foo::bar::{Qux, quux::{Fez, Fizz}};", | ||
984 | ) | ||
985 | } | ||
986 | |||
987 | #[test] | ||
988 | fn merge_groups_full_nested_deep() { | ||
989 | check_full( | ||
990 | "std::foo::bar::quux::Baz", | ||
991 | r"use std::foo::bar::{Qux, quux::{Fez, Fizz}};", | ||
992 | r"use std::foo::bar::{Qux, quux::{Baz, Fez, Fizz}};", | ||
993 | ) | ||
994 | } | ||
995 | |||
996 | #[test] | ||
997 | fn merge_groups_full_nested_long() { | ||
998 | check_full( | ||
999 | "std::foo::bar::Baz", | ||
1000 | r"use std::{foo::bar::Qux};", | ||
1001 | r"use std::{foo::bar::{Baz, Qux}};", | ||
1002 | ); | ||
1003 | } | ||
1004 | |||
1005 | #[test] | ||
1006 | fn merge_groups_last_nested_long() { | ||
1007 | check_full( | ||
1008 | "std::foo::bar::Baz", | ||
1009 | r"use std::{foo::bar::Qux};", | ||
1010 | r"use std::{foo::bar::{Baz, Qux}};", | ||
1011 | ); | ||
1012 | } | ||
1013 | |||
1014 | #[test] | ||
1015 | fn merge_groups_skip_pub() { | ||
1016 | check_full( | ||
1017 | "std::io", | ||
1018 | r"pub use std::fmt::{Result, Display};", | ||
1019 | r"pub use std::fmt::{Result, Display}; | ||
1020 | use std::io;", | ||
1021 | ) | ||
1022 | } | ||
1023 | |||
1024 | #[test] | ||
1025 | fn merge_groups_skip_pub_crate() { | ||
1026 | check_full( | ||
1027 | "std::io", | ||
1028 | r"pub(crate) use std::fmt::{Result, Display};", | ||
1029 | r"pub(crate) use std::fmt::{Result, Display}; | ||
1030 | use std::io;", | ||
1031 | ) | ||
1032 | } | ||
1033 | |||
1034 | #[test] | ||
1035 | #[ignore] // FIXME: Support this | ||
1036 | fn split_out_merge() { | ||
1037 | check_last( | ||
1038 | "std::fmt::Result", | ||
1039 | r"use std::{fmt, io};", | ||
1040 | r"use std::fmt::{self, Result}; | ||
1041 | use std::io;", | ||
1042 | ) | ||
1043 | } | ||
1044 | |||
1045 | #[test] | ||
1046 | fn merge_into_module_import() { | ||
1047 | check_full( | ||
1048 | "std::fmt::Result", | ||
1049 | r"use std::{fmt, io};", | ||
1050 | r"use std::{fmt::{self, Result}, io};", | ||
1051 | ) | ||
1052 | } | ||
1053 | |||
1054 | #[test] | ||
1055 | fn merge_groups_self() { | ||
1056 | check_full("std::fmt::Debug", r"use std::fmt;", r"use std::fmt::{self, Debug};") | ||
1057 | } | ||
1058 | |||
1059 | #[test] | ||
1060 | fn merge_mod_into_glob() { | ||
1061 | check_full( | ||
1062 | "token::TokenKind", | ||
1063 | r"use token::TokenKind::*;", | ||
1064 | r"use token::TokenKind::{*, self};", | ||
1065 | ) | ||
1066 | // FIXME: have it emit `use token::TokenKind::{self, *}`? | ||
1067 | } | ||
1068 | |||
1069 | #[test] | ||
1070 | fn merge_self_glob() { | ||
1071 | check_full("self", r"use self::*;", r"use self::{*, self};") | ||
1072 | // FIXME: have it emit `use {self, *}`? | ||
1073 | } | ||
1074 | |||
1075 | #[test] | ||
1076 | fn merge_glob_nested() { | ||
1077 | check_full( | ||
1078 | "foo::bar::quux::Fez", | ||
1079 | r"use foo::bar::{Baz, quux::*};", | ||
1080 | r"use foo::bar::{Baz, quux::{self::*, Fez}};", | ||
1081 | ) | ||
1082 | } | ||
1083 | |||
1084 | #[test] | ||
1085 | fn merge_nested_considers_first_segments() { | ||
1086 | check_full( | ||
1087 | "hir_ty::display::write_bounds_like_dyn_trait", | ||
1088 | r"use hir_ty::{autoderef, display::{HirDisplayError, HirFormatter}, method_resolution};", | ||
1089 | r"use hir_ty::{autoderef, display::{HirDisplayError, HirFormatter, write_bounds_like_dyn_trait}, method_resolution};", | ||
1090 | ); | ||
1091 | } | ||
1092 | |||
1093 | #[test] | ||
1094 | fn skip_merge_last_too_long() { | ||
1095 | check_last( | ||
1096 | "foo::bar", | ||
1097 | r"use foo::bar::baz::Qux;", | ||
1098 | r"use foo::bar; | ||
1099 | use foo::bar::baz::Qux;", | ||
1100 | ); | ||
1101 | } | ||
1102 | |||
1103 | #[test] | ||
1104 | fn skip_merge_last_too_long2() { | ||
1105 | check_last( | ||
1106 | "foo::bar::baz::Qux", | ||
1107 | r"use foo::bar;", | ||
1108 | r"use foo::bar; | ||
1109 | use foo::bar::baz::Qux;", | ||
1110 | ); | ||
1111 | } | ||
1112 | |||
1113 | #[test] | ||
1114 | fn insert_short_before_long() { | ||
1115 | check_none( | ||
1116 | "foo::bar", | ||
1117 | r"use foo::bar::baz::Qux;", | ||
1118 | r"use foo::bar; | ||
1119 | use foo::bar::baz::Qux;", | ||
1120 | ); | ||
1121 | } | ||
1122 | |||
1123 | #[test] | ||
1124 | fn merge_last_fail() { | ||
1125 | check_merge_only_fail( | ||
1126 | r"use foo::bar::{baz::{Qux, Fez}};", | ||
1127 | r"use foo::bar::{baaz::{Quux, Feez}};", | ||
1128 | MergeBehaviour::Last, | ||
1129 | ); | ||
1130 | } | ||
1131 | |||
1132 | #[test] | ||
1133 | fn merge_last_fail1() { | ||
1134 | check_merge_only_fail( | ||
1135 | r"use foo::bar::{baz::{Qux, Fez}};", | ||
1136 | r"use foo::bar::baaz::{Quux, Feez};", | ||
1137 | MergeBehaviour::Last, | ||
1138 | ); | ||
1139 | } | ||
1140 | |||
1141 | #[test] | ||
1142 | fn merge_last_fail2() { | ||
1143 | check_merge_only_fail( | ||
1144 | r"use foo::bar::baz::{Qux, Fez};", | ||
1145 | r"use foo::bar::{baaz::{Quux, Feez}};", | ||
1146 | MergeBehaviour::Last, | ||
1147 | ); | ||
1148 | } | ||
1149 | |||
1150 | #[test] | ||
1151 | fn merge_last_fail3() { | ||
1152 | check_merge_only_fail( | ||
1153 | r"use foo::bar::baz::{Qux, Fez};", | ||
1154 | r"use foo::bar::baaz::{Quux, Feez};", | ||
1155 | MergeBehaviour::Last, | ||
1156 | ); | ||
1157 | } | ||
1158 | |||
1159 | fn check( | ||
1160 | path: &str, | ||
1161 | ra_fixture_before: &str, | ||
1162 | ra_fixture_after: &str, | ||
1163 | mb: Option<MergeBehaviour>, | ||
1164 | module: bool, | ||
1165 | ) { | ||
1166 | let mut syntax = ast::SourceFile::parse(ra_fixture_before).tree().syntax().clone(); | ||
1167 | if module { | ||
1168 | syntax = syntax.descendants().find_map(ast::Module::cast).unwrap().syntax().clone(); | ||
1169 | } | ||
1170 | let file = super::ImportScope::from(syntax).unwrap(); | ||
1171 | let path = ast::SourceFile::parse(&format!("use {};", path)) | ||
1172 | .tree() | ||
1173 | .syntax() | ||
1174 | .descendants() | ||
1175 | .find_map(ast::Path::cast) | ||
1176 | .unwrap(); | ||
1177 | |||
1178 | let rewriter = insert_use(&file, path, mb); | ||
1179 | let result = rewriter.rewrite(file.as_syntax_node()).to_string(); | ||
1180 | assert_eq_text!(&result, ra_fixture_after); | ||
1181 | } | ||
1182 | |||
1183 | fn check_full(path: &str, ra_fixture_before: &str, ra_fixture_after: &str) { | ||
1184 | check(path, ra_fixture_before, ra_fixture_after, Some(MergeBehaviour::Full), false) | ||
1185 | } | ||
1186 | |||
1187 | fn check_last(path: &str, ra_fixture_before: &str, ra_fixture_after: &str) { | ||
1188 | check(path, ra_fixture_before, ra_fixture_after, Some(MergeBehaviour::Last), false) | ||
1189 | } | ||
1190 | |||
1191 | fn check_none(path: &str, ra_fixture_before: &str, ra_fixture_after: &str) { | ||
1192 | check(path, ra_fixture_before, ra_fixture_after, None, false) | ||
1193 | } | ||
1194 | |||
1195 | fn check_merge_only_fail(ra_fixture0: &str, ra_fixture1: &str, mb: MergeBehaviour) { | ||
1196 | let use0 = ast::SourceFile::parse(ra_fixture0) | ||
1197 | .tree() | ||
1198 | .syntax() | ||
1199 | .descendants() | ||
1200 | .find_map(ast::Use::cast) | ||
1201 | .unwrap(); | ||
1202 | |||
1203 | let use1 = ast::SourceFile::parse(ra_fixture1) | ||
1204 | .tree() | ||
1205 | .syntax() | ||
1206 | .descendants() | ||
1207 | .find_map(ast::Use::cast) | ||
1208 | .unwrap(); | ||
1209 | |||
1210 | let result = try_merge_imports(&use0, &use1, mb); | ||
1211 | assert_eq!(result.map(|u| u.to_string()), None); | ||
1212 | } | ||
1213 | } | ||
diff --git a/crates/ide_db/src/helpers/insert_use/tests.rs b/crates/ide_db/src/helpers/insert_use/tests.rs new file mode 100644 index 000000000..86bfa5b41 --- /dev/null +++ b/crates/ide_db/src/helpers/insert_use/tests.rs | |||
@@ -0,0 +1,620 @@ | |||
1 | use super::*; | ||
2 | |||
3 | use test_utils::assert_eq_text; | ||
4 | |||
5 | #[test] | ||
6 | fn insert_existing() { | ||
7 | check_full("std::fs", "use std::fs;", "use std::fs;") | ||
8 | } | ||
9 | |||
10 | #[test] | ||
11 | fn insert_start() { | ||
12 | check_none( | ||
13 | "std::bar::AA", | ||
14 | r" | ||
15 | use std::bar::B; | ||
16 | use std::bar::D; | ||
17 | use std::bar::F; | ||
18 | use std::bar::G;", | ||
19 | r" | ||
20 | use std::bar::AA; | ||
21 | use std::bar::B; | ||
22 | use std::bar::D; | ||
23 | use std::bar::F; | ||
24 | use std::bar::G;", | ||
25 | ) | ||
26 | } | ||
27 | |||
28 | #[test] | ||
29 | fn insert_start_indent() { | ||
30 | mark::check!(insert_use_indent_after); | ||
31 | check_none( | ||
32 | "std::bar::AA", | ||
33 | r" | ||
34 | use std::bar::B; | ||
35 | use std::bar::D;", | ||
36 | r" | ||
37 | use std::bar::AA; | ||
38 | use std::bar::B; | ||
39 | use std::bar::D;", | ||
40 | ) | ||
41 | } | ||
42 | |||
43 | #[test] | ||
44 | fn insert_middle() { | ||
45 | check_none( | ||
46 | "std::bar::EE", | ||
47 | r" | ||
48 | use std::bar::A; | ||
49 | use std::bar::D; | ||
50 | use std::bar::F; | ||
51 | use std::bar::G;", | ||
52 | r" | ||
53 | use std::bar::A; | ||
54 | use std::bar::D; | ||
55 | use std::bar::EE; | ||
56 | use std::bar::F; | ||
57 | use std::bar::G;", | ||
58 | ) | ||
59 | } | ||
60 | |||
61 | #[test] | ||
62 | fn insert_middle_indent() { | ||
63 | check_none( | ||
64 | "std::bar::EE", | ||
65 | r" | ||
66 | use std::bar::A; | ||
67 | use std::bar::D; | ||
68 | use std::bar::F; | ||
69 | use std::bar::G;", | ||
70 | r" | ||
71 | use std::bar::A; | ||
72 | use std::bar::D; | ||
73 | use std::bar::EE; | ||
74 | use std::bar::F; | ||
75 | use std::bar::G;", | ||
76 | ) | ||
77 | } | ||
78 | |||
79 | #[test] | ||
80 | fn insert_end() { | ||
81 | check_none( | ||
82 | "std::bar::ZZ", | ||
83 | r" | ||
84 | use std::bar::A; | ||
85 | use std::bar::D; | ||
86 | use std::bar::F; | ||
87 | use std::bar::G;", | ||
88 | r" | ||
89 | use std::bar::A; | ||
90 | use std::bar::D; | ||
91 | use std::bar::F; | ||
92 | use std::bar::G; | ||
93 | use std::bar::ZZ;", | ||
94 | ) | ||
95 | } | ||
96 | |||
97 | #[test] | ||
98 | fn insert_end_indent() { | ||
99 | mark::check!(insert_use_indent_before); | ||
100 | check_none( | ||
101 | "std::bar::ZZ", | ||
102 | r" | ||
103 | use std::bar::A; | ||
104 | use std::bar::D; | ||
105 | use std::bar::F; | ||
106 | use std::bar::G;", | ||
107 | r" | ||
108 | use std::bar::A; | ||
109 | use std::bar::D; | ||
110 | use std::bar::F; | ||
111 | use std::bar::G; | ||
112 | use std::bar::ZZ;", | ||
113 | ) | ||
114 | } | ||
115 | |||
116 | #[test] | ||
117 | fn insert_middle_nested() { | ||
118 | check_none( | ||
119 | "std::bar::EE", | ||
120 | r" | ||
121 | use std::bar::A; | ||
122 | use std::bar::{D, Z}; // example of weird imports due to user | ||
123 | use std::bar::F; | ||
124 | use std::bar::G;", | ||
125 | r" | ||
126 | use std::bar::A; | ||
127 | use std::bar::EE; | ||
128 | use std::bar::{D, Z}; // example of weird imports due to user | ||
129 | use std::bar::F; | ||
130 | use std::bar::G;", | ||
131 | ) | ||
132 | } | ||
133 | |||
134 | #[test] | ||
135 | fn insert_middle_groups() { | ||
136 | check_none( | ||
137 | "foo::bar::GG", | ||
138 | r" | ||
139 | use std::bar::A; | ||
140 | use std::bar::D; | ||
141 | |||
142 | use foo::bar::F; | ||
143 | use foo::bar::H;", | ||
144 | r" | ||
145 | use std::bar::A; | ||
146 | use std::bar::D; | ||
147 | |||
148 | use foo::bar::F; | ||
149 | use foo::bar::GG; | ||
150 | use foo::bar::H;", | ||
151 | ) | ||
152 | } | ||
153 | |||
154 | #[test] | ||
155 | fn insert_first_matching_group() { | ||
156 | check_none( | ||
157 | "foo::bar::GG", | ||
158 | r" | ||
159 | use foo::bar::A; | ||
160 | use foo::bar::D; | ||
161 | |||
162 | use std; | ||
163 | |||
164 | use foo::bar::F; | ||
165 | use foo::bar::H;", | ||
166 | r" | ||
167 | use foo::bar::A; | ||
168 | use foo::bar::D; | ||
169 | use foo::bar::GG; | ||
170 | |||
171 | use std; | ||
172 | |||
173 | use foo::bar::F; | ||
174 | use foo::bar::H;", | ||
175 | ) | ||
176 | } | ||
177 | |||
178 | #[test] | ||
179 | fn insert_missing_group_std() { | ||
180 | check_none( | ||
181 | "std::fmt", | ||
182 | r" | ||
183 | use foo::bar::A; | ||
184 | use foo::bar::D;", | ||
185 | r" | ||
186 | use std::fmt; | ||
187 | |||
188 | use foo::bar::A; | ||
189 | use foo::bar::D;", | ||
190 | ) | ||
191 | } | ||
192 | |||
193 | #[test] | ||
194 | fn insert_missing_group_self() { | ||
195 | check_none( | ||
196 | "self::fmt", | ||
197 | r" | ||
198 | use foo::bar::A; | ||
199 | use foo::bar::D;", | ||
200 | r" | ||
201 | use foo::bar::A; | ||
202 | use foo::bar::D; | ||
203 | |||
204 | use self::fmt;", | ||
205 | ) | ||
206 | } | ||
207 | |||
208 | #[test] | ||
209 | fn insert_no_imports() { | ||
210 | check_full( | ||
211 | "foo::bar", | ||
212 | "fn main() {}", | ||
213 | r"use foo::bar; | ||
214 | |||
215 | fn main() {}", | ||
216 | ) | ||
217 | } | ||
218 | |||
219 | #[test] | ||
220 | fn insert_empty_file() { | ||
221 | // empty files will get two trailing newlines | ||
222 | // this is due to the test case insert_no_imports above | ||
223 | check_full( | ||
224 | "foo::bar", | ||
225 | "", | ||
226 | r"use foo::bar; | ||
227 | |||
228 | ", | ||
229 | ) | ||
230 | } | ||
231 | |||
232 | #[test] | ||
233 | fn insert_empty_module() { | ||
234 | mark::check!(insert_use_no_indent_after); | ||
235 | check( | ||
236 | "foo::bar", | ||
237 | "mod x {}", | ||
238 | r"{ | ||
239 | use foo::bar; | ||
240 | }", | ||
241 | None, | ||
242 | true, | ||
243 | ) | ||
244 | } | ||
245 | |||
246 | #[test] | ||
247 | fn insert_after_inner_attr() { | ||
248 | check_full( | ||
249 | "foo::bar", | ||
250 | r"#![allow(unused_imports)]", | ||
251 | r"#![allow(unused_imports)] | ||
252 | |||
253 | use foo::bar;", | ||
254 | ) | ||
255 | } | ||
256 | |||
257 | #[test] | ||
258 | fn insert_after_inner_attr2() { | ||
259 | check_full( | ||
260 | "foo::bar", | ||
261 | r"#![allow(unused_imports)] | ||
262 | |||
263 | #![no_std] | ||
264 | fn main() {}", | ||
265 | r"#![allow(unused_imports)] | ||
266 | |||
267 | #![no_std] | ||
268 | |||
269 | use foo::bar; | ||
270 | fn main() {}", | ||
271 | ); | ||
272 | } | ||
273 | |||
274 | #[test] | ||
275 | fn inserts_after_single_line_inner_comments() { | ||
276 | check_none( | ||
277 | "foo::bar::Baz", | ||
278 | "//! Single line inner comments do not allow any code before them.", | ||
279 | r#"//! Single line inner comments do not allow any code before them. | ||
280 | |||
281 | use foo::bar::Baz;"#, | ||
282 | ); | ||
283 | } | ||
284 | |||
285 | #[test] | ||
286 | fn inserts_after_multiline_inner_comments() { | ||
287 | check_none( | ||
288 | "foo::bar::Baz", | ||
289 | r#"/*! Multiline inner comments do not allow any code before them. */ | ||
290 | |||
291 | /*! Still an inner comment, cannot place any code before. */ | ||
292 | fn main() {}"#, | ||
293 | r#"/*! Multiline inner comments do not allow any code before them. */ | ||
294 | |||
295 | /*! Still an inner comment, cannot place any code before. */ | ||
296 | |||
297 | use foo::bar::Baz; | ||
298 | fn main() {}"#, | ||
299 | ) | ||
300 | } | ||
301 | |||
302 | #[test] | ||
303 | fn inserts_after_all_inner_items() { | ||
304 | check_none( | ||
305 | "foo::bar::Baz", | ||
306 | r#"#![allow(unused_imports)] | ||
307 | /*! Multiline line comment 2 */ | ||
308 | |||
309 | |||
310 | //! Single line comment 1 | ||
311 | #![no_std] | ||
312 | //! Single line comment 2 | ||
313 | fn main() {}"#, | ||
314 | r#"#![allow(unused_imports)] | ||
315 | /*! Multiline line comment 2 */ | ||
316 | |||
317 | |||
318 | //! Single line comment 1 | ||
319 | #![no_std] | ||
320 | //! Single line comment 2 | ||
321 | |||
322 | use foo::bar::Baz; | ||
323 | fn main() {}"#, | ||
324 | ) | ||
325 | } | ||
326 | |||
327 | #[test] | ||
328 | fn merge_groups() { | ||
329 | check_last("std::io", r"use std::fmt;", r"use std::{fmt, io};") | ||
330 | } | ||
331 | |||
332 | #[test] | ||
333 | fn merge_groups_last() { | ||
334 | check_last( | ||
335 | "std::io", | ||
336 | r"use std::fmt::{Result, Display};", | ||
337 | r"use std::fmt::{Result, Display}; | ||
338 | use std::io;", | ||
339 | ) | ||
340 | } | ||
341 | |||
342 | #[test] | ||
343 | fn merge_last_into_self() { | ||
344 | check_last("foo::bar::baz", r"use foo::bar;", r"use foo::bar::{self, baz};"); | ||
345 | } | ||
346 | |||
347 | #[test] | ||
348 | fn merge_groups_full() { | ||
349 | check_full( | ||
350 | "std::io", | ||
351 | r"use std::fmt::{Result, Display};", | ||
352 | r"use std::{fmt::{Result, Display}, io};", | ||
353 | ) | ||
354 | } | ||
355 | |||
356 | #[test] | ||
357 | fn merge_groups_long_full() { | ||
358 | check_full("std::foo::bar::Baz", r"use std::foo::bar::Qux;", r"use std::foo::bar::{Baz, Qux};") | ||
359 | } | ||
360 | |||
361 | #[test] | ||
362 | fn merge_groups_long_last() { | ||
363 | check_last("std::foo::bar::Baz", r"use std::foo::bar::Qux;", r"use std::foo::bar::{Baz, Qux};") | ||
364 | } | ||
365 | |||
366 | #[test] | ||
367 | fn merge_groups_long_full_list() { | ||
368 | check_full( | ||
369 | "std::foo::bar::Baz", | ||
370 | r"use std::foo::bar::{Qux, Quux};", | ||
371 | r"use std::foo::bar::{Baz, Quux, Qux};", | ||
372 | ) | ||
373 | } | ||
374 | |||
375 | #[test] | ||
376 | fn merge_groups_long_last_list() { | ||
377 | check_last( | ||
378 | "std::foo::bar::Baz", | ||
379 | r"use std::foo::bar::{Qux, Quux};", | ||
380 | r"use std::foo::bar::{Baz, Quux, Qux};", | ||
381 | ) | ||
382 | } | ||
383 | |||
384 | #[test] | ||
385 | fn merge_groups_long_full_nested() { | ||
386 | check_full( | ||
387 | "std::foo::bar::Baz", | ||
388 | r"use std::foo::bar::{Qux, quux::{Fez, Fizz}};", | ||
389 | r"use std::foo::bar::{Baz, Qux, quux::{Fez, Fizz}};", | ||
390 | ) | ||
391 | } | ||
392 | |||
393 | #[test] | ||
394 | fn merge_groups_long_last_nested() { | ||
395 | check_last( | ||
396 | "std::foo::bar::Baz", | ||
397 | r"use std::foo::bar::{Qux, quux::{Fez, Fizz}};", | ||
398 | r"use std::foo::bar::Baz; | ||
399 | use std::foo::bar::{Qux, quux::{Fez, Fizz}};", | ||
400 | ) | ||
401 | } | ||
402 | |||
403 | #[test] | ||
404 | fn merge_groups_full_nested_deep() { | ||
405 | check_full( | ||
406 | "std::foo::bar::quux::Baz", | ||
407 | r"use std::foo::bar::{Qux, quux::{Fez, Fizz}};", | ||
408 | r"use std::foo::bar::{Qux, quux::{Baz, Fez, Fizz}};", | ||
409 | ) | ||
410 | } | ||
411 | |||
412 | #[test] | ||
413 | fn merge_groups_full_nested_long() { | ||
414 | check_full( | ||
415 | "std::foo::bar::Baz", | ||
416 | r"use std::{foo::bar::Qux};", | ||
417 | r"use std::{foo::bar::{Baz, Qux}};", | ||
418 | ); | ||
419 | } | ||
420 | |||
421 | #[test] | ||
422 | fn merge_groups_last_nested_long() { | ||
423 | check_full( | ||
424 | "std::foo::bar::Baz", | ||
425 | r"use std::{foo::bar::Qux};", | ||
426 | r"use std::{foo::bar::{Baz, Qux}};", | ||
427 | ); | ||
428 | } | ||
429 | |||
430 | #[test] | ||
431 | fn merge_groups_skip_pub() { | ||
432 | check_full( | ||
433 | "std::io", | ||
434 | r"pub use std::fmt::{Result, Display};", | ||
435 | r"pub use std::fmt::{Result, Display}; | ||
436 | use std::io;", | ||
437 | ) | ||
438 | } | ||
439 | |||
440 | #[test] | ||
441 | fn merge_groups_skip_pub_crate() { | ||
442 | check_full( | ||
443 | "std::io", | ||
444 | r"pub(crate) use std::fmt::{Result, Display};", | ||
445 | r"pub(crate) use std::fmt::{Result, Display}; | ||
446 | use std::io;", | ||
447 | ) | ||
448 | } | ||
449 | |||
450 | #[test] | ||
451 | #[ignore] // FIXME: Support this | ||
452 | fn split_out_merge() { | ||
453 | check_last( | ||
454 | "std::fmt::Result", | ||
455 | r"use std::{fmt, io};", | ||
456 | r"use std::fmt::{self, Result}; | ||
457 | use std::io;", | ||
458 | ) | ||
459 | } | ||
460 | |||
461 | #[test] | ||
462 | fn merge_into_module_import() { | ||
463 | check_full("std::fmt::Result", r"use std::{fmt, io};", r"use std::{fmt::{self, Result}, io};") | ||
464 | } | ||
465 | |||
466 | #[test] | ||
467 | fn merge_groups_self() { | ||
468 | check_full("std::fmt::Debug", r"use std::fmt;", r"use std::fmt::{self, Debug};") | ||
469 | } | ||
470 | |||
471 | #[test] | ||
472 | fn merge_mod_into_glob() { | ||
473 | check_full("token::TokenKind", r"use token::TokenKind::*;", r"use token::TokenKind::{*, self};") | ||
474 | // FIXME: have it emit `use token::TokenKind::{self, *}`? | ||
475 | } | ||
476 | |||
477 | #[test] | ||
478 | fn merge_self_glob() { | ||
479 | check_full("self", r"use self::*;", r"use self::{*, self};") | ||
480 | // FIXME: have it emit `use {self, *}`? | ||
481 | } | ||
482 | |||
483 | #[test] | ||
484 | fn merge_glob_nested() { | ||
485 | check_full( | ||
486 | "foo::bar::quux::Fez", | ||
487 | r"use foo::bar::{Baz, quux::*};", | ||
488 | r"use foo::bar::{Baz, quux::{self::*, Fez}};", | ||
489 | ) | ||
490 | } | ||
491 | |||
492 | #[test] | ||
493 | fn merge_nested_considers_first_segments() { | ||
494 | check_full( | ||
495 | "hir_ty::display::write_bounds_like_dyn_trait", | ||
496 | r"use hir_ty::{autoderef, display::{HirDisplayError, HirFormatter}, method_resolution};", | ||
497 | r"use hir_ty::{autoderef, display::{HirDisplayError, HirFormatter, write_bounds_like_dyn_trait}, method_resolution};", | ||
498 | ); | ||
499 | } | ||
500 | |||
501 | #[test] | ||
502 | fn skip_merge_last_too_long() { | ||
503 | check_last( | ||
504 | "foo::bar", | ||
505 | r"use foo::bar::baz::Qux;", | ||
506 | r"use foo::bar; | ||
507 | use foo::bar::baz::Qux;", | ||
508 | ); | ||
509 | } | ||
510 | |||
511 | #[test] | ||
512 | fn skip_merge_last_too_long2() { | ||
513 | check_last( | ||
514 | "foo::bar::baz::Qux", | ||
515 | r"use foo::bar;", | ||
516 | r"use foo::bar; | ||
517 | use foo::bar::baz::Qux;", | ||
518 | ); | ||
519 | } | ||
520 | |||
521 | #[test] | ||
522 | fn insert_short_before_long() { | ||
523 | check_none( | ||
524 | "foo::bar", | ||
525 | r"use foo::bar::baz::Qux;", | ||
526 | r"use foo::bar; | ||
527 | use foo::bar::baz::Qux;", | ||
528 | ); | ||
529 | } | ||
530 | |||
531 | #[test] | ||
532 | fn merge_last_fail() { | ||
533 | check_merge_only_fail( | ||
534 | r"use foo::bar::{baz::{Qux, Fez}};", | ||
535 | r"use foo::bar::{baaz::{Quux, Feez}};", | ||
536 | MergeBehaviour::Last, | ||
537 | ); | ||
538 | } | ||
539 | |||
540 | #[test] | ||
541 | fn merge_last_fail1() { | ||
542 | check_merge_only_fail( | ||
543 | r"use foo::bar::{baz::{Qux, Fez}};", | ||
544 | r"use foo::bar::baaz::{Quux, Feez};", | ||
545 | MergeBehaviour::Last, | ||
546 | ); | ||
547 | } | ||
548 | |||
549 | #[test] | ||
550 | fn merge_last_fail2() { | ||
551 | check_merge_only_fail( | ||
552 | r"use foo::bar::baz::{Qux, Fez};", | ||
553 | r"use foo::bar::{baaz::{Quux, Feez}};", | ||
554 | MergeBehaviour::Last, | ||
555 | ); | ||
556 | } | ||
557 | |||
558 | #[test] | ||
559 | fn merge_last_fail3() { | ||
560 | check_merge_only_fail( | ||
561 | r"use foo::bar::baz::{Qux, Fez};", | ||
562 | r"use foo::bar::baaz::{Quux, Feez};", | ||
563 | MergeBehaviour::Last, | ||
564 | ); | ||
565 | } | ||
566 | |||
567 | fn check( | ||
568 | path: &str, | ||
569 | ra_fixture_before: &str, | ||
570 | ra_fixture_after: &str, | ||
571 | mb: Option<MergeBehaviour>, | ||
572 | module: bool, | ||
573 | ) { | ||
574 | let mut syntax = ast::SourceFile::parse(ra_fixture_before).tree().syntax().clone(); | ||
575 | if module { | ||
576 | syntax = syntax.descendants().find_map(ast::Module::cast).unwrap().syntax().clone(); | ||
577 | } | ||
578 | let file = super::ImportScope::from(syntax).unwrap(); | ||
579 | let path = ast::SourceFile::parse(&format!("use {};", path)) | ||
580 | .tree() | ||
581 | .syntax() | ||
582 | .descendants() | ||
583 | .find_map(ast::Path::cast) | ||
584 | .unwrap(); | ||
585 | |||
586 | let rewriter = insert_use(&file, path, mb); | ||
587 | let result = rewriter.rewrite(file.as_syntax_node()).to_string(); | ||
588 | assert_eq_text!(&result, ra_fixture_after); | ||
589 | } | ||
590 | |||
591 | fn check_full(path: &str, ra_fixture_before: &str, ra_fixture_after: &str) { | ||
592 | check(path, ra_fixture_before, ra_fixture_after, Some(MergeBehaviour::Full), false) | ||
593 | } | ||
594 | |||
595 | fn check_last(path: &str, ra_fixture_before: &str, ra_fixture_after: &str) { | ||
596 | check(path, ra_fixture_before, ra_fixture_after, Some(MergeBehaviour::Last), false) | ||
597 | } | ||
598 | |||
599 | fn check_none(path: &str, ra_fixture_before: &str, ra_fixture_after: &str) { | ||
600 | check(path, ra_fixture_before, ra_fixture_after, None, false) | ||
601 | } | ||
602 | |||
603 | fn check_merge_only_fail(ra_fixture0: &str, ra_fixture1: &str, mb: MergeBehaviour) { | ||
604 | let use0 = ast::SourceFile::parse(ra_fixture0) | ||
605 | .tree() | ||
606 | .syntax() | ||
607 | .descendants() | ||
608 | .find_map(ast::Use::cast) | ||
609 | .unwrap(); | ||
610 | |||
611 | let use1 = ast::SourceFile::parse(ra_fixture1) | ||
612 | .tree() | ||
613 | .syntax() | ||
614 | .descendants() | ||
615 | .find_map(ast::Use::cast) | ||
616 | .unwrap(); | ||
617 | |||
618 | let result = try_merge_imports(&use0, &use1, mb); | ||
619 | assert_eq!(result.map(|u| u.to_string()), None); | ||
620 | } | ||
diff --git a/crates/ide_db/src/line_index.rs b/crates/ide_db/src/line_index.rs index a381f7fb8..41226305e 100644 --- a/crates/ide_db/src/line_index.rs +++ b/crates/ide_db/src/line_index.rs | |||
@@ -149,133 +149,4 @@ impl LineIndex { | |||
149 | } | 149 | } |
150 | 150 | ||
151 | #[cfg(test)] | 151 | #[cfg(test)] |
152 | mod tests { | 152 | mod tests; |
153 | use super::*; | ||
154 | |||
155 | #[test] | ||
156 | fn test_line_index() { | ||
157 | let text = "hello\nworld"; | ||
158 | let index = LineIndex::new(text); | ||
159 | assert_eq!(index.line_col(0.into()), LineCol { line: 0, col_utf16: 0 }); | ||
160 | assert_eq!(index.line_col(1.into()), LineCol { line: 0, col_utf16: 1 }); | ||
161 | assert_eq!(index.line_col(5.into()), LineCol { line: 0, col_utf16: 5 }); | ||
162 | assert_eq!(index.line_col(6.into()), LineCol { line: 1, col_utf16: 0 }); | ||
163 | assert_eq!(index.line_col(7.into()), LineCol { line: 1, col_utf16: 1 }); | ||
164 | assert_eq!(index.line_col(8.into()), LineCol { line: 1, col_utf16: 2 }); | ||
165 | assert_eq!(index.line_col(10.into()), LineCol { line: 1, col_utf16: 4 }); | ||
166 | assert_eq!(index.line_col(11.into()), LineCol { line: 1, col_utf16: 5 }); | ||
167 | assert_eq!(index.line_col(12.into()), LineCol { line: 1, col_utf16: 6 }); | ||
168 | |||
169 | let text = "\nhello\nworld"; | ||
170 | let index = LineIndex::new(text); | ||
171 | assert_eq!(index.line_col(0.into()), LineCol { line: 0, col_utf16: 0 }); | ||
172 | assert_eq!(index.line_col(1.into()), LineCol { line: 1, col_utf16: 0 }); | ||
173 | assert_eq!(index.line_col(2.into()), LineCol { line: 1, col_utf16: 1 }); | ||
174 | assert_eq!(index.line_col(6.into()), LineCol { line: 1, col_utf16: 5 }); | ||
175 | assert_eq!(index.line_col(7.into()), LineCol { line: 2, col_utf16: 0 }); | ||
176 | } | ||
177 | |||
178 | #[test] | ||
179 | fn test_char_len() { | ||
180 | assert_eq!('メ'.len_utf8(), 3); | ||
181 | assert_eq!('メ'.len_utf16(), 1); | ||
182 | } | ||
183 | |||
184 | #[test] | ||
185 | fn test_empty_index() { | ||
186 | let col_index = LineIndex::new( | ||
187 | " | ||
188 | const C: char = 'x'; | ||
189 | ", | ||
190 | ); | ||
191 | assert_eq!(col_index.utf16_lines.len(), 0); | ||
192 | } | ||
193 | |||
194 | #[test] | ||
195 | fn test_single_char() { | ||
196 | let col_index = LineIndex::new( | ||
197 | " | ||
198 | const C: char = 'メ'; | ||
199 | ", | ||
200 | ); | ||
201 | |||
202 | assert_eq!(col_index.utf16_lines.len(), 1); | ||
203 | assert_eq!(col_index.utf16_lines[&1].len(), 1); | ||
204 | assert_eq!(col_index.utf16_lines[&1][0], Utf16Char { start: 17.into(), end: 20.into() }); | ||
205 | |||
206 | // UTF-8 to UTF-16, no changes | ||
207 | assert_eq!(col_index.utf8_to_utf16_col(1, 15.into()), 15); | ||
208 | |||
209 | // UTF-8 to UTF-16 | ||
210 | assert_eq!(col_index.utf8_to_utf16_col(1, 22.into()), 20); | ||
211 | |||
212 | // UTF-16 to UTF-8, no changes | ||
213 | assert_eq!(col_index.utf16_to_utf8_col(1, 15), TextSize::from(15)); | ||
214 | |||
215 | // UTF-16 to UTF-8 | ||
216 | assert_eq!(col_index.utf16_to_utf8_col(1, 19), TextSize::from(21)); | ||
217 | |||
218 | let col_index = LineIndex::new("a𐐏b"); | ||
219 | assert_eq!(col_index.utf16_to_utf8_col(0, 3), TextSize::from(5)); | ||
220 | } | ||
221 | |||
222 | #[test] | ||
223 | fn test_string() { | ||
224 | let col_index = LineIndex::new( | ||
225 | " | ||
226 | const C: char = \"メ メ\"; | ||
227 | ", | ||
228 | ); | ||
229 | |||
230 | assert_eq!(col_index.utf16_lines.len(), 1); | ||
231 | assert_eq!(col_index.utf16_lines[&1].len(), 2); | ||
232 | assert_eq!(col_index.utf16_lines[&1][0], Utf16Char { start: 17.into(), end: 20.into() }); | ||
233 | assert_eq!(col_index.utf16_lines[&1][1], Utf16Char { start: 21.into(), end: 24.into() }); | ||
234 | |||
235 | // UTF-8 to UTF-16 | ||
236 | assert_eq!(col_index.utf8_to_utf16_col(1, 15.into()), 15); | ||
237 | |||
238 | assert_eq!(col_index.utf8_to_utf16_col(1, 21.into()), 19); | ||
239 | assert_eq!(col_index.utf8_to_utf16_col(1, 25.into()), 21); | ||
240 | |||
241 | assert!(col_index.utf8_to_utf16_col(2, 15.into()) == 15); | ||
242 | |||
243 | // UTF-16 to UTF-8 | ||
244 | assert_eq!(col_index.utf16_to_utf8_col(1, 15), TextSize::from(15)); | ||
245 | |||
246 | // メ UTF-8: 0xE3 0x83 0xA1, UTF-16: 0x30E1 | ||
247 | assert_eq!(col_index.utf16_to_utf8_col(1, 17), TextSize::from(17)); // first メ at 17..20 | ||
248 | assert_eq!(col_index.utf16_to_utf8_col(1, 18), TextSize::from(20)); // space | ||
249 | assert_eq!(col_index.utf16_to_utf8_col(1, 19), TextSize::from(21)); // second メ at 21..24 | ||
250 | |||
251 | assert_eq!(col_index.utf16_to_utf8_col(2, 15), TextSize::from(15)); | ||
252 | } | ||
253 | |||
254 | #[test] | ||
255 | fn test_splitlines() { | ||
256 | fn r(lo: u32, hi: u32) -> TextRange { | ||
257 | TextRange::new(lo.into(), hi.into()) | ||
258 | } | ||
259 | |||
260 | let text = "a\nbb\nccc\n"; | ||
261 | let line_index = LineIndex::new(text); | ||
262 | |||
263 | let actual = line_index.lines(r(0, 9)).collect::<Vec<_>>(); | ||
264 | let expected = vec![r(0, 2), r(2, 5), r(5, 9)]; | ||
265 | assert_eq!(actual, expected); | ||
266 | |||
267 | let text = ""; | ||
268 | let line_index = LineIndex::new(text); | ||
269 | |||
270 | let actual = line_index.lines(r(0, 0)).collect::<Vec<_>>(); | ||
271 | let expected = vec![]; | ||
272 | assert_eq!(actual, expected); | ||
273 | |||
274 | let text = "\n"; | ||
275 | let line_index = LineIndex::new(text); | ||
276 | |||
277 | let actual = line_index.lines(r(0, 1)).collect::<Vec<_>>(); | ||
278 | let expected = vec![r(0, 1)]; | ||
279 | assert_eq!(actual, expected) | ||
280 | } | ||
281 | } | ||
diff --git a/crates/ide_db/src/line_index/tests.rs b/crates/ide_db/src/line_index/tests.rs new file mode 100644 index 000000000..05f7484e8 --- /dev/null +++ b/crates/ide_db/src/line_index/tests.rs | |||
@@ -0,0 +1,128 @@ | |||
1 | use super::*; | ||
2 | |||
3 | #[test] | ||
4 | fn test_line_index() { | ||
5 | let text = "hello\nworld"; | ||
6 | let index = LineIndex::new(text); | ||
7 | assert_eq!(index.line_col(0.into()), LineCol { line: 0, col_utf16: 0 }); | ||
8 | assert_eq!(index.line_col(1.into()), LineCol { line: 0, col_utf16: 1 }); | ||
9 | assert_eq!(index.line_col(5.into()), LineCol { line: 0, col_utf16: 5 }); | ||
10 | assert_eq!(index.line_col(6.into()), LineCol { line: 1, col_utf16: 0 }); | ||
11 | assert_eq!(index.line_col(7.into()), LineCol { line: 1, col_utf16: 1 }); | ||
12 | assert_eq!(index.line_col(8.into()), LineCol { line: 1, col_utf16: 2 }); | ||
13 | assert_eq!(index.line_col(10.into()), LineCol { line: 1, col_utf16: 4 }); | ||
14 | assert_eq!(index.line_col(11.into()), LineCol { line: 1, col_utf16: 5 }); | ||
15 | assert_eq!(index.line_col(12.into()), LineCol { line: 1, col_utf16: 6 }); | ||
16 | |||
17 | let text = "\nhello\nworld"; | ||
18 | let index = LineIndex::new(text); | ||
19 | assert_eq!(index.line_col(0.into()), LineCol { line: 0, col_utf16: 0 }); | ||
20 | assert_eq!(index.line_col(1.into()), LineCol { line: 1, col_utf16: 0 }); | ||
21 | assert_eq!(index.line_col(2.into()), LineCol { line: 1, col_utf16: 1 }); | ||
22 | assert_eq!(index.line_col(6.into()), LineCol { line: 1, col_utf16: 5 }); | ||
23 | assert_eq!(index.line_col(7.into()), LineCol { line: 2, col_utf16: 0 }); | ||
24 | } | ||
25 | |||
26 | #[test] | ||
27 | fn test_char_len() { | ||
28 | assert_eq!('メ'.len_utf8(), 3); | ||
29 | assert_eq!('メ'.len_utf16(), 1); | ||
30 | } | ||
31 | |||
32 | #[test] | ||
33 | fn test_empty_index() { | ||
34 | let col_index = LineIndex::new( | ||
35 | " | ||
36 | const C: char = 'x'; | ||
37 | ", | ||
38 | ); | ||
39 | assert_eq!(col_index.utf16_lines.len(), 0); | ||
40 | } | ||
41 | |||
42 | #[test] | ||
43 | fn test_single_char() { | ||
44 | let col_index = LineIndex::new( | ||
45 | " | ||
46 | const C: char = 'メ'; | ||
47 | ", | ||
48 | ); | ||
49 | |||
50 | assert_eq!(col_index.utf16_lines.len(), 1); | ||
51 | assert_eq!(col_index.utf16_lines[&1].len(), 1); | ||
52 | assert_eq!(col_index.utf16_lines[&1][0], Utf16Char { start: 17.into(), end: 20.into() }); | ||
53 | |||
54 | // UTF-8 to UTF-16, no changes | ||
55 | assert_eq!(col_index.utf8_to_utf16_col(1, 15.into()), 15); | ||
56 | |||
57 | // UTF-8 to UTF-16 | ||
58 | assert_eq!(col_index.utf8_to_utf16_col(1, 22.into()), 20); | ||
59 | |||
60 | // UTF-16 to UTF-8, no changes | ||
61 | assert_eq!(col_index.utf16_to_utf8_col(1, 15), TextSize::from(15)); | ||
62 | |||
63 | // UTF-16 to UTF-8 | ||
64 | assert_eq!(col_index.utf16_to_utf8_col(1, 19), TextSize::from(21)); | ||
65 | |||
66 | let col_index = LineIndex::new("a𐐏b"); | ||
67 | assert_eq!(col_index.utf16_to_utf8_col(0, 3), TextSize::from(5)); | ||
68 | } | ||
69 | |||
70 | #[test] | ||
71 | fn test_string() { | ||
72 | let col_index = LineIndex::new( | ||
73 | " | ||
74 | const C: char = \"メ メ\"; | ||
75 | ", | ||
76 | ); | ||
77 | |||
78 | assert_eq!(col_index.utf16_lines.len(), 1); | ||
79 | assert_eq!(col_index.utf16_lines[&1].len(), 2); | ||
80 | assert_eq!(col_index.utf16_lines[&1][0], Utf16Char { start: 17.into(), end: 20.into() }); | ||
81 | assert_eq!(col_index.utf16_lines[&1][1], Utf16Char { start: 21.into(), end: 24.into() }); | ||
82 | |||
83 | // UTF-8 to UTF-16 | ||
84 | assert_eq!(col_index.utf8_to_utf16_col(1, 15.into()), 15); | ||
85 | |||
86 | assert_eq!(col_index.utf8_to_utf16_col(1, 21.into()), 19); | ||
87 | assert_eq!(col_index.utf8_to_utf16_col(1, 25.into()), 21); | ||
88 | |||
89 | assert!(col_index.utf8_to_utf16_col(2, 15.into()) == 15); | ||
90 | |||
91 | // UTF-16 to UTF-8 | ||
92 | assert_eq!(col_index.utf16_to_utf8_col(1, 15), TextSize::from(15)); | ||
93 | |||
94 | // メ UTF-8: 0xE3 0x83 0xA1, UTF-16: 0x30E1 | ||
95 | assert_eq!(col_index.utf16_to_utf8_col(1, 17), TextSize::from(17)); // first メ at 17..20 | ||
96 | assert_eq!(col_index.utf16_to_utf8_col(1, 18), TextSize::from(20)); // space | ||
97 | assert_eq!(col_index.utf16_to_utf8_col(1, 19), TextSize::from(21)); // second メ at 21..24 | ||
98 | |||
99 | assert_eq!(col_index.utf16_to_utf8_col(2, 15), TextSize::from(15)); | ||
100 | } | ||
101 | |||
102 | #[test] | ||
103 | fn test_splitlines() { | ||
104 | fn r(lo: u32, hi: u32) -> TextRange { | ||
105 | TextRange::new(lo.into(), hi.into()) | ||
106 | } | ||
107 | |||
108 | let text = "a\nbb\nccc\n"; | ||
109 | let line_index = LineIndex::new(text); | ||
110 | |||
111 | let actual = line_index.lines(r(0, 9)).collect::<Vec<_>>(); | ||
112 | let expected = vec![r(0, 2), r(2, 5), r(5, 9)]; | ||
113 | assert_eq!(actual, expected); | ||
114 | |||
115 | let text = ""; | ||
116 | let line_index = LineIndex::new(text); | ||
117 | |||
118 | let actual = line_index.lines(r(0, 0)).collect::<Vec<_>>(); | ||
119 | let expected = vec![]; | ||
120 | assert_eq!(actual, expected); | ||
121 | |||
122 | let text = "\n"; | ||
123 | let line_index = LineIndex::new(text); | ||
124 | |||
125 | let actual = line_index.lines(r(0, 1)).collect::<Vec<_>>(); | ||
126 | let expected = vec![r(0, 1)]; | ||
127 | assert_eq!(actual, expected) | ||
128 | } | ||
diff --git a/crates/ide_db/src/traits.rs b/crates/ide_db/src/traits.rs index f57b6dd91..78a43f587 100644 --- a/crates/ide_db/src/traits.rs +++ b/crates/ide_db/src/traits.rs | |||
@@ -78,150 +78,4 @@ pub fn get_missing_assoc_items( | |||
78 | } | 78 | } |
79 | 79 | ||
80 | #[cfg(test)] | 80 | #[cfg(test)] |
81 | mod tests { | 81 | mod tests; |
82 | use crate::RootDatabase; | ||
83 | use base_db::{fixture::ChangeFixture, FilePosition}; | ||
84 | use expect_test::{expect, Expect}; | ||
85 | use hir::Semantics; | ||
86 | use syntax::ast::{self, AstNode}; | ||
87 | use test_utils::RangeOrOffset; | ||
88 | |||
89 | /// Creates analysis from a multi-file fixture, returns positions marked with <|>. | ||
90 | pub(crate) fn position(ra_fixture: &str) -> (RootDatabase, FilePosition) { | ||
91 | let change_fixture = ChangeFixture::parse(ra_fixture); | ||
92 | let mut database = RootDatabase::default(); | ||
93 | database.apply_change(change_fixture.change); | ||
94 | let (file_id, range_or_offset) = | ||
95 | change_fixture.file_position.expect("expected a marker (<|>)"); | ||
96 | let offset = match range_or_offset { | ||
97 | RangeOrOffset::Range(_) => panic!(), | ||
98 | RangeOrOffset::Offset(it) => it, | ||
99 | }; | ||
100 | (database, FilePosition { file_id, offset }) | ||
101 | } | ||
102 | |||
103 | fn check_trait(ra_fixture: &str, expect: Expect) { | ||
104 | let (db, position) = position(ra_fixture); | ||
105 | let sema = Semantics::new(&db); | ||
106 | let file = sema.parse(position.file_id); | ||
107 | let impl_block: ast::Impl = | ||
108 | sema.find_node_at_offset_with_descend(file.syntax(), position.offset).unwrap(); | ||
109 | let trait_ = crate::traits::resolve_target_trait(&sema, &impl_block); | ||
110 | let actual = match trait_ { | ||
111 | Some(trait_) => trait_.name(&db).to_string(), | ||
112 | None => String::new(), | ||
113 | }; | ||
114 | expect.assert_eq(&actual); | ||
115 | } | ||
116 | |||
117 | fn check_missing_assoc(ra_fixture: &str, expect: Expect) { | ||
118 | let (db, position) = position(ra_fixture); | ||
119 | let sema = Semantics::new(&db); | ||
120 | let file = sema.parse(position.file_id); | ||
121 | let impl_block: ast::Impl = | ||
122 | sema.find_node_at_offset_with_descend(file.syntax(), position.offset).unwrap(); | ||
123 | let items = crate::traits::get_missing_assoc_items(&sema, &impl_block); | ||
124 | let actual = items | ||
125 | .into_iter() | ||
126 | .map(|item| item.name(&db).unwrap().to_string()) | ||
127 | .collect::<Vec<_>>() | ||
128 | .join("\n"); | ||
129 | expect.assert_eq(&actual); | ||
130 | } | ||
131 | |||
132 | #[test] | ||
133 | fn resolve_trait() { | ||
134 | check_trait( | ||
135 | r#" | ||
136 | pub trait Foo { | ||
137 | fn bar(); | ||
138 | } | ||
139 | impl Foo for u8 { | ||
140 | <|> | ||
141 | } | ||
142 | "#, | ||
143 | expect![["Foo"]], | ||
144 | ); | ||
145 | check_trait( | ||
146 | r#" | ||
147 | pub trait Foo { | ||
148 | fn bar(); | ||
149 | } | ||
150 | impl Foo for u8 { | ||
151 | fn bar() { | ||
152 | fn baz() { | ||
153 | <|> | ||
154 | } | ||
155 | baz(); | ||
156 | } | ||
157 | } | ||
158 | "#, | ||
159 | expect![["Foo"]], | ||
160 | ); | ||
161 | check_trait( | ||
162 | r#" | ||
163 | pub trait Foo { | ||
164 | fn bar(); | ||
165 | } | ||
166 | pub struct Bar; | ||
167 | impl Bar { | ||
168 | <|> | ||
169 | } | ||
170 | "#, | ||
171 | expect![[""]], | ||
172 | ); | ||
173 | } | ||
174 | |||
175 | #[test] | ||
176 | fn missing_assoc_items() { | ||
177 | check_missing_assoc( | ||
178 | r#" | ||
179 | pub trait Foo { | ||
180 | const FOO: u8; | ||
181 | fn bar(); | ||
182 | } | ||
183 | impl Foo for u8 { | ||
184 | <|> | ||
185 | }"#, | ||
186 | expect![[r#" | ||
187 | FOO | ||
188 | bar"#]], | ||
189 | ); | ||
190 | |||
191 | check_missing_assoc( | ||
192 | r#" | ||
193 | pub trait Foo { | ||
194 | const FOO: u8; | ||
195 | fn bar(); | ||
196 | } | ||
197 | impl Foo for u8 { | ||
198 | const FOO: u8 = 10; | ||
199 | <|> | ||
200 | }"#, | ||
201 | expect![[r#" | ||
202 | bar"#]], | ||
203 | ); | ||
204 | |||
205 | check_missing_assoc( | ||
206 | r#" | ||
207 | pub trait Foo { | ||
208 | const FOO: u8; | ||
209 | fn bar(); | ||
210 | } | ||
211 | impl Foo for u8 { | ||
212 | const FOO: u8 = 10; | ||
213 | fn bar() {<|>} | ||
214 | }"#, | ||
215 | expect![[r#""#]], | ||
216 | ); | ||
217 | |||
218 | check_missing_assoc( | ||
219 | r#" | ||
220 | pub struct Foo; | ||
221 | impl Foo { | ||
222 | fn bar() {<|>} | ||
223 | }"#, | ||
224 | expect![[r#""#]], | ||
225 | ); | ||
226 | } | ||
227 | } | ||
diff --git a/crates/ide_db/src/traits/tests.rs b/crates/ide_db/src/traits/tests.rs new file mode 100644 index 000000000..09c7ac3ec --- /dev/null +++ b/crates/ide_db/src/traits/tests.rs | |||
@@ -0,0 +1,144 @@ | |||
1 | use crate::RootDatabase; | ||
2 | use base_db::{fixture::ChangeFixture, FilePosition}; | ||
3 | use expect_test::{expect, Expect}; | ||
4 | use hir::Semantics; | ||
5 | use syntax::ast::{self, AstNode}; | ||
6 | use test_utils::RangeOrOffset; | ||
7 | |||
8 | /// Creates analysis from a multi-file fixture, returns positions marked with <|>. | ||
9 | pub(crate) fn position(ra_fixture: &str) -> (RootDatabase, FilePosition) { | ||
10 | let change_fixture = ChangeFixture::parse(ra_fixture); | ||
11 | let mut database = RootDatabase::default(); | ||
12 | database.apply_change(change_fixture.change); | ||
13 | let (file_id, range_or_offset) = change_fixture.file_position.expect("expected a marker (<|>)"); | ||
14 | let offset = match range_or_offset { | ||
15 | RangeOrOffset::Range(_) => panic!(), | ||
16 | RangeOrOffset::Offset(it) => it, | ||
17 | }; | ||
18 | (database, FilePosition { file_id, offset }) | ||
19 | } | ||
20 | |||
21 | fn check_trait(ra_fixture: &str, expect: Expect) { | ||
22 | let (db, position) = position(ra_fixture); | ||
23 | let sema = Semantics::new(&db); | ||
24 | let file = sema.parse(position.file_id); | ||
25 | let impl_block: ast::Impl = | ||
26 | sema.find_node_at_offset_with_descend(file.syntax(), position.offset).unwrap(); | ||
27 | let trait_ = crate::traits::resolve_target_trait(&sema, &impl_block); | ||
28 | let actual = match trait_ { | ||
29 | Some(trait_) => trait_.name(&db).to_string(), | ||
30 | None => String::new(), | ||
31 | }; | ||
32 | expect.assert_eq(&actual); | ||
33 | } | ||
34 | |||
35 | fn check_missing_assoc(ra_fixture: &str, expect: Expect) { | ||
36 | let (db, position) = position(ra_fixture); | ||
37 | let sema = Semantics::new(&db); | ||
38 | let file = sema.parse(position.file_id); | ||
39 | let impl_block: ast::Impl = | ||
40 | sema.find_node_at_offset_with_descend(file.syntax(), position.offset).unwrap(); | ||
41 | let items = crate::traits::get_missing_assoc_items(&sema, &impl_block); | ||
42 | let actual = items | ||
43 | .into_iter() | ||
44 | .map(|item| item.name(&db).unwrap().to_string()) | ||
45 | .collect::<Vec<_>>() | ||
46 | .join("\n"); | ||
47 | expect.assert_eq(&actual); | ||
48 | } | ||
49 | |||
50 | #[test] | ||
51 | fn resolve_trait() { | ||
52 | check_trait( | ||
53 | r#" | ||
54 | pub trait Foo { | ||
55 | fn bar(); | ||
56 | } | ||
57 | impl Foo for u8 { | ||
58 | <|> | ||
59 | } | ||
60 | "#, | ||
61 | expect![["Foo"]], | ||
62 | ); | ||
63 | check_trait( | ||
64 | r#" | ||
65 | pub trait Foo { | ||
66 | fn bar(); | ||
67 | } | ||
68 | impl Foo for u8 { | ||
69 | fn bar() { | ||
70 | fn baz() { | ||
71 | <|> | ||
72 | } | ||
73 | baz(); | ||
74 | } | ||
75 | } | ||
76 | "#, | ||
77 | expect![["Foo"]], | ||
78 | ); | ||
79 | check_trait( | ||
80 | r#" | ||
81 | pub trait Foo { | ||
82 | fn bar(); | ||
83 | } | ||
84 | pub struct Bar; | ||
85 | impl Bar { | ||
86 | <|> | ||
87 | } | ||
88 | "#, | ||
89 | expect![[""]], | ||
90 | ); | ||
91 | } | ||
92 | |||
93 | #[test] | ||
94 | fn missing_assoc_items() { | ||
95 | check_missing_assoc( | ||
96 | r#" | ||
97 | pub trait Foo { | ||
98 | const FOO: u8; | ||
99 | fn bar(); | ||
100 | } | ||
101 | impl Foo for u8 { | ||
102 | <|> | ||
103 | }"#, | ||
104 | expect![[r#" | ||
105 | FOO | ||
106 | bar"#]], | ||
107 | ); | ||
108 | |||
109 | check_missing_assoc( | ||
110 | r#" | ||
111 | pub trait Foo { | ||
112 | const FOO: u8; | ||
113 | fn bar(); | ||
114 | } | ||
115 | impl Foo for u8 { | ||
116 | const FOO: u8 = 10; | ||
117 | <|> | ||
118 | }"#, | ||
119 | expect![[r#" | ||
120 | bar"#]], | ||
121 | ); | ||
122 | |||
123 | check_missing_assoc( | ||
124 | r#" | ||
125 | pub trait Foo { | ||
126 | const FOO: u8; | ||
127 | fn bar(); | ||
128 | } | ||
129 | impl Foo for u8 { | ||
130 | const FOO: u8 = 10; | ||
131 | fn bar() {<|>} | ||
132 | }"#, | ||
133 | expect![[r#""#]], | ||
134 | ); | ||
135 | |||
136 | check_missing_assoc( | ||
137 | r#" | ||
138 | pub struct Foo; | ||
139 | impl Foo { | ||
140 | fn bar() {<|>} | ||
141 | }"#, | ||
142 | expect![[r#""#]], | ||
143 | ); | ||
144 | } | ||