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.rs1885
1 files changed, 1883 insertions, 2 deletions
diff --git a/crates/ide/src/diagnostics.rs b/crates/ide/src/diagnostics.rs
index d5c954b8b..4193aabf5 100644
--- a/crates/ide/src/diagnostics.rs
+++ b/crates/ide/src/diagnostics.rs
@@ -204,8 +204,9 @@ pub(crate) fn diagnostics(
204 ); 204 );
205 }); 205 });
206 206
207 let internal_diagnostics = cfg!(test);
207 match sema.to_module_def(file_id) { 208 match sema.to_module_def(file_id) {
208 Some(m) => m.diagnostics(db, &mut sink), 209 Some(m) => m.diagnostics(db, &mut sink, internal_diagnostics),
209 None => { 210 None => {
210 sink.push(UnlinkedFile { file_id, node: SyntaxNodePtr::new(&parse.tree().syntax()) }); 211 sink.push(UnlinkedFile { file_id, node: SyntaxNodePtr::new(&parse.tree().syntax()) });
211 } 212 }
@@ -305,6 +306,7 @@ fn unresolved_fix(id: &'static str, label: &str, target: TextRange) -> Assist {
305#[cfg(test)] 306#[cfg(test)]
306mod tests { 307mod tests {
307 use expect_test::Expect; 308 use expect_test::Expect;
309 use hir::diagnostics::DiagnosticCode;
308 use ide_assists::AssistResolveStrategy; 310 use ide_assists::AssistResolveStrategy;
309 use stdx::trim_indent; 311 use stdx::trim_indent;
310 use test_utils::{assert_eq_text, extract_annotations}; 312 use test_utils::{assert_eq_text, extract_annotations};
@@ -410,7 +412,12 @@ mod tests {
410 .unwrap(); 412 .unwrap();
411 413
412 let expected = extract_annotations(&*analysis.file_text(file_id).unwrap()); 414 let expected = extract_annotations(&*analysis.file_text(file_id).unwrap());
413 let actual = diagnostics.into_iter().map(|d| (d.range, d.message)).collect::<Vec<_>>(); 415 let mut actual = diagnostics
416 .into_iter()
417 .filter(|d| d.code != Some(DiagnosticCode("inactive-code")))
418 .map(|d| (d.range, d.message))
419 .collect::<Vec<_>>();
420 actual.sort_by_key(|(range, _)| range.start());
414 assert_eq!(expected, actual); 421 assert_eq!(expected, actual);
415 } 422 }
416 423
@@ -719,4 +726,1878 @@ mod foo;
719"#, 726"#,
720 ); 727 );
721 } 728 }
729
730 #[test]
731 fn break_outside_of_loop() {
732 check_diagnostics(
733 r#"
734fn foo() { break; }
735 //^^^^^ break outside of loop
736"#,
737 );
738 }
739
740 #[test]
741 fn no_such_field_diagnostics() {
742 check_diagnostics(
743 r#"
744struct S { foo: i32, bar: () }
745impl S {
746 fn new() -> S {
747 S {
748 //^ Missing structure fields:
749 //| - bar
750 foo: 92,
751 baz: 62,
752 //^^^^^^^ no such field
753 }
754 }
755}
756"#,
757 );
758 }
759 #[test]
760 fn no_such_field_with_feature_flag_diagnostics() {
761 check_diagnostics(
762 r#"
763//- /lib.rs crate:foo cfg:feature=foo
764struct MyStruct {
765 my_val: usize,
766 #[cfg(feature = "foo")]
767 bar: bool,
768}
769
770impl MyStruct {
771 #[cfg(feature = "foo")]
772 pub(crate) fn new(my_val: usize, bar: bool) -> Self {
773 Self { my_val, bar }
774 }
775 #[cfg(not(feature = "foo"))]
776 pub(crate) fn new(my_val: usize, _bar: bool) -> Self {
777 Self { my_val }
778 }
779}
780"#,
781 );
782 }
783
784 #[test]
785 fn no_such_field_enum_with_feature_flag_diagnostics() {
786 check_diagnostics(
787 r#"
788//- /lib.rs crate:foo cfg:feature=foo
789enum Foo {
790 #[cfg(not(feature = "foo"))]
791 Buz,
792 #[cfg(feature = "foo")]
793 Bar,
794 Baz
795}
796
797fn test_fn(f: Foo) {
798 match f {
799 Foo::Bar => {},
800 Foo::Baz => {},
801 }
802}
803"#,
804 );
805 }
806
807 #[test]
808 fn no_such_field_with_feature_flag_diagnostics_on_struct_lit() {
809 check_diagnostics(
810 r#"
811//- /lib.rs crate:foo cfg:feature=foo
812struct S {
813 #[cfg(feature = "foo")]
814 foo: u32,
815 #[cfg(not(feature = "foo"))]
816 bar: u32,
817}
818
819impl S {
820 #[cfg(feature = "foo")]
821 fn new(foo: u32) -> Self {
822 Self { foo }
823 }
824 #[cfg(not(feature = "foo"))]
825 fn new(bar: u32) -> Self {
826 Self { bar }
827 }
828 fn new2(bar: u32) -> Self {
829 #[cfg(feature = "foo")]
830 { Self { foo: bar } }
831 #[cfg(not(feature = "foo"))]
832 { Self { bar } }
833 }
834 fn new2(val: u32) -> Self {
835 Self {
836 #[cfg(feature = "foo")]
837 foo: val,
838 #[cfg(not(feature = "foo"))]
839 bar: val,
840 }
841 }
842}
843"#,
844 );
845 }
846
847 #[test]
848 fn no_such_field_with_type_macro() {
849 check_diagnostics(
850 r#"
851macro_rules! Type { () => { u32 }; }
852struct Foo { bar: Type![] }
853
854impl Foo {
855 fn new() -> Self {
856 Foo { bar: 0 }
857 }
858}
859"#,
860 );
861 }
862
863 #[test]
864 fn missing_unsafe_diagnostic_with_raw_ptr() {
865 check_diagnostics(
866 r#"
867fn main() {
868 let x = &5 as *const usize;
869 unsafe { let y = *x; }
870 let z = *x;
871} //^^ This operation is unsafe and requires an unsafe function or block
872"#,
873 )
874 }
875
876 #[test]
877 fn missing_unsafe_diagnostic_with_unsafe_call() {
878 check_diagnostics(
879 r#"
880struct HasUnsafe;
881
882impl HasUnsafe {
883 unsafe fn unsafe_fn(&self) {
884 let x = &5 as *const usize;
885 let y = *x;
886 }
887}
888
889unsafe fn unsafe_fn() {
890 let x = &5 as *const usize;
891 let y = *x;
892}
893
894fn main() {
895 unsafe_fn();
896 //^^^^^^^^^^^ This operation is unsafe and requires an unsafe function or block
897 HasUnsafe.unsafe_fn();
898 //^^^^^^^^^^^^^^^^^^^^^ This operation is unsafe and requires an unsafe function or block
899 unsafe {
900 unsafe_fn();
901 HasUnsafe.unsafe_fn();
902 }
903}
904"#,
905 );
906 }
907
908 #[test]
909 fn missing_unsafe_diagnostic_with_static_mut() {
910 check_diagnostics(
911 r#"
912struct Ty {
913 a: u8,
914}
915
916static mut STATIC_MUT: Ty = Ty { a: 0 };
917
918fn main() {
919 let x = STATIC_MUT.a;
920 //^^^^^^^^^^ This operation is unsafe and requires an unsafe function or block
921 unsafe {
922 let x = STATIC_MUT.a;
923 }
924}
925"#,
926 );
927 }
928
929 #[test]
930 fn no_missing_unsafe_diagnostic_with_safe_intrinsic() {
931 check_diagnostics(
932 r#"
933extern "rust-intrinsic" {
934 pub fn bitreverse(x: u32) -> u32; // Safe intrinsic
935 pub fn floorf32(x: f32) -> f32; // Unsafe intrinsic
936}
937
938fn main() {
939 let _ = bitreverse(12);
940 let _ = floorf32(12.0);
941 //^^^^^^^^^^^^^^ This operation is unsafe and requires an unsafe function or block
942}
943"#,
944 );
945 }
946
947 // Register the required standard library types to make the tests work
948 fn add_filter_map_with_find_next_boilerplate(body: &str) -> String {
949 let prefix = r#"
950 //- /main.rs crate:main deps:core
951 use core::iter::Iterator;
952 use core::option::Option::{self, Some, None};
953 "#;
954 let suffix = r#"
955 //- /core/lib.rs crate:core
956 pub mod option {
957 pub enum Option<T> { Some(T), None }
958 }
959 pub mod iter {
960 pub trait Iterator {
961 type Item;
962 fn filter_map<B, F>(self, f: F) -> FilterMap where F: FnMut(Self::Item) -> Option<B> { FilterMap }
963 fn next(&mut self) -> Option<Self::Item>;
964 }
965 pub struct FilterMap {}
966 impl Iterator for FilterMap {
967 type Item = i32;
968 fn next(&mut self) -> i32 { 7 }
969 }
970 }
971 "#;
972 format!("{}{}{}", prefix, body, suffix)
973 }
974
975 #[test]
976 fn replace_filter_map_next_with_find_map2() {
977 check_diagnostics(&add_filter_map_with_find_next_boilerplate(
978 r#"
979 fn foo() {
980 let m = [1, 2, 3].iter().filter_map(|x| if *x == 2 { Some (4) } else { None }).next();
981 //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ replace filter_map(..).next() with find_map(..)
982 }
983 "#,
984 ));
985 }
986
987 #[test]
988 fn replace_filter_map_next_with_find_map_no_diagnostic_without_next() {
989 check_diagnostics(&add_filter_map_with_find_next_boilerplate(
990 r#"
991 fn foo() {
992 let m = [1, 2, 3]
993 .iter()
994 .filter_map(|x| if *x == 2 { Some (4) } else { None })
995 .len();
996 }
997 "#,
998 ));
999 }
1000
1001 #[test]
1002 fn replace_filter_map_next_with_find_map_no_diagnostic_with_intervening_methods() {
1003 check_diagnostics(&add_filter_map_with_find_next_boilerplate(
1004 r#"
1005 fn foo() {
1006 let m = [1, 2, 3]
1007 .iter()
1008 .filter_map(|x| if *x == 2 { Some (4) } else { None })
1009 .map(|x| x + 2)
1010 .len();
1011 }
1012 "#,
1013 ));
1014 }
1015
1016 #[test]
1017 fn replace_filter_map_next_with_find_map_no_diagnostic_if_not_in_chain() {
1018 check_diagnostics(&add_filter_map_with_find_next_boilerplate(
1019 r#"
1020 fn foo() {
1021 let m = [1, 2, 3]
1022 .iter()
1023 .filter_map(|x| if *x == 2 { Some (4) } else { None });
1024 let n = m.next();
1025 }
1026 "#,
1027 ));
1028 }
1029
1030 #[test]
1031 fn missing_record_pat_field_diagnostic() {
1032 check_diagnostics(
1033 r#"
1034struct S { foo: i32, bar: () }
1035fn baz(s: S) {
1036 let S { foo: _ } = s;
1037 //^ Missing structure fields:
1038 //| - bar
1039}
1040"#,
1041 );
1042 }
1043
1044 #[test]
1045 fn missing_record_pat_field_no_diagnostic_if_not_exhaustive() {
1046 check_diagnostics(
1047 r"
1048struct S { foo: i32, bar: () }
1049fn baz(s: S) -> i32 {
1050 match s {
1051 S { foo, .. } => foo,
1052 }
1053}
1054",
1055 )
1056 }
1057
1058 #[test]
1059 fn missing_record_pat_field_box() {
1060 check_diagnostics(
1061 r"
1062struct S { s: Box<u32> }
1063fn x(a: S) {
1064 let S { box s } = a;
1065}
1066",
1067 )
1068 }
1069
1070 #[test]
1071 fn missing_record_pat_field_ref() {
1072 check_diagnostics(
1073 r"
1074struct S { s: u32 }
1075fn x(a: S) {
1076 let S { ref s } = a;
1077}
1078",
1079 )
1080 }
1081
1082 #[test]
1083 fn simple_free_fn_zero() {
1084 check_diagnostics(
1085 r#"
1086fn zero() {}
1087fn f() { zero(1); }
1088 //^^^^^^^ Expected 0 arguments, found 1
1089"#,
1090 );
1091
1092 check_diagnostics(
1093 r#"
1094fn zero() {}
1095fn f() { zero(); }
1096"#,
1097 );
1098 }
1099
1100 #[test]
1101 fn simple_free_fn_one() {
1102 check_diagnostics(
1103 r#"
1104fn one(arg: u8) {}
1105fn f() { one(); }
1106 //^^^^^ Expected 1 argument, found 0
1107"#,
1108 );
1109
1110 check_diagnostics(
1111 r#"
1112fn one(arg: u8) {}
1113fn f() { one(1); }
1114"#,
1115 );
1116 }
1117
1118 #[test]
1119 fn method_as_fn() {
1120 check_diagnostics(
1121 r#"
1122struct S;
1123impl S { fn method(&self) {} }
1124
1125fn 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) {} }
1135
1136fn f() {
1137 S::method(&S);
1138 S.method();
1139}
1140"#,
1141 );
1142 }
1143
1144 #[test]
1145 fn method_with_arg() {
1146 check_diagnostics(
1147 r#"
1148struct S;
1149impl S { fn method(&self, arg: u8) {} }
1150
1151 fn f() {
1152 S.method();
1153 } //^^^^^^^^^^ Expected 1 argument, found 0
1154 "#,
1155 );
1156
1157 check_diagnostics(
1158 r#"
1159struct S;
1160impl S { fn method(&self, arg: u8) {} }
1161
1162fn f() {
1163 S::method(&S, 0);
1164 S.method(1);
1165}
1166"#,
1167 );
1168 }
1169
1170 #[test]
1171 fn method_unknown_receiver() {
1172 // note: this is incorrect code, so there might be errors on this in the
1173 // future, but we shouldn't emit an argument count diagnostic here
1174 check_diagnostics(
1175 r#"
1176trait Foo { fn method(&self, arg: usize) {} }
1177
1178fn f() {
1179 let x;
1180 x.method();
1181}
1182"#,
1183 );
1184 }
1185
1186 #[test]
1187 fn tuple_struct() {
1188 check_diagnostics(
1189 r#"
1190struct Tup(u8, u16);
1191fn f() {
1192 Tup(0);
1193} //^^^^^^ Expected 2 arguments, found 1
1194"#,
1195 )
1196 }
1197
1198 #[test]
1199 fn enum_variant() {
1200 check_diagnostics(
1201 r#"
1202enum En { Variant(u8, u16), }
1203fn f() {
1204 En::Variant(0);
1205} //^^^^^^^^^^^^^^ Expected 2 arguments, found 1
1206"#,
1207 )
1208 }
1209
1210 #[test]
1211 fn enum_variant_type_macro() {
1212 check_diagnostics(
1213 r#"
1214macro_rules! Type {
1215 () => { u32 };
1216}
1217enum Foo {
1218 Bar(Type![])
1219}
1220impl Foo {
1221 fn new() {
1222 Foo::Bar(0);
1223 Foo::Bar(0, 1);
1224 //^^^^^^^^^^^^^^ Expected 1 argument, found 2
1225 Foo::Bar();
1226 //^^^^^^^^^^ Expected 1 argument, found 0
1227 }
1228}
1229 "#,
1230 );
1231 }
1232
1233 #[test]
1234 fn varargs() {
1235 check_diagnostics(
1236 r#"
1237extern "C" {
1238 fn fixed(fixed: u8);
1239 fn varargs(fixed: u8, ...);
1240 fn varargs2(...);
1241}
1242
1243fn f() {
1244 unsafe {
1245 fixed(0);
1246 fixed(0, 1);
1247 //^^^^^^^^^^^ Expected 1 argument, found 2
1248 varargs(0);
1249 varargs(0, 1);
1250 varargs2();
1251 varargs2(0);
1252 varargs2(0, 1);
1253 }
1254}
1255 "#,
1256 )
1257 }
1258
1259 #[test]
1260 fn arg_count_lambda() {
1261 check_diagnostics(
1262 r#"
1263fn main() {
1264 let f = |()| ();
1265 f();
1266 //^^^ Expected 1 argument, found 0
1267 f(());
1268 f((), ());
1269 //^^^^^^^^^ Expected 1 argument, found 2
1270}
1271"#,
1272 )
1273 }
1274
1275 #[test]
1276 fn cfgd_out_call_arguments() {
1277 check_diagnostics(
1278 r#"
1279struct C(#[cfg(FALSE)] ());
1280impl C {
1281 fn new() -> Self {
1282 Self(
1283 #[cfg(FALSE)]
1284 (),
1285 )
1286 }
1287
1288 fn method(&self) {}
1289}
1290
1291fn main() {
1292 C::new().method(#[cfg(FALSE)] 0);
1293}
1294 "#,
1295 );
1296 }
1297
1298 #[test]
1299 fn cfgd_out_fn_params() {
1300 check_diagnostics(
1301 r#"
1302fn foo(#[cfg(NEVER)] x: ()) {}
1303
1304struct S;
1305
1306impl S {
1307 fn method(#[cfg(NEVER)] self) {}
1308 fn method2(#[cfg(NEVER)] self, arg: u8) {}
1309 fn method3(self, #[cfg(NEVER)] arg: u8) {}
1310}
1311
1312extern "C" {
1313 fn fixed(fixed: u8, #[cfg(NEVER)] ...);
1314 fn varargs(#[cfg(not(NEVER))] ...);
1315}
1316
1317fn main() {
1318 foo();
1319 S::method();
1320 S::method2(0);
1321 S::method3(S);
1322 S.method3();
1323 unsafe {
1324 fixed(0);
1325 varargs(1, 2, 3);
1326 }
1327}
1328 "#,
1329 )
1330 }
1331
1332 #[test]
1333 fn missing_semicolon() {
1334 check_diagnostics(
1335 r#"
1336 fn test() -> i32 { 123; }
1337 //^^^ Remove this semicolon
1338 "#,
1339 );
1340 }
1341
1342 #[test]
1343 fn import_extern_crate_clash_with_inner_item() {
1344 // This is more of a resolver test, but doesn't really work with the hir_def testsuite.
1345
1346 check_diagnostics(
1347 r#"
1348//- /lib.rs crate:lib deps:jwt
1349mod permissions;
1350
1351use permissions::jwt;
1352
1353fn f() {
1354 fn inner() {}
1355 jwt::Claims {}; // should resolve to the local one with 0 fields, and not get a diagnostic
1356}
1357
1358//- /permissions.rs
1359pub mod jwt {
1360 pub struct Claims {}
1361}
1362
1363//- /jwt/lib.rs crate:jwt
1364pub struct Claims {
1365 field: u8,
1366}
1367 "#,
1368 );
1369 }
1370}
1371
1372#[cfg(test)]
1373pub(super) mod match_check_tests {
1374 use crate::diagnostics::tests::check_diagnostics;
1375
1376 #[test]
1377 fn empty_tuple() {
1378 check_diagnostics(
1379 r#"
1380fn main() {
1381 match () { }
1382 //^^ Missing match arm
1383 match (()) { }
1384 //^^^^ Missing match arm
1385
1386 match () { _ => (), }
1387 match () { () => (), }
1388 match (()) { (()) => (), }
1389}
1390"#,
1391 );
1392 }
1393
1394 #[test]
1395 fn tuple_of_two_empty_tuple() {
1396 check_diagnostics(
1397 r#"
1398fn main() {
1399 match ((), ()) { }
1400 //^^^^^^^^ Missing match arm
1401
1402 match ((), ()) { ((), ()) => (), }
1403}
1404"#,
1405 );
1406 }
1407
1408 #[test]
1409 fn boolean() {
1410 check_diagnostics(
1411 r#"
1412fn test_main() {
1413 match false { }
1414 //^^^^^ Missing match arm
1415 match false { true => (), }
1416 //^^^^^ Missing match arm
1417 match (false, true) {}
1418 //^^^^^^^^^^^^^ Missing match arm
1419 match (false, true) { (true, true) => (), }
1420 //^^^^^^^^^^^^^ Missing match arm
1421 match (false, true) {
1422 //^^^^^^^^^^^^^ Missing match arm
1423 (false, true) => (),
1424 (false, false) => (),
1425 (true, false) => (),
1426 }
1427 match (false, true) { (true, _x) => (), }
1428 //^^^^^^^^^^^^^ Missing match arm
1429
1430 match false { true => (), false => (), }
1431 match (false, true) {
1432 (false, _) => (),
1433 (true, false) => (),
1434 (_, true) => (),
1435 }
1436 match (false, true) {
1437 (true, true) => (),
1438 (true, false) => (),
1439 (false, true) => (),
1440 (false, false) => (),
1441 }
1442 match (false, true) {
1443 (true, _x) => (),
1444 (false, true) => (),
1445 (false, false) => (),
1446 }
1447 match (false, true, false) {
1448 (false, ..) => (),
1449 (true, ..) => (),
1450 }
1451 match (false, true, false) {
1452 (.., false) => (),
1453 (.., true) => (),
1454 }
1455 match (false, true, false) { (..) => (), }
1456}
1457"#,
1458 );
1459 }
1460
1461 #[test]
1462 fn tuple_of_tuple_and_bools() {
1463 check_diagnostics(
1464 r#"
1465fn main() {
1466 match (false, ((), false)) {}
1467 //^^^^^^^^^^^^^^^^^^^^ Missing match arm
1468 match (false, ((), false)) { (true, ((), true)) => (), }
1469 //^^^^^^^^^^^^^^^^^^^^ Missing match arm
1470 match (false, ((), false)) { (true, _) => (), }
1471 //^^^^^^^^^^^^^^^^^^^^ Missing match arm
1472
1473 match (false, ((), false)) {
1474 (true, ((), true)) => (),
1475 (true, ((), false)) => (),
1476 (false, ((), true)) => (),
1477 (false, ((), false)) => (),
1478 }
1479 match (false, ((), false)) {
1480 (true, ((), true)) => (),
1481 (true, ((), false)) => (),
1482 (false, _) => (),
1483 }
1484}
1485"#,
1486 );
1487 }
1488
1489 #[test]
1490 fn enums() {
1491 check_diagnostics(
1492 r#"
1493enum Either { A, B, }
1494
1495fn main() {
1496 match Either::A { }
1497 //^^^^^^^^^ Missing match arm
1498 match Either::B { Either::A => (), }
1499 //^^^^^^^^^ Missing match arm
1500
1501 match &Either::B {
1502 //^^^^^^^^^^ Missing match arm
1503 Either::A => (),
1504 }
1505
1506 match Either::B {
1507 Either::A => (), Either::B => (),
1508 }
1509 match &Either::B {
1510 Either::A => (), Either::B => (),
1511 }
1512}
1513"#,
1514 );
1515 }
1516
1517 #[test]
1518 fn enum_containing_bool() {
1519 check_diagnostics(
1520 r#"
1521enum Either { A(bool), B }
1522
1523fn main() {
1524 match Either::B { }
1525 //^^^^^^^^^ Missing match arm
1526 match Either::B {
1527 //^^^^^^^^^ Missing match arm
1528 Either::A(true) => (), Either::B => ()
1529 }
1530
1531 match Either::B {
1532 Either::A(true) => (),
1533 Either::A(false) => (),
1534 Either::B => (),
1535 }
1536 match Either::B {
1537 Either::B => (),
1538 _ => (),
1539 }
1540 match Either::B {
1541 Either::A(_) => (),
1542 Either::B => (),
1543 }
1544
1545}
1546 "#,
1547 );
1548 }
1549
1550 #[test]
1551 fn enum_different_sizes() {
1552 check_diagnostics(
1553 r#"
1554enum Either { A(bool), B(bool, bool) }
1555
1556fn main() {
1557 match Either::A(false) {
1558 //^^^^^^^^^^^^^^^^ Missing match arm
1559 Either::A(_) => (),
1560 Either::B(false, _) => (),
1561 }
1562
1563 match Either::A(false) {
1564 Either::A(_) => (),
1565 Either::B(true, _) => (),
1566 Either::B(false, _) => (),
1567 }
1568 match Either::A(false) {
1569 Either::A(true) | Either::A(false) => (),
1570 Either::B(true, _) => (),
1571 Either::B(false, _) => (),
1572 }
1573}
1574"#,
1575 );
1576 }
1577
1578 #[test]
1579 fn tuple_of_enum_no_diagnostic() {
1580 check_diagnostics(
1581 r#"
1582enum Either { A(bool), B(bool, bool) }
1583enum Either2 { C, D }
1584
1585fn main() {
1586 match (Either::A(false), Either2::C) {
1587 (Either::A(true), _) | (Either::A(false), _) => (),
1588 (Either::B(true, _), Either2::C) => (),
1589 (Either::B(false, _), Either2::C) => (),
1590 (Either::B(_, _), Either2::D) => (),
1591 }
1592}
1593"#,
1594 );
1595 }
1596
1597 #[test]
1598 fn or_pattern_no_diagnostic() {
1599 check_diagnostics(
1600 r#"
1601enum Either {A, B}
1602
1603fn main() {
1604 match (Either::A, Either::B) {
1605 (Either::A | Either::B, _) => (),
1606 }
1607}"#,
1608 )
1609 }
1610
1611 #[test]
1612 fn mismatched_types() {
1613 // Match statements with arms that don't match the
1614 // expression pattern do not fire this diagnostic.
1615 check_diagnostics(
1616 r#"
1617enum Either { A, B }
1618enum Either2 { C, D }
1619
1620fn main() {
1621 match Either::A {
1622 Either2::C => (),
1623 // ^^^^^^^^^^ Internal: match check bailed out
1624 Either2::D => (),
1625 }
1626 match (true, false) {
1627 (true, false, true) => (),
1628 // ^^^^^^^^^^^^^^^^^^^ Internal: match check bailed out
1629 (true) => (),
1630 }
1631 match (true, false) { (true,) => {} }
1632 // ^^^^^^^ Internal: match check bailed out
1633 match (0) { () => () }
1634 // ^^ Internal: match check bailed out
1635 match Unresolved::Bar { Unresolved::Baz => () }
1636}
1637 "#,
1638 );
1639 }
1640
1641 #[test]
1642 fn mismatched_types_in_or_patterns() {
1643 check_diagnostics(
1644 r#"
1645fn main() {
1646 match false { true | () => {} }
1647 // ^^^^^^^^^ Internal: match check bailed out
1648 match (false,) { (true | (),) => {} }
1649 // ^^^^^^^^^^^^ Internal: match check bailed out
1650}
1651"#,
1652 );
1653 }
1654
1655 #[test]
1656 fn malformed_match_arm_tuple_enum_missing_pattern() {
1657 // We are testing to be sure we don't panic here when the match
1658 // arm `Either::B` is missing its pattern.
1659 check_diagnostics(
1660 r#"
1661enum Either { A, B(u32) }
1662
1663fn main() {
1664 match Either::A {
1665 Either::A => (),
1666 Either::B() => (),
1667 }
1668}
1669"#,
1670 );
1671 }
1672
1673 #[test]
1674 fn malformed_match_arm_extra_fields() {
1675 check_diagnostics(
1676 r#"
1677enum A { B(isize, isize), C }
1678fn main() {
1679 match A::B(1, 2) {
1680 A::B(_, _, _) => (),
1681 // ^^^^^^^^^^^^^ Internal: match check bailed out
1682 }
1683 match A::B(1, 2) {
1684 A::C(_) => (),
1685 // ^^^^^^^ Internal: match check bailed out
1686 }
1687}
1688"#,
1689 );
1690 }
1691
1692 #[test]
1693 fn expr_diverges() {
1694 check_diagnostics(
1695 r#"
1696enum Either { A, B }
1697
1698fn main() {
1699 match loop {} {
1700 Either::A => (),
1701 // ^^^^^^^^^ Internal: match check bailed out
1702 Either::B => (),
1703 }
1704 match loop {} {
1705 Either::A => (),
1706 // ^^^^^^^^^ Internal: match check bailed out
1707 }
1708 match loop { break Foo::A } {
1709 //^^^^^^^^^^^^^^^^^^^^^ Missing match arm
1710 Either::A => (),
1711 }
1712 match loop { break Foo::A } {
1713 Either::A => (),
1714 Either::B => (),
1715 }
1716}
1717"#,
1718 );
1719 }
1720
1721 #[test]
1722 fn expr_partially_diverges() {
1723 check_diagnostics(
1724 r#"
1725enum Either<T> { A(T), B }
1726
1727fn foo() -> Either<!> { Either::B }
1728fn main() -> u32 {
1729 match foo() {
1730 Either::A(val) => val,
1731 Either::B => 0,
1732 }
1733}
1734"#,
1735 );
1736 }
1737
1738 #[test]
1739 fn enum_record() {
1740 check_diagnostics(
1741 r#"
1742enum Either { A { foo: bool }, B }
1743
1744fn main() {
1745 let a = Either::A { foo: true };
1746 match a { }
1747 //^ Missing match arm
1748 match a { Either::A { foo: true } => () }
1749 //^ Missing match arm
1750 match a {
1751 Either::A { } => (),
1752 //^^^^^^^^^ Missing structure fields:
1753 // | - foo
1754 Either::B => (),
1755 }
1756 match a {
1757 //^ Missing match arm
1758 Either::A { } => (),
1759 } //^^^^^^^^^ Missing structure fields:
1760 // | - foo
1761
1762 match a {
1763 Either::A { foo: true } => (),
1764 Either::A { foo: false } => (),
1765 Either::B => (),
1766 }
1767 match a {
1768 Either::A { foo: _ } => (),
1769 Either::B => (),
1770 }
1771}
1772"#,
1773 );
1774 }
1775
1776 #[test]
1777 fn enum_record_fields_out_of_order() {
1778 check_diagnostics(
1779 r#"
1780enum Either {
1781 A { foo: bool, bar: () },
1782 B,
1783}
1784
1785fn main() {
1786 let a = Either::A { foo: true, bar: () };
1787 match a {
1788 //^ Missing match arm
1789 Either::A { bar: (), foo: false } => (),
1790 Either::A { foo: true, bar: () } => (),
1791 }
1792
1793 match a {
1794 Either::A { bar: (), foo: false } => (),
1795 Either::A { foo: true, bar: () } => (),
1796 Either::B => (),
1797 }
1798}
1799"#,
1800 );
1801 }
1802
1803 #[test]
1804 fn enum_record_ellipsis() {
1805 check_diagnostics(
1806 r#"
1807enum Either {
1808 A { foo: bool, bar: bool },
1809 B,
1810}
1811
1812fn main() {
1813 let a = Either::B;
1814 match a {
1815 //^ Missing match arm
1816 Either::A { foo: true, .. } => (),
1817 Either::B => (),
1818 }
1819 match a {
1820 //^ Missing match arm
1821 Either::A { .. } => (),
1822 }
1823
1824 match a {
1825 Either::A { foo: true, .. } => (),
1826 Either::A { foo: false, .. } => (),
1827 Either::B => (),
1828 }
1829
1830 match a {
1831 Either::A { .. } => (),
1832 Either::B => (),
1833 }
1834}
1835"#,
1836 );
1837 }
1838
1839 #[test]
1840 fn enum_tuple_partial_ellipsis() {
1841 check_diagnostics(
1842 r#"
1843enum Either {
1844 A(bool, bool, bool, bool),
1845 B,
1846}
1847
1848fn main() {
1849 match Either::B {
1850 //^^^^^^^^^ Missing match arm
1851 Either::A(true, .., true) => (),
1852 Either::A(true, .., false) => (),
1853 Either::A(false, .., false) => (),
1854 Either::B => (),
1855 }
1856 match Either::B {
1857 //^^^^^^^^^ Missing match arm
1858 Either::A(true, .., true) => (),
1859 Either::A(true, .., false) => (),
1860 Either::A(.., true) => (),
1861 Either::B => (),
1862 }
1863
1864 match Either::B {
1865 Either::A(true, .., true) => (),
1866 Either::A(true, .., false) => (),
1867 Either::A(false, .., true) => (),
1868 Either::A(false, .., false) => (),
1869 Either::B => (),
1870 }
1871 match Either::B {
1872 Either::A(true, .., true) => (),
1873 Either::A(true, .., false) => (),
1874 Either::A(.., true) => (),
1875 Either::A(.., false) => (),
1876 Either::B => (),
1877 }
1878}
1879"#,
1880 );
1881 }
1882
1883 #[test]
1884 fn never() {
1885 check_diagnostics(
1886 r#"
1887enum Never {}
1888
1889fn enum_(never: Never) {
1890 match never {}
1891}
1892fn enum_ref(never: &Never) {
1893 match never {}
1894 //^^^^^ Missing match arm
1895}
1896fn bang(never: !) {
1897 match never {}
1898}
1899"#,
1900 );
1901 }
1902
1903 #[test]
1904 fn unknown_type() {
1905 check_diagnostics(
1906 r#"
1907enum Option<T> { Some(T), None }
1908
1909fn main() {
1910 // `Never` is deliberately not defined so that it's an uninferred type.
1911 match Option::<Never>::None {
1912 None => (),
1913 Some(never) => match never {},
1914 // ^^^^^^^^^^^ Internal: match check bailed out
1915 }
1916 match Option::<Never>::None {
1917 //^^^^^^^^^^^^^^^^^^^^^ Missing match arm
1918 Option::Some(_never) => {},
1919 }
1920}
1921"#,
1922 );
1923 }
1924
1925 #[test]
1926 fn tuple_of_bools_with_ellipsis_at_end_missing_arm() {
1927 check_diagnostics(
1928 r#"
1929fn main() {
1930 match (false, true, false) {
1931 //^^^^^^^^^^^^^^^^^^^^ Missing match arm
1932 (false, ..) => (),
1933 }
1934}"#,
1935 );
1936 }
1937
1938 #[test]
1939 fn tuple_of_bools_with_ellipsis_at_beginning_missing_arm() {
1940 check_diagnostics(
1941 r#"
1942fn main() {
1943 match (false, true, false) {
1944 //^^^^^^^^^^^^^^^^^^^^ Missing match arm
1945 (.., false) => (),
1946 }
1947}"#,
1948 );
1949 }
1950
1951 #[test]
1952 fn tuple_of_bools_with_ellipsis_in_middle_missing_arm() {
1953 check_diagnostics(
1954 r#"
1955fn main() {
1956 match (false, true, false) {
1957 //^^^^^^^^^^^^^^^^^^^^ Missing match arm
1958 (true, .., false) => (),
1959 }
1960}"#,
1961 );
1962 }
1963
1964 #[test]
1965 fn record_struct() {
1966 check_diagnostics(
1967 r#"struct Foo { a: bool }
1968fn main(f: Foo) {
1969 match f {}
1970 //^ Missing match arm
1971 match f { Foo { a: true } => () }
1972 //^ Missing match arm
1973 match &f { Foo { a: true } => () }
1974 //^^ Missing match arm
1975 match f { Foo { a: _ } => () }
1976 match f {
1977 Foo { a: true } => (),
1978 Foo { a: false } => (),
1979 }
1980 match &f {
1981 Foo { a: true } => (),
1982 Foo { a: false } => (),
1983 }
1984}
1985"#,
1986 );
1987 }
1988
1989 #[test]
1990 fn tuple_struct() {
1991 check_diagnostics(
1992 r#"struct Foo(bool);
1993fn main(f: Foo) {
1994 match f {}
1995 //^ Missing match arm
1996 match f { Foo(true) => () }
1997 //^ Missing match arm
1998 match f {
1999 Foo(true) => (),
2000 Foo(false) => (),
2001 }
2002}
2003"#,
2004 );
2005 }
2006
2007 #[test]
2008 fn unit_struct() {
2009 check_diagnostics(
2010 r#"struct Foo;
2011fn main(f: Foo) {
2012 match f {}
2013 //^ Missing match arm
2014 match f { Foo => () }
2015}
2016"#,
2017 );
2018 }
2019
2020 #[test]
2021 fn record_struct_ellipsis() {
2022 check_diagnostics(
2023 r#"struct Foo { foo: bool, bar: bool }
2024fn main(f: Foo) {
2025 match f { Foo { foo: true, .. } => () }
2026 //^ Missing match arm
2027 match f {
2028 //^ Missing match arm
2029 Foo { foo: true, .. } => (),
2030 Foo { bar: false, .. } => ()
2031 }
2032 match f { Foo { .. } => () }
2033 match f {
2034 Foo { foo: true, .. } => (),
2035 Foo { foo: false, .. } => ()
2036 }
2037}
2038"#,
2039 );
2040 }
2041
2042 #[test]
2043 fn internal_or() {
2044 check_diagnostics(
2045 r#"
2046fn main() {
2047 enum Either { A(bool), B }
2048 match Either::B {
2049 //^^^^^^^^^ Missing match arm
2050 Either::A(true | false) => (),
2051 }
2052}
2053"#,
2054 );
2055 }
2056
2057 #[test]
2058 fn no_panic_at_unimplemented_subpattern_type() {
2059 check_diagnostics(
2060 r#"
2061struct S { a: char}
2062fn main(v: S) {
2063 match v { S{ a } => {} }
2064 match v { S{ a: _x } => {} }
2065 match v { S{ a: 'a' } => {} }
2066 //^^^^^^^^^^^ Internal: match check bailed out
2067 match v { S{..} => {} }
2068 match v { _ => {} }
2069 match v { }
2070 //^ Missing match arm
2071}
2072"#,
2073 );
2074 }
2075
2076 #[test]
2077 fn binding() {
2078 check_diagnostics(
2079 r#"
2080fn main() {
2081 match true {
2082 _x @ true => {}
2083 false => {}
2084 }
2085 match true { _x @ true => {} }
2086 //^^^^ Missing match arm
2087}
2088"#,
2089 );
2090 }
2091
2092 #[test]
2093 fn binding_ref_has_correct_type() {
2094 // Asserts `PatKind::Binding(ref _x): bool`, not &bool.
2095 // If that's not true match checking will panic with "incompatible constructors"
2096 // FIXME: make facilities to test this directly like `tests::check_infer(..)`
2097 check_diagnostics(
2098 r#"
2099enum Foo { A }
2100fn main() {
2101 // FIXME: this should not bail out but current behavior is such as the old algorithm.
2102 // ExprValidator::validate_match(..) checks types of top level patterns incorrecly.
2103 match Foo::A {
2104 ref _x => {}
2105 // ^^^^^^ Internal: match check bailed out
2106 Foo::A => {}
2107 }
2108 match (true,) {
2109 (ref _x,) => {}
2110 (true,) => {}
2111 }
2112}
2113"#,
2114 );
2115 }
2116
2117 #[test]
2118 fn enum_non_exhaustive() {
2119 check_diagnostics(
2120 r#"
2121//- /lib.rs crate:lib
2122#[non_exhaustive]
2123pub enum E { A, B }
2124fn _local() {
2125 match E::A { _ => {} }
2126 match E::A {
2127 E::A => {}
2128 E::B => {}
2129 }
2130 match E::A {
2131 E::A | E::B => {}
2132 }
2133}
2134
2135//- /main.rs crate:main deps:lib
2136use lib::E;
2137fn main() {
2138 match E::A { _ => {} }
2139 match E::A {
2140 //^^^^ Missing match arm
2141 E::A => {}
2142 E::B => {}
2143 }
2144 match E::A {
2145 //^^^^ Missing match arm
2146 E::A | E::B => {}
2147 }
2148}
2149"#,
2150 );
2151 }
2152
2153 #[test]
2154 fn match_guard() {
2155 check_diagnostics(
2156 r#"
2157fn main() {
2158 match true {
2159 true if false => {}
2160 true => {}
2161 false => {}
2162 }
2163 match true {
2164 //^^^^ Missing match arm
2165 true if false => {}
2166 false => {}
2167 }
2168}
2169"#,
2170 );
2171 }
2172
2173 #[test]
2174 fn pattern_type_is_of_substitution() {
2175 check_diagnostics(
2176 r#"
2177struct Foo<T>(T);
2178struct Bar;
2179fn main() {
2180 match Foo(Bar) {
2181 _ | Foo(Bar) => {}
2182 }
2183}
2184"#,
2185 );
2186 }
2187
2188 #[test]
2189 fn record_struct_no_such_field() {
2190 check_diagnostics(
2191 r#"
2192struct Foo { }
2193fn main(f: Foo) {
2194 match f { Foo { bar } => () }
2195 // ^^^^^^^^^^^ Internal: match check bailed out
2196}
2197"#,
2198 );
2199 }
2200
2201 #[test]
2202 fn match_ergonomics_issue_9095() {
2203 check_diagnostics(
2204 r#"
2205enum Foo<T> { A(T) }
2206fn main() {
2207 match &Foo::A(true) {
2208 _ => {}
2209 Foo::A(_) => {}
2210 }
2211}
2212"#,
2213 );
2214 }
2215
2216 mod false_negatives {
2217 //! The implementation of match checking here is a work in progress. As we roll this out, we
2218 //! prefer false negatives to false positives (ideally there would be no false positives). This
2219 //! test module should document known false negatives. Eventually we will have a complete
2220 //! implementation of match checking and this module will be empty.
2221 //!
2222 //! The reasons for documenting known false negatives:
2223 //!
2224 //! 1. It acts as a backlog of work that can be done to improve the behavior of the system.
2225 //! 2. It ensures the code doesn't panic when handling these cases.
2226 use super::*;
2227
2228 #[test]
2229 fn integers() {
2230 // We don't currently check integer exhaustiveness.
2231 check_diagnostics(
2232 r#"
2233fn main() {
2234 match 5 {
2235 10 => (),
2236 // ^^ Internal: match check bailed out
2237 11..20 => (),
2238 }
2239}
2240"#,
2241 );
2242 }
2243
2244 #[test]
2245 fn reference_patterns_at_top_level() {
2246 check_diagnostics(
2247 r#"
2248fn main() {
2249 match &false {
2250 &true => {}
2251 // ^^^^^ Internal: match check bailed out
2252 }
2253}
2254 "#,
2255 );
2256 }
2257
2258 #[test]
2259 fn reference_patterns_in_fields() {
2260 check_diagnostics(
2261 r#"
2262fn main() {
2263 match (&false,) {
2264 (true,) => {}
2265 // ^^^^^^^ Internal: match check bailed out
2266 }
2267 match (&false,) {
2268 (&true,) => {}
2269 // ^^^^^^^^ Internal: match check bailed out
2270 }
2271}
2272 "#,
2273 );
2274 }
2275 }
2276}
2277
2278#[cfg(test)]
2279mod decl_check_tests {
2280 use crate::diagnostics::tests::check_diagnostics;
2281
2282 #[test]
2283 fn incorrect_function_name() {
2284 check_diagnostics(
2285 r#"
2286fn NonSnakeCaseName() {}
2287// ^^^^^^^^^^^^^^^^ Function `NonSnakeCaseName` should have snake_case name, e.g. `non_snake_case_name`
2288"#,
2289 );
2290 }
2291
2292 #[test]
2293 fn incorrect_function_params() {
2294 check_diagnostics(
2295 r#"
2296fn foo(SomeParam: u8) {}
2297 // ^^^^^^^^^ Parameter `SomeParam` should have snake_case name, e.g. `some_param`
2298
2299fn foo2(ok_param: &str, CAPS_PARAM: u8) {}
2300 // ^^^^^^^^^^ Parameter `CAPS_PARAM` should have snake_case name, e.g. `caps_param`
2301"#,
2302 );
2303 }
2304
2305 #[test]
2306 fn incorrect_variable_names() {
2307 check_diagnostics(
2308 r#"
2309fn foo() {
2310 let SOME_VALUE = 10;
2311 // ^^^^^^^^^^ Variable `SOME_VALUE` should have snake_case name, e.g. `some_value`
2312 let AnotherValue = 20;
2313 // ^^^^^^^^^^^^ Variable `AnotherValue` should have snake_case name, e.g. `another_value`
2314}
2315"#,
2316 );
2317 }
2318
2319 #[test]
2320 fn incorrect_struct_names() {
2321 check_diagnostics(
2322 r#"
2323struct non_camel_case_name {}
2324 // ^^^^^^^^^^^^^^^^^^^ Structure `non_camel_case_name` should have CamelCase name, e.g. `NonCamelCaseName`
2325
2326struct SCREAMING_CASE {}
2327 // ^^^^^^^^^^^^^^ Structure `SCREAMING_CASE` should have CamelCase name, e.g. `ScreamingCase`
2328"#,
2329 );
2330 }
2331
2332 #[test]
2333 fn no_diagnostic_for_camel_cased_acronyms_in_struct_name() {
2334 check_diagnostics(
2335 r#"
2336struct AABB {}
2337"#,
2338 );
2339 }
2340
2341 #[test]
2342 fn incorrect_struct_field() {
2343 check_diagnostics(
2344 r#"
2345struct SomeStruct { SomeField: u8 }
2346 // ^^^^^^^^^ Field `SomeField` should have snake_case name, e.g. `some_field`
2347"#,
2348 );
2349 }
2350
2351 #[test]
2352 fn incorrect_enum_names() {
2353 check_diagnostics(
2354 r#"
2355enum some_enum { Val(u8) }
2356 // ^^^^^^^^^ Enum `some_enum` should have CamelCase name, e.g. `SomeEnum`
2357
2358enum SOME_ENUM {}
2359 // ^^^^^^^^^ Enum `SOME_ENUM` should have CamelCase name, e.g. `SomeEnum`
2360"#,
2361 );
2362 }
2363
2364 #[test]
2365 fn no_diagnostic_for_camel_cased_acronyms_in_enum_name() {
2366 check_diagnostics(
2367 r#"
2368enum AABB {}
2369"#,
2370 );
2371 }
2372
2373 #[test]
2374 fn incorrect_enum_variant_name() {
2375 check_diagnostics(
2376 r#"
2377enum SomeEnum { SOME_VARIANT(u8) }
2378 // ^^^^^^^^^^^^ Variant `SOME_VARIANT` should have CamelCase name, e.g. `SomeVariant`
2379"#,
2380 );
2381 }
2382
2383 #[test]
2384 fn incorrect_const_name() {
2385 check_diagnostics(
2386 r#"
2387const some_weird_const: u8 = 10;
2388 // ^^^^^^^^^^^^^^^^ Constant `some_weird_const` should have UPPER_SNAKE_CASE name, e.g. `SOME_WEIRD_CONST`
2389"#,
2390 );
2391 }
2392
2393 #[test]
2394 fn incorrect_static_name() {
2395 check_diagnostics(
2396 r#"
2397static some_weird_const: u8 = 10;
2398 // ^^^^^^^^^^^^^^^^ Static variable `some_weird_const` should have UPPER_SNAKE_CASE name, e.g. `SOME_WEIRD_CONST`
2399"#,
2400 );
2401 }
2402
2403 #[test]
2404 fn fn_inside_impl_struct() {
2405 check_diagnostics(
2406 r#"
2407struct someStruct;
2408 // ^^^^^^^^^^ Structure `someStruct` should have CamelCase name, e.g. `SomeStruct`
2409
2410impl someStruct {
2411 fn SomeFunc(&self) {
2412 // ^^^^^^^^ Function `SomeFunc` should have snake_case name, e.g. `some_func`
2413 let WHY_VAR_IS_CAPS = 10;
2414 // ^^^^^^^^^^^^^^^ Variable `WHY_VAR_IS_CAPS` should have snake_case name, e.g. `why_var_is_caps`
2415 }
2416}
2417"#,
2418 );
2419 }
2420
2421 #[test]
2422 fn no_diagnostic_for_enum_varinats() {
2423 check_diagnostics(
2424 r#"
2425enum Option { Some, None }
2426
2427fn main() {
2428 match Option::None {
2429 None => (),
2430 Some => (),
2431 }
2432}
2433"#,
2434 );
2435 }
2436
2437 #[test]
2438 fn non_let_bind() {
2439 check_diagnostics(
2440 r#"
2441enum Option { Some, None }
2442
2443fn main() {
2444 match Option::None {
2445 SOME_VAR @ None => (),
2446 // ^^^^^^^^ Variable `SOME_VAR` should have snake_case name, e.g. `some_var`
2447 Some => (),
2448 }
2449}
2450"#,
2451 );
2452 }
2453
2454 #[test]
2455 fn allow_attributes() {
2456 check_diagnostics(
2457 r#"
2458#[allow(non_snake_case)]
2459fn NonSnakeCaseName(SOME_VAR: u8) -> u8{
2460 // cov_flags generated output from elsewhere in this file
2461 extern "C" {
2462 #[no_mangle]
2463 static lower_case: u8;
2464 }
2465
2466 let OtherVar = SOME_VAR + 1;
2467 OtherVar
2468}
2469
2470#[allow(nonstandard_style)]
2471mod CheckNonstandardStyle {
2472 fn HiImABadFnName() {}
2473}
2474
2475#[allow(bad_style)]
2476mod CheckBadStyle {
2477 fn HiImABadFnName() {}
2478}
2479
2480mod F {
2481 #![allow(non_snake_case)]
2482 fn CheckItWorksWithModAttr(BAD_NAME_HI: u8) {}
2483}
2484
2485#[allow(non_snake_case, non_camel_case_types)]
2486pub struct some_type {
2487 SOME_FIELD: u8,
2488 SomeField: u16,
2489}
2490
2491#[allow(non_upper_case_globals)]
2492pub const some_const: u8 = 10;
2493
2494#[allow(non_upper_case_globals)]
2495pub static SomeStatic: u8 = 10;
2496 "#,
2497 );
2498 }
2499
2500 #[test]
2501 fn allow_attributes_crate_attr() {
2502 check_diagnostics(
2503 r#"
2504#![allow(non_snake_case)]
2505
2506mod F {
2507 fn CheckItWorksWithCrateAttr(BAD_NAME_HI: u8) {}
2508}
2509 "#,
2510 );
2511 }
2512
2513 #[test]
2514 #[ignore]
2515 fn bug_trait_inside_fn() {
2516 // FIXME:
2517 // This is broken, and in fact, should not even be looked at by this
2518 // lint in the first place. There's weird stuff going on in the
2519 // collection phase.
2520 // It's currently being brought in by:
2521 // * validate_func on `a` recursing into modules
2522 // * then it finds the trait and then the function while iterating
2523 // through modules
2524 // * then validate_func is called on Dirty
2525 // * ... which then proceeds to look at some unknown module taking no
2526 // attrs from either the impl or the fn a, and then finally to the root
2527 // module
2528 //
2529 // It should find the attribute on the trait, but it *doesn't even see
2530 // the trait* as far as I can tell.
2531
2532 check_diagnostics(
2533 r#"
2534trait T { fn a(); }
2535struct U {}
2536impl T for U {
2537 fn a() {
2538 // this comes out of bitflags, mostly
2539 #[allow(non_snake_case)]
2540 trait __BitFlags {
2541 const HiImAlsoBad: u8 = 2;
2542 #[inline]
2543 fn Dirty(&self) -> bool {
2544 false
2545 }
2546 }
2547
2548 }
2549}
2550 "#,
2551 );
2552 }
2553
2554 #[test]
2555 #[ignore]
2556 fn bug_traits_arent_checked() {
2557 // FIXME: Traits and functions in traits aren't currently checked by
2558 // r-a, even though rustc will complain about them.
2559 check_diagnostics(
2560 r#"
2561trait BAD_TRAIT {
2562 // ^^^^^^^^^ Trait `BAD_TRAIT` should have CamelCase name, e.g. `BadTrait`
2563 fn BAD_FUNCTION();
2564 // ^^^^^^^^^^^^ Function `BAD_FUNCTION` should have snake_case name, e.g. `bad_function`
2565 fn BadFunction();
2566 // ^^^^^^^^^^^^ Function `BadFunction` should have snake_case name, e.g. `bad_function`
2567}
2568 "#,
2569 );
2570 }
2571
2572 #[test]
2573 fn ignores_extern_items() {
2574 cov_mark::check!(extern_func_incorrect_case_ignored);
2575 cov_mark::check!(extern_static_incorrect_case_ignored);
2576 check_diagnostics(
2577 r#"
2578extern {
2579 fn NonSnakeCaseName(SOME_VAR: u8) -> u8;
2580 pub static SomeStatic: u8 = 10;
2581}
2582 "#,
2583 );
2584 }
2585
2586 #[test]
2587 fn infinite_loop_inner_items() {
2588 check_diagnostics(
2589 r#"
2590fn qualify() {
2591 mod foo {
2592 use super::*;
2593 }
2594}
2595 "#,
2596 )
2597 }
2598
2599 #[test] // Issue #8809.
2600 fn parenthesized_parameter() {
2601 check_diagnostics(r#"fn f((O): _) {}"#)
2602 }
722} 2603}