diff options
Diffstat (limited to 'crates/ra_hir_ty/src/tests.rs')
-rw-r--r-- | crates/ra_hir_ty/src/tests.rs | 436 |
1 files changed, 28 insertions, 408 deletions
diff --git a/crates/ra_hir_ty/src/tests.rs b/crates/ra_hir_ty/src/tests.rs index eeac34d14..45bc14c37 100644 --- a/crates/ra_hir_ty/src/tests.rs +++ b/crates/ra_hir_ty/src/tests.rs | |||
@@ -10,6 +10,7 @@ mod display_source_code; | |||
10 | 10 | ||
11 | use std::sync::Arc; | 11 | use std::sync::Arc; |
12 | 12 | ||
13 | use expect::Expect; | ||
13 | use hir_def::{ | 14 | use hir_def::{ |
14 | body::{BodySourceMap, SyntheticSyntax}, | 15 | body::{BodySourceMap, SyntheticSyntax}, |
15 | child_by_source::ChildBySource, | 16 | child_by_source::ChildBySource, |
@@ -20,8 +21,7 @@ use hir_def::{ | |||
20 | AssocItemId, DefWithBodyId, LocalModuleId, Lookup, ModuleDefId, | 21 | AssocItemId, DefWithBodyId, LocalModuleId, Lookup, ModuleDefId, |
21 | }; | 22 | }; |
22 | use hir_expand::{db::AstDatabase, InFile}; | 23 | use hir_expand::{db::AstDatabase, InFile}; |
23 | use insta::assert_snapshot; | 24 | use ra_db::{fixture::WithFixture, FileRange, SourceDatabase, SourceDatabaseExt}; |
24 | use ra_db::{fixture::WithFixture, salsa::Database, FileRange, SourceDatabase}; | ||
25 | use ra_syntax::{ | 25 | use ra_syntax::{ |
26 | algo, | 26 | algo, |
27 | ast::{self, AstNode}, | 27 | ast::{self, AstNode}, |
@@ -34,8 +34,21 @@ use crate::{ | |||
34 | }; | 34 | }; |
35 | 35 | ||
36 | // These tests compare the inference results for all expressions in a file | 36 | // These tests compare the inference results for all expressions in a file |
37 | // against snapshots of the expected results using insta. Use cargo-insta to | 37 | // against snapshots of the expected results using expect. Use |
38 | // update the snapshots. | 38 | // `env UPDATE_EXPECT=1 cargo test -p ra_hir_ty` to update the snapshots. |
39 | |||
40 | fn setup_tracing() -> tracing::subscriber::DefaultGuard { | ||
41 | use tracing_subscriber::{layer::SubscriberExt, EnvFilter, Registry}; | ||
42 | use tracing_tree::HierarchicalLayer; | ||
43 | let filter = EnvFilter::from_env("CHALK_DEBUG"); | ||
44 | let layer = HierarchicalLayer::default() | ||
45 | .with_indent_lines(true) | ||
46 | .with_ansi(false) | ||
47 | .with_indent_amount(2) | ||
48 | .with_writer(std::io::stderr); | ||
49 | let subscriber = Registry::default().with(filter).with(layer); | ||
50 | tracing::subscriber::set_default(subscriber) | ||
51 | } | ||
39 | 52 | ||
40 | fn check_types(ra_fixture: &str) { | 53 | fn check_types(ra_fixture: &str) { |
41 | check_types_impl(ra_fixture, false) | 54 | check_types_impl(ra_fixture, false) |
@@ -46,6 +59,7 @@ fn check_types_source_code(ra_fixture: &str) { | |||
46 | } | 59 | } |
47 | 60 | ||
48 | fn check_types_impl(ra_fixture: &str, display_source: bool) { | 61 | fn check_types_impl(ra_fixture: &str, display_source: bool) { |
62 | let _tracing = setup_tracing(); | ||
49 | let db = TestDB::with_files(ra_fixture); | 63 | let db = TestDB::with_files(ra_fixture); |
50 | let mut checked_one = false; | 64 | let mut checked_one = false; |
51 | for (file_id, annotations) in db.extract_annotations() { | 65 | for (file_id, annotations) in db.extract_annotations() { |
@@ -86,6 +100,7 @@ fn infer(ra_fixture: &str) -> String { | |||
86 | } | 100 | } |
87 | 101 | ||
88 | fn infer_with_mismatches(content: &str, include_mismatches: bool) -> String { | 102 | fn infer_with_mismatches(content: &str, include_mismatches: bool) -> String { |
103 | let _tracing = setup_tracing(); | ||
89 | let (db, file_id) = TestDB::with_single_file(content); | 104 | let (db, file_id) = TestDB::with_single_file(content); |
90 | 105 | ||
91 | let mut buf = String::new(); | 106 | let mut buf = String::new(); |
@@ -317,7 +332,7 @@ fn typing_whitespace_inside_a_function_should_not_invalidate_types() { | |||
317 | " | 332 | " |
318 | .to_string(); | 333 | .to_string(); |
319 | 334 | ||
320 | db.query_mut(ra_db::FileTextQuery).set(pos.file_id, Arc::new(new_text)); | 335 | db.set_file_text(pos.file_id, Arc::new(new_text)); |
321 | 336 | ||
322 | { | 337 | { |
323 | let events = db.log_executed(|| { | 338 | let events = db.log_executed(|| { |
@@ -331,409 +346,14 @@ fn typing_whitespace_inside_a_function_should_not_invalidate_types() { | |||
331 | } | 346 | } |
332 | } | 347 | } |
333 | 348 | ||
334 | #[test] | 349 | fn check_infer(ra_fixture: &str, expect: Expect) { |
335 | fn no_such_field_diagnostics() { | 350 | let mut actual = infer(ra_fixture); |
336 | let diagnostics = TestDB::with_files( | 351 | actual.push('\n'); |
337 | r" | 352 | expect.assert_eq(&actual); |
338 | //- /lib.rs | ||
339 | struct S { foo: i32, bar: () } | ||
340 | impl S { | ||
341 | fn new() -> S { | ||
342 | S { | ||
343 | foo: 92, | ||
344 | baz: 62, | ||
345 | } | ||
346 | } | ||
347 | } | ||
348 | ", | ||
349 | ) | ||
350 | .diagnostics() | ||
351 | .0; | ||
352 | |||
353 | assert_snapshot!(diagnostics, @r###" | ||
354 | "baz: 62": no such field | ||
355 | "{\n foo: 92,\n baz: 62,\n }": Missing structure fields: | ||
356 | - bar | ||
357 | "### | ||
358 | ); | ||
359 | } | ||
360 | |||
361 | #[test] | ||
362 | fn no_such_field_with_feature_flag_diagnostics() { | ||
363 | let diagnostics = TestDB::with_files( | ||
364 | r#" | ||
365 | //- /lib.rs crate:foo cfg:feature=foo | ||
366 | struct MyStruct { | ||
367 | my_val: usize, | ||
368 | #[cfg(feature = "foo")] | ||
369 | bar: bool, | ||
370 | } | ||
371 | |||
372 | impl MyStruct { | ||
373 | #[cfg(feature = "foo")] | ||
374 | pub(crate) fn new(my_val: usize, bar: bool) -> Self { | ||
375 | Self { my_val, bar } | ||
376 | } | ||
377 | |||
378 | #[cfg(not(feature = "foo"))] | ||
379 | pub(crate) fn new(my_val: usize, _bar: bool) -> Self { | ||
380 | Self { my_val } | ||
381 | } | ||
382 | } | ||
383 | "#, | ||
384 | ) | ||
385 | .diagnostics() | ||
386 | .0; | ||
387 | |||
388 | assert_snapshot!(diagnostics, @r###""###); | ||
389 | } | ||
390 | |||
391 | #[test] | ||
392 | fn no_such_field_enum_with_feature_flag_diagnostics() { | ||
393 | let diagnostics = TestDB::with_files( | ||
394 | r#" | ||
395 | //- /lib.rs crate:foo cfg:feature=foo | ||
396 | enum Foo { | ||
397 | #[cfg(not(feature = "foo"))] | ||
398 | Buz, | ||
399 | #[cfg(feature = "foo")] | ||
400 | Bar, | ||
401 | Baz | ||
402 | } | ||
403 | |||
404 | fn test_fn(f: Foo) { | ||
405 | match f { | ||
406 | Foo::Bar => {}, | ||
407 | Foo::Baz => {}, | ||
408 | } | ||
409 | } | ||
410 | "#, | ||
411 | ) | ||
412 | .diagnostics() | ||
413 | .0; | ||
414 | |||
415 | assert_snapshot!(diagnostics, @r###""###); | ||
416 | } | ||
417 | |||
418 | #[test] | ||
419 | fn no_such_field_with_feature_flag_diagnostics_on_struct_lit() { | ||
420 | let diagnostics = TestDB::with_files( | ||
421 | r#" | ||
422 | //- /lib.rs crate:foo cfg:feature=foo | ||
423 | struct S { | ||
424 | #[cfg(feature = "foo")] | ||
425 | foo: u32, | ||
426 | #[cfg(not(feature = "foo"))] | ||
427 | bar: u32, | ||
428 | } | ||
429 | |||
430 | impl S { | ||
431 | #[cfg(feature = "foo")] | ||
432 | fn new(foo: u32) -> Self { | ||
433 | Self { foo } | ||
434 | } | ||
435 | #[cfg(not(feature = "foo"))] | ||
436 | fn new(bar: u32) -> Self { | ||
437 | Self { bar } | ||
438 | } | ||
439 | } | ||
440 | "#, | ||
441 | ) | ||
442 | .diagnostics() | ||
443 | .0; | ||
444 | |||
445 | assert_snapshot!(diagnostics, @r###""###); | ||
446 | } | ||
447 | |||
448 | #[test] | ||
449 | fn no_such_field_with_feature_flag_diagnostics_on_block_expr() { | ||
450 | let diagnostics = TestDB::with_files( | ||
451 | r#" | ||
452 | //- /lib.rs crate:foo cfg:feature=foo | ||
453 | struct S { | ||
454 | #[cfg(feature = "foo")] | ||
455 | foo: u32, | ||
456 | #[cfg(not(feature = "foo"))] | ||
457 | bar: u32, | ||
458 | } | ||
459 | |||
460 | impl S { | ||
461 | fn new(bar: u32) -> Self { | ||
462 | #[cfg(feature = "foo")] | ||
463 | { | ||
464 | Self { foo: bar } | ||
465 | } | ||
466 | #[cfg(not(feature = "foo"))] | ||
467 | { | ||
468 | Self { bar } | ||
469 | } | ||
470 | } | ||
471 | } | ||
472 | "#, | ||
473 | ) | ||
474 | .diagnostics() | ||
475 | .0; | ||
476 | |||
477 | assert_snapshot!(diagnostics, @r###""###); | ||
478 | } | ||
479 | |||
480 | #[test] | ||
481 | fn no_such_field_with_feature_flag_diagnostics_on_struct_fields() { | ||
482 | let diagnostics = TestDB::with_files( | ||
483 | r#" | ||
484 | //- /lib.rs crate:foo cfg:feature=foo | ||
485 | struct S { | ||
486 | #[cfg(feature = "foo")] | ||
487 | foo: u32, | ||
488 | #[cfg(not(feature = "foo"))] | ||
489 | bar: u32, | ||
490 | } | ||
491 | |||
492 | impl S { | ||
493 | fn new(val: u32) -> Self { | ||
494 | Self { | ||
495 | #[cfg(feature = "foo")] | ||
496 | foo: val, | ||
497 | #[cfg(not(feature = "foo"))] | ||
498 | bar: val, | ||
499 | } | ||
500 | } | ||
501 | } | ||
502 | "#, | ||
503 | ) | ||
504 | .diagnostics() | ||
505 | .0; | ||
506 | |||
507 | assert_snapshot!(diagnostics, @r###""###); | ||
508 | } | ||
509 | |||
510 | #[test] | ||
511 | fn no_such_field_with_type_macro() { | ||
512 | let diagnostics = TestDB::with_files( | ||
513 | r" | ||
514 | macro_rules! Type { | ||
515 | () => { u32 }; | ||
516 | } | ||
517 | |||
518 | struct Foo { | ||
519 | bar: Type![], | ||
520 | } | ||
521 | impl Foo { | ||
522 | fn new() -> Self { | ||
523 | Foo { bar: 0 } | ||
524 | } | ||
525 | } | ||
526 | ", | ||
527 | ) | ||
528 | .diagnostics() | ||
529 | .0; | ||
530 | |||
531 | assert_snapshot!(diagnostics, @r###""###); | ||
532 | } | 353 | } |
533 | 354 | ||
534 | #[test] | 355 | fn check_infer_with_mismatches(ra_fixture: &str, expect: Expect) { |
535 | fn missing_record_pat_field_diagnostic() { | 356 | let mut actual = infer_with_mismatches(ra_fixture, true); |
536 | let diagnostics = TestDB::with_files( | 357 | actual.push('\n'); |
537 | r" | 358 | expect.assert_eq(&actual); |
538 | //- /lib.rs | ||
539 | struct S { foo: i32, bar: () } | ||
540 | fn baz(s: S) { | ||
541 | let S { foo: _ } = s; | ||
542 | } | ||
543 | ", | ||
544 | ) | ||
545 | .diagnostics() | ||
546 | .0; | ||
547 | |||
548 | assert_snapshot!(diagnostics, @r###" | ||
549 | "{ foo: _ }": Missing structure fields: | ||
550 | - bar | ||
551 | "### | ||
552 | ); | ||
553 | } | ||
554 | |||
555 | #[test] | ||
556 | fn missing_record_pat_field_no_diagnostic_if_not_exhaustive() { | ||
557 | let diagnostics = TestDB::with_files( | ||
558 | r" | ||
559 | //- /lib.rs | ||
560 | struct S { foo: i32, bar: () } | ||
561 | fn baz(s: S) -> i32 { | ||
562 | match s { | ||
563 | S { foo, .. } => foo, | ||
564 | } | ||
565 | } | ||
566 | ", | ||
567 | ) | ||
568 | .diagnostics() | ||
569 | .0; | ||
570 | |||
571 | assert_snapshot!(diagnostics, @""); | ||
572 | } | ||
573 | |||
574 | #[test] | ||
575 | fn missing_unsafe_diagnostic_with_raw_ptr() { | ||
576 | let diagnostics = TestDB::with_files( | ||
577 | r" | ||
578 | //- /lib.rs | ||
579 | fn missing_unsafe() { | ||
580 | let x = &5 as *const usize; | ||
581 | let y = *x; | ||
582 | } | ||
583 | ", | ||
584 | ) | ||
585 | .diagnostics() | ||
586 | .0; | ||
587 | |||
588 | assert_snapshot!(diagnostics, @r#""*x": This operation is unsafe and requires an unsafe function or block"#); | ||
589 | } | ||
590 | |||
591 | #[test] | ||
592 | fn missing_unsafe_diagnostic_with_unsafe_call() { | ||
593 | let diagnostics = TestDB::with_files( | ||
594 | r" | ||
595 | //- /lib.rs | ||
596 | unsafe fn unsafe_fn() { | ||
597 | let x = &5 as *const usize; | ||
598 | let y = *x; | ||
599 | } | ||
600 | |||
601 | fn missing_unsafe() { | ||
602 | unsafe_fn(); | ||
603 | } | ||
604 | ", | ||
605 | ) | ||
606 | .diagnostics() | ||
607 | .0; | ||
608 | |||
609 | assert_snapshot!(diagnostics, @r#""unsafe_fn()": This operation is unsafe and requires an unsafe function or block"#); | ||
610 | } | ||
611 | |||
612 | #[test] | ||
613 | fn missing_unsafe_diagnostic_with_unsafe_method_call() { | ||
614 | let diagnostics = TestDB::with_files( | ||
615 | r" | ||
616 | struct HasUnsafe; | ||
617 | |||
618 | impl HasUnsafe { | ||
619 | unsafe fn unsafe_fn(&self) { | ||
620 | let x = &5 as *const usize; | ||
621 | let y = *x; | ||
622 | } | ||
623 | } | ||
624 | |||
625 | fn missing_unsafe() { | ||
626 | HasUnsafe.unsafe_fn(); | ||
627 | } | ||
628 | |||
629 | ", | ||
630 | ) | ||
631 | .diagnostics() | ||
632 | .0; | ||
633 | |||
634 | assert_snapshot!(diagnostics, @r#""HasUnsafe.unsafe_fn()": This operation is unsafe and requires an unsafe function or block"#); | ||
635 | } | ||
636 | |||
637 | #[test] | ||
638 | fn no_missing_unsafe_diagnostic_with_raw_ptr_in_unsafe_block() { | ||
639 | let diagnostics = TestDB::with_files( | ||
640 | r" | ||
641 | fn nothing_to_see_move_along() { | ||
642 | let x = &5 as *const usize; | ||
643 | unsafe { | ||
644 | let y = *x; | ||
645 | } | ||
646 | } | ||
647 | ", | ||
648 | ) | ||
649 | .diagnostics() | ||
650 | .0; | ||
651 | |||
652 | assert_snapshot!(diagnostics, @""); | ||
653 | } | ||
654 | |||
655 | #[test] | ||
656 | fn missing_unsafe_diagnostic_with_raw_ptr_outside_unsafe_block() { | ||
657 | let diagnostics = TestDB::with_files( | ||
658 | r" | ||
659 | fn nothing_to_see_move_along() { | ||
660 | let x = &5 as *const usize; | ||
661 | unsafe { | ||
662 | let y = *x; | ||
663 | } | ||
664 | let z = *x; | ||
665 | } | ||
666 | ", | ||
667 | ) | ||
668 | .diagnostics() | ||
669 | .0; | ||
670 | |||
671 | assert_snapshot!(diagnostics, @r#""*x": This operation is unsafe and requires an unsafe function or block"#); | ||
672 | } | ||
673 | |||
674 | #[test] | ||
675 | fn no_missing_unsafe_diagnostic_with_unsafe_call_in_unsafe_block() { | ||
676 | let diagnostics = TestDB::with_files( | ||
677 | r" | ||
678 | unsafe fn unsafe_fn() { | ||
679 | let x = &5 as *const usize; | ||
680 | let y = *x; | ||
681 | } | ||
682 | |||
683 | fn nothing_to_see_move_along() { | ||
684 | unsafe { | ||
685 | unsafe_fn(); | ||
686 | } | ||
687 | } | ||
688 | ", | ||
689 | ) | ||
690 | .diagnostics() | ||
691 | .0; | ||
692 | |||
693 | assert_snapshot!(diagnostics, @""); | ||
694 | } | ||
695 | |||
696 | #[test] | ||
697 | fn no_missing_unsafe_diagnostic_with_unsafe_method_call_in_unsafe_block() { | ||
698 | let diagnostics = TestDB::with_files( | ||
699 | r" | ||
700 | struct HasUnsafe; | ||
701 | |||
702 | impl HasUnsafe { | ||
703 | unsafe fn unsafe_fn() { | ||
704 | let x = &5 as *const usize; | ||
705 | let y = *x; | ||
706 | } | ||
707 | } | ||
708 | |||
709 | fn nothing_to_see_move_along() { | ||
710 | unsafe { | ||
711 | HasUnsafe.unsafe_fn(); | ||
712 | } | ||
713 | } | ||
714 | |||
715 | ", | ||
716 | ) | ||
717 | .diagnostics() | ||
718 | .0; | ||
719 | |||
720 | assert_snapshot!(diagnostics, @""); | ||
721 | } | ||
722 | |||
723 | #[test] | ||
724 | fn break_outside_of_loop() { | ||
725 | let diagnostics = TestDB::with_files( | ||
726 | r" | ||
727 | //- /lib.rs | ||
728 | fn foo() { | ||
729 | break; | ||
730 | } | ||
731 | ", | ||
732 | ) | ||
733 | .diagnostics() | ||
734 | .0; | ||
735 | |||
736 | assert_snapshot!(diagnostics, @r###""break": break outside of loop | ||
737 | "### | ||
738 | ); | ||
739 | } | 359 | } |