aboutsummaryrefslogtreecommitdiff
path: root/crates
diff options
context:
space:
mode:
Diffstat (limited to 'crates')
-rw-r--r--crates/ra_hir_ty/src/_match.rs790
-rw-r--r--crates/ra_ide/src/snapshots/highlight_doctest.html6
-rw-r--r--crates/ra_ide/src/ssr.rs74
-rw-r--r--crates/ra_ide/src/syntax_highlighting/injection.rs14
-rw-r--r--crates/ra_ide/src/syntax_highlighting/tests.rs6
-rw-r--r--crates/rust-analyzer/src/config.rs5
-rw-r--r--crates/rust-analyzer/src/diagnostics.rs6
-rw-r--r--crates/rust-analyzer/src/diagnostics/snapshots/rust_analyzer__diagnostics__to_proto__tests__snap_rustc_unused_variable_as_hint.snap86
-rw-r--r--crates/rust-analyzer/src/diagnostics/snapshots/rust_analyzer__diagnostics__to_proto__tests__snap_rustc_unused_variable_as_info.snap86
-rw-r--r--crates/rust-analyzer/src/diagnostics/to_proto.rs213
-rw-r--r--crates/rust-analyzer/src/main_loop.rs1
11 files changed, 832 insertions, 455 deletions
diff --git a/crates/ra_hir_ty/src/_match.rs b/crates/ra_hir_ty/src/_match.rs
index fff257193..02a7a61f1 100644
--- a/crates/ra_hir_ty/src/_match.rs
+++ b/crates/ra_hir_ty/src/_match.rs
@@ -362,7 +362,12 @@ impl PatStack {
362 cx: &MatchCheckCtx, 362 cx: &MatchCheckCtx,
363 constructor: &Constructor, 363 constructor: &Constructor,
364 ) -> MatchCheckResult<Option<PatStack>> { 364 ) -> MatchCheckResult<Option<PatStack>> {
365 let result = match (self.head().as_pat(cx), constructor) { 365 if self.is_empty() {
366 return Ok(None);
367 }
368
369 let head_pat = self.head().as_pat(cx);
370 let result = match (head_pat, constructor) {
366 (Pat::Tuple { args: ref pat_ids, ellipsis }, Constructor::Tuple { arity: _ }) => { 371 (Pat::Tuple { args: ref pat_ids, ellipsis }, Constructor::Tuple { arity: _ }) => {
367 if ellipsis.is_some() { 372 if ellipsis.is_some() {
368 // If there are ellipsis here, we should add the correct number of 373 // If there are ellipsis here, we should add the correct number of
@@ -531,7 +536,7 @@ impl Matrix {
531 } 536 }
532 537
533 fn heads(&self) -> Vec<PatIdOrWild> { 538 fn heads(&self) -> Vec<PatIdOrWild> {
534 self.0.iter().map(|p| p.head()).collect() 539 self.0.iter().flat_map(|p| p.get_head()).collect()
535 } 540 }
536 541
537 /// Computes `D(self)` for each contained PatStack. 542 /// Computes `D(self)` for each contained PatStack.
@@ -837,194 +842,193 @@ mod tests {
837 842
838 pub(super) use crate::{diagnostics::MissingMatchArms, test_db::TestDB}; 843 pub(super) use crate::{diagnostics::MissingMatchArms, test_db::TestDB};
839 844
840 pub(super) fn check_diagnostic_message(content: &str) -> String { 845 pub(super) fn check_diagnostic_message(ra_fixture: &str) -> String {
841 TestDB::with_single_file(content).0.diagnostic::<MissingMatchArms>().0 846 TestDB::with_single_file(ra_fixture).0.diagnostic::<MissingMatchArms>().0
842 } 847 }
843 848
844 pub(super) fn check_diagnostic(content: &str) { 849 pub(super) fn check_diagnostic(ra_fixture: &str) {
845 let diagnostic_count = 850 let diagnostic_count =
846 TestDB::with_single_file(content).0.diagnostic::<MissingMatchArms>().1; 851 TestDB::with_single_file(ra_fixture).0.diagnostic::<MissingMatchArms>().1;
847 852
848 assert_eq!(1, diagnostic_count, "no diagnostic reported"); 853 assert_eq!(1, diagnostic_count, "no diagnostic reported");
849 } 854 }
850 855
851 pub(super) fn check_no_diagnostic(content: &str) { 856 pub(super) fn check_no_diagnostic(ra_fixture: &str) {
852 let diagnostic_count = 857 let diagnostic_count =
853 TestDB::with_single_file(content).0.diagnostic::<MissingMatchArms>().1; 858 TestDB::with_single_file(ra_fixture).0.diagnostic::<MissingMatchArms>().1;
854 859
855 assert_eq!(0, diagnostic_count, "expected no diagnostic, found one"); 860 assert_eq!(0, diagnostic_count, "expected no diagnostic, found one");
856 } 861 }
857 862
858 #[test] 863 #[test]
859 fn empty_tuple_no_arms_diagnostic_message() { 864 fn empty_tuple_no_arms_diagnostic_message() {
860 let content = r"
861 fn test_fn() {
862 match () {
863 }
864 }
865 ";
866
867 assert_snapshot!( 865 assert_snapshot!(
868 check_diagnostic_message(content), 866 check_diagnostic_message(r"
867 fn test_fn() {
868 match () {
869 }
870 }
871 "),
869 @"\"()\": Missing match arm\n" 872 @"\"()\": Missing match arm\n"
870 ); 873 );
871 } 874 }
872 875
873 #[test] 876 #[test]
874 fn empty_tuple_no_arms() { 877 fn empty_tuple_no_arms() {
875 let content = r" 878 check_diagnostic(
879 r"
876 fn test_fn() { 880 fn test_fn() {
877 match () { 881 match () {
878 } 882 }
879 } 883 }
880 "; 884 ",
881 885 );
882 check_diagnostic(content);
883 } 886 }
884 887
885 #[test] 888 #[test]
886 fn empty_tuple_wild() { 889 fn empty_tuple_wild() {
887 let content = r" 890 check_no_diagnostic(
891 r"
888 fn test_fn() { 892 fn test_fn() {
889 match () { 893 match () {
890 _ => {} 894 _ => {}
891 } 895 }
892 } 896 }
893 "; 897 ",
894 898 );
895 check_no_diagnostic(content);
896 } 899 }
897 900
898 #[test] 901 #[test]
899 fn empty_tuple_no_diagnostic() { 902 fn empty_tuple_no_diagnostic() {
900 let content = r" 903 check_no_diagnostic(
904 r"
901 fn test_fn() { 905 fn test_fn() {
902 match () { 906 match () {
903 () => {} 907 () => {}
904 } 908 }
905 } 909 }
906 "; 910 ",
907 911 );
908 check_no_diagnostic(content);
909 } 912 }
910 913
911 #[test] 914 #[test]
912 fn tuple_of_empty_tuple_no_arms() { 915 fn tuple_of_empty_tuple_no_arms() {
913 let content = r" 916 check_diagnostic(
917 r"
914 fn test_fn() { 918 fn test_fn() {
915 match (()) { 919 match (()) {
916 } 920 }
917 } 921 }
918 "; 922 ",
919 923 );
920 check_diagnostic(content);
921 } 924 }
922 925
923 #[test] 926 #[test]
924 fn tuple_of_empty_tuple_no_diagnostic() { 927 fn tuple_of_empty_tuple_no_diagnostic() {
925 let content = r" 928 check_no_diagnostic(
929 r"
926 fn test_fn() { 930 fn test_fn() {
927 match (()) { 931 match (()) {
928 (()) => {} 932 (()) => {}
929 } 933 }
930 } 934 }
931 "; 935 ",
932 936 );
933 check_no_diagnostic(content);
934 } 937 }
935 938
936 #[test] 939 #[test]
937 fn tuple_of_two_empty_tuple_no_arms() { 940 fn tuple_of_two_empty_tuple_no_arms() {
938 let content = r" 941 check_diagnostic(
942 r"
939 fn test_fn() { 943 fn test_fn() {
940 match ((), ()) { 944 match ((), ()) {
941 } 945 }
942 } 946 }
943 "; 947 ",
944 948 );
945 check_diagnostic(content);
946 } 949 }
947 950
948 #[test] 951 #[test]
949 fn tuple_of_two_empty_tuple_no_diagnostic() { 952 fn tuple_of_two_empty_tuple_no_diagnostic() {
950 let content = r" 953 check_no_diagnostic(
954 r"
951 fn test_fn() { 955 fn test_fn() {
952 match ((), ()) { 956 match ((), ()) {
953 ((), ()) => {} 957 ((), ()) => {}
954 } 958 }
955 } 959 }
956 "; 960 ",
957 961 );
958 check_no_diagnostic(content);
959 } 962 }
960 963
961 #[test] 964 #[test]
962 fn bool_no_arms() { 965 fn bool_no_arms() {
963 let content = r" 966 check_diagnostic(
967 r"
964 fn test_fn() { 968 fn test_fn() {
965 match false { 969 match false {
966 } 970 }
967 } 971 }
968 "; 972 ",
969 973 );
970 check_diagnostic(content);
971 } 974 }
972 975
973 #[test] 976 #[test]
974 fn bool_missing_arm() { 977 fn bool_missing_arm() {
975 let content = r" 978 check_diagnostic(
979 r"
976 fn test_fn() { 980 fn test_fn() {
977 match false { 981 match false {
978 true => {} 982 true => {}
979 } 983 }
980 } 984 }
981 "; 985 ",
982 986 );
983 check_diagnostic(content);
984 } 987 }
985 988
986 #[test] 989 #[test]
987 fn bool_no_diagnostic() { 990 fn bool_no_diagnostic() {
988 let content = r" 991 check_no_diagnostic(
992 r"
989 fn test_fn() { 993 fn test_fn() {
990 match false { 994 match false {
991 true => {} 995 true => {}
992 false => {} 996 false => {}
993 } 997 }
994 } 998 }
995 "; 999 ",
996 1000 );
997 check_no_diagnostic(content);
998 } 1001 }
999 1002
1000 #[test] 1003 #[test]
1001 fn tuple_of_bools_no_arms() { 1004 fn tuple_of_bools_no_arms() {
1002 let content = r" 1005 check_diagnostic(
1006 r"
1003 fn test_fn() { 1007 fn test_fn() {
1004 match (false, true) { 1008 match (false, true) {
1005 } 1009 }
1006 } 1010 }
1007 "; 1011 ",
1008 1012 );
1009 check_diagnostic(content);
1010 } 1013 }
1011 1014
1012 #[test] 1015 #[test]
1013 fn tuple_of_bools_missing_arms() { 1016 fn tuple_of_bools_missing_arms() {
1014 let content = r" 1017 check_diagnostic(
1018 r"
1015 fn test_fn() { 1019 fn test_fn() {
1016 match (false, true) { 1020 match (false, true) {
1017 (true, true) => {}, 1021 (true, true) => {},
1018 } 1022 }
1019 } 1023 }
1020 "; 1024 ",
1021 1025 );
1022 check_diagnostic(content);
1023 } 1026 }
1024 1027
1025 #[test] 1028 #[test]
1026 fn tuple_of_bools_missing_arm() { 1029 fn tuple_of_bools_missing_arm() {
1027 let content = r" 1030 check_diagnostic(
1031 r"
1028 fn test_fn() { 1032 fn test_fn() {
1029 match (false, true) { 1033 match (false, true) {
1030 (false, true) => {}, 1034 (false, true) => {},
@@ -1032,14 +1036,14 @@ mod tests {
1032 (true, false) => {}, 1036 (true, false) => {},
1033 } 1037 }
1034 } 1038 }
1035 "; 1039 ",
1036 1040 );
1037 check_diagnostic(content);
1038 } 1041 }
1039 1042
1040 #[test] 1043 #[test]
1041 fn tuple_of_bools_with_wilds() { 1044 fn tuple_of_bools_with_wilds() {
1042 let content = r" 1045 check_no_diagnostic(
1046 r"
1043 fn test_fn() { 1047 fn test_fn() {
1044 match (false, true) { 1048 match (false, true) {
1045 (false, _) => {}, 1049 (false, _) => {},
@@ -1047,14 +1051,14 @@ mod tests {
1047 (_, true) => {}, 1051 (_, true) => {},
1048 } 1052 }
1049 } 1053 }
1050 "; 1054 ",
1051 1055 );
1052 check_no_diagnostic(content);
1053 } 1056 }
1054 1057
1055 #[test] 1058 #[test]
1056 fn tuple_of_bools_no_diagnostic() { 1059 fn tuple_of_bools_no_diagnostic() {
1057 let content = r" 1060 check_no_diagnostic(
1061 r"
1058 fn test_fn() { 1062 fn test_fn() {
1059 match (false, true) { 1063 match (false, true) {
1060 (true, true) => {}, 1064 (true, true) => {},
@@ -1063,27 +1067,27 @@ mod tests {
1063 (false, false) => {}, 1067 (false, false) => {},
1064 } 1068 }
1065 } 1069 }
1066 "; 1070 ",
1067 1071 );
1068 check_no_diagnostic(content);
1069 } 1072 }
1070 1073
1071 #[test] 1074 #[test]
1072 fn tuple_of_bools_binding_missing_arms() { 1075 fn tuple_of_bools_binding_missing_arms() {
1073 let content = r" 1076 check_diagnostic(
1077 r"
1074 fn test_fn() { 1078 fn test_fn() {
1075 match (false, true) { 1079 match (false, true) {
1076 (true, _x) => {}, 1080 (true, _x) => {},
1077 } 1081 }
1078 } 1082 }
1079 "; 1083 ",
1080 1084 );
1081 check_diagnostic(content);
1082 } 1085 }
1083 1086
1084 #[test] 1087 #[test]
1085 fn tuple_of_bools_binding_no_diagnostic() { 1088 fn tuple_of_bools_binding_no_diagnostic() {
1086 let content = r" 1089 check_no_diagnostic(
1090 r"
1087 fn test_fn() { 1091 fn test_fn() {
1088 match (false, true) { 1092 match (false, true) {
1089 (true, _x) => {}, 1093 (true, _x) => {},
@@ -1091,80 +1095,80 @@ mod tests {
1091 (false, false) => {}, 1095 (false, false) => {},
1092 } 1096 }
1093 } 1097 }
1094 "; 1098 ",
1095 1099 );
1096 check_no_diagnostic(content);
1097 } 1100 }
1098 1101
1099 #[test] 1102 #[test]
1100 fn tuple_of_bools_with_ellipsis_at_end_no_diagnostic() { 1103 fn tuple_of_bools_with_ellipsis_at_end_no_diagnostic() {
1101 let content = r" 1104 check_no_diagnostic(
1105 r"
1102 fn test_fn() { 1106 fn test_fn() {
1103 match (false, true, false) { 1107 match (false, true, false) {
1104 (false, ..) => {}, 1108 (false, ..) => {},
1105 (true, ..) => {}, 1109 (true, ..) => {},
1106 } 1110 }
1107 } 1111 }
1108 "; 1112 ",
1109 1113 );
1110 check_no_diagnostic(content);
1111 } 1114 }
1112 1115
1113 #[test] 1116 #[test]
1114 fn tuple_of_bools_with_ellipsis_at_beginning_no_diagnostic() { 1117 fn tuple_of_bools_with_ellipsis_at_beginning_no_diagnostic() {
1115 let content = r" 1118 check_no_diagnostic(
1119 r"
1116 fn test_fn() { 1120 fn test_fn() {
1117 match (false, true, false) { 1121 match (false, true, false) {
1118 (.., false) => {}, 1122 (.., false) => {},
1119 (.., true) => {}, 1123 (.., true) => {},
1120 } 1124 }
1121 } 1125 }
1122 "; 1126 ",
1123 1127 );
1124 check_no_diagnostic(content);
1125 } 1128 }
1126 1129
1127 #[test] 1130 #[test]
1128 fn tuple_of_bools_with_ellipsis_no_diagnostic() { 1131 fn tuple_of_bools_with_ellipsis_no_diagnostic() {
1129 let content = r" 1132 check_no_diagnostic(
1133 r"
1130 fn test_fn() { 1134 fn test_fn() {
1131 match (false, true, false) { 1135 match (false, true, false) {
1132 (..) => {}, 1136 (..) => {},
1133 } 1137 }
1134 } 1138 }
1135 "; 1139 ",
1136 1140 );
1137 check_no_diagnostic(content);
1138 } 1141 }
1139 1142
1140 #[test] 1143 #[test]
1141 fn tuple_of_tuple_and_bools_no_arms() { 1144 fn tuple_of_tuple_and_bools_no_arms() {
1142 let content = r" 1145 check_diagnostic(
1146 r"
1143 fn test_fn() { 1147 fn test_fn() {
1144 match (false, ((), false)) { 1148 match (false, ((), false)) {
1145 } 1149 }
1146 } 1150 }
1147 "; 1151 ",
1148 1152 );
1149 check_diagnostic(content);
1150 } 1153 }
1151 1154
1152 #[test] 1155 #[test]
1153 fn tuple_of_tuple_and_bools_missing_arms() { 1156 fn tuple_of_tuple_and_bools_missing_arms() {
1154 let content = r" 1157 check_diagnostic(
1158 r"
1155 fn test_fn() { 1159 fn test_fn() {
1156 match (false, ((), false)) { 1160 match (false, ((), false)) {
1157 (true, ((), true)) => {}, 1161 (true, ((), true)) => {},
1158 } 1162 }
1159 } 1163 }
1160 "; 1164 ",
1161 1165 );
1162 check_diagnostic(content);
1163 } 1166 }
1164 1167
1165 #[test] 1168 #[test]
1166 fn tuple_of_tuple_and_bools_no_diagnostic() { 1169 fn tuple_of_tuple_and_bools_no_diagnostic() {
1167 let content = r" 1170 check_no_diagnostic(
1171 r"
1168 fn test_fn() { 1172 fn test_fn() {
1169 match (false, ((), false)) { 1173 match (false, ((), false)) {
1170 (true, ((), true)) => {}, 1174 (true, ((), true)) => {},
@@ -1173,27 +1177,27 @@ mod tests {
1173 (false, ((), false)) => {}, 1177 (false, ((), false)) => {},
1174 } 1178 }
1175 } 1179 }
1176 "; 1180 ",
1177 1181 );
1178 check_no_diagnostic(content);
1179 } 1182 }
1180 1183
1181 #[test] 1184 #[test]
1182 fn tuple_of_tuple_and_bools_wildcard_missing_arms() { 1185 fn tuple_of_tuple_and_bools_wildcard_missing_arms() {
1183 let content = r" 1186 check_diagnostic(
1187 r"
1184 fn test_fn() { 1188 fn test_fn() {
1185 match (false, ((), false)) { 1189 match (false, ((), false)) {
1186 (true, _) => {}, 1190 (true, _) => {},
1187 } 1191 }
1188 } 1192 }
1189 "; 1193 ",
1190 1194 );
1191 check_diagnostic(content);
1192 } 1195 }
1193 1196
1194 #[test] 1197 #[test]
1195 fn tuple_of_tuple_and_bools_wildcard_no_diagnostic() { 1198 fn tuple_of_tuple_and_bools_wildcard_no_diagnostic() {
1196 let content = r" 1199 check_no_diagnostic(
1200 r"
1197 fn test_fn() { 1201 fn test_fn() {
1198 match (false, ((), false)) { 1202 match (false, ((), false)) {
1199 (true, ((), true)) => {}, 1203 (true, ((), true)) => {},
@@ -1201,14 +1205,14 @@ mod tests {
1201 (false, _) => {}, 1205 (false, _) => {},
1202 } 1206 }
1203 } 1207 }
1204 "; 1208 ",
1205 1209 );
1206 check_no_diagnostic(content);
1207 } 1210 }
1208 1211
1209 #[test] 1212 #[test]
1210 fn enum_no_arms() { 1213 fn enum_no_arms() {
1211 let content = r" 1214 check_diagnostic(
1215 r"
1212 enum Either { 1216 enum Either {
1213 A, 1217 A,
1214 B, 1218 B,
@@ -1217,14 +1221,14 @@ mod tests {
1217 match Either::A { 1221 match Either::A {
1218 } 1222 }
1219 } 1223 }
1220 "; 1224 ",
1221 1225 );
1222 check_diagnostic(content);
1223 } 1226 }
1224 1227
1225 #[test] 1228 #[test]
1226 fn enum_missing_arms() { 1229 fn enum_missing_arms() {
1227 let content = r" 1230 check_diagnostic(
1231 r"
1228 enum Either { 1232 enum Either {
1229 A, 1233 A,
1230 B, 1234 B,
@@ -1234,14 +1238,14 @@ mod tests {
1234 Either::A => {}, 1238 Either::A => {},
1235 } 1239 }
1236 } 1240 }
1237 "; 1241 ",
1238 1242 );
1239 check_diagnostic(content);
1240 } 1243 }
1241 1244
1242 #[test] 1245 #[test]
1243 fn enum_no_diagnostic() { 1246 fn enum_no_diagnostic() {
1244 let content = r" 1247 check_no_diagnostic(
1248 r"
1245 enum Either { 1249 enum Either {
1246 A, 1250 A,
1247 B, 1251 B,
@@ -1252,14 +1256,14 @@ mod tests {
1252 Either::B => {}, 1256 Either::B => {},
1253 } 1257 }
1254 } 1258 }
1255 "; 1259 ",
1256 1260 );
1257 check_no_diagnostic(content);
1258 } 1261 }
1259 1262
1260 #[test] 1263 #[test]
1261 fn enum_ref_missing_arms() { 1264 fn enum_ref_missing_arms() {
1262 let content = r" 1265 check_diagnostic(
1266 r"
1263 enum Either { 1267 enum Either {
1264 A, 1268 A,
1265 B, 1269 B,
@@ -1269,14 +1273,14 @@ mod tests {
1269 Either::A => {}, 1273 Either::A => {},
1270 } 1274 }
1271 } 1275 }
1272 "; 1276 ",
1273 1277 );
1274 check_diagnostic(content);
1275 } 1278 }
1276 1279
1277 #[test] 1280 #[test]
1278 fn enum_ref_no_diagnostic() { 1281 fn enum_ref_no_diagnostic() {
1279 let content = r" 1282 check_no_diagnostic(
1283 r"
1280 enum Either { 1284 enum Either {
1281 A, 1285 A,
1282 B, 1286 B,
@@ -1287,14 +1291,14 @@ mod tests {
1287 Either::B => {}, 1291 Either::B => {},
1288 } 1292 }
1289 } 1293 }
1290 "; 1294 ",
1291 1295 );
1292 check_no_diagnostic(content);
1293 } 1296 }
1294 1297
1295 #[test] 1298 #[test]
1296 fn enum_containing_bool_no_arms() { 1299 fn enum_containing_bool_no_arms() {
1297 let content = r" 1300 check_diagnostic(
1301 r"
1298 enum Either { 1302 enum Either {
1299 A(bool), 1303 A(bool),
1300 B, 1304 B,
@@ -1303,14 +1307,14 @@ mod tests {
1303 match Either::B { 1307 match Either::B {
1304 } 1308 }
1305 } 1309 }
1306 "; 1310 ",
1307 1311 );
1308 check_diagnostic(content);
1309 } 1312 }
1310 1313
1311 #[test] 1314 #[test]
1312 fn enum_containing_bool_missing_arms() { 1315 fn enum_containing_bool_missing_arms() {
1313 let content = r" 1316 check_diagnostic(
1317 r"
1314 enum Either { 1318 enum Either {
1315 A(bool), 1319 A(bool),
1316 B, 1320 B,
@@ -1321,14 +1325,14 @@ mod tests {
1321 Either::B => (), 1325 Either::B => (),
1322 } 1326 }
1323 } 1327 }
1324 "; 1328 ",
1325 1329 );
1326 check_diagnostic(content);
1327 } 1330 }
1328 1331
1329 #[test] 1332 #[test]
1330 fn enum_containing_bool_no_diagnostic() { 1333 fn enum_containing_bool_no_diagnostic() {
1331 let content = r" 1334 check_no_diagnostic(
1335 r"
1332 enum Either { 1336 enum Either {
1333 A(bool), 1337 A(bool),
1334 B, 1338 B,
@@ -1340,14 +1344,14 @@ mod tests {
1340 Either::B => (), 1344 Either::B => (),
1341 } 1345 }
1342 } 1346 }
1343 "; 1347 ",
1344 1348 );
1345 check_no_diagnostic(content);
1346 } 1349 }
1347 1350
1348 #[test] 1351 #[test]
1349 fn enum_containing_bool_with_wild_no_diagnostic() { 1352 fn enum_containing_bool_with_wild_no_diagnostic() {
1350 let content = r" 1353 check_no_diagnostic(
1354 r"
1351 enum Either { 1355 enum Either {
1352 A(bool), 1356 A(bool),
1353 B, 1357 B,
@@ -1358,14 +1362,14 @@ mod tests {
1358 _ => (), 1362 _ => (),
1359 } 1363 }
1360 } 1364 }
1361 "; 1365 ",
1362 1366 );
1363 check_no_diagnostic(content);
1364 } 1367 }
1365 1368
1366 #[test] 1369 #[test]
1367 fn enum_containing_bool_with_wild_2_no_diagnostic() { 1370 fn enum_containing_bool_with_wild_2_no_diagnostic() {
1368 let content = r" 1371 check_no_diagnostic(
1372 r"
1369 enum Either { 1373 enum Either {
1370 A(bool), 1374 A(bool),
1371 B, 1375 B,
@@ -1376,14 +1380,14 @@ mod tests {
1376 Either::B => (), 1380 Either::B => (),
1377 } 1381 }
1378 } 1382 }
1379 "; 1383 ",
1380 1384 );
1381 check_no_diagnostic(content);
1382 } 1385 }
1383 1386
1384 #[test] 1387 #[test]
1385 fn enum_different_sizes_missing_arms() { 1388 fn enum_different_sizes_missing_arms() {
1386 let content = r" 1389 check_diagnostic(
1390 r"
1387 enum Either { 1391 enum Either {
1388 A(bool), 1392 A(bool),
1389 B(bool, bool), 1393 B(bool, bool),
@@ -1394,14 +1398,14 @@ mod tests {
1394 Either::B(false, _) => (), 1398 Either::B(false, _) => (),
1395 } 1399 }
1396 } 1400 }
1397 "; 1401 ",
1398 1402 );
1399 check_diagnostic(content);
1400 } 1403 }
1401 1404
1402 #[test] 1405 #[test]
1403 fn enum_different_sizes_no_diagnostic() { 1406 fn enum_different_sizes_no_diagnostic() {
1404 let content = r" 1407 check_no_diagnostic(
1408 r"
1405 enum Either { 1409 enum Either {
1406 A(bool), 1410 A(bool),
1407 B(bool, bool), 1411 B(bool, bool),
@@ -1413,14 +1417,14 @@ mod tests {
1413 Either::B(false, _) => (), 1417 Either::B(false, _) => (),
1414 } 1418 }
1415 } 1419 }
1416 "; 1420 ",
1417 1421 );
1418 check_no_diagnostic(content);
1419 } 1422 }
1420 1423
1421 #[test] 1424 #[test]
1422 fn or_no_diagnostic() { 1425 fn or_no_diagnostic() {
1423 let content = r" 1426 check_no_diagnostic(
1427 r"
1424 enum Either { 1428 enum Either {
1425 A(bool), 1429 A(bool),
1426 B(bool, bool), 1430 B(bool, bool),
@@ -1432,14 +1436,14 @@ mod tests {
1432 Either::B(false, _) => (), 1436 Either::B(false, _) => (),
1433 } 1437 }
1434 } 1438 }
1435 "; 1439 ",
1436 1440 );
1437 check_no_diagnostic(content);
1438 } 1441 }
1439 1442
1440 #[test] 1443 #[test]
1441 fn tuple_of_enum_no_diagnostic() { 1444 fn tuple_of_enum_no_diagnostic() {
1442 let content = r" 1445 check_no_diagnostic(
1446 r"
1443 enum Either { 1447 enum Either {
1444 A(bool), 1448 A(bool),
1445 B(bool, bool), 1449 B(bool, bool),
@@ -1456,14 +1460,16 @@ mod tests {
1456 (Either::B(_, _), Either2::D) => (), 1460 (Either::B(_, _), Either2::D) => (),
1457 } 1461 }
1458 } 1462 }
1459 "; 1463 ",
1460 1464 );
1461 check_no_diagnostic(content);
1462 } 1465 }
1463 1466
1464 #[test] 1467 #[test]
1465 fn mismatched_types() { 1468 fn mismatched_types() {
1466 let content = r" 1469 // Match statements with arms that don't match the
1470 // expression pattern do not fire this diagnostic.
1471 check_no_diagnostic(
1472 r"
1467 enum Either { 1473 enum Either {
1468 A, 1474 A,
1469 B, 1475 B,
@@ -1478,47 +1484,47 @@ mod tests {
1478 Either2::D => (), 1484 Either2::D => (),
1479 } 1485 }
1480 } 1486 }
1481 "; 1487 ",
1482 1488 );
1483 // Match statements with arms that don't match the
1484 // expression pattern do not fire this diagnostic.
1485 check_no_diagnostic(content);
1486 } 1489 }
1487 1490
1488 #[test] 1491 #[test]
1489 fn mismatched_types_with_different_arity() { 1492 fn mismatched_types_with_different_arity() {
1490 let content = r" 1493 // Match statements with arms that don't match the
1494 // expression pattern do not fire this diagnostic.
1495 check_no_diagnostic(
1496 r"
1491 fn test_fn() { 1497 fn test_fn() {
1492 match (true, false) { 1498 match (true, false) {
1493 (true, false, true) => (), 1499 (true, false, true) => (),
1494 (true) => (), 1500 (true) => (),
1495 } 1501 }
1496 } 1502 }
1497 "; 1503 ",
1498 1504 );
1499 // Match statements with arms that don't match the
1500 // expression pattern do not fire this diagnostic.
1501 check_no_diagnostic(content);
1502 } 1505 }
1503 1506
1504 #[test] 1507 #[test]
1505 fn malformed_match_arm_tuple_missing_pattern() { 1508 fn malformed_match_arm_tuple_missing_pattern() {
1506 let content = r" 1509 // Match statements with arms that don't match the
1510 // expression pattern do not fire this diagnostic.
1511 check_no_diagnostic(
1512 r"
1507 fn test_fn() { 1513 fn test_fn() {
1508 match (0) { 1514 match (0) {
1509 () => (), 1515 () => (),
1510 } 1516 }
1511 } 1517 }
1512 "; 1518 ",
1513 1519 );
1514 // Match statements with arms that don't match the
1515 // expression pattern do not fire this diagnostic.
1516 check_no_diagnostic(content);
1517 } 1520 }
1518 1521
1519 #[test] 1522 #[test]
1520 fn malformed_match_arm_tuple_enum_missing_pattern() { 1523 fn malformed_match_arm_tuple_enum_missing_pattern() {
1521 let content = r" 1524 // We are testing to be sure we don't panic here when the match
1525 // arm `Either::B` is missing its pattern.
1526 check_no_diagnostic(
1527 r"
1522 enum Either { 1528 enum Either {
1523 A, 1529 A,
1524 B(u32), 1530 B(u32),
@@ -1529,32 +1535,30 @@ mod tests {
1529 Either::B() => (), 1535 Either::B() => (),
1530 } 1536 }
1531 } 1537 }
1532 "; 1538 ",
1533 1539 );
1534 // We are testing to be sure we don't panic here when the match
1535 // arm `Either::B` is missing its pattern.
1536 check_no_diagnostic(content);
1537 } 1540 }
1538 1541
1539 #[test] 1542 #[test]
1540 fn enum_not_in_scope() { 1543 fn enum_not_in_scope() {
1541 let content = r" 1544 // The enum is not in scope so we don't perform exhaustiveness
1545 // checking, but we want to be sure we don't panic here (and
1546 // we don't create a diagnostic).
1547 check_no_diagnostic(
1548 r"
1542 fn test_fn() { 1549 fn test_fn() {
1543 match Foo::Bar { 1550 match Foo::Bar {
1544 Foo::Baz => (), 1551 Foo::Baz => (),
1545 } 1552 }
1546 } 1553 }
1547 "; 1554 ",
1548 1555 );
1549 // The enum is not in scope so we don't perform exhaustiveness
1550 // checking, but we want to be sure we don't panic here (and
1551 // we don't create a diagnostic).
1552 check_no_diagnostic(content);
1553 } 1556 }
1554 1557
1555 #[test] 1558 #[test]
1556 fn expr_diverges() { 1559 fn expr_diverges() {
1557 let content = r" 1560 check_no_diagnostic(
1561 r"
1558 enum Either { 1562 enum Either {
1559 A, 1563 A,
1560 B, 1564 B,
@@ -1565,14 +1569,14 @@ mod tests {
1565 Either::B => (), 1569 Either::B => (),
1566 } 1570 }
1567 } 1571 }
1568 "; 1572 ",
1569 1573 );
1570 check_no_diagnostic(content);
1571 } 1574 }
1572 1575
1573 #[test] 1576 #[test]
1574 fn expr_loop_with_break() { 1577 fn expr_loop_with_break() {
1575 let content = r" 1578 check_no_diagnostic(
1579 r"
1576 enum Either { 1580 enum Either {
1577 A, 1581 A,
1578 B, 1582 B,
@@ -1583,14 +1587,14 @@ mod tests {
1583 Either::B => (), 1587 Either::B => (),
1584 } 1588 }
1585 } 1589 }
1586 "; 1590 ",
1587 1591 );
1588 check_no_diagnostic(content);
1589 } 1592 }
1590 1593
1591 #[test] 1594 #[test]
1592 fn expr_partially_diverges() { 1595 fn expr_partially_diverges() {
1593 let content = r" 1596 check_no_diagnostic(
1597 r"
1594 enum Either<T> { 1598 enum Either<T> {
1595 A(T), 1599 A(T),
1596 B, 1600 B,
@@ -1604,14 +1608,14 @@ mod tests {
1604 Either::B => 0, 1608 Either::B => 0,
1605 } 1609 }
1606 } 1610 }
1607 "; 1611 ",
1608 1612 );
1609 check_no_diagnostic(content);
1610 } 1613 }
1611 1614
1612 #[test] 1615 #[test]
1613 fn enum_record_no_arms() { 1616 fn enum_record_no_arms() {
1614 let content = r" 1617 check_diagnostic(
1618 r"
1615 enum Either { 1619 enum Either {
1616 A { foo: bool }, 1620 A { foo: bool },
1617 B, 1621 B,
@@ -1621,14 +1625,14 @@ mod tests {
1621 match a { 1625 match a {
1622 } 1626 }
1623 } 1627 }
1624 "; 1628 ",
1625 1629 );
1626 check_diagnostic(content);
1627 } 1630 }
1628 1631
1629 #[test] 1632 #[test]
1630 fn enum_record_missing_arms() { 1633 fn enum_record_missing_arms() {
1631 let content = r" 1634 check_diagnostic(
1635 r"
1632 enum Either { 1636 enum Either {
1633 A { foo: bool }, 1637 A { foo: bool },
1634 B, 1638 B,
@@ -1639,14 +1643,14 @@ mod tests {
1639 Either::A { foo: true } => (), 1643 Either::A { foo: true } => (),
1640 } 1644 }
1641 } 1645 }
1642 "; 1646 ",
1643 1647 );
1644 check_diagnostic(content);
1645 } 1648 }
1646 1649
1647 #[test] 1650 #[test]
1648 fn enum_record_no_diagnostic() { 1651 fn enum_record_no_diagnostic() {
1649 let content = r" 1652 check_no_diagnostic(
1653 r"
1650 enum Either { 1654 enum Either {
1651 A { foo: bool }, 1655 A { foo: bool },
1652 B, 1656 B,
@@ -1659,14 +1663,17 @@ mod tests {
1659 Either::B => (), 1663 Either::B => (),
1660 } 1664 }
1661 } 1665 }
1662 "; 1666 ",
1663 1667 );
1664 check_no_diagnostic(content);
1665 } 1668 }
1666 1669
1667 #[test] 1670 #[test]
1668 fn enum_record_missing_field_no_diagnostic() { 1671 fn enum_record_missing_field_no_diagnostic() {
1669 let content = r" 1672 // When `Either::A` is missing a struct member, we don't want
1673 // to fire the missing match arm diagnostic. This should fire
1674 // some other diagnostic.
1675 check_no_diagnostic(
1676 r"
1670 enum Either { 1677 enum Either {
1671 A { foo: bool }, 1678 A { foo: bool },
1672 B, 1679 B,
@@ -1678,17 +1685,16 @@ mod tests {
1678 Either::B => (), 1685 Either::B => (),
1679 } 1686 }
1680 } 1687 }
1681 "; 1688 ",
1682 1689 );
1683 // When `Either::A` is missing a struct member, we don't want
1684 // to fire the missing match arm diagnostic. This should fire
1685 // some other diagnostic.
1686 check_no_diagnostic(content);
1687 } 1690 }
1688 1691
1689 #[test] 1692 #[test]
1690 fn enum_record_missing_field_missing_match_arm() { 1693 fn enum_record_missing_field_missing_match_arm() {
1691 let content = r" 1694 // Even though `Either::A` is missing fields, we still want to fire
1695 // the missing arm diagnostic here, since we know `Either::B` is missing.
1696 check_diagnostic(
1697 r"
1692 enum Either { 1698 enum Either {
1693 A { foo: bool }, 1699 A { foo: bool },
1694 B, 1700 B,
@@ -1699,16 +1705,14 @@ mod tests {
1699 Either::A { } => (), 1705 Either::A { } => (),
1700 } 1706 }
1701 } 1707 }
1702 "; 1708 ",
1703 1709 );
1704 // Even though `Either::A` is missing fields, we still want to fire
1705 // the missing arm diagnostic here, since we know `Either::B` is missing.
1706 check_diagnostic(content);
1707 } 1710 }
1708 1711
1709 #[test] 1712 #[test]
1710 fn enum_record_no_diagnostic_wild() { 1713 fn enum_record_no_diagnostic_wild() {
1711 let content = r" 1714 check_no_diagnostic(
1715 r"
1712 enum Either { 1716 enum Either {
1713 A { foo: bool }, 1717 A { foo: bool },
1714 B, 1718 B,
@@ -1720,14 +1724,14 @@ mod tests {
1720 Either::B => (), 1724 Either::B => (),
1721 } 1725 }
1722 } 1726 }
1723 "; 1727 ",
1724 1728 );
1725 check_no_diagnostic(content);
1726 } 1729 }
1727 1730
1728 #[test] 1731 #[test]
1729 fn enum_record_fields_out_of_order_missing_arm() { 1732 fn enum_record_fields_out_of_order_missing_arm() {
1730 let content = r" 1733 check_diagnostic(
1734 r"
1731 enum Either { 1735 enum Either {
1732 A { foo: bool, bar: () }, 1736 A { foo: bool, bar: () },
1733 B, 1737 B,
@@ -1739,14 +1743,14 @@ mod tests {
1739 Either::A { foo: true, bar: () } => (), 1743 Either::A { foo: true, bar: () } => (),
1740 } 1744 }
1741 } 1745 }
1742 "; 1746 ",
1743 1747 );
1744 check_diagnostic(content);
1745 } 1748 }
1746 1749
1747 #[test] 1750 #[test]
1748 fn enum_record_fields_out_of_order_no_diagnostic() { 1751 fn enum_record_fields_out_of_order_no_diagnostic() {
1749 let content = r" 1752 check_no_diagnostic(
1753 r"
1750 enum Either { 1754 enum Either {
1751 A { foo: bool, bar: () }, 1755 A { foo: bool, bar: () },
1752 B, 1756 B,
@@ -1759,89 +1763,89 @@ mod tests {
1759 Either::B => (), 1763 Either::B => (),
1760 } 1764 }
1761 } 1765 }
1762 "; 1766 ",
1763 1767 );
1764 check_no_diagnostic(content);
1765 } 1768 }
1766 1769
1767 #[test] 1770 #[test]
1768 fn enum_record_ellipsis_missing_arm() { 1771 fn enum_record_ellipsis_missing_arm() {
1769 let content = r" 1772 check_diagnostic(
1770 enum Either { 1773 r"
1771 A { foo: bool, bar: bool }, 1774 enum Either {
1772 B, 1775 A { foo: bool, bar: bool },
1773 } 1776 B,
1774 fn test_fn() { 1777 }
1775 match Either::B { 1778 fn test_fn() {
1776 Either::A { foo: true, .. } => (), 1779 match Either::B {
1777 Either::B => (), 1780 Either::A { foo: true, .. } => (),
1778 } 1781 Either::B => (),
1779 } 1782 }
1780 "; 1783 }
1781 1784 ",
1782 check_diagnostic(content); 1785 );
1783 } 1786 }
1784 1787
1785 #[test] 1788 #[test]
1786 fn enum_record_ellipsis_no_diagnostic() { 1789 fn enum_record_ellipsis_no_diagnostic() {
1787 let content = r" 1790 check_no_diagnostic(
1788 enum Either { 1791 r"
1789 A { foo: bool, bar: bool }, 1792 enum Either {
1790 B, 1793 A { foo: bool, bar: bool },
1791 } 1794 B,
1792 fn test_fn() { 1795 }
1793 let a = Either::A { foo: true }; 1796 fn test_fn() {
1794 match a { 1797 let a = Either::A { foo: true };
1795 Either::A { foo: true, .. } => (), 1798 match a {
1796 Either::A { foo: false, .. } => (), 1799 Either::A { foo: true, .. } => (),
1797 Either::B => (), 1800 Either::A { foo: false, .. } => (),
1798 } 1801 Either::B => (),
1799 } 1802 }
1800 "; 1803 }
1801 1804 ",
1802 check_no_diagnostic(content); 1805 );
1803 } 1806 }
1804 1807
1805 #[test] 1808 #[test]
1806 fn enum_record_ellipsis_all_fields_missing_arm() { 1809 fn enum_record_ellipsis_all_fields_missing_arm() {
1807 let content = r" 1810 check_diagnostic(
1808 enum Either { 1811 r"
1809 A { foo: bool, bar: bool }, 1812 enum Either {
1810 B, 1813 A { foo: bool, bar: bool },
1811 } 1814 B,
1812 fn test_fn() { 1815 }
1813 let a = Either::B; 1816 fn test_fn() {
1814 match a { 1817 let a = Either::B;
1815 Either::A { .. } => (), 1818 match a {
1816 } 1819 Either::A { .. } => (),
1817 } 1820 }
1818 "; 1821 }
1819 1822 ",
1820 check_diagnostic(content); 1823 );
1821 } 1824 }
1822 1825
1823 #[test] 1826 #[test]
1824 fn enum_record_ellipsis_all_fields_no_diagnostic() { 1827 fn enum_record_ellipsis_all_fields_no_diagnostic() {
1825 let content = r" 1828 check_no_diagnostic(
1826 enum Either { 1829 r"
1827 A { foo: bool, bar: bool }, 1830 enum Either {
1828 B, 1831 A { foo: bool, bar: bool },
1829 } 1832 B,
1830 fn test_fn() { 1833 }
1831 let a = Either::B; 1834 fn test_fn() {
1832 match a { 1835 let a = Either::B;
1833 Either::A { .. } => (), 1836 match a {
1834 Either::B => (), 1837 Either::A { .. } => (),
1835 } 1838 Either::B => (),
1836 } 1839 }
1837 "; 1840 }
1838 1841 ",
1839 check_no_diagnostic(content); 1842 );
1840 } 1843 }
1841 1844
1842 #[test] 1845 #[test]
1843 fn enum_tuple_partial_ellipsis_no_diagnostic() { 1846 fn enum_tuple_partial_ellipsis_no_diagnostic() {
1844 let content = r" 1847 check_no_diagnostic(
1848 r"
1845 enum Either { 1849 enum Either {
1846 A(bool, bool, bool, bool), 1850 A(bool, bool, bool, bool),
1847 B, 1851 B,
@@ -1855,14 +1859,14 @@ mod tests {
1855 Either::B => {}, 1859 Either::B => {},
1856 } 1860 }
1857 } 1861 }
1858 "; 1862 ",
1859 1863 );
1860 check_no_diagnostic(content);
1861 } 1864 }
1862 1865
1863 #[test] 1866 #[test]
1864 fn enum_tuple_partial_ellipsis_2_no_diagnostic() { 1867 fn enum_tuple_partial_ellipsis_2_no_diagnostic() {
1865 let content = r" 1868 check_no_diagnostic(
1869 r"
1866 enum Either { 1870 enum Either {
1867 A(bool, bool, bool, bool), 1871 A(bool, bool, bool, bool),
1868 B, 1872 B,
@@ -1876,14 +1880,14 @@ mod tests {
1876 Either::B => {}, 1880 Either::B => {},
1877 } 1881 }
1878 } 1882 }
1879 "; 1883 ",
1880 1884 );
1881 check_no_diagnostic(content);
1882 } 1885 }
1883 1886
1884 #[test] 1887 #[test]
1885 fn enum_tuple_partial_ellipsis_missing_arm() { 1888 fn enum_tuple_partial_ellipsis_missing_arm() {
1886 let content = r" 1889 check_diagnostic(
1890 r"
1887 enum Either { 1891 enum Either {
1888 A(bool, bool, bool, bool), 1892 A(bool, bool, bool, bool),
1889 B, 1893 B,
@@ -1896,14 +1900,14 @@ mod tests {
1896 Either::B => {}, 1900 Either::B => {},
1897 } 1901 }
1898 } 1902 }
1899 "; 1903 ",
1900 1904 );
1901 check_diagnostic(content);
1902 } 1905 }
1903 1906
1904 #[test] 1907 #[test]
1905 fn enum_tuple_partial_ellipsis_2_missing_arm() { 1908 fn enum_tuple_partial_ellipsis_2_missing_arm() {
1906 let content = r" 1909 check_diagnostic(
1910 r"
1907 enum Either { 1911 enum Either {
1908 A(bool, bool, bool, bool), 1912 A(bool, bool, bool, bool),
1909 B, 1913 B,
@@ -1916,14 +1920,14 @@ mod tests {
1916 Either::B => {}, 1920 Either::B => {},
1917 } 1921 }
1918 } 1922 }
1919 "; 1923 ",
1920 1924 );
1921 check_diagnostic(content);
1922 } 1925 }
1923 1926
1924 #[test] 1927 #[test]
1925 fn enum_tuple_ellipsis_no_diagnostic() { 1928 fn enum_tuple_ellipsis_no_diagnostic() {
1926 let content = r" 1929 check_no_diagnostic(
1930 r"
1927 enum Either { 1931 enum Either {
1928 A(bool, bool, bool, bool), 1932 A(bool, bool, bool, bool),
1929 B, 1933 B,
@@ -1934,51 +1938,51 @@ mod tests {
1934 Either::B => {}, 1938 Either::B => {},
1935 } 1939 }
1936 } 1940 }
1937 "; 1941 ",
1938 1942 );
1939 check_no_diagnostic(content);
1940 } 1943 }
1941 1944
1942 #[test] 1945 #[test]
1943 fn enum_never() { 1946 fn enum_never() {
1944 let content = r" 1947 check_no_diagnostic(
1948 r"
1945 enum Never {} 1949 enum Never {}
1946 1950
1947 fn test_fn(never: Never) { 1951 fn test_fn(never: Never) {
1948 match never {} 1952 match never {}
1949 } 1953 }
1950 "; 1954 ",
1951 1955 );
1952 check_no_diagnostic(content);
1953 } 1956 }
1954 1957
1955 #[test] 1958 #[test]
1956 fn type_never() { 1959 fn type_never() {
1957 let content = r" 1960 check_no_diagnostic(
1961 r"
1958 fn test_fn(never: !) { 1962 fn test_fn(never: !) {
1959 match never {} 1963 match never {}
1960 } 1964 }
1961 "; 1965 ",
1962 1966 );
1963 check_no_diagnostic(content);
1964 } 1967 }
1965 1968
1966 #[test] 1969 #[test]
1967 fn enum_never_ref() { 1970 fn enum_never_ref() {
1968 let content = r" 1971 check_no_diagnostic(
1972 r"
1969 enum Never {} 1973 enum Never {}
1970 1974
1971 fn test_fn(never: &Never) { 1975 fn test_fn(never: &Never) {
1972 match never {} 1976 match never {}
1973 } 1977 }
1974 "; 1978 ",
1975 1979 );
1976 check_no_diagnostic(content);
1977 } 1980 }
1978 1981
1979 #[test] 1982 #[test]
1980 fn expr_diverges_missing_arm() { 1983 fn expr_diverges_missing_arm() {
1981 let content = r" 1984 check_no_diagnostic(
1985 r"
1982 enum Either { 1986 enum Either {
1983 A, 1987 A,
1984 B, 1988 B,
@@ -1988,9 +1992,27 @@ mod tests {
1988 Either::A => (), 1992 Either::A => (),
1989 } 1993 }
1990 } 1994 }
1991 "; 1995 ",
1996 );
1997 }
1998
1999 #[test]
2000 fn or_pattern_panic() {
2001 check_no_diagnostic(
2002 r"
2003 pub enum Category {
2004 Infinity,
2005 Zero,
2006 }
1992 2007
1993 check_no_diagnostic(content); 2008 fn panic(a: Category, b: Category) {
2009 match (a, b) {
2010 (Category::Zero | Category::Infinity, _) => {}
2011 (_, Category::Zero | Category::Infinity) => {}
2012 }
2013 }
2014 ",
2015 );
1994 } 2016 }
1995} 2017}
1996 2018
@@ -2010,23 +2032,26 @@ mod false_negatives {
2010 2032
2011 #[test] 2033 #[test]
2012 fn integers() { 2034 fn integers() {
2013 let content = r" 2035 // This is a false negative.
2036 // We don't currently check integer exhaustiveness.
2037 check_no_diagnostic(
2038 r"
2014 fn test_fn() { 2039 fn test_fn() {
2015 match 5 { 2040 match 5 {
2016 10 => (), 2041 10 => (),
2017 11..20 => (), 2042 11..20 => (),
2018 } 2043 }
2019 } 2044 }
2020 "; 2045 ",
2021 2046 );
2022 // This is a false negative.
2023 // We don't currently check integer exhaustiveness.
2024 check_no_diagnostic(content);
2025 } 2047 }
2026 2048
2027 #[test] 2049 #[test]
2028 fn internal_or() { 2050 fn internal_or() {
2029 let content = r" 2051 // This is a false negative.
2052 // We do not currently handle patterns with internal `or`s.
2053 check_no_diagnostic(
2054 r"
2030 fn test_fn() { 2055 fn test_fn() {
2031 enum Either { 2056 enum Either {
2032 A(bool), 2057 A(bool),
@@ -2036,16 +2061,18 @@ mod false_negatives {
2036 Either::A(true | false) => (), 2061 Either::A(true | false) => (),
2037 } 2062 }
2038 } 2063 }
2039 "; 2064 ",
2040 2065 );
2041 // This is a false negative.
2042 // We do not currently handle patterns with internal `or`s.
2043 check_no_diagnostic(content);
2044 } 2066 }
2045 2067
2046 #[test] 2068 #[test]
2047 fn expr_loop_missing_arm() { 2069 fn expr_loop_missing_arm() {
2048 let content = r" 2070 // This is a false negative.
2071 // We currently infer the type of `loop { break Foo::A }` to `!`, which
2072 // causes us to skip the diagnostic since `Either::A` doesn't type check
2073 // with `!`.
2074 check_diagnostic(
2075 r"
2049 enum Either { 2076 enum Either {
2050 A, 2077 A,
2051 B, 2078 B,
@@ -2055,48 +2082,46 @@ mod false_negatives {
2055 Either::A => (), 2082 Either::A => (),
2056 } 2083 }
2057 } 2084 }
2058 "; 2085 ",
2059 2086 );
2060 // This is a false negative.
2061 // We currently infer the type of `loop { break Foo::A }` to `!`, which
2062 // causes us to skip the diagnostic since `Either::A` doesn't type check
2063 // with `!`.
2064 check_diagnostic(content);
2065 } 2087 }
2066 2088
2067 #[test] 2089 #[test]
2068 fn tuple_of_bools_with_ellipsis_at_end_missing_arm() { 2090 fn tuple_of_bools_with_ellipsis_at_end_missing_arm() {
2069 let content = r" 2091 // This is a false negative.
2092 // We don't currently handle tuple patterns with ellipsis.
2093 check_no_diagnostic(
2094 r"
2070 fn test_fn() { 2095 fn test_fn() {
2071 match (false, true, false) { 2096 match (false, true, false) {
2072 (false, ..) => {}, 2097 (false, ..) => {},
2073 } 2098 }
2074 } 2099 }
2075 "; 2100 ",
2076 2101 );
2077 // This is a false negative.
2078 // We don't currently handle tuple patterns with ellipsis.
2079 check_no_diagnostic(content);
2080 } 2102 }
2081 2103
2082 #[test] 2104 #[test]
2083 fn tuple_of_bools_with_ellipsis_at_beginning_missing_arm() { 2105 fn tuple_of_bools_with_ellipsis_at_beginning_missing_arm() {
2084 let content = r" 2106 // This is a false negative.
2107 // We don't currently handle tuple patterns with ellipsis.
2108 check_no_diagnostic(
2109 r"
2085 fn test_fn() { 2110 fn test_fn() {
2086 match (false, true, false) { 2111 match (false, true, false) {
2087 (.., false) => {}, 2112 (.., false) => {},
2088 } 2113 }
2089 } 2114 }
2090 "; 2115 ",
2091 2116 );
2092 // This is a false negative.
2093 // We don't currently handle tuple patterns with ellipsis.
2094 check_no_diagnostic(content);
2095 } 2117 }
2096 2118
2097 #[test] 2119 #[test]
2098 fn struct_missing_arm() { 2120 fn struct_missing_arm() {
2099 let content = r" 2121 // This is a false negative.
2122 // We don't currently handle structs.
2123 check_no_diagnostic(
2124 r"
2100 struct Foo { 2125 struct Foo {
2101 a: bool, 2126 a: bool,
2102 } 2127 }
@@ -2105,10 +2130,7 @@ mod false_negatives {
2105 Foo { a: true } => {}, 2130 Foo { a: true } => {},
2106 } 2131 }
2107 } 2132 }
2108 "; 2133 ",
2109 2134 );
2110 // This is a false negative.
2111 // We don't currently handle structs.
2112 check_no_diagnostic(content);
2113 } 2135 }
2114} 2136}
diff --git a/crates/ra_ide/src/snapshots/highlight_doctest.html b/crates/ra_ide/src/snapshots/highlight_doctest.html
index 5228df267..13a5d1b12 100644
--- a/crates/ra_ide/src/snapshots/highlight_doctest.html
+++ b/crates/ra_ide/src/snapshots/highlight_doctest.html
@@ -73,9 +73,13 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
73 <span class="comment">///</span> 73 <span class="comment">///</span>
74 <span class="comment">/// ```</span> 74 <span class="comment">/// ```</span>
75 <span class="comment">///</span> 75 <span class="comment">///</span>
76 <span class="comment">/// ```</span> 76 <span class="comment">/// ```rust,no_run</span>
77 <span class="comment">/// </span><span class="keyword">let</span> <span class="variable declaration">foobar</span> = <span class="struct">Foo</span>::<span class="function">new</span>().<span class="function">bar</span>(); 77 <span class="comment">/// </span><span class="keyword">let</span> <span class="variable declaration">foobar</span> = <span class="struct">Foo</span>::<span class="function">new</span>().<span class="function">bar</span>();
78 <span class="comment">/// ```</span> 78 <span class="comment">/// ```</span>
79 <span class="comment">///</span>
80 <span class="comment">/// ```sh</span>
81 <span class="comment">/// echo 1</span>
82 <span class="comment">/// ```</span>
79 <span class="keyword">pub</span> <span class="keyword">fn</span> <span class="function declaration">foo</span>(&<span class="self_keyword">self</span>) -&gt; <span class="builtin_type">bool</span> { 83 <span class="keyword">pub</span> <span class="keyword">fn</span> <span class="function declaration">foo</span>(&<span class="self_keyword">self</span>) -&gt; <span class="builtin_type">bool</span> {
80 <span class="bool_literal">true</span> 84 <span class="bool_literal">true</span>
81 } 85 }
diff --git a/crates/ra_ide/src/ssr.rs b/crates/ra_ide/src/ssr.rs
index 93e9aee1d..762aab962 100644
--- a/crates/ra_ide/src/ssr.rs
+++ b/crates/ra_ide/src/ssr.rs
@@ -27,11 +27,11 @@ impl std::error::Error for SsrError {}
27// 27//
28// Search and replace with named wildcards that will match any expression. 28// Search and replace with named wildcards that will match any expression.
29// The syntax for a structural search replace command is `<search_pattern> ==>> <replace_pattern>`. 29// The syntax for a structural search replace command is `<search_pattern> ==>> <replace_pattern>`.
30// A `$<name>:expr` placeholder in the search pattern will match any expression and `$<name>` will reference it in the replacement. 30// A `$<name>` placeholder in the search pattern will match any AST node and `$<name>` will reference it in the replacement.
31// Available via the command `rust-analyzer.ssr`. 31// Available via the command `rust-analyzer.ssr`.
32// 32//
33// ```rust 33// ```rust
34// // Using structural search replace command [foo($a:expr, $b:expr) ==>> ($a).foo($b)] 34// // Using structural search replace command [foo($a, $b) ==>> ($a).foo($b)]
35// 35//
36// // BEFORE 36// // BEFORE
37// String::from(foo(y + 5, z)) 37// String::from(foo(y + 5, z))
@@ -79,7 +79,7 @@ struct SsrPattern {
79 vars: Vec<Var>, 79 vars: Vec<Var>,
80} 80}
81 81
82/// represents an `$var` in an SSR query 82/// Represents a `$var` in an SSR query.
83#[derive(Debug, Clone, PartialEq, Eq, Hash)] 83#[derive(Debug, Clone, PartialEq, Eq, Hash)]
84struct Var(String); 84struct Var(String);
85 85
@@ -122,8 +122,7 @@ impl FromStr for SsrQuery {
122 let mut pattern = it.next().expect("something").to_string(); 122 let mut pattern = it.next().expect("something").to_string();
123 123
124 for part in it.map(split_by_var) { 124 for part in it.map(split_by_var) {
125 let (var, var_type, remainder) = part?; 125 let (var, remainder) = part?;
126 is_expr(var_type)?;
127 let new_var = create_name(var, &mut vars)?; 126 let new_var = create_name(var, &mut vars)?;
128 pattern.push_str(new_var); 127 pattern.push_str(new_var);
129 pattern.push_str(remainder); 128 pattern.push_str(remainder);
@@ -166,15 +165,11 @@ fn traverse(node: &SyntaxNode, go: &mut impl FnMut(&SyntaxNode) -> bool) {
166 } 165 }
167} 166}
168 167
169fn split_by_var(s: &str) -> Result<(&str, &str, &str), SsrError> { 168fn split_by_var(s: &str) -> Result<(&str, &str), SsrError> {
170 let end_of_name = s.find(':').ok_or_else(|| SsrError("Use $<name>:expr".into()))?; 169 let end_of_name = s.find(|c| !char::is_ascii_alphanumeric(&c)).unwrap_or_else(|| s.len());
171 let name = &s[0..end_of_name]; 170 let name = &s[..end_of_name];
172 is_name(name)?; 171 is_name(name)?;
173 let type_begin = end_of_name + 1; 172 Ok((name, &s[end_of_name..]))
174 let type_length =
175 s[type_begin..].find(|c| !char::is_ascii_alphanumeric(&c)).unwrap_or_else(|| s.len());
176 let type_name = &s[type_begin..type_begin + type_length];
177 Ok((name, type_name, &s[type_begin + type_length..]))
178} 173}
179 174
180fn is_name(s: &str) -> Result<(), SsrError> { 175fn is_name(s: &str) -> Result<(), SsrError> {
@@ -185,14 +180,6 @@ fn is_name(s: &str) -> Result<(), SsrError> {
185 } 180 }
186} 181}
187 182
188fn is_expr(s: &str) -> Result<(), SsrError> {
189 if s == "expr" {
190 Ok(())
191 } else {
192 Err(SsrError("Only $<name>:expr is supported".into()))
193 }
194}
195
196fn replace_in_template(template: String, var: &str, new_var: &str) -> String { 183fn replace_in_template(template: String, var: &str, new_var: &str) -> String {
197 let name = format!("${}", var); 184 let name = format!("${}", var);
198 template.replace(&name, new_var) 185 template.replace(&name, new_var)
@@ -450,7 +437,7 @@ mod tests {
450 437
451 #[test] 438 #[test]
452 fn parser_happy_case() { 439 fn parser_happy_case() {
453 let result: SsrQuery = "foo($a:expr, $b:expr) ==>> bar($b, $a)".parse().unwrap(); 440 let result: SsrQuery = "foo($a, $b) ==>> bar($b, $a)".parse().unwrap();
454 assert_eq!(&result.pattern.pattern.text(), "foo(__search_pattern_a, __search_pattern_b)"); 441 assert_eq!(&result.pattern.pattern.text(), "foo(__search_pattern_a, __search_pattern_b)");
455 assert_eq!(result.pattern.vars.len(), 2); 442 assert_eq!(result.pattern.vars.len(), 2);
456 assert_eq!(result.pattern.vars[0].0, "__search_pattern_a"); 443 assert_eq!(result.pattern.vars[0].0, "__search_pattern_a");
@@ -477,30 +464,9 @@ mod tests {
477 } 464 }
478 465
479 #[test] 466 #[test]
480 fn parser_no_pattern_type() {
481 assert_eq!(parse_error_text("foo($a) ==>>"), "Parse error: Use $<name>:expr");
482 }
483
484 #[test]
485 fn parser_invalid_name() {
486 assert_eq!(
487 parse_error_text("foo($a+:expr) ==>>"),
488 "Parse error: Name can contain only alphanumerics and _"
489 );
490 }
491
492 #[test]
493 fn parser_invalid_type() {
494 assert_eq!(
495 parse_error_text("foo($a:ident) ==>>"),
496 "Parse error: Only $<name>:expr is supported"
497 );
498 }
499
500 #[test]
501 fn parser_repeated_name() { 467 fn parser_repeated_name() {
502 assert_eq!( 468 assert_eq!(
503 parse_error_text("foo($a:expr, $a:expr) ==>>"), 469 parse_error_text("foo($a, $a) ==>>"),
504 "Parse error: Name `a` repeats more than once" 470 "Parse error: Name `a` repeats more than once"
505 ); 471 );
506 } 472 }
@@ -517,7 +483,7 @@ mod tests {
517 483
518 #[test] 484 #[test]
519 fn parse_match_replace() { 485 fn parse_match_replace() {
520 let query: SsrQuery = "foo($x:expr) ==>> bar($x)".parse().unwrap(); 486 let query: SsrQuery = "foo($x) ==>> bar($x)".parse().unwrap();
521 let input = "fn main() { foo(1+2); }"; 487 let input = "fn main() { foo(1+2); }";
522 488
523 let code = SourceFile::parse(input).tree(); 489 let code = SourceFile::parse(input).tree();
@@ -549,7 +515,7 @@ mod tests {
549 #[test] 515 #[test]
550 fn ssr_function_to_method() { 516 fn ssr_function_to_method() {
551 assert_ssr_transform( 517 assert_ssr_transform(
552 "my_function($a:expr, $b:expr) ==>> ($a).my_method($b)", 518 "my_function($a, $b) ==>> ($a).my_method($b)",
553 "loop { my_function( other_func(x, y), z + w) }", 519 "loop { my_function( other_func(x, y), z + w) }",
554 "loop { (other_func(x, y)).my_method(z + w) }", 520 "loop { (other_func(x, y)).my_method(z + w) }",
555 ) 521 )
@@ -558,7 +524,7 @@ mod tests {
558 #[test] 524 #[test]
559 fn ssr_nested_function() { 525 fn ssr_nested_function() {
560 assert_ssr_transform( 526 assert_ssr_transform(
561 "foo($a:expr, $b:expr, $c:expr) ==>> bar($c, baz($a, $b))", 527 "foo($a, $b, $c) ==>> bar($c, baz($a, $b))",
562 "fn main { foo (x + value.method(b), x+y-z, true && false) }", 528 "fn main { foo (x + value.method(b), x+y-z, true && false) }",
563 "fn main { bar(true && false, baz(x + value.method(b), x+y-z)) }", 529 "fn main { bar(true && false, baz(x + value.method(b), x+y-z)) }",
564 ) 530 )
@@ -567,7 +533,7 @@ mod tests {
567 #[test] 533 #[test]
568 fn ssr_expected_spacing() { 534 fn ssr_expected_spacing() {
569 assert_ssr_transform( 535 assert_ssr_transform(
570 "foo($x:expr) + bar() ==>> bar($x)", 536 "foo($x) + bar() ==>> bar($x)",
571 "fn main() { foo(5) + bar() }", 537 "fn main() { foo(5) + bar() }",
572 "fn main() { bar(5) }", 538 "fn main() { bar(5) }",
573 ); 539 );
@@ -576,7 +542,7 @@ mod tests {
576 #[test] 542 #[test]
577 fn ssr_with_extra_space() { 543 fn ssr_with_extra_space() {
578 assert_ssr_transform( 544 assert_ssr_transform(
579 "foo($x:expr ) + bar() ==>> bar($x)", 545 "foo($x ) + bar() ==>> bar($x)",
580 "fn main() { foo( 5 ) +bar( ) }", 546 "fn main() { foo( 5 ) +bar( ) }",
581 "fn main() { bar(5) }", 547 "fn main() { bar(5) }",
582 ); 548 );
@@ -585,7 +551,7 @@ mod tests {
585 #[test] 551 #[test]
586 fn ssr_keeps_nested_comment() { 552 fn ssr_keeps_nested_comment() {
587 assert_ssr_transform( 553 assert_ssr_transform(
588 "foo($x:expr) ==>> bar($x)", 554 "foo($x) ==>> bar($x)",
589 "fn main() { foo(other(5 /* using 5 */)) }", 555 "fn main() { foo(other(5 /* using 5 */)) }",
590 "fn main() { bar(other(5 /* using 5 */)) }", 556 "fn main() { bar(other(5 /* using 5 */)) }",
591 ) 557 )
@@ -594,7 +560,7 @@ mod tests {
594 #[test] 560 #[test]
595 fn ssr_keeps_comment() { 561 fn ssr_keeps_comment() {
596 assert_ssr_transform( 562 assert_ssr_transform(
597 "foo($x:expr) ==>> bar($x)", 563 "foo($x) ==>> bar($x)",
598 "fn main() { foo(5 /* using 5 */) }", 564 "fn main() { foo(5 /* using 5 */) }",
599 "fn main() { bar(5)/* using 5 */ }", 565 "fn main() { bar(5)/* using 5 */ }",
600 ) 566 )
@@ -603,7 +569,7 @@ mod tests {
603 #[test] 569 #[test]
604 fn ssr_struct_lit() { 570 fn ssr_struct_lit() {
605 assert_ssr_transform( 571 assert_ssr_transform(
606 "foo{a: $a:expr, b: $b:expr} ==>> foo::new($a, $b)", 572 "foo{a: $a, b: $b} ==>> foo::new($a, $b)",
607 "fn main() { foo{b:2, a:1} }", 573 "fn main() { foo{b:2, a:1} }",
608 "fn main() { foo::new(1, 2) }", 574 "fn main() { foo::new(1, 2) }",
609 ) 575 )
@@ -612,7 +578,7 @@ mod tests {
612 #[test] 578 #[test]
613 fn ssr_call_and_method_call() { 579 fn ssr_call_and_method_call() {
614 assert_ssr_transform( 580 assert_ssr_transform(
615 "foo::<'a>($a:expr, $b:expr)) ==>> foo2($a, $b)", 581 "foo::<'a>($a, $b)) ==>> foo2($a, $b)",
616 "fn main() { get().bar.foo::<'a>(1); }", 582 "fn main() { get().bar.foo::<'a>(1); }",
617 "fn main() { foo2(get().bar, 1); }", 583 "fn main() { foo2(get().bar, 1); }",
618 ) 584 )
@@ -621,7 +587,7 @@ mod tests {
621 #[test] 587 #[test]
622 fn ssr_method_call_and_call() { 588 fn ssr_method_call_and_call() {
623 assert_ssr_transform( 589 assert_ssr_transform(
624 "$o:expr.foo::<i32>($a:expr)) ==>> $o.foo2($a)", 590 "$o.foo::<i32>($a)) ==>> $o.foo2($a)",
625 "fn main() { X::foo::<i32>(x, 1); }", 591 "fn main() { X::foo::<i32>(x, 1); }",
626 "fn main() { x.foo2(1); }", 592 "fn main() { x.foo2(1); }",
627 ) 593 )
diff --git a/crates/ra_ide/src/syntax_highlighting/injection.rs b/crates/ra_ide/src/syntax_highlighting/injection.rs
index a02ffe59e..929a5cc5c 100644
--- a/crates/ra_ide/src/syntax_highlighting/injection.rs
+++ b/crates/ra_ide/src/syntax_highlighting/injection.rs
@@ -53,6 +53,10 @@ pub(super) fn highlight_injection(
53/// Mapping from extracted documentation code to original code 53/// Mapping from extracted documentation code to original code
54type RangesMap = BTreeMap<TextSize, TextSize>; 54type RangesMap = BTreeMap<TextSize, TextSize>;
55 55
56const RUSTDOC_FENCE: &'static str = "```";
57const RUSTDOC_FENCE_TOKENS: &[&'static str] =
58 &["", "rust", "should_panic", "ignore", "no_run", "compile_fail", "edition2015", "edition2018"];
59
56/// Extracts Rust code from documentation comments as well as a mapping from 60/// Extracts Rust code from documentation comments as well as a mapping from
57/// the extracted source code back to the original source ranges. 61/// the extracted source code back to the original source ranges.
58/// Lastly, a vector of new comment highlight ranges (spanning only the 62/// Lastly, a vector of new comment highlight ranges (spanning only the
@@ -67,6 +71,7 @@ pub(super) fn extract_doc_comments(
67 // Mapping from extracted documentation code to original code 71 // Mapping from extracted documentation code to original code
68 let mut range_mapping: RangesMap = BTreeMap::new(); 72 let mut range_mapping: RangesMap = BTreeMap::new();
69 let mut line_start = TextSize::try_from(prefix.len()).unwrap(); 73 let mut line_start = TextSize::try_from(prefix.len()).unwrap();
74 let mut is_codeblock = false;
70 let mut is_doctest = false; 75 let mut is_doctest = false;
71 // Replace the original, line-spanning comment ranges by new, only comment-prefix 76 // Replace the original, line-spanning comment ranges by new, only comment-prefix
72 // spanning comment ranges. 77 // spanning comment ranges.
@@ -76,8 +81,13 @@ pub(super) fn extract_doc_comments(
76 .filter_map(|el| el.into_token().and_then(ast::Comment::cast)) 81 .filter_map(|el| el.into_token().and_then(ast::Comment::cast))
77 .filter(|comment| comment.kind().doc.is_some()) 82 .filter(|comment| comment.kind().doc.is_some())
78 .filter(|comment| { 83 .filter(|comment| {
79 if comment.text().contains("```") { 84 if let Some(idx) = comment.text().find(RUSTDOC_FENCE) {
80 is_doctest = !is_doctest; 85 is_codeblock = !is_codeblock;
86 // Check whether code is rust by inspecting fence guards
87 let guards = &comment.text()[idx + RUSTDOC_FENCE.len()..];
88 let is_rust =
89 guards.split(',').all(|sub| RUSTDOC_FENCE_TOKENS.contains(&sub.trim()));
90 is_doctest = is_codeblock && is_rust;
81 false 91 false
82 } else { 92 } else {
83 is_doctest 93 is_doctest
diff --git a/crates/ra_ide/src/syntax_highlighting/tests.rs b/crates/ra_ide/src/syntax_highlighting/tests.rs
index 062b3ff4a..ebf5b50ac 100644
--- a/crates/ra_ide/src/syntax_highlighting/tests.rs
+++ b/crates/ra_ide/src/syntax_highlighting/tests.rs
@@ -329,9 +329,13 @@ impl Foo {
329 /// 329 ///
330 /// ``` 330 /// ```
331 /// 331 ///
332 /// ``` 332 /// ```rust,no_run
333 /// let foobar = Foo::new().bar(); 333 /// let foobar = Foo::new().bar();
334 /// ``` 334 /// ```
335 ///
336 /// ```sh
337 /// echo 1
338 /// ```
335 pub fn foo(&self) -> bool { 339 pub fn foo(&self) -> bool {
336 true 340 true
337 } 341 }
diff --git a/crates/rust-analyzer/src/config.rs b/crates/rust-analyzer/src/config.rs
index 0e7a937a0..0df7427cb 100644
--- a/crates/rust-analyzer/src/config.rs
+++ b/crates/rust-analyzer/src/config.rs
@@ -9,6 +9,7 @@
9 9
10use std::{ffi::OsString, path::PathBuf}; 10use std::{ffi::OsString, path::PathBuf};
11 11
12use crate::diagnostics::DiagnosticsConfig;
12use lsp_types::ClientCapabilities; 13use lsp_types::ClientCapabilities;
13use ra_flycheck::FlycheckConfig; 14use ra_flycheck::FlycheckConfig;
14use ra_ide::{AssistConfig, CompletionConfig, HoverConfig, InlayHintsConfig}; 15use ra_ide::{AssistConfig, CompletionConfig, HoverConfig, InlayHintsConfig};
@@ -20,6 +21,7 @@ pub struct Config {
20 pub client_caps: ClientCapsConfig, 21 pub client_caps: ClientCapsConfig,
21 22
22 pub publish_diagnostics: bool, 23 pub publish_diagnostics: bool,
24 pub diagnostics: DiagnosticsConfig,
23 pub lru_capacity: Option<usize>, 25 pub lru_capacity: Option<usize>,
24 pub proc_macro_srv: Option<(PathBuf, Vec<OsString>)>, 26 pub proc_macro_srv: Option<(PathBuf, Vec<OsString>)>,
25 pub files: FilesConfig, 27 pub files: FilesConfig,
@@ -136,6 +138,7 @@ impl Default for Config {
136 138
137 with_sysroot: true, 139 with_sysroot: true,
138 publish_diagnostics: true, 140 publish_diagnostics: true,
141 diagnostics: DiagnosticsConfig::default(),
139 lru_capacity: None, 142 lru_capacity: None,
140 proc_macro_srv: None, 143 proc_macro_srv: None,
141 files: FilesConfig { watcher: FilesWatcher::Notify, exclude: Vec::new() }, 144 files: FilesConfig { watcher: FilesWatcher::Notify, exclude: Vec::new() },
@@ -184,6 +187,8 @@ impl Config {
184 187
185 set(value, "/withSysroot", &mut self.with_sysroot); 188 set(value, "/withSysroot", &mut self.with_sysroot);
186 set(value, "/diagnostics/enable", &mut self.publish_diagnostics); 189 set(value, "/diagnostics/enable", &mut self.publish_diagnostics);
190 set(value, "/diagnostics/warningsAsInfo", &mut self.diagnostics.warnings_as_info);
191 set(value, "/diagnostics/warningsAsHint", &mut self.diagnostics.warnings_as_hint);
187 set(value, "/lruCapacity", &mut self.lru_capacity); 192 set(value, "/lruCapacity", &mut self.lru_capacity);
188 self.files.watcher = match get(value, "/files/watcher") { 193 self.files.watcher = match get(value, "/files/watcher") {
189 Some("client") => FilesWatcher::Client, 194 Some("client") => FilesWatcher::Client,
diff --git a/crates/rust-analyzer/src/diagnostics.rs b/crates/rust-analyzer/src/diagnostics.rs
index 25856c543..290609e7f 100644
--- a/crates/rust-analyzer/src/diagnostics.rs
+++ b/crates/rust-analyzer/src/diagnostics.rs
@@ -11,6 +11,12 @@ use crate::lsp_ext;
11pub type CheckFixes = Arc<HashMap<FileId, Vec<Fix>>>; 11pub type CheckFixes = Arc<HashMap<FileId, Vec<Fix>>>;
12 12
13#[derive(Debug, Default, Clone)] 13#[derive(Debug, Default, Clone)]
14pub struct DiagnosticsConfig {
15 pub warnings_as_info: Vec<String>,
16 pub warnings_as_hint: Vec<String>,
17}
18
19#[derive(Debug, Default, Clone)]
14pub struct DiagnosticCollection { 20pub struct DiagnosticCollection {
15 pub native: HashMap<FileId, Vec<Diagnostic>>, 21 pub native: HashMap<FileId, Vec<Diagnostic>>,
16 pub check: HashMap<FileId, Vec<Diagnostic>>, 22 pub check: HashMap<FileId, Vec<Diagnostic>>,
diff --git a/crates/rust-analyzer/src/diagnostics/snapshots/rust_analyzer__diagnostics__to_proto__tests__snap_rustc_unused_variable_as_hint.snap b/crates/rust-analyzer/src/diagnostics/snapshots/rust_analyzer__diagnostics__to_proto__tests__snap_rustc_unused_variable_as_hint.snap
new file mode 100644
index 000000000..f0273315e
--- /dev/null
+++ b/crates/rust-analyzer/src/diagnostics/snapshots/rust_analyzer__diagnostics__to_proto__tests__snap_rustc_unused_variable_as_hint.snap
@@ -0,0 +1,86 @@
1---
2source: crates/rust-analyzer/src/diagnostics/to_proto.rs
3expression: diag
4---
5[
6 MappedRustDiagnostic {
7 location: Location {
8 uri: "file:///test/driver/subcommand/repl.rs",
9 range: Range {
10 start: Position {
11 line: 290,
12 character: 8,
13 },
14 end: Position {
15 line: 290,
16 character: 11,
17 },
18 },
19 },
20 diagnostic: Diagnostic {
21 range: Range {
22 start: Position {
23 line: 290,
24 character: 8,
25 },
26 end: Position {
27 line: 290,
28 character: 11,
29 },
30 },
31 severity: Some(
32 Hint,
33 ),
34 code: Some(
35 String(
36 "unused_variables",
37 ),
38 ),
39 source: Some(
40 "rustc",
41 ),
42 message: "unused variable: `foo`\n#[warn(unused_variables)] on by default",
43 related_information: None,
44 tags: Some(
45 [
46 Unnecessary,
47 ],
48 ),
49 },
50 fixes: [
51 CodeAction {
52 title: "consider prefixing with an underscore",
53 id: None,
54 group: None,
55 kind: Some(
56 "quickfix",
57 ),
58 command: None,
59 edit: Some(
60 SnippetWorkspaceEdit {
61 changes: Some(
62 {
63 "file:///test/driver/subcommand/repl.rs": [
64 TextEdit {
65 range: Range {
66 start: Position {
67 line: 290,
68 character: 8,
69 },
70 end: Position {
71 line: 290,
72 character: 11,
73 },
74 },
75 new_text: "_foo",
76 },
77 ],
78 },
79 ),
80 document_changes: None,
81 },
82 ),
83 },
84 ],
85 },
86]
diff --git a/crates/rust-analyzer/src/diagnostics/snapshots/rust_analyzer__diagnostics__to_proto__tests__snap_rustc_unused_variable_as_info.snap b/crates/rust-analyzer/src/diagnostics/snapshots/rust_analyzer__diagnostics__to_proto__tests__snap_rustc_unused_variable_as_info.snap
new file mode 100644
index 000000000..85fd050fd
--- /dev/null
+++ b/crates/rust-analyzer/src/diagnostics/snapshots/rust_analyzer__diagnostics__to_proto__tests__snap_rustc_unused_variable_as_info.snap
@@ -0,0 +1,86 @@
1---
2source: crates/rust-analyzer/src/diagnostics/to_proto.rs
3expression: diag
4---
5[
6 MappedRustDiagnostic {
7 location: Location {
8 uri: "file:///test/driver/subcommand/repl.rs",
9 range: Range {
10 start: Position {
11 line: 290,
12 character: 8,
13 },
14 end: Position {
15 line: 290,
16 character: 11,
17 },
18 },
19 },
20 diagnostic: Diagnostic {
21 range: Range {
22 start: Position {
23 line: 290,
24 character: 8,
25 },
26 end: Position {
27 line: 290,
28 character: 11,
29 },
30 },
31 severity: Some(
32 Information,
33 ),
34 code: Some(
35 String(
36 "unused_variables",
37 ),
38 ),
39 source: Some(
40 "rustc",
41 ),
42 message: "unused variable: `foo`\n#[warn(unused_variables)] on by default",
43 related_information: None,
44 tags: Some(
45 [
46 Unnecessary,
47 ],
48 ),
49 },
50 fixes: [
51 CodeAction {
52 title: "consider prefixing with an underscore",
53 id: None,
54 group: None,
55 kind: Some(
56 "quickfix",
57 ),
58 command: None,
59 edit: Some(
60 SnippetWorkspaceEdit {
61 changes: Some(
62 {
63 "file:///test/driver/subcommand/repl.rs": [
64 TextEdit {
65 range: Range {
66 start: Position {
67 line: 290,
68 character: 8,
69 },
70 end: Position {
71 line: 290,
72 character: 11,
73 },
74 },
75 new_text: "_foo",
76 },
77 ],
78 },
79 ),
80 document_changes: None,
81 },
82 ),
83 },
84 ],
85 },
86]
diff --git a/crates/rust-analyzer/src/diagnostics/to_proto.rs b/crates/rust-analyzer/src/diagnostics/to_proto.rs
index 24ff9b280..ba74f15f3 100644
--- a/crates/rust-analyzer/src/diagnostics/to_proto.rs
+++ b/crates/rust-analyzer/src/diagnostics/to_proto.rs
@@ -9,14 +9,24 @@ use lsp_types::{
9use ra_flycheck::{Applicability, DiagnosticLevel, DiagnosticSpan, DiagnosticSpanMacroExpansion}; 9use ra_flycheck::{Applicability, DiagnosticLevel, DiagnosticSpan, DiagnosticSpanMacroExpansion};
10use stdx::format_to; 10use stdx::format_to;
11 11
12use super::DiagnosticsConfig;
12use crate::{lsp_ext, to_proto::url_from_abs_path}; 13use crate::{lsp_ext, to_proto::url_from_abs_path};
13 14
14/// Converts a Rust level string to a LSP severity 15/// Determines the LSP severity from a diagnostic
15fn map_level_to_severity(val: DiagnosticLevel) -> Option<DiagnosticSeverity> { 16fn map_diagnostic_to_severity(
16 let res = match val { 17 config: &DiagnosticsConfig,
18 val: &ra_flycheck::Diagnostic,
19) -> Option<DiagnosticSeverity> {
20 let res = match val.level {
17 DiagnosticLevel::Ice => DiagnosticSeverity::Error, 21 DiagnosticLevel::Ice => DiagnosticSeverity::Error,
18 DiagnosticLevel::Error => DiagnosticSeverity::Error, 22 DiagnosticLevel::Error => DiagnosticSeverity::Error,
19 DiagnosticLevel::Warning => DiagnosticSeverity::Warning, 23 DiagnosticLevel::Warning => match &val.code {
24 Some(code) if config.warnings_as_hint.contains(&code.code) => DiagnosticSeverity::Hint,
25 Some(code) if config.warnings_as_info.contains(&code.code) => {
26 DiagnosticSeverity::Information
27 }
28 _ => DiagnosticSeverity::Warning,
29 },
20 DiagnosticLevel::Note => DiagnosticSeverity::Information, 30 DiagnosticLevel::Note => DiagnosticSeverity::Information,
21 DiagnosticLevel::Help => DiagnosticSeverity::Hint, 31 DiagnosticLevel::Help => DiagnosticSeverity::Hint,
22 DiagnosticLevel::Unknown => return None, 32 DiagnosticLevel::Unknown => return None,
@@ -172,6 +182,7 @@ pub(crate) struct MappedRustDiagnostic {
172/// 182///
173/// If the diagnostic has no primary span this will return `None` 183/// If the diagnostic has no primary span this will return `None`
174pub(crate) fn map_rust_diagnostic_to_lsp( 184pub(crate) fn map_rust_diagnostic_to_lsp(
185 config: &DiagnosticsConfig,
175 rd: &ra_flycheck::Diagnostic, 186 rd: &ra_flycheck::Diagnostic,
176 workspace_root: &Path, 187 workspace_root: &Path,
177) -> Vec<MappedRustDiagnostic> { 188) -> Vec<MappedRustDiagnostic> {
@@ -180,7 +191,7 @@ pub(crate) fn map_rust_diagnostic_to_lsp(
180 return Vec::new(); 191 return Vec::new();
181 } 192 }
182 193
183 let severity = map_level_to_severity(rd.level); 194 let severity = map_diagnostic_to_severity(config, rd);
184 195
185 let mut source = String::from("rustc"); 196 let mut source = String::from("rustc");
186 let mut code = rd.code.as_ref().map(|c| c.code.clone()); 197 let mut code = rd.code.as_ref().map(|c| c.code.clone());
@@ -328,7 +339,7 @@ mod tests {
328 ); 339 );
329 340
330 let workspace_root = Path::new("/test/"); 341 let workspace_root = Path::new("/test/");
331 let diag = map_rust_diagnostic_to_lsp(&diag, workspace_root); 342 let diag = map_rust_diagnostic_to_lsp(&DiagnosticsConfig::default(), &diag, workspace_root);
332 insta::assert_debug_snapshot!(diag); 343 insta::assert_debug_snapshot!(diag);
333 } 344 }
334 345
@@ -410,7 +421,183 @@ mod tests {
410 ); 421 );
411 422
412 let workspace_root = Path::new("/test/"); 423 let workspace_root = Path::new("/test/");
413 let diag = map_rust_diagnostic_to_lsp(&diag, workspace_root); 424 let diag = map_rust_diagnostic_to_lsp(&DiagnosticsConfig::default(), &diag, workspace_root);
425 insta::assert_debug_snapshot!(diag);
426 }
427
428 #[test]
429 #[cfg(not(windows))]
430 fn snap_rustc_unused_variable_as_info() {
431 let diag = parse_diagnostic(
432 r##"{
433 "message": "unused variable: `foo`",
434 "code": {
435 "code": "unused_variables",
436 "explanation": null
437 },
438 "level": "warning",
439 "spans": [
440 {
441 "file_name": "driver/subcommand/repl.rs",
442 "byte_start": 9228,
443 "byte_end": 9231,
444 "line_start": 291,
445 "line_end": 291,
446 "column_start": 9,
447 "column_end": 12,
448 "is_primary": true,
449 "text": [
450 {
451 "text": " let foo = 42;",
452 "highlight_start": 9,
453 "highlight_end": 12
454 }
455 ],
456 "label": null,
457 "suggested_replacement": null,
458 "suggestion_applicability": null,
459 "expansion": null
460 }
461 ],
462 "children": [
463 {
464 "message": "#[warn(unused_variables)] on by default",
465 "code": null,
466 "level": "note",
467 "spans": [],
468 "children": [],
469 "rendered": null
470 },
471 {
472 "message": "consider prefixing with an underscore",
473 "code": null,
474 "level": "help",
475 "spans": [
476 {
477 "file_name": "driver/subcommand/repl.rs",
478 "byte_start": 9228,
479 "byte_end": 9231,
480 "line_start": 291,
481 "line_end": 291,
482 "column_start": 9,
483 "column_end": 12,
484 "is_primary": true,
485 "text": [
486 {
487 "text": " let foo = 42;",
488 "highlight_start": 9,
489 "highlight_end": 12
490 }
491 ],
492 "label": null,
493 "suggested_replacement": "_foo",
494 "suggestion_applicability": "MachineApplicable",
495 "expansion": null
496 }
497 ],
498 "children": [],
499 "rendered": null
500 }
501 ],
502 "rendered": "warning: unused variable: `foo`\n --> driver/subcommand/repl.rs:291:9\n |\n291 | let foo = 42;\n | ^^^ help: consider prefixing with an underscore: `_foo`\n |\n = note: #[warn(unused_variables)] on by default\n\n"
503 }"##,
504 );
505
506 let config = DiagnosticsConfig {
507 warnings_as_info: vec!["unused_variables".to_string()],
508 ..DiagnosticsConfig::default()
509 };
510
511 let workspace_root = Path::new("/test/");
512 let diag = map_rust_diagnostic_to_lsp(&config, &diag, workspace_root);
513 insta::assert_debug_snapshot!(diag);
514 }
515
516 #[test]
517 #[cfg(not(windows))]
518 fn snap_rustc_unused_variable_as_hint() {
519 let diag = parse_diagnostic(
520 r##"{
521 "message": "unused variable: `foo`",
522 "code": {
523 "code": "unused_variables",
524 "explanation": null
525 },
526 "level": "warning",
527 "spans": [
528 {
529 "file_name": "driver/subcommand/repl.rs",
530 "byte_start": 9228,
531 "byte_end": 9231,
532 "line_start": 291,
533 "line_end": 291,
534 "column_start": 9,
535 "column_end": 12,
536 "is_primary": true,
537 "text": [
538 {
539 "text": " let foo = 42;",
540 "highlight_start": 9,
541 "highlight_end": 12
542 }
543 ],
544 "label": null,
545 "suggested_replacement": null,
546 "suggestion_applicability": null,
547 "expansion": null
548 }
549 ],
550 "children": [
551 {
552 "message": "#[warn(unused_variables)] on by default",
553 "code": null,
554 "level": "note",
555 "spans": [],
556 "children": [],
557 "rendered": null
558 },
559 {
560 "message": "consider prefixing with an underscore",
561 "code": null,
562 "level": "help",
563 "spans": [
564 {
565 "file_name": "driver/subcommand/repl.rs",
566 "byte_start": 9228,
567 "byte_end": 9231,
568 "line_start": 291,
569 "line_end": 291,
570 "column_start": 9,
571 "column_end": 12,
572 "is_primary": true,
573 "text": [
574 {
575 "text": " let foo = 42;",
576 "highlight_start": 9,
577 "highlight_end": 12
578 }
579 ],
580 "label": null,
581 "suggested_replacement": "_foo",
582 "suggestion_applicability": "MachineApplicable",
583 "expansion": null
584 }
585 ],
586 "children": [],
587 "rendered": null
588 }
589 ],
590 "rendered": "warning: unused variable: `foo`\n --> driver/subcommand/repl.rs:291:9\n |\n291 | let foo = 42;\n | ^^^ help: consider prefixing with an underscore: `_foo`\n |\n = note: #[warn(unused_variables)] on by default\n\n"
591 }"##,
592 );
593
594 let config = DiagnosticsConfig {
595 warnings_as_hint: vec!["unused_variables".to_string()],
596 ..DiagnosticsConfig::default()
597 };
598
599 let workspace_root = Path::new("/test/");
600 let diag = map_rust_diagnostic_to_lsp(&config, &diag, workspace_root);
414 insta::assert_debug_snapshot!(diag); 601 insta::assert_debug_snapshot!(diag);
415 } 602 }
416 603
@@ -534,7 +721,7 @@ mod tests {
534 ); 721 );
535 722
536 let workspace_root = Path::new("/test/"); 723 let workspace_root = Path::new("/test/");
537 let diag = map_rust_diagnostic_to_lsp(&diag, workspace_root); 724 let diag = map_rust_diagnostic_to_lsp(&DiagnosticsConfig::default(), &diag, workspace_root);
538 insta::assert_debug_snapshot!(diag); 725 insta::assert_debug_snapshot!(diag);
539 } 726 }
540 727
@@ -654,7 +841,7 @@ mod tests {
654 ); 841 );
655 842
656 let workspace_root = Path::new("/test/"); 843 let workspace_root = Path::new("/test/");
657 let diag = map_rust_diagnostic_to_lsp(&diag, workspace_root); 844 let diag = map_rust_diagnostic_to_lsp(&DiagnosticsConfig::default(), &diag, workspace_root);
658 insta::assert_debug_snapshot!(diag); 845 insta::assert_debug_snapshot!(diag);
659 } 846 }
660 847
@@ -697,7 +884,7 @@ mod tests {
697 ); 884 );
698 885
699 let workspace_root = Path::new("/test/"); 886 let workspace_root = Path::new("/test/");
700 let diag = map_rust_diagnostic_to_lsp(&diag, workspace_root); 887 let diag = map_rust_diagnostic_to_lsp(&DiagnosticsConfig::default(), &diag, workspace_root);
701 insta::assert_debug_snapshot!(diag); 888 insta::assert_debug_snapshot!(diag);
702 } 889 }
703 890
@@ -968,7 +1155,7 @@ mod tests {
968 ); 1155 );
969 1156
970 let workspace_root = Path::new("/test/"); 1157 let workspace_root = Path::new("/test/");
971 let diag = map_rust_diagnostic_to_lsp(&diag, workspace_root); 1158 let diag = map_rust_diagnostic_to_lsp(&DiagnosticsConfig::default(), &diag, workspace_root);
972 insta::assert_debug_snapshot!(diag); 1159 insta::assert_debug_snapshot!(diag);
973 } 1160 }
974 1161
@@ -1197,7 +1384,7 @@ mod tests {
1197 ); 1384 );
1198 1385
1199 let workspace_root = Path::new("/test/"); 1386 let workspace_root = Path::new("/test/");
1200 let diag = map_rust_diagnostic_to_lsp(&diag, workspace_root); 1387 let diag = map_rust_diagnostic_to_lsp(&DiagnosticsConfig::default(), &diag, workspace_root);
1201 insta::assert_debug_snapshot!(diag); 1388 insta::assert_debug_snapshot!(diag);
1202 } 1389 }
1203 1390
@@ -1330,7 +1517,7 @@ mod tests {
1330 ); 1517 );
1331 1518
1332 let workspace_root = Path::new("/test/"); 1519 let workspace_root = Path::new("/test/");
1333 let diag = map_rust_diagnostic_to_lsp(&diag, workspace_root); 1520 let diag = map_rust_diagnostic_to_lsp(&DiagnosticsConfig::default(), &diag, workspace_root);
1334 insta::assert_debug_snapshot!(diag); 1521 insta::assert_debug_snapshot!(diag);
1335 } 1522 }
1336} 1523}
diff --git a/crates/rust-analyzer/src/main_loop.rs b/crates/rust-analyzer/src/main_loop.rs
index 887253d5b..80cfd3c28 100644
--- a/crates/rust-analyzer/src/main_loop.rs
+++ b/crates/rust-analyzer/src/main_loop.rs
@@ -719,6 +719,7 @@ fn on_check_task(
719 719
720 CheckTask::AddDiagnostic { workspace_root, diagnostic } => { 720 CheckTask::AddDiagnostic { workspace_root, diagnostic } => {
721 let diagnostics = crate::diagnostics::to_proto::map_rust_diagnostic_to_lsp( 721 let diagnostics = crate::diagnostics::to_proto::map_rust_diagnostic_to_lsp(
722 &global_state.config.diagnostics,
722 &diagnostic, 723 &diagnostic,
723 &workspace_root, 724 &workspace_root,
724 ); 725 );