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.rs499
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
7mod unresolved_module; 7mod break_outside_of_loop;
8mod inactive_code;
9mod macro_error;
10mod mismatched_arg_count;
11mod missing_fields;
12mod missing_unsafe;
13mod no_such_field;
14mod unimplemented_builtin_macro;
8mod unresolved_extern_crate; 15mod unresolved_extern_crate;
9mod unresolved_import; 16mod unresolved_import;
10mod unresolved_macro_call; 17mod unresolved_macro_call;
18mod unresolved_module;
11mod unresolved_proc_macro; 19mod unresolved_proc_macro;
12mod macro_error;
13mod inactive_code;
14mod missing_fields;
15 20
16mod fixes; 21mod fixes;
17mod field_shorthand; 22mod 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#"
722fn foo() { break; }
723 //^^^^^ break outside of loop
724"#,
725 );
726 }
727
728 #[test]
729 fn no_such_field_diagnostics() {
730 check_diagnostics(
731 r#"
732struct S { foo: i32, bar: () }
733impl 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
752struct MyStruct {
753 my_val: usize,
754 #[cfg(feature = "foo")]
755 bar: bool,
756}
757
758impl 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
777enum Foo {
778 #[cfg(not(feature = "foo"))]
779 Buz,
780 #[cfg(feature = "foo")]
781 Bar,
782 Baz
783}
784
785fn 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
800struct S {
801 #[cfg(feature = "foo")]
802 foo: u32,
803 #[cfg(not(feature = "foo"))]
804 bar: u32,
805}
806
807impl 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#"
839macro_rules! Type { () => { u32 }; }
840struct Foo { bar: Type![] }
841
842impl 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#"
855fn 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#"
868struct HasUnsafe;
869
870impl HasUnsafe {
871 unsafe fn unsafe_fn(&self) {
872 let x = &5 as *const usize;
873 let y = *x;
874 }
875}
876
877unsafe fn unsafe_fn() {
878 let x = &5 as *const usize;
879 let y = *x;
880}
881
882fn 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#"
900struct Ty {
901 a: u8,
902}
903
904static mut STATIC_MUT: Ty = Ty { a: 0 };
905
906fn 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#"
921extern "rust-intrinsic" {
922 pub fn bitreverse(x: u32) -> u32; // Safe intrinsic
923 pub fn floorf32(x: f32) -> f32; // Unsafe intrinsic
924}
925
926fn 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#"
1060fn zero() {}
1061fn f() { zero(1); }
1062 //^^^^^^^ Expected 0 arguments, found 1
1063"#,
1064 );
1065
1066 check_diagnostics(
1067 r#"
1068fn zero() {}
1069fn f() { zero(); }
1070"#,
1071 );
1072 }
1073
1074 #[test]
1075 fn simple_free_fn_one() {
1076 check_diagnostics(
1077 r#"
1078fn one(arg: u8) {}
1079fn f() { one(); }
1080 //^^^^^ Expected 1 argument, found 0
1081"#,
1082 );
1083
1084 check_diagnostics(
1085 r#"
1086fn one(arg: u8) {}
1087fn f() { one(1); }
1088"#,
1089 );
1090 }
1091
1092 #[test]
1093 fn method_as_fn() {
1094 check_diagnostics(
1095 r#"
1096struct S;
1097impl S { fn method(&self) {} }
1098
1099fn f() {
1100 S::method();
1101} //^^^^^^^^^^^ Expected 1 argument, found 0
1102"#,
1103 );
1104
1105 check_diagnostics(
1106 r#"
1107struct S;
1108impl S { fn method(&self) {} }
1109
1110fn 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#"
1122struct S;
1123impl 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#"
1133struct S;
1134impl S { fn method(&self, arg: u8) {} }
1135
1136fn 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#"
1150trait Foo { fn method(&self, arg: usize) {} }
1151
1152fn f() {
1153 let x;
1154 x.method();
1155}
1156"#,
1157 );
1158 }
1159
1160 #[test]
1161 fn tuple_struct() {
1162 check_diagnostics(
1163 r#"
1164struct Tup(u8, u16);
1165fn 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#"
1176enum En { Variant(u8, u16), }
1177fn 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#"
1188macro_rules! Type {
1189 () => { u32 };
1190}
1191enum Foo {
1192 Bar(Type![])
1193}
1194impl 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#"
1211extern "C" {
1212 fn fixed(fixed: u8);
1213 fn varargs(fixed: u8, ...);
1214 fn varargs2(...);
1215}
1216
1217fn 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#"
1237fn 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#"
1253struct C(#[cfg(FALSE)] ());
1254impl C {
1255 fn new() -> Self {
1256 Self(
1257 #[cfg(FALSE)]
1258 (),
1259 )
1260 }
1261
1262 fn method(&self) {}
1263}
1264
1265fn 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#"
1276fn foo(#[cfg(NEVER)] x: ()) {}
1277
1278struct S;
1279
1280impl 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
1286extern "C" {
1287 fn fixed(fixed: u8, #[cfg(NEVER)] ...);
1288 fn varargs(#[cfg(not(NEVER))] ...);
1289}
1290
1291fn 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#"