aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_hir_ty/src/tests.rs
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_hir_ty/src/tests.rs')
-rw-r--r--crates/ra_hir_ty/src/tests.rs199
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};
22use hir_expand::{db::AstDatabase, InFile}; 22use hir_expand::{db::AstDatabase, InFile};
23use insta::assert_snapshot; 23use insta::assert_snapshot;
24use ra_db::{fixture::WithFixture, salsa::Database, FilePosition, SourceDatabase}; 24use ra_db::{fixture::WithFixture, salsa::Database, FileRange, SourceDatabase};
25use ra_syntax::{ 25use ra_syntax::{
26 algo, 26 algo,
27 ast::{self, AstNode}, 27 ast::{self, AstNode},
28 SyntaxNode, 28 SyntaxNode,
29}; 29};
30use stdx::format_to; 30use stdx::format_to;
31use test_utils::extract_annotations;
31 32
32use crate::{ 33use 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
40fn type_at_pos(db: &TestDB, pos: FilePosition) -> String { 41fn 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
44fn displayed_source_at_pos(db: &TestDB, pos: FilePosition) -> String { 45fn 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
48fn type_at_pos_displayed( 49fn 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
70fn 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
70fn 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
75fn infer(ra_fixture: &str) -> String { 87fn 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]
554fn missing_unsafe_diagnostic_with_raw_ptr() {
555 let diagnostics = TestDB::with_files(
556 r"
557//- /lib.rs
558fn 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]
571fn missing_unsafe_diagnostic_with_unsafe_call() {
572 let diagnostics = TestDB::with_files(
573 r"
574//- /lib.rs
575unsafe fn unsafe_fn() {
576 let x = &5 as *const usize;
577 let y = *x;
578}
579
580fn 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]
592fn missing_unsafe_diagnostic_with_unsafe_method_call() {
593 let diagnostics = TestDB::with_files(
594 r"
595struct HasUnsafe;
596
597impl HasUnsafe {
598 unsafe fn unsafe_fn(&self) {
599 let x = &5 as *const usize;
600 let y = *x;
601 }
602}
603
604fn 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]
617fn no_missing_unsafe_diagnostic_with_raw_ptr_in_unsafe_block() {
618 let diagnostics = TestDB::with_files(
619 r"
620fn 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]
635fn missing_unsafe_diagnostic_with_raw_ptr_outside_unsafe_block() {
636 let diagnostics = TestDB::with_files(
637 r"
638fn 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]
654fn no_missing_unsafe_diagnostic_with_unsafe_call_in_unsafe_block() {
655 let diagnostics = TestDB::with_files(
656 r"
657unsafe fn unsafe_fn() {
658 let x = &5 as *const usize;
659 let y = *x;
660}
661
662fn 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]
676fn no_missing_unsafe_diagnostic_with_unsafe_method_call_in_unsafe_block() {
677 let diagnostics = TestDB::with_files(
678 r"
679struct HasUnsafe;
680
681impl HasUnsafe {
682 unsafe fn unsafe_fn() {
683 let x = &5 as *const usize;
684 let y = *x;
685 }
686}
687
688fn 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]
542fn break_outside_of_loop() { 703fn break_outside_of_loop() {
543 let diagnostics = TestDB::with_files( 704 let diagnostics = TestDB::with_files(
544 r" 705 r"