diff options
Diffstat (limited to 'crates/ide/src/diagnostics.rs')
-rw-r--r-- | crates/ide/src/diagnostics.rs | 499 |
1 files changed, 17 insertions, 482 deletions
diff --git a/crates/ide/src/diagnostics.rs b/crates/ide/src/diagnostics.rs index aeccf1164..4c92d0cf4 100644 --- a/crates/ide/src/diagnostics.rs +++ b/crates/ide/src/diagnostics.rs | |||
@@ -4,14 +4,19 @@ | |||
4 | //! macro-expanded files, but we need to present them to the users in terms of | 4 | //! macro-expanded files, but we need to present them to the users in terms of |
5 | //! original files. So we need to map the ranges. | 5 | //! original files. So we need to map the ranges. |
6 | 6 | ||
7 | mod unresolved_module; | 7 | mod break_outside_of_loop; |
8 | mod inactive_code; | ||
9 | mod macro_error; | ||
10 | mod mismatched_arg_count; | ||
11 | mod missing_fields; | ||
12 | mod missing_unsafe; | ||
13 | mod no_such_field; | ||
14 | mod unimplemented_builtin_macro; | ||
8 | mod unresolved_extern_crate; | 15 | mod unresolved_extern_crate; |
9 | mod unresolved_import; | 16 | mod unresolved_import; |
10 | mod unresolved_macro_call; | 17 | mod unresolved_macro_call; |
18 | mod unresolved_module; | ||
11 | mod unresolved_proc_macro; | 19 | mod unresolved_proc_macro; |
12 | mod macro_error; | ||
13 | mod inactive_code; | ||
14 | mod missing_fields; | ||
15 | 20 | ||
16 | mod fixes; | 21 | mod fixes; |
17 | mod field_shorthand; | 22 | mod field_shorthand; |
@@ -160,9 +165,6 @@ pub(crate) fn diagnostics( | |||
160 | .on::<hir::diagnostics::MissingOkOrSomeInTailExpr, _>(|d| { | 165 | .on::<hir::diagnostics::MissingOkOrSomeInTailExpr, _>(|d| { |
161 | res.borrow_mut().push(diagnostic_with_fix(d, &sema, resolve)); | 166 | res.borrow_mut().push(diagnostic_with_fix(d, &sema, resolve)); |
162 | }) | 167 | }) |
163 | .on::<hir::diagnostics::NoSuchField, _>(|d| { | ||
164 | res.borrow_mut().push(diagnostic_with_fix(d, &sema, resolve)); | ||
165 | }) | ||
166 | .on::<hir::diagnostics::RemoveThisSemicolon, _>(|d| { | 168 | .on::<hir::diagnostics::RemoveThisSemicolon, _>(|d| { |
167 | res.borrow_mut().push(diagnostic_with_fix(d, &sema, resolve)); | 169 | res.borrow_mut().push(diagnostic_with_fix(d, &sema, resolve)); |
168 | }) | 170 | }) |
@@ -185,11 +187,6 @@ pub(crate) fn diagnostics( | |||
185 | .with_code(Some(d.code())), | 187 | .with_code(Some(d.code())), |
186 | ); | 188 | ); |
187 | }) | 189 | }) |
188 | .on::<hir::diagnostics::UnimplementedBuiltinMacro, _>(|d| { | ||
189 | let display_range = sema.diagnostics_display_range(d.display_source()).range; | ||
190 | res.borrow_mut() | ||
191 | .push(Diagnostic::hint(display_range, d.message()).with_code(Some(d.code()))); | ||
192 | }) | ||
193 | // Only collect experimental diagnostics when they're enabled. | 190 | // Only collect experimental diagnostics when they're enabled. |
194 | .filter(|diag| !(diag.is_experimental() && config.disable_experimental)) | 191 | .filter(|diag| !(diag.is_experimental() && config.disable_experimental)) |
195 | .filter(|diag| !config.disabled.contains(diag.code().as_str())); | 192 | .filter(|diag| !config.disabled.contains(diag.code().as_str())); |
@@ -224,13 +221,18 @@ pub(crate) fn diagnostics( | |||
224 | for diag in diags { | 221 | for diag in diags { |
225 | #[rustfmt::skip] | 222 | #[rustfmt::skip] |
226 | let d = match diag { | 223 | let d = match diag { |
227 | AnyDiagnostic::UnresolvedModule(d) => unresolved_module::unresolved_module(&ctx, &d), | 224 | AnyDiagnostic::BreakOutsideOfLoop(d) => break_outside_of_loop::break_outside_of_loop(&ctx, &d), |
225 | AnyDiagnostic::MacroError(d) => macro_error::macro_error(&ctx, &d), | ||
226 | AnyDiagnostic::MissingFields(d) => missing_fields::missing_fields(&ctx, &d), | ||
227 | AnyDiagnostic::MissingUnsafe(d) => missing_unsafe::missing_unsafe(&ctx, &d), | ||
228 | AnyDiagnostic::MismatchedArgCount(d) => mismatched_arg_count::mismatched_arg_count(&ctx, &d), | ||
229 | AnyDiagnostic::NoSuchField(d) => no_such_field::no_such_field(&ctx, &d), | ||
230 | AnyDiagnostic::UnimplementedBuiltinMacro(d) => unimplemented_builtin_macro::unimplemented_builtin_macro(&ctx, &d), | ||
228 | AnyDiagnostic::UnresolvedExternCrate(d) => unresolved_extern_crate::unresolved_extern_crate(&ctx, &d), | 231 | AnyDiagnostic::UnresolvedExternCrate(d) => unresolved_extern_crate::unresolved_extern_crate(&ctx, &d), |
229 | AnyDiagnostic::UnresolvedImport(d) => unresolved_import::unresolved_import(&ctx, &d), | 232 | AnyDiagnostic::UnresolvedImport(d) => unresolved_import::unresolved_import(&ctx, &d), |
230 | AnyDiagnostic::UnresolvedMacroCall(d) => unresolved_macro_call::unresolved_macro_call(&ctx, &d), | 233 | AnyDiagnostic::UnresolvedMacroCall(d) => unresolved_macro_call::unresolved_macro_call(&ctx, &d), |
234 | AnyDiagnostic::UnresolvedModule(d) => unresolved_module::unresolved_module(&ctx, &d), | ||
231 | AnyDiagnostic::UnresolvedProcMacro(d) => unresolved_proc_macro::unresolved_proc_macro(&ctx, &d), | 235 | AnyDiagnostic::UnresolvedProcMacro(d) => unresolved_proc_macro::unresolved_proc_macro(&ctx, &d), |
232 | AnyDiagnostic::MissingFields(d) => missing_fields::missing_fields(&ctx, &d), | ||
233 | AnyDiagnostic::MacroError(d) => macro_error::macro_error(&ctx, &d), | ||
234 | 236 | ||
235 | AnyDiagnostic::InactiveCode(d) => match inactive_code::inactive_code(&ctx, &d) { | 237 | AnyDiagnostic::InactiveCode(d) => match inactive_code::inactive_code(&ctx, &d) { |
236 | Some(it) => it, | 238 | Some(it) => it, |
@@ -715,223 +717,6 @@ mod foo; | |||
715 | ); | 717 | ); |
716 | } | 718 | } |
717 | 719 | ||
718 | #[test] | ||
719 | fn break_outside_of_loop() { | ||
720 | check_diagnostics( | ||
721 | r#" | ||
722 | fn foo() { break; } | ||
723 | //^^^^^ break outside of loop | ||
724 | "#, | ||
725 | ); | ||
726 | } | ||
727 | |||
728 | #[test] | ||
729 | fn no_such_field_diagnostics() { | ||
730 | check_diagnostics( | ||
731 | r#" | ||
732 | struct S { foo: i32, bar: () } | ||
733 | impl S { | ||
734 | fn new() -> S { | ||
735 | S { | ||
736 | //^ Missing structure fields: | ||
737 | //| - bar | ||
738 | foo: 92, | ||
739 | baz: 62, | ||
740 | //^^^^^^^ no such field | ||
741 | } | ||
742 | } | ||
743 | } | ||
744 | "#, | ||
745 | ); | ||
746 | } | ||
747 | #[test] | ||
748 | fn no_such_field_with_feature_flag_diagnostics() { | ||
749 | check_diagnostics( | ||
750 | r#" | ||
751 | //- /lib.rs crate:foo cfg:feature=foo | ||
752 | struct MyStruct { | ||
753 | my_val: usize, | ||
754 | #[cfg(feature = "foo")] | ||
755 | bar: bool, | ||
756 | } | ||
757 | |||
758 | impl MyStruct { | ||
759 | #[cfg(feature = "foo")] | ||
760 | pub(crate) fn new(my_val: usize, bar: bool) -> Self { | ||
761 | Self { my_val, bar } | ||
762 | } | ||
763 | #[cfg(not(feature = "foo"))] | ||
764 | pub(crate) fn new(my_val: usize, _bar: bool) -> Self { | ||
765 | Self { my_val } | ||
766 | } | ||
767 | } | ||
768 | "#, | ||
769 | ); | ||
770 | } | ||
771 | |||
772 | #[test] | ||
773 | fn no_such_field_enum_with_feature_flag_diagnostics() { | ||
774 | check_diagnostics( | ||
775 | r#" | ||
776 | //- /lib.rs crate:foo cfg:feature=foo | ||
777 | enum Foo { | ||
778 | #[cfg(not(feature = "foo"))] | ||
779 | Buz, | ||
780 | #[cfg(feature = "foo")] | ||
781 | Bar, | ||
782 | Baz | ||
783 | } | ||
784 | |||
785 | fn test_fn(f: Foo) { | ||
786 | match f { | ||
787 | Foo::Bar => {}, | ||
788 | Foo::Baz => {}, | ||
789 | } | ||
790 | } | ||
791 | "#, | ||
792 | ); | ||
793 | } | ||
794 | |||
795 | #[test] | ||
796 | fn no_such_field_with_feature_flag_diagnostics_on_struct_lit() { | ||
797 | check_diagnostics( | ||
798 | r#" | ||
799 | //- /lib.rs crate:foo cfg:feature=foo | ||
800 | struct S { | ||
801 | #[cfg(feature = "foo")] | ||
802 | foo: u32, | ||
803 | #[cfg(not(feature = "foo"))] | ||
804 | bar: u32, | ||
805 | } | ||
806 | |||
807 | impl S { | ||
808 | #[cfg(feature = "foo")] | ||
809 | fn new(foo: u32) -> Self { | ||
810 | Self { foo } | ||
811 | } | ||
812 | #[cfg(not(feature = "foo"))] | ||
813 | fn new(bar: u32) -> Self { | ||
814 | Self { bar } | ||
815 | } | ||
816 | fn new2(bar: u32) -> Self { | ||
817 | #[cfg(feature = "foo")] | ||
818 | { Self { foo: bar } } | ||
819 | #[cfg(not(feature = "foo"))] | ||
820 | { Self { bar } } | ||
821 | } | ||
822 | fn new2(val: u32) -> Self { | ||
823 | Self { | ||
824 | #[cfg(feature = "foo")] | ||
825 | foo: val, | ||
826 | #[cfg(not(feature = "foo"))] | ||
827 | bar: val, | ||
828 | } | ||
829 | } | ||
830 | } | ||
831 | "#, | ||
832 | ); | ||
833 | } | ||
834 | |||
835 | #[test] | ||
836 | fn no_such_field_with_type_macro() { | ||
837 | check_diagnostics( | ||
838 | r#" | ||
839 | macro_rules! Type { () => { u32 }; } | ||
840 | struct Foo { bar: Type![] } | ||
841 | |||
842 | impl Foo { | ||
843 | fn new() -> Self { | ||
844 | Foo { bar: 0 } | ||
845 | } | ||
846 | } | ||
847 | "#, | ||
848 | ); | ||
849 | } | ||
850 | |||
851 | #[test] | ||
852 | fn missing_unsafe_diagnostic_with_raw_ptr() { | ||
853 | check_diagnostics( | ||
854 | r#" | ||
855 | fn main() { | ||
856 | let x = &5 as *const usize; | ||
857 | unsafe { let y = *x; } | ||
858 | let z = *x; | ||
859 | } //^^ This operation is unsafe and requires an unsafe function or block | ||
860 | "#, | ||
861 | ) | ||
862 | } | ||
863 | |||
864 | #[test] | ||
865 | fn missing_unsafe_diagnostic_with_unsafe_call() { | ||
866 | check_diagnostics( | ||
867 | r#" | ||
868 | struct HasUnsafe; | ||
869 | |||
870 | impl HasUnsafe { | ||
871 | unsafe fn unsafe_fn(&self) { | ||
872 | let x = &5 as *const usize; | ||
873 | let y = *x; | ||
874 | } | ||
875 | } | ||
876 | |||
877 | unsafe fn unsafe_fn() { | ||
878 | let x = &5 as *const usize; | ||
879 | let y = *x; | ||
880 | } | ||
881 | |||
882 | fn main() { | ||
883 | unsafe_fn(); | ||
884 | //^^^^^^^^^^^ This operation is unsafe and requires an unsafe function or block | ||
885 | HasUnsafe.unsafe_fn(); | ||
886 | //^^^^^^^^^^^^^^^^^^^^^ This operation is unsafe and requires an unsafe function or block | ||
887 | unsafe { | ||
888 | unsafe_fn(); | ||
889 | HasUnsafe.unsafe_fn(); | ||
890 | } | ||
891 | } | ||
892 | "#, | ||
893 | ); | ||
894 | } | ||
895 | |||
896 | #[test] | ||
897 | fn missing_unsafe_diagnostic_with_static_mut() { | ||
898 | check_diagnostics( | ||
899 | r#" | ||
900 | struct Ty { | ||
901 | a: u8, | ||
902 | } | ||
903 | |||
904 | static mut STATIC_MUT: Ty = Ty { a: 0 }; | ||
905 | |||
906 | fn main() { | ||
907 | let x = STATIC_MUT.a; | ||
908 | //^^^^^^^^^^ This operation is unsafe and requires an unsafe function or block | ||
909 | unsafe { | ||
910 | let x = STATIC_MUT.a; | ||
911 | } | ||
912 | } | ||
913 | "#, | ||
914 | ); | ||
915 | } | ||
916 | |||
917 | #[test] | ||
918 | fn no_missing_unsafe_diagnostic_with_safe_intrinsic() { | ||
919 | check_diagnostics( | ||
920 | r#" | ||
921 | extern "rust-intrinsic" { | ||
922 | pub fn bitreverse(x: u32) -> u32; // Safe intrinsic | ||
923 | pub fn floorf32(x: f32) -> f32; // Unsafe intrinsic | ||
924 | } | ||
925 | |||
926 | fn main() { | ||
927 | let _ = bitreverse(12); | ||
928 | let _ = floorf32(12.0); | ||
929 | //^^^^^^^^^^^^^^ This operation is unsafe and requires an unsafe function or block | ||
930 | } | ||
931 | "#, | ||
932 | ); | ||
933 | } | ||
934 | |||
935 | // Register the required standard library types to make the tests work | 720 | // Register the required standard library types to make the tests work |
936 | fn add_filter_map_with_find_next_boilerplate(body: &str) -> String { | 721 | fn add_filter_map_with_find_next_boilerplate(body: &str) -> String { |
937 | let prefix = r#" | 722 | let prefix = r#" |
@@ -1054,256 +839,6 @@ fn x(a: S) { | |||
1054 | } | 839 | } |
1055 | 840 | ||
1056 | #[test] | 841 | #[test] |
1057 | fn simple_free_fn_zero() { | ||
1058 | check_diagnostics( | ||
1059 | r#" | ||
1060 | fn zero() {} | ||
1061 | fn f() { zero(1); } | ||
1062 | //^^^^^^^ Expected 0 arguments, found 1 | ||
1063 | "#, | ||
1064 | ); | ||
1065 | |||
1066 | check_diagnostics( | ||
1067 | r#" | ||
1068 | fn zero() {} | ||
1069 | fn f() { zero(); } | ||
1070 | "#, | ||
1071 | ); | ||
1072 | } | ||
1073 | |||
1074 | #[test] | ||
1075 | fn simple_free_fn_one() { | ||
1076 | check_diagnostics( | ||
1077 | r#" | ||
1078 | fn one(arg: u8) {} | ||
1079 | fn f() { one(); } | ||
1080 | //^^^^^ Expected 1 argument, found 0 | ||
1081 | "#, | ||
1082 | ); | ||
1083 | |||
1084 | check_diagnostics( | ||
1085 | r#" | ||
1086 | fn one(arg: u8) {} | ||
1087 | fn f() { one(1); } | ||
1088 | "#, | ||
1089 | ); | ||
1090 | } | ||
1091 | |||
1092 | #[test] | ||
1093 | fn method_as_fn() { | ||
1094 | check_diagnostics( | ||
1095 | r#" | ||
1096 | struct S; | ||
1097 | impl S { fn method(&self) {} } | ||
1098 | |||
1099 | fn f() { | ||
1100 | S::method(); | ||
1101 | } //^^^^^^^^^^^ Expected 1 argument, found 0 | ||
1102 | "#, | ||
1103 | ); | ||
1104 | |||
1105 | check_diagnostics( | ||
1106 | r#" | ||
1107 | struct S; | ||
1108 | impl S { fn method(&self) {} } | ||
1109 | |||
1110 | fn f() { | ||
1111 | S::method(&S); | ||
1112 | S.method(); | ||
1113 | } | ||
1114 | "#, | ||
1115 | ); | ||
1116 | } | ||
1117 | |||
1118 | #[test] | ||
1119 | fn method_with_arg() { | ||
1120 | check_diagnostics( | ||
1121 | r#" | ||
1122 | struct S; | ||
1123 | impl S { fn method(&self, arg: u8) {} } | ||
1124 | |||
1125 | fn f() { | ||
1126 | S.method(); | ||
1127 | } //^^^^^^^^^^ Expected 1 argument, found 0 | ||
1128 | "#, | ||
1129 | ); | ||
1130 | |||
1131 | check_diagnostics( | ||
1132 | r#" | ||
1133 | struct S; | ||
1134 | impl S { fn method(&self, arg: u8) {} } | ||
1135 | |||
1136 | fn f() { | ||
1137 | S::method(&S, 0); | ||
1138 | S.method(1); | ||
1139 | } | ||
1140 | "#, | ||
1141 | ); | ||
1142 | } | ||
1143 | |||
1144 | #[test] | ||
1145 | fn method_unknown_receiver() { | ||
1146 | // note: this is incorrect code, so there might be errors on this in the | ||
1147 | // future, but we shouldn't emit an argument count diagnostic here | ||
1148 | check_diagnostics( | ||
1149 | r#" | ||
1150 | trait Foo { fn method(&self, arg: usize) {} } | ||
1151 | |||
1152 | fn f() { | ||
1153 | let x; | ||
1154 | x.method(); | ||
1155 | } | ||
1156 | "#, | ||
1157 | ); | ||
1158 | } | ||
1159 | |||
1160 | #[test] | ||
1161 | fn tuple_struct() { | ||
1162 | check_diagnostics( | ||
1163 | r#" | ||
1164 | struct Tup(u8, u16); | ||
1165 | fn f() { | ||
1166 | Tup(0); | ||
1167 | } //^^^^^^ Expected 2 arguments, found 1 | ||
1168 | "#, | ||
1169 | ) | ||
1170 | } | ||
1171 | |||
1172 | #[test] | ||
1173 | fn enum_variant() { | ||
1174 | check_diagnostics( | ||
1175 | r#" | ||
1176 | enum En { Variant(u8, u16), } | ||
1177 | fn f() { | ||
1178 | En::Variant(0); | ||
1179 | } //^^^^^^^^^^^^^^ Expected 2 arguments, found 1 | ||
1180 | "#, | ||
1181 | ) | ||
1182 | } | ||
1183 | |||
1184 | #[test] | ||
1185 | fn enum_variant_type_macro() { | ||
1186 | check_diagnostics( | ||
1187 | r#" | ||
1188 | macro_rules! Type { | ||
1189 | () => { u32 }; | ||
1190 | } | ||
1191 | enum Foo { | ||
1192 | Bar(Type![]) | ||
1193 | } | ||
1194 | impl Foo { | ||
1195 | fn new() { | ||
1196 | Foo::Bar(0); | ||
1197 | Foo::Bar(0, 1); | ||
1198 | //^^^^^^^^^^^^^^ Expected 1 argument, found 2 | ||
1199 | Foo::Bar(); | ||
1200 | //^^^^^^^^^^ Expected 1 argument, found 0 | ||
1201 | } | ||
1202 | } | ||
1203 | "#, | ||
1204 | ); | ||
1205 | } | ||
1206 | |||
1207 | #[test] | ||
1208 | fn varargs() { | ||
1209 | check_diagnostics( | ||
1210 | r#" | ||
1211 | extern "C" { | ||
1212 | fn fixed(fixed: u8); | ||
1213 | fn varargs(fixed: u8, ...); | ||
1214 | fn varargs2(...); | ||
1215 | } | ||
1216 | |||
1217 | fn f() { | ||
1218 | unsafe { | ||
1219 | fixed(0); | ||
1220 | fixed(0, 1); | ||
1221 | //^^^^^^^^^^^ Expected 1 argument, found 2 | ||
1222 | varargs(0); | ||
1223 | varargs(0, 1); | ||
1224 | varargs2(); | ||
1225 | varargs2(0); | ||
1226 | varargs2(0, 1); | ||
1227 | } | ||
1228 | } | ||
1229 | "#, | ||
1230 | ) | ||
1231 | } | ||
1232 | |||
1233 | #[test] | ||
1234 | fn arg_count_lambda() { | ||
1235 | check_diagnostics( | ||
1236 | r#" | ||
1237 | fn main() { | ||
1238 | let f = |()| (); | ||
1239 | f(); | ||
1240 | //^^^ Expected 1 argument, found 0 | ||
1241 | f(()); | ||
1242 | f((), ()); | ||
1243 | //^^^^^^^^^ Expected 1 argument, found 2 | ||
1244 | } | ||
1245 | "#, | ||
1246 | ) | ||
1247 | } | ||
1248 | |||
1249 | #[test] | ||
1250 | fn cfgd_out_call_arguments() { | ||
1251 | check_diagnostics( | ||
1252 | r#" | ||
1253 | struct C(#[cfg(FALSE)] ()); | ||
1254 | impl C { | ||
1255 | fn new() -> Self { | ||
1256 | Self( | ||
1257 | #[cfg(FALSE)] | ||
1258 | (), | ||
1259 | ) | ||
1260 | } | ||
1261 | |||
1262 | fn method(&self) {} | ||
1263 | } | ||
1264 | |||
1265 | fn main() { | ||
1266 | C::new().method(#[cfg(FALSE)] 0); | ||
1267 | } | ||
1268 | "#, | ||
1269 | ); | ||
1270 | } | ||
1271 | |||
1272 | #[test] | ||
1273 | fn cfgd_out_fn_params() { | ||
1274 | check_diagnostics( | ||
1275 | r#" | ||
1276 | fn foo(#[cfg(NEVER)] x: ()) {} | ||
1277 | |||
1278 | struct S; | ||
1279 | |||
1280 | impl S { | ||
1281 | fn method(#[cfg(NEVER)] self) {} | ||
1282 | fn method2(#[cfg(NEVER)] self, arg: u8) {} | ||
1283 | fn method3(self, #[cfg(NEVER)] arg: u8) {} | ||
1284 | } | ||
1285 | |||
1286 | extern "C" { | ||
1287 | fn fixed(fixed: u8, #[cfg(NEVER)] ...); | ||
1288 | fn varargs(#[cfg(not(NEVER))] ...); | ||
1289 | } | ||
1290 | |||
1291 | fn main() { | ||
1292 | foo(); | ||
1293 | S::method(); | ||
1294 | S::method2(0); | ||
1295 | S::method3(S); | ||
1296 | S.method3(); | ||
1297 | unsafe { | ||
1298 | fixed(0); | ||
1299 | varargs(1, 2, 3); | ||
1300 | } | ||
1301 | } | ||
1302 | "#, | ||
1303 | ) | ||
1304 | } | ||
1305 | |||
1306 | #[test] | ||
1307 | fn missing_semicolon() { | 842 | fn missing_semicolon() { |
1308 | check_diagnostics( | 843 | check_diagnostics( |
1309 | r#" | 844 | r#" |