diff options
Diffstat (limited to 'crates')
8 files changed, 812 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 | ); |