diff options
9 files changed, 830 insertions, 468 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/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)] |
84 | struct Var(String); | 84 | struct 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 | ||
169 | fn split_by_var(s: &str) -> Result<(&str, &str, &str), SsrError> { | 168 | fn 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 | ||
180 | fn is_name(s: &str) -> Result<(), SsrError> { | 175 | fn is_name(s: &str) -> Result<(), SsrError> { |
@@ -185,14 +180,6 @@ fn is_name(s: &str) -> Result<(), SsrError> { | |||
185 | } | 180 | } |
186 | } | 181 | } |
187 | 182 | ||
188 | fn 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 | |||
196 | fn replace_in_template(template: String, var: &str, new_var: &str) -> String { | 183 | fn 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/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 | ||
10 | use std::{ffi::OsString, path::PathBuf}; | 10 | use std::{ffi::OsString, path::PathBuf}; |
11 | 11 | ||
12 | use crate::diagnostics::DiagnosticsConfig; | ||
12 | use lsp_types::ClientCapabilities; | 13 | use lsp_types::ClientCapabilities; |
13 | use ra_flycheck::FlycheckConfig; | 14 | use ra_flycheck::FlycheckConfig; |
14 | use ra_ide::{AssistConfig, CompletionConfig, HoverConfig, InlayHintsConfig}; | 15 | use 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; | |||
11 | pub type CheckFixes = Arc<HashMap<FileId, Vec<Fix>>>; | 11 | pub type CheckFixes = Arc<HashMap<FileId, Vec<Fix>>>; |
12 | 12 | ||
13 | #[derive(Debug, Default, Clone)] | 13 | #[derive(Debug, Default, Clone)] |
14 | pub struct DiagnosticsConfig { | ||
15 | pub warnings_as_info: Vec<String>, | ||
16 | pub warnings_as_hint: Vec<String>, | ||
17 | } | ||
18 | |||
19 | #[derive(Debug, Default, Clone)] | ||
14 | pub struct DiagnosticCollection { | 20 | pub 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 | --- | ||
2 | source: crates/rust-analyzer/src/diagnostics/to_proto.rs | ||
3 | expression: 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 | --- | ||
2 | source: crates/rust-analyzer/src/diagnostics/to_proto.rs | ||
3 | expression: 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::{ | |||
9 | use ra_flycheck::{Applicability, DiagnosticLevel, DiagnosticSpan, DiagnosticSpanMacroExpansion}; | 9 | use ra_flycheck::{Applicability, DiagnosticLevel, DiagnosticSpan, DiagnosticSpanMacroExpansion}; |
10 | use stdx::format_to; | 10 | use stdx::format_to; |
11 | 11 | ||
12 | use super::DiagnosticsConfig; | ||
12 | use crate::{lsp_ext, to_proto::url_from_abs_path}; | 13 | use 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 |
15 | fn map_level_to_severity(val: DiagnosticLevel) -> Option<DiagnosticSeverity> { | 16 | fn 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` |
174 | pub(crate) fn map_rust_diagnostic_to_lsp( | 184 | pub(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 cc9bb1726..80cfd3c28 100644 --- a/crates/rust-analyzer/src/main_loop.rs +++ b/crates/rust-analyzer/src/main_loop.rs | |||
@@ -669,14 +669,11 @@ fn apply_document_changes( | |||
669 | mut line_index: Cow<'_, LineIndex>, | 669 | mut line_index: Cow<'_, LineIndex>, |
670 | content_changes: Vec<TextDocumentContentChangeEvent>, | 670 | content_changes: Vec<TextDocumentContentChangeEvent>, |
671 | ) { | 671 | ) { |
672 | // Remove when https://github.com/rust-analyzer/rust-analyzer/issues/4263 is fixed. | ||
673 | let backup_text = old_text.clone(); | ||
674 | let backup_changes = content_changes.clone(); | ||
675 | |||
676 | // The changes we got must be applied sequentially, but can cross lines so we | 672 | // The changes we got must be applied sequentially, but can cross lines so we |
677 | // have to keep our line index updated. | 673 | // have to keep our line index updated. |
678 | // Some clients (e.g. Code) sort the ranges in reverse. As an optimization, we | 674 | // Some clients (e.g. Code) sort the ranges in reverse. As an optimization, we |
679 | // remember the last valid line in the index and only rebuild it if needed. | 675 | // remember the last valid line in the index and only rebuild it if needed. |
676 | // The VFS will normalize the end of lines to `\n`. | ||
680 | enum IndexValid { | 677 | enum IndexValid { |
681 | All, | 678 | All, |
682 | UpToLineExclusive(u64), | 679 | UpToLineExclusive(u64), |
@@ -700,19 +697,7 @@ fn apply_document_changes( | |||
700 | } | 697 | } |
701 | index_valid = IndexValid::UpToLineExclusive(range.start.line); | 698 | index_valid = IndexValid::UpToLineExclusive(range.start.line); |
702 | let range = from_proto::text_range(&line_index, range); | 699 | let range = from_proto::text_range(&line_index, range); |
703 | let mut text = old_text.to_owned(); | 700 | old_text.replace_range(Range::<usize>::from(range), &change.text); |
704 | match std::panic::catch_unwind(move || { | ||
705 | text.replace_range(Range::<usize>::from(range), &change.text); | ||
706 | text | ||
707 | }) { | ||
708 | Ok(t) => *old_text = t, | ||
709 | Err(e) => { | ||
710 | eprintln!("Bug in incremental text synchronization. Please report the following output on https://github.com/rust-analyzer/rust-analyzer/issues/4263"); | ||
711 | dbg!(&backup_text); | ||
712 | dbg!(&backup_changes); | ||
713 | std::panic::resume_unwind(e); | ||
714 | } | ||
715 | } | ||
716 | } | 701 | } |
717 | None => { | 702 | None => { |
718 | *old_text = change.text; | 703 | *old_text = change.text; |
@@ -734,6 +719,7 @@ fn on_check_task( | |||
734 | 719 | ||
735 | CheckTask::AddDiagnostic { workspace_root, diagnostic } => { | 720 | CheckTask::AddDiagnostic { workspace_root, diagnostic } => { |
736 | 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, | ||
737 | &diagnostic, | 723 | &diagnostic, |
738 | &workspace_root, | 724 | &workspace_root, |
739 | ); | 725 | ); |
diff --git a/editors/code/package.json b/editors/code/package.json index e2027970d..3acc375f6 100644 --- a/editors/code/package.json +++ b/editors/code/package.json | |||
@@ -525,6 +525,24 @@ | |||
525 | "markdownDescription": "Internal config for debugging, disables loading of sysroot crates", | 525 | "markdownDescription": "Internal config for debugging, disables loading of sysroot crates", |
526 | "type": "boolean", | 526 | "type": "boolean", |
527 | "default": true | 527 | "default": true |
528 | }, | ||
529 | "rust-analyzer.diagnostics.warningsAsInfo": { | ||
530 | "type": "array", | ||
531 | "uniqueItems": true, | ||
532 | "items": { | ||
533 | "type": "string" | ||
534 | }, | ||
535 | "description": "List of warnings that should be displayed with info severity.\nThe warnings will be indicated by a blue squiggly underline in code and a blue icon in the problems panel.", | ||
536 | "default": [] | ||
537 | }, | ||
538 | "rust-analyzer.diagnostics.warningsAsHint": { | ||
539 | "type": "array", | ||
540 | "uniqueItems": true, | ||
541 | "items": { | ||
542 | "type": "string" | ||
543 | }, | ||
544 | "description": "List of warnings warnings that should be displayed with hint severity.\nThe warnings will be indicated by faded text or three dots in code and will not show up in te problems panel.", | ||
545 | "default": [] | ||
528 | } | 546 | } |
529 | } | 547 | } |
530 | }, | 548 | }, |