diff options
Diffstat (limited to 'crates/ra_hir_ty/src/tests.rs')
-rw-r--r-- | crates/ra_hir_ty/src/tests.rs | 199 |
1 files changed, 180 insertions, 19 deletions
diff --git a/crates/ra_hir_ty/src/tests.rs b/crates/ra_hir_ty/src/tests.rs index 85ff26a36..5424e6bb1 100644 --- a/crates/ra_hir_ty/src/tests.rs +++ b/crates/ra_hir_ty/src/tests.rs | |||
@@ -17,17 +17,18 @@ use hir_def::{ | |||
17 | item_scope::ItemScope, | 17 | item_scope::ItemScope, |
18 | keys, | 18 | keys, |
19 | nameres::CrateDefMap, | 19 | nameres::CrateDefMap, |
20 | AssocItemId, DefWithBodyId, LocalModuleId, Lookup, ModuleDefId, ModuleId, | 20 | AssocItemId, DefWithBodyId, LocalModuleId, Lookup, ModuleDefId, |
21 | }; | 21 | }; |
22 | use hir_expand::{db::AstDatabase, InFile}; | 22 | use hir_expand::{db::AstDatabase, InFile}; |
23 | use insta::assert_snapshot; | 23 | use insta::assert_snapshot; |
24 | use ra_db::{fixture::WithFixture, salsa::Database, FilePosition, SourceDatabase}; | 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}, |
28 | SyntaxNode, | 28 | SyntaxNode, |
29 | }; | 29 | }; |
30 | use stdx::format_to; | 30 | use stdx::format_to; |
31 | use test_utils::extract_annotations; | ||
31 | 32 | ||
32 | use crate::{ | 33 | use crate::{ |
33 | db::HirDatabase, display::HirDisplay, infer::TypeMismatch, test_db::TestDB, InferenceResult, Ty, | 34 | db::HirDatabase, display::HirDisplay, infer::TypeMismatch, test_db::TestDB, InferenceResult, Ty, |
@@ -37,21 +38,38 @@ use crate::{ | |||
37 | // against snapshots of the expected results using insta. Use cargo-insta to | 38 | // against snapshots of the expected results using insta. Use cargo-insta to |
38 | // update the snapshots. | 39 | // update the snapshots. |
39 | 40 | ||
40 | fn type_at_pos(db: &TestDB, pos: FilePosition) -> String { | 41 | fn check_types(ra_fixture: &str) { |
41 | type_at_pos_displayed(db, pos, |ty, _| ty.display(db).to_string()) | 42 | check_types_impl(ra_fixture, false) |
42 | } | 43 | } |
43 | 44 | ||
44 | fn displayed_source_at_pos(db: &TestDB, pos: FilePosition) -> String { | 45 | fn check_types_source_code(ra_fixture: &str) { |
45 | type_at_pos_displayed(db, pos, |ty, module_id| ty.display_source_code(db, module_id).unwrap()) | 46 | check_types_impl(ra_fixture, true) |
46 | } | 47 | } |
47 | 48 | ||
48 | fn type_at_pos_displayed( | 49 | fn check_types_impl(ra_fixture: &str, display_source: bool) { |
49 | db: &TestDB, | 50 | let db = TestDB::with_files(ra_fixture); |
50 | pos: FilePosition, | 51 | let mut checked_one = false; |
51 | display_fn: impl FnOnce(&Ty, ModuleId) -> String, | 52 | for file_id in db.all_files() { |
52 | ) -> String { | 53 | let text = db.parse(file_id).syntax_node().to_string(); |
54 | let annotations = extract_annotations(&text); | ||
55 | for (range, expected) in annotations { | ||
56 | let ty = type_at_range(&db, FileRange { file_id, range }); | ||
57 | let actual = if display_source { | ||
58 | let module = db.module_for_file(file_id); | ||
59 | ty.display_source_code(&db, module).unwrap() | ||
60 | } else { | ||
61 | ty.display(&db).to_string() | ||
62 | }; | ||
63 | assert_eq!(expected, actual); | ||
64 | checked_one = true; | ||
65 | } | ||
66 | } | ||
67 | assert!(checked_one, "no `//^` annotations found"); | ||
68 | } | ||
69 | |||
70 | fn type_at_range(db: &TestDB, pos: FileRange) -> Ty { | ||
53 | let file = db.parse(pos.file_id).ok().unwrap(); | 71 | let file = db.parse(pos.file_id).ok().unwrap(); |
54 | let expr = algo::find_node_at_offset::<ast::Expr>(file.syntax(), pos.offset).unwrap(); | 72 | let expr = algo::find_node_at_range::<ast::Expr>(file.syntax(), pos.range).unwrap(); |
55 | let fn_def = expr.syntax().ancestors().find_map(ast::FnDef::cast).unwrap(); | 73 | let fn_def = expr.syntax().ancestors().find_map(ast::FnDef::cast).unwrap(); |
56 | let module = db.module_for_file(pos.file_id); | 74 | let module = db.module_for_file(pos.file_id); |
57 | let func = *module.child_by_source(db)[keys::FUNCTION] | 75 | let func = *module.child_by_source(db)[keys::FUNCTION] |
@@ -61,17 +79,11 @@ fn type_at_pos_displayed( | |||
61 | let (_body, source_map) = db.body_with_source_map(func.into()); | 79 | let (_body, source_map) = db.body_with_source_map(func.into()); |
62 | if let Some(expr_id) = source_map.node_expr(InFile::new(pos.file_id.into(), &expr)) { | 80 | if let Some(expr_id) = source_map.node_expr(InFile::new(pos.file_id.into(), &expr)) { |
63 | let infer = db.infer(func.into()); | 81 | let infer = db.infer(func.into()); |
64 | let ty = &infer[expr_id]; | 82 | return infer[expr_id].clone(); |
65 | return display_fn(ty, module); | ||
66 | } | 83 | } |
67 | panic!("Can't find expression") | 84 | panic!("Can't find expression") |
68 | } | 85 | } |
69 | 86 | ||
70 | fn type_at(ra_fixture: &str) -> String { | ||
71 | let (db, file_pos) = TestDB::with_position(ra_fixture); | ||
72 | type_at_pos(&db, file_pos) | ||
73 | } | ||
74 | |||
75 | fn infer(ra_fixture: &str) -> String { | 87 | fn infer(ra_fixture: &str) -> String { |
76 | infer_with_mismatches(ra_fixture, false) | 88 | infer_with_mismatches(ra_fixture, false) |
77 | } | 89 | } |
@@ -539,6 +551,155 @@ fn missing_record_pat_field_no_diagnostic_if_not_exhaustive() { | |||
539 | } | 551 | } |
540 | 552 | ||
541 | #[test] | 553 | #[test] |
554 | fn missing_unsafe_diagnostic_with_raw_ptr() { | ||
555 | let diagnostics = TestDB::with_files( | ||
556 | r" | ||
557 | //- /lib.rs | ||
558 | fn missing_unsafe() { | ||
559 | let x = &5 as *const usize; | ||
560 | let y = *x; | ||
561 | } | ||
562 | ", | ||
563 | ) | ||
564 | .diagnostics() | ||
565 | .0; | ||
566 | |||
567 | assert_snapshot!(diagnostics, @r#""*x": This operation is unsafe and requires an unsafe function or block"#); | ||
568 | } | ||
569 | |||
570 | #[test] | ||
571 | fn missing_unsafe_diagnostic_with_unsafe_call() { | ||
572 | let diagnostics = TestDB::with_files( | ||
573 | r" | ||
574 | //- /lib.rs | ||
575 | unsafe fn unsafe_fn() { | ||
576 | let x = &5 as *const usize; | ||
577 | let y = *x; | ||
578 | } | ||
579 | |||
580 | fn missing_unsafe() { | ||
581 | unsafe_fn(); | ||
582 | } | ||
583 | ", | ||
584 | ) | ||
585 | .diagnostics() | ||
586 | .0; | ||
587 | |||
588 | assert_snapshot!(diagnostics, @r#""unsafe_fn()": This operation is unsafe and requires an unsafe function or block"#); | ||
589 | } | ||
590 | |||
591 | #[test] | ||
592 | fn missing_unsafe_diagnostic_with_unsafe_method_call() { | ||
593 | let diagnostics = TestDB::with_files( | ||
594 | r" | ||
595 | struct HasUnsafe; | ||
596 | |||
597 | impl HasUnsafe { | ||
598 | unsafe fn unsafe_fn(&self) { | ||
599 | let x = &5 as *const usize; | ||
600 | let y = *x; | ||
601 | } | ||
602 | } | ||
603 | |||
604 | fn missing_unsafe() { | ||
605 | HasUnsafe.unsafe_fn(); | ||
606 | } | ||
607 | |||
608 | ", | ||
609 | ) | ||
610 | .diagnostics() | ||
611 | .0; | ||
612 | |||
613 | assert_snapshot!(diagnostics, @r#""HasUnsafe.unsafe_fn()": This operation is unsafe and requires an unsafe function or block"#); | ||
614 | } | ||
615 | |||
616 | #[test] | ||
617 | fn no_missing_unsafe_diagnostic_with_raw_ptr_in_unsafe_block() { | ||
618 | let diagnostics = TestDB::with_files( | ||
619 | r" | ||
620 | fn nothing_to_see_move_along() { | ||
621 | let x = &5 as *const usize; | ||
622 | unsafe { | ||
623 | let y = *x; | ||
624 | } | ||
625 | } | ||
626 | ", | ||
627 | ) | ||
628 | .diagnostics() | ||
629 | .0; | ||
630 | |||
631 | assert_snapshot!(diagnostics, @""); | ||
632 | } | ||
633 | |||
634 | #[test] | ||
635 | fn missing_unsafe_diagnostic_with_raw_ptr_outside_unsafe_block() { | ||
636 | let diagnostics = TestDB::with_files( | ||
637 | r" | ||
638 | fn nothing_to_see_move_along() { | ||
639 | let x = &5 as *const usize; | ||
640 | unsafe { | ||
641 | let y = *x; | ||
642 | } | ||
643 | let z = *x; | ||
644 | } | ||
645 | ", | ||
646 | ) | ||
647 | .diagnostics() | ||
648 | .0; | ||
649 | |||
650 | assert_snapshot!(diagnostics, @r#""*x": This operation is unsafe and requires an unsafe function or block"#); | ||
651 | } | ||
652 | |||
653 | #[test] | ||
654 | fn no_missing_unsafe_diagnostic_with_unsafe_call_in_unsafe_block() { | ||
655 | let diagnostics = TestDB::with_files( | ||
656 | r" | ||
657 | unsafe fn unsafe_fn() { | ||
658 | let x = &5 as *const usize; | ||
659 | let y = *x; | ||
660 | } | ||
661 | |||
662 | fn nothing_to_see_move_along() { | ||
663 | unsafe { | ||
664 | unsafe_fn(); | ||
665 | } | ||
666 | } | ||
667 | ", | ||
668 | ) | ||
669 | .diagnostics() | ||
670 | .0; | ||
671 | |||
672 | assert_snapshot!(diagnostics, @""); | ||
673 | } | ||
674 | |||
675 | #[test] | ||
676 | fn no_missing_unsafe_diagnostic_with_unsafe_method_call_in_unsafe_block() { | ||
677 | let diagnostics = TestDB::with_files( | ||
678 | r" | ||
679 | struct HasUnsafe; | ||
680 | |||
681 | impl HasUnsafe { | ||
682 | unsafe fn unsafe_fn() { | ||
683 | let x = &5 as *const usize; | ||
684 | let y = *x; | ||
685 | } | ||
686 | } | ||
687 | |||
688 | fn nothing_to_see_move_along() { | ||
689 | unsafe { | ||
690 | HasUnsafe.unsafe_fn(); | ||
691 | } | ||
692 | } | ||
693 | |||
694 | ", | ||
695 | ) | ||
696 | .diagnostics() | ||
697 | .0; | ||
698 | |||
699 | assert_snapshot!(diagnostics, @""); | ||
700 | } | ||
701 | |||
702 | #[test] | ||
542 | fn break_outside_of_loop() { | 703 | fn break_outside_of_loop() { |
543 | let diagnostics = TestDB::with_files( | 704 | let diagnostics = TestDB::with_files( |
544 | r" | 705 | r" |