diff options
author | Zac Pullar-Strecker <[email protected]> | 2020-07-31 03:12:44 +0100 |
---|---|---|
committer | Zac Pullar-Strecker <[email protected]> | 2020-07-31 03:12:44 +0100 |
commit | f05d7b41a719d848844b054a16477b29d0f063c6 (patch) | |
tree | 0a8a0946e8aef2ce64d4c13d0035ba41cce2daf3 /crates/ra_hir_ty/src/tests.rs | |
parent | 73ff610e41959e3e7c78a2b4b25b086883132956 (diff) | |
parent | 6b7cb8b5ab539fc4333ce34bc29bf77c976f232a (diff) |
Merge remote-tracking branch 'upstream/master' into 503-hover-doc-links
Hasn't fixed tests yet.
Diffstat (limited to 'crates/ra_hir_ty/src/tests.rs')
-rw-r--r-- | crates/ra_hir_ty/src/tests.rs | 419 |
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 | ||
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,23 +21,34 @@ 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}, |
28 | SyntaxNode, | 28 | SyntaxNode, |
29 | }; | 29 | }; |
30 | use stdx::format_to; | 30 | use stdx::format_to; |
31 | use test_utils::extract_annotations; | ||
32 | 31 | ||
33 | use crate::{ | 32 | use 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 | |||
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 | } | ||
40 | 52 | ||
41 | fn check_types(ra_fixture: &str) { | 53 | fn 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 | ||
49 | 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(); | ||
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) { | |||
70 | fn type_at_range(db: &TestDB, pos: FileRange) -> Ty { | 81 | fn 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 | ||
91 | 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(); | ||
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] | 349 | fn check_infer(ra_fixture: &str, expect: Expect) { |
338 | fn 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] | ||
365 | fn 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] | ||
395 | fn 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] | ||
422 | fn 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] | ||
452 | fn 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] | ||
484 | fn 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] | ||
514 | fn 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] | ||
535 | fn 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] | ||
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 | } | 353 | } |
607 | 354 | ||
608 | ", | 355 | fn 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] | ||
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] | ||
703 | fn 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 | } |