aboutsummaryrefslogtreecommitdiff
path: root/crates/ide/src/diagnostics.rs
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ide/src/diagnostics.rs')
-rw-r--r--crates/ide/src/diagnostics.rs225
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)]
306mod tests { 306mod 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#"
733fn foo() { break; }
734 //^^^^^ break outside of loop
735"#,
736 );
737 }
738
739 #[test]
740 fn no_such_field_diagnostics() {
741 check_diagnostics(
742 r#"
743struct S { foo: i32, bar: () }
744impl 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
763struct MyStruct {
764 my_val: usize,
765 #[cfg(feature = "foo")]
766 bar: bool,
767}
768
769impl 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
788enum Foo {
789 #[cfg(not(feature = "foo"))]
790 Buz,
791 #[cfg(feature = "foo")]
792 Bar,
793 Baz
794}
795
796fn 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
811struct S {
812 #[cfg(feature = "foo")]
813 foo: u32,
814 #[cfg(not(feature = "foo"))]
815 bar: u32,
816}
817
818impl 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#"
850macro_rules! Type { () => { u32 }; }
851struct Foo { bar: Type![] }
852
853impl 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#"
866fn 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#"
879struct HasUnsafe;
880
881impl HasUnsafe {
882 unsafe fn unsafe_fn(&self) {
883 let x = &5 as *const usize;
884 let y = *x;
885 }
886}
887
888unsafe fn unsafe_fn() {
889 let x = &5 as *const usize;
890 let y = *x;
891}
892
893fn 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#"
911struct Ty {
912 a: u8,
913}
914
915static mut STATIC_MUT: Ty = Ty { a: 0 };
916
917fn 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#"
932extern "rust-intrinsic" {
933 pub fn bitreverse(x: u32) -> u32; // Safe intrinsic
934 pub fn floorf32(x: f32) -> f32; // Unsafe intrinsic
935}
936
937fn 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}