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.rs419
1 files changed, 30 insertions, 389 deletions
diff --git a/crates/ra_hir_ty/src/tests.rs b/crates/ra_hir_ty/src/tests.rs
index 5424e6bb1..016e689ff 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
11use std::sync::Arc; 11use std::sync::Arc;
12 12
13use expect::Expect;
13use hir_def::{ 14use hir_def::{
14 body::{BodySourceMap, SyntheticSyntax}, 15 body::{BodySourceMap, SyntheticSyntax},
15 child_by_source::ChildBySource, 16 child_by_source::ChildBySource,
@@ -20,23 +21,34 @@ use hir_def::{
20 AssocItemId, DefWithBodyId, LocalModuleId, Lookup, ModuleDefId, 21 AssocItemId, DefWithBodyId, LocalModuleId, Lookup, ModuleDefId,
21}; 22};
22use hir_expand::{db::AstDatabase, InFile}; 23use hir_expand::{db::AstDatabase, InFile};
23use insta::assert_snapshot; 24use ra_db::{fixture::WithFixture, FileRange, SourceDatabase, SourceDatabaseExt};
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;
32 31
33use crate::{ 32use crate::{
34 db::HirDatabase, display::HirDisplay, infer::TypeMismatch, test_db::TestDB, InferenceResult, Ty, 33 db::HirDatabase, display::HirDisplay, infer::TypeMismatch, test_db::TestDB, InferenceResult, Ty,
35}; 34};
36 35
37// 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
38// against snapshots of the expected results using insta. Use cargo-insta to 37// against snapshots of the expected results using expect. Use
39// update the snapshots. 38// `env UPDATE_EXPECT=1 cargo test -p ra_hir_ty` to update the snapshots.
39
40fn 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}
40 52
41fn check_types(ra_fixture: &str) { 53fn check_types(ra_fixture: &str) {
42 check_types_impl(ra_fixture, false) 54 check_types_impl(ra_fixture, false)
@@ -47,11 +59,10 @@ fn check_types_source_code(ra_fixture: &str) {
47} 59}
48 60
49fn check_types_impl(ra_fixture: &str, display_source: bool) { 61fn check_types_impl(ra_fixture: &str, display_source: bool) {
62 let _tracing = setup_tracing();
50 let db = TestDB::with_files(ra_fixture); 63 let db = TestDB::with_files(ra_fixture);
51 let mut checked_one = false; 64 let mut checked_one = false;
52 for file_id in db.all_files() { 65 for (file_id, annotations) in db.extract_annotations() {
53 let text = db.parse(file_id).syntax_node().to_string();
54 let annotations = extract_annotations(&text);
55 for (range, expected) in annotations { 66 for (range, expected) in annotations {
56 let ty = type_at_range(&db, FileRange { file_id, range }); 67 let ty = type_at_range(&db, FileRange { file_id, range });
57 let actual = if display_source { 68 let actual = if display_source {
@@ -70,7 +81,7 @@ fn check_types_impl(ra_fixture: &str, display_source: bool) {
70fn type_at_range(db: &TestDB, pos: FileRange) -> Ty { 81fn type_at_range(db: &TestDB, pos: FileRange) -> Ty {
71 let file = db.parse(pos.file_id).ok().unwrap(); 82 let file = db.parse(pos.file_id).ok().unwrap();
72 let expr = algo::find_node_at_range::<ast::Expr>(file.syntax(), pos.range).unwrap(); 83 let expr = algo::find_node_at_range::<ast::Expr>(file.syntax(), pos.range).unwrap();
73 let fn_def = expr.syntax().ancestors().find_map(ast::FnDef::cast).unwrap(); 84 let fn_def = expr.syntax().ancestors().find_map(ast::Fn::cast).unwrap();
74 let module = db.module_for_file(pos.file_id); 85 let module = db.module_for_file(pos.file_id);
75 let func = *module.child_by_source(db)[keys::FUNCTION] 86 let func = *module.child_by_source(db)[keys::FUNCTION]
76 .get(&InFile::new(pos.file_id.into(), fn_def)) 87 .get(&InFile::new(pos.file_id.into(), fn_def))
@@ -89,6 +100,7 @@ fn infer(ra_fixture: &str) -> String {
89} 100}
90 101
91fn infer_with_mismatches(content: &str, include_mismatches: bool) -> String { 102fn infer_with_mismatches(content: &str, include_mismatches: bool) -> String {
103 let _tracing = setup_tracing();
92 let (db, file_id) = TestDB::with_single_file(content); 104 let (db, file_id) = TestDB::with_single_file(content);
93 105
94 let mut buf = String::new(); 106 let mut buf = String::new();
@@ -320,7 +332,7 @@ fn typing_whitespace_inside_a_function_should_not_invalidate_types() {
320 " 332 "
321 .to_string(); 333 .to_string();
322 334
323 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));
324 336
325 { 337 {
326 let events = db.log_executed(|| { 338 let events = db.log_executed(|| {
@@ -334,385 +346,14 @@ fn typing_whitespace_inside_a_function_should_not_invalidate_types() {
334 } 346 }
335} 347}
336 348
337#[test] 349fn check_infer(ra_fixture: &str, expect: Expect) {
338fn no_such_field_diagnostics() { 350 let mut actual = infer(ra_fixture);
339 let diagnostics = TestDB::with_files( 351 actual.push('\n');
340 r" 352 expect.assert_eq(&actual);
341 //- /lib.rs
342 struct S { foo: i32, bar: () }
343 impl S {
344 fn new() -> S {
345 S {
346 foo: 92,
347 baz: 62,
348 }
349 }
350 }
351 ",
352 )
353 .diagnostics()
354 .0;
355
356 assert_snapshot!(diagnostics, @r###"
357 "baz: 62": no such field
358 "{\n foo: 92,\n baz: 62,\n }": Missing structure fields:
359 - bar
360 "###
361 );
362}
363
364#[test]
365fn no_such_field_with_feature_flag_diagnostics() {
366 let diagnostics = TestDB::with_files(
367 r#"
368 //- /lib.rs crate:foo cfg:feature=foo
369 struct MyStruct {
370 my_val: usize,
371 #[cfg(feature = "foo")]
372 bar: bool,
373 }
374
375 impl MyStruct {
376 #[cfg(feature = "foo")]
377 pub(crate) fn new(my_val: usize, bar: bool) -> Self {
378 Self { my_val, bar }
379 }
380
381 #[cfg(not(feature = "foo"))]
382 pub(crate) fn new(my_val: usize, _bar: bool) -> Self {
383 Self { my_val }
384 }
385 }
386 "#,
387 )
388 .diagnostics()
389 .0;
390
391 assert_snapshot!(diagnostics, @r###""###);
392}
393
394#[test]
395fn no_such_field_enum_with_feature_flag_diagnostics() {
396 let diagnostics = TestDB::with_files(
397 r#"
398 //- /lib.rs crate:foo cfg:feature=foo
399 enum Foo {
400 #[cfg(not(feature = "foo"))]
401 Buz,
402 #[cfg(feature = "foo")]
403 Bar,
404 Baz
405 }
406
407 fn test_fn(f: Foo) {
408 match f {
409 Foo::Bar => {},
410 Foo::Baz => {},
411 }
412 }
413 "#,
414 )
415 .diagnostics()
416 .0;
417
418 assert_snapshot!(diagnostics, @r###""###);
419}
420
421#[test]
422fn no_such_field_with_feature_flag_diagnostics_on_struct_lit() {
423 let diagnostics = TestDB::with_files(
424 r#"
425 //- /lib.rs crate:foo cfg:feature=foo
426 struct S {
427 #[cfg(feature = "foo")]
428 foo: u32,
429 #[cfg(not(feature = "foo"))]
430 bar: u32,
431 }
432
433 impl S {
434 #[cfg(feature = "foo")]
435 fn new(foo: u32) -> Self {
436 Self { foo }
437 }
438 #[cfg(not(feature = "foo"))]
439 fn new(bar: u32) -> Self {
440 Self { bar }
441 }
442 }
443 "#,
444 )
445 .diagnostics()
446 .0;
447
448 assert_snapshot!(diagnostics, @r###""###);
449}
450
451#[test]
452fn no_such_field_with_feature_flag_diagnostics_on_block_expr() {
453 let diagnostics = TestDB::with_files(
454 r#"
455 //- /lib.rs crate:foo cfg:feature=foo
456 struct S {
457 #[cfg(feature = "foo")]
458 foo: u32,
459 #[cfg(not(feature = "foo"))]
460 bar: u32,
461 }
462
463 impl S {
464 fn new(bar: u32) -> Self {
465 #[cfg(feature = "foo")]
466 {
467 Self { foo: bar }
468 }
469 #[cfg(not(feature = "foo"))]
470 {
471 Self { bar }
472 }
473 }
474 }
475 "#,
476 )
477 .diagnostics()
478 .0;
479
480 assert_snapshot!(diagnostics, @r###""###);
481}
482
483#[test]
484fn no_such_field_with_feature_flag_diagnostics_on_struct_fields() {
485 let diagnostics = TestDB::with_files(
486 r#"
487 //- /lib.rs crate:foo cfg:feature=foo
488 struct S {
489 #[cfg(feature = "foo")]
490 foo: u32,
491 #[cfg(not(feature = "foo"))]
492 bar: u32,
493 }
494
495 impl S {
496 fn new(val: u32) -> Self {
497 Self {
498 #[cfg(feature = "foo")]
499 foo: val,
500 #[cfg(not(feature = "foo"))]
501 bar: val,
502 }
503 }
504 }
505 "#,
506 )
507 .diagnostics()
508 .0;
509
510 assert_snapshot!(diagnostics, @r###""###);
511}
512
513#[test]
514fn missing_record_pat_field_diagnostic() {
515 let diagnostics = TestDB::with_files(
516 r"
517 //- /lib.rs
518 struct S { foo: i32, bar: () }
519 fn baz(s: S) {
520 let S { foo: _ } = s;
521 }
522 ",
523 )
524 .diagnostics()
525 .0;
526
527 assert_snapshot!(diagnostics, @r###"
528 "{ foo: _ }": Missing structure fields:
529 - bar
530 "###
531 );
532}
533
534#[test]
535fn missing_record_pat_field_no_diagnostic_if_not_exhaustive() {
536 let diagnostics = TestDB::with_files(
537 r"
538 //- /lib.rs
539 struct S { foo: i32, bar: () }
540 fn baz(s: S) -> i32 {
541 match s {
542 S { foo, .. } => foo,
543 }
544 }
545 ",
546 )
547 .diagnostics()
548 .0;
549
550 assert_snapshot!(diagnostics, @"");
551}
552
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} 353}
607 354
608", 355fn check_infer_with_mismatches(ra_fixture: &str, expect: Expect) {
609 ) 356 let mut actual = infer_with_mismatches(ra_fixture, true);
610 .diagnostics() 357 actual.push('\n');
611 .0; 358 expect.assert_eq(&actual);
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]
703fn break_outside_of_loop() {
704 let diagnostics = TestDB::with_files(
705 r"
706 //- /lib.rs
707 fn foo() {
708 break;
709 }
710 ",
711 )
712 .diagnostics()
713 .0;
714
715 assert_snapshot!(diagnostics, @r###""break": break outside of loop
716 "###
717 );
718} 359}