diff options
Diffstat (limited to 'crates/ide')
-rw-r--r-- | crates/ide/src/diagnostics.rs | 225 |
1 files changed, 224 insertions, 1 deletions
diff --git a/crates/ide/src/diagnostics.rs b/crates/ide/src/diagnostics.rs index d5c954b8b..b791747c2 100644 --- a/crates/ide/src/diagnostics.rs +++ b/crates/ide/src/diagnostics.rs | |||
@@ -305,6 +305,7 @@ fn unresolved_fix(id: &'static str, label: &str, target: TextRange) -> Assist { | |||
305 | #[cfg(test)] | 305 | #[cfg(test)] |
306 | mod tests { | 306 | mod tests { |
307 | use expect_test::Expect; | 307 | use expect_test::Expect; |
308 | use hir::diagnostics::DiagnosticCode; | ||
308 | use ide_assists::AssistResolveStrategy; | 309 | use ide_assists::AssistResolveStrategy; |
309 | use stdx::trim_indent; | 310 | use stdx::trim_indent; |
310 | use test_utils::{assert_eq_text, extract_annotations}; | 311 | use test_utils::{assert_eq_text, extract_annotations}; |
@@ -410,7 +411,12 @@ mod tests { | |||
410 | .unwrap(); | 411 | .unwrap(); |
411 | 412 | ||
412 | let expected = extract_annotations(&*analysis.file_text(file_id).unwrap()); | 413 | let expected = extract_annotations(&*analysis.file_text(file_id).unwrap()); |
413 | let actual = diagnostics.into_iter().map(|d| (d.range, d.message)).collect::<Vec<_>>(); | 414 | let mut actual = diagnostics |
415 | .into_iter() | ||
416 | .filter(|d| d.code != Some(DiagnosticCode("inactive-code"))) | ||
417 | .map(|d| (d.range, d.message)) | ||
418 | .collect::<Vec<_>>(); | ||
419 | actual.sort_by_key(|(range, _)| range.start()); | ||
414 | assert_eq!(expected, actual); | 420 | assert_eq!(expected, actual); |
415 | } | 421 | } |
416 | 422 | ||
@@ -719,4 +725,221 @@ mod foo; | |||
719 | "#, | 725 | "#, |
720 | ); | 726 | ); |
721 | } | 727 | } |
728 | |||
729 | #[test] | ||
730 | fn break_outside_of_loop() { | ||
731 | check_diagnostics( | ||
732 | r#" | ||
733 | fn foo() { break; } | ||
734 | //^^^^^ break outside of loop | ||
735 | "#, | ||
736 | ); | ||
737 | } | ||
738 | |||
739 | #[test] | ||
740 | fn no_such_field_diagnostics() { | ||
741 | check_diagnostics( | ||
742 | r#" | ||
743 | struct S { foo: i32, bar: () } | ||
744 | impl S { | ||
745 | fn new() -> S { | ||
746 | S { | ||
747 | //^ Missing structure fields: | ||
748 | //| - bar | ||
749 | foo: 92, | ||
750 | baz: 62, | ||
751 | //^^^^^^^ no such field | ||
752 | } | ||
753 | } | ||
754 | } | ||
755 | "#, | ||
756 | ); | ||
757 | } | ||
758 | #[test] | ||
759 | fn no_such_field_with_feature_flag_diagnostics() { | ||
760 | check_diagnostics( | ||
761 | r#" | ||
762 | //- /lib.rs crate:foo cfg:feature=foo | ||
763 | struct MyStruct { | ||
764 | my_val: usize, | ||
765 | #[cfg(feature = "foo")] | ||
766 | bar: bool, | ||
767 | } | ||
768 | |||
769 | impl MyStruct { | ||
770 | #[cfg(feature = "foo")] | ||
771 | pub(crate) fn new(my_val: usize, bar: bool) -> Self { | ||
772 | Self { my_val, bar } | ||
773 | } | ||
774 | #[cfg(not(feature = "foo"))] | ||
775 | pub(crate) fn new(my_val: usize, _bar: bool) -> Self { | ||
776 | Self { my_val } | ||
777 | } | ||
778 | } | ||
779 | "#, | ||
780 | ); | ||
781 | } | ||
782 | |||
783 | #[test] | ||
784 | fn no_such_field_enum_with_feature_flag_diagnostics() { | ||
785 | check_diagnostics( | ||
786 | r#" | ||
787 | //- /lib.rs crate:foo cfg:feature=foo | ||
788 | enum Foo { | ||
789 | #[cfg(not(feature = "foo"))] | ||
790 | Buz, | ||
791 | #[cfg(feature = "foo")] | ||
792 | Bar, | ||
793 | Baz | ||
794 | } | ||
795 | |||
796 | fn test_fn(f: Foo) { | ||
797 | match f { | ||
798 | Foo::Bar => {}, | ||
799 | Foo::Baz => {}, | ||
800 | } | ||
801 | } | ||
802 | "#, | ||
803 | ); | ||
804 | } | ||
805 | |||
806 | #[test] | ||
807 | fn no_such_field_with_feature_flag_diagnostics_on_struct_lit() { | ||
808 | check_diagnostics( | ||
809 | r#" | ||
810 | //- /lib.rs crate:foo cfg:feature=foo | ||
811 | struct S { | ||
812 | #[cfg(feature = "foo")] | ||
813 | foo: u32, | ||
814 | #[cfg(not(feature = "foo"))] | ||
815 | bar: u32, | ||
816 | } | ||
817 | |||
818 | impl S { | ||
819 | #[cfg(feature = "foo")] | ||
820 | fn new(foo: u32) -> Self { | ||
821 | Self { foo } | ||
822 | } | ||
823 | #[cfg(not(feature = "foo"))] | ||
824 | fn new(bar: u32) -> Self { | ||
825 | Self { bar } | ||
826 | } | ||
827 | fn new2(bar: u32) -> Self { | ||
828 | #[cfg(feature = "foo")] | ||
829 | { Self { foo: bar } } | ||
830 | #[cfg(not(feature = "foo"))] | ||
831 | { Self { bar } } | ||
832 | } | ||
833 | fn new2(val: u32) -> Self { | ||
834 | Self { | ||
835 | #[cfg(feature = "foo")] | ||
836 | foo: val, | ||
837 | #[cfg(not(feature = "foo"))] | ||
838 | bar: val, | ||
839 | } | ||
840 | } | ||
841 | } | ||
842 | "#, | ||
843 | ); | ||
844 | } | ||
845 | |||
846 | #[test] | ||
847 | fn no_such_field_with_type_macro() { | ||
848 | check_diagnostics( | ||
849 | r#" | ||
850 | macro_rules! Type { () => { u32 }; } | ||
851 | struct Foo { bar: Type![] } | ||
852 | |||
853 | impl Foo { | ||
854 | fn new() -> Self { | ||
855 | Foo { bar: 0 } | ||
856 | } | ||
857 | } | ||
858 | "#, | ||
859 | ); | ||
860 | } | ||
861 | |||
862 | #[test] | ||
863 | fn missing_unsafe_diagnostic_with_raw_ptr() { | ||
864 | check_diagnostics( | ||
865 | r#" | ||
866 | fn main() { | ||
867 | let x = &5 as *const usize; | ||
868 | unsafe { let y = *x; } | ||
869 | let z = *x; | ||
870 | } //^^ This operation is unsafe and requires an unsafe function or block | ||
871 | "#, | ||
872 | ) | ||
873 | } | ||
874 | |||
875 | #[test] | ||
876 | fn missing_unsafe_diagnostic_with_unsafe_call() { | ||
877 | check_diagnostics( | ||
878 | r#" | ||
879 | struct HasUnsafe; | ||
880 | |||
881 | impl HasUnsafe { | ||
882 | unsafe fn unsafe_fn(&self) { | ||
883 | let x = &5 as *const usize; | ||
884 | let y = *x; | ||
885 | } | ||
886 | } | ||
887 | |||
888 | unsafe fn unsafe_fn() { | ||
889 | let x = &5 as *const usize; | ||
890 | let y = *x; | ||
891 | } | ||
892 | |||
893 | fn main() { | ||
894 | unsafe_fn(); | ||
895 | //^^^^^^^^^^^ This operation is unsafe and requires an unsafe function or block | ||
896 | HasUnsafe.unsafe_fn(); | ||
897 | //^^^^^^^^^^^^^^^^^^^^^ This operation is unsafe and requires an unsafe function or block | ||
898 | unsafe { | ||
899 | unsafe_fn(); | ||
900 | HasUnsafe.unsafe_fn(); | ||
901 | } | ||
902 | } | ||
903 | "#, | ||
904 | ); | ||
905 | } | ||
906 | |||
907 | #[test] | ||
908 | fn missing_unsafe_diagnostic_with_static_mut() { | ||
909 | check_diagnostics( | ||
910 | r#" | ||
911 | struct Ty { | ||
912 | a: u8, | ||
913 | } | ||
914 | |||
915 | static mut STATIC_MUT: Ty = Ty { a: 0 }; | ||
916 | |||
917 | fn main() { | ||
918 | let x = STATIC_MUT.a; | ||
919 | //^^^^^^^^^^ This operation is unsafe and requires an unsafe function or block | ||
920 | unsafe { | ||
921 | let x = STATIC_MUT.a; | ||
922 | } | ||
923 | } | ||
924 | "#, | ||
925 | ); | ||
926 | } | ||
927 | |||
928 | #[test] | ||
929 | fn no_missing_unsafe_diagnostic_with_safe_intrinsic() { | ||
930 | check_diagnostics( | ||
931 | r#" | ||
932 | extern "rust-intrinsic" { | ||
933 | pub fn bitreverse(x: u32) -> u32; // Safe intrinsic | ||
934 | pub fn floorf32(x: f32) -> f32; // Unsafe intrinsic | ||
935 | } | ||
936 | |||
937 | fn main() { | ||
938 | let _ = bitreverse(12); | ||
939 | let _ = floorf32(12.0); | ||
940 | //^^^^^^^^^^^^^^ This operation is unsafe and requires an unsafe function or block | ||
941 | } | ||
942 | "#, | ||
943 | ); | ||
944 | } | ||
722 | } | 945 | } |