diff options
author | Aleksey Kladov <[email protected]> | 2021-06-13 18:06:25 +0100 |
---|---|---|
committer | Aleksey Kladov <[email protected]> | 2021-06-13 18:06:25 +0100 |
commit | 8d391ec981562785ec92ce3afe950972c523f925 (patch) | |
tree | 7729eb4ae1ef7a4cf0e0be42dfc2ef36c65cec1e /crates/ide/src | |
parent | bccf77f26cd504de14f7d7d03f9f2a85d0fabb3d (diff) |
internal: refactor mismatched args count diagnostic
Diffstat (limited to 'crates/ide/src')
-rw-r--r-- | crates/ide/src/diagnostics.rs | 252 | ||||
-rw-r--r-- | crates/ide/src/diagnostics/mismatched_arg_count.rs | 272 |
2 files changed, 274 insertions, 250 deletions
diff --git a/crates/ide/src/diagnostics.rs b/crates/ide/src/diagnostics.rs index 67390345f..4c92d0cf4 100644 --- a/crates/ide/src/diagnostics.rs +++ b/crates/ide/src/diagnostics.rs | |||
@@ -7,6 +7,7 @@ | |||
7 | mod break_outside_of_loop; | 7 | mod break_outside_of_loop; |
8 | mod inactive_code; | 8 | mod inactive_code; |
9 | mod macro_error; | 9 | mod macro_error; |
10 | mod mismatched_arg_count; | ||
10 | mod missing_fields; | 11 | mod missing_fields; |
11 | mod missing_unsafe; | 12 | mod missing_unsafe; |
12 | mod no_such_field; | 13 | mod no_such_field; |
@@ -224,6 +225,7 @@ pub(crate) fn diagnostics( | |||
224 | AnyDiagnostic::MacroError(d) => macro_error::macro_error(&ctx, &d), | 225 | AnyDiagnostic::MacroError(d) => macro_error::macro_error(&ctx, &d), |
225 | AnyDiagnostic::MissingFields(d) => missing_fields::missing_fields(&ctx, &d), | 226 | AnyDiagnostic::MissingFields(d) => missing_fields::missing_fields(&ctx, &d), |
226 | AnyDiagnostic::MissingUnsafe(d) => missing_unsafe::missing_unsafe(&ctx, &d), | 227 | AnyDiagnostic::MissingUnsafe(d) => missing_unsafe::missing_unsafe(&ctx, &d), |
228 | AnyDiagnostic::MismatchedArgCount(d) => mismatched_arg_count::mismatched_arg_count(&ctx, &d), | ||
227 | AnyDiagnostic::NoSuchField(d) => no_such_field::no_such_field(&ctx, &d), | 229 | AnyDiagnostic::NoSuchField(d) => no_such_field::no_such_field(&ctx, &d), |
228 | AnyDiagnostic::UnimplementedBuiltinMacro(d) => unimplemented_builtin_macro::unimplemented_builtin_macro(&ctx, &d), | 230 | AnyDiagnostic::UnimplementedBuiltinMacro(d) => unimplemented_builtin_macro::unimplemented_builtin_macro(&ctx, &d), |
229 | AnyDiagnostic::UnresolvedExternCrate(d) => unresolved_extern_crate::unresolved_extern_crate(&ctx, &d), | 231 | AnyDiagnostic::UnresolvedExternCrate(d) => unresolved_extern_crate::unresolved_extern_crate(&ctx, &d), |
@@ -837,256 +839,6 @@ fn x(a: S) { | |||
837 | } | 839 | } |
838 | 840 | ||
839 | #[test] | 841 | #[test] |
840 | fn simple_free_fn_zero() { | ||
841 | check_diagnostics( | ||
842 | r#" | ||
843 | fn zero() {} | ||
844 | fn f() { zero(1); } | ||
845 | //^^^^^^^ Expected 0 arguments, found 1 | ||
846 | "#, | ||
847 | ); | ||
848 | |||
849 | check_diagnostics( | ||
850 | r#" | ||
851 | fn zero() {} | ||
852 | fn f() { zero(); } | ||
853 | "#, | ||
854 | ); | ||
855 | } | ||
856 | |||
857 | #[test] | ||
858 | fn simple_free_fn_one() { | ||
859 | check_diagnostics( | ||
860 | r#" | ||
861 | fn one(arg: u8) {} | ||
862 | fn f() { one(); } | ||
863 | //^^^^^ Expected 1 argument, found 0 | ||
864 | "#, | ||
865 | ); | ||
866 | |||
867 | check_diagnostics( | ||
868 | r#" | ||
869 | fn one(arg: u8) {} | ||
870 | fn f() { one(1); } | ||
871 | "#, | ||
872 | ); | ||
873 | } | ||
874 | |||
875 | #[test] | ||
876 | fn method_as_fn() { | ||
877 | check_diagnostics( | ||
878 | r#" | ||
879 | struct S; | ||
880 | impl S { fn method(&self) {} } | ||
881 | |||
882 | fn f() { | ||
883 | S::method(); | ||
884 | } //^^^^^^^^^^^ Expected 1 argument, found 0 | ||
885 | "#, | ||
886 | ); | ||
887 | |||
888 | check_diagnostics( | ||
889 | r#" | ||
890 | struct S; | ||
891 | impl S { fn method(&self) {} } | ||
892 | |||
893 | fn f() { | ||
894 | S::method(&S); | ||
895 | S.method(); | ||
896 | } | ||
897 | "#, | ||
898 | ); | ||
899 | } | ||
900 | |||
901 | #[test] | ||
902 | fn method_with_arg() { | ||
903 | check_diagnostics( | ||
904 | r#" | ||
905 | struct S; | ||
906 | impl S { fn method(&self, arg: u8) {} } | ||
907 | |||
908 | fn f() { | ||
909 | S.method(); | ||
910 | } //^^^^^^^^^^ Expected 1 argument, found 0 | ||
911 | "#, | ||
912 | ); | ||
913 | |||
914 | check_diagnostics( | ||
915 | r#" | ||
916 | struct S; | ||
917 | impl S { fn method(&self, arg: u8) {} } | ||
918 | |||
919 | fn f() { | ||
920 | S::method(&S, 0); | ||
921 | S.method(1); | ||
922 | } | ||
923 | "#, | ||
924 | ); | ||
925 | } | ||
926 | |||
927 | #[test] | ||
928 | fn method_unknown_receiver() { | ||
929 | // note: this is incorrect code, so there might be errors on this in the | ||
930 | // future, but we shouldn't emit an argument count diagnostic here | ||
931 | check_diagnostics( | ||
932 | r#" | ||
933 | trait Foo { fn method(&self, arg: usize) {} } | ||
934 | |||
935 | fn f() { | ||
936 | let x; | ||
937 | x.method(); | ||
938 | } | ||
939 | "#, | ||
940 | ); | ||
941 | } | ||
942 | |||
943 | #[test] | ||
944 | fn tuple_struct() { | ||
945 | check_diagnostics( | ||
946 | r#" | ||
947 | struct Tup(u8, u16); | ||
948 | fn f() { | ||
949 | Tup(0); | ||
950 | } //^^^^^^ Expected 2 arguments, found 1 | ||
951 | "#, | ||
952 | ) | ||
953 | } | ||
954 | |||
955 | #[test] | ||
956 | fn enum_variant() { | ||
957 | check_diagnostics( | ||
958 | r#" | ||
959 | enum En { Variant(u8, u16), } | ||
960 | fn f() { | ||
961 | En::Variant(0); | ||
962 | } //^^^^^^^^^^^^^^ Expected 2 arguments, found 1 | ||
963 | "#, | ||
964 | ) | ||
965 | } | ||
966 | |||
967 | #[test] | ||
968 | fn enum_variant_type_macro() { | ||
969 | check_diagnostics( | ||
970 | r#" | ||
971 | macro_rules! Type { | ||
972 | () => { u32 }; | ||
973 | } | ||
974 | enum Foo { | ||
975 | Bar(Type![]) | ||
976 | } | ||
977 | impl Foo { | ||
978 | fn new() { | ||
979 | Foo::Bar(0); | ||
980 | Foo::Bar(0, 1); | ||
981 | //^^^^^^^^^^^^^^ Expected 1 argument, found 2 | ||
982 | Foo::Bar(); | ||
983 | //^^^^^^^^^^ Expected 1 argument, found 0 | ||
984 | } | ||
985 | } | ||
986 | "#, | ||
987 | ); | ||
988 | } | ||
989 | |||
990 | #[test] | ||
991 | fn varargs() { | ||
992 | check_diagnostics( | ||
993 | r#" | ||
994 | extern "C" { | ||
995 | fn fixed(fixed: u8); | ||
996 | fn varargs(fixed: u8, ...); | ||
997 | fn varargs2(...); | ||
998 | } | ||
999 | |||
1000 | fn f() { | ||
1001 | unsafe { | ||
1002 | fixed(0); | ||
1003 | fixed(0, 1); | ||
1004 | //^^^^^^^^^^^ Expected 1 argument, found 2 | ||
1005 | varargs(0); | ||
1006 | varargs(0, 1); | ||
1007 | varargs2(); | ||
1008 | varargs2(0); | ||
1009 | varargs2(0, 1); | ||
1010 | } | ||
1011 | } | ||
1012 | "#, | ||
1013 | ) | ||
1014 | } | ||
1015 | |||
1016 | #[test] | ||
1017 | fn arg_count_lambda() { | ||
1018 | check_diagnostics( | ||
1019 | r#" | ||
1020 | fn main() { | ||
1021 | let f = |()| (); | ||
1022 | f(); | ||
1023 | //^^^ Expected 1 argument, found 0 | ||
1024 | f(()); | ||
1025 | f((), ()); | ||
1026 | //^^^^^^^^^ Expected 1 argument, found 2 | ||
1027 | } | ||
1028 | "#, | ||
1029 | ) | ||
1030 | } | ||
1031 | |||
1032 | #[test] | ||
1033 | fn cfgd_out_call_arguments() { | ||
1034 | check_diagnostics( | ||
1035 | r#" | ||
1036 | struct C(#[cfg(FALSE)] ()); | ||
1037 | impl C { | ||
1038 | fn new() -> Self { | ||
1039 | Self( | ||
1040 | #[cfg(FALSE)] | ||
1041 | (), | ||
1042 | ) | ||
1043 | } | ||
1044 | |||
1045 | fn method(&self) {} | ||
1046 | } | ||
1047 | |||
1048 | fn main() { | ||
1049 | C::new().method(#[cfg(FALSE)] 0); | ||
1050 | } | ||
1051 | "#, | ||
1052 | ); | ||
1053 | } | ||
1054 | |||
1055 | #[test] | ||
1056 | fn cfgd_out_fn_params() { | ||
1057 | check_diagnostics( | ||
1058 | r#" | ||
1059 | fn foo(#[cfg(NEVER)] x: ()) {} | ||
1060 | |||
1061 | struct S; | ||
1062 | |||
1063 | impl S { | ||
1064 | fn method(#[cfg(NEVER)] self) {} | ||
1065 | fn method2(#[cfg(NEVER)] self, arg: u8) {} | ||
1066 | fn method3(self, #[cfg(NEVER)] arg: u8) {} | ||
1067 | } | ||
1068 | |||
1069 | extern "C" { | ||
1070 | fn fixed(fixed: u8, #[cfg(NEVER)] ...); | ||
1071 | fn varargs(#[cfg(not(NEVER))] ...); | ||
1072 | } | ||
1073 | |||
1074 | fn main() { | ||
1075 | foo(); | ||
1076 | S::method(); | ||
1077 | S::method2(0); | ||
1078 | S::method3(S); | ||
1079 | S.method3(); | ||
1080 | unsafe { | ||
1081 | fixed(0); | ||
1082 | varargs(1, 2, 3); | ||
1083 | } | ||
1084 | } | ||
1085 | "#, | ||
1086 | ) | ||
1087 | } | ||
1088 | |||
1089 | #[test] | ||
1090 | fn missing_semicolon() { | 842 | fn missing_semicolon() { |
1091 | check_diagnostics( | 843 | check_diagnostics( |
1092 | r#" | 844 | r#" |
diff --git a/crates/ide/src/diagnostics/mismatched_arg_count.rs b/crates/ide/src/diagnostics/mismatched_arg_count.rs new file mode 100644 index 000000000..08e1cfa5f --- /dev/null +++ b/crates/ide/src/diagnostics/mismatched_arg_count.rs | |||
@@ -0,0 +1,272 @@ | |||
1 | use crate::diagnostics::{Diagnostic, DiagnosticsContext}; | ||
2 | |||
3 | // Diagnostic: mismatched-arg-count | ||
4 | // | ||
5 | // This diagnostic is triggered if a function is invoked with an incorrect amount of arguments. | ||
6 | pub(super) fn mismatched_arg_count( | ||
7 | ctx: &DiagnosticsContext<'_>, | ||
8 | d: &hir::MismatchedArgCount, | ||
9 | ) -> Diagnostic { | ||
10 | let s = if d.expected == 1 { "" } else { "s" }; | ||
11 | let message = format!("expected {} argument{}, found {}", d.expected, s, d.found); | ||
12 | Diagnostic::new( | ||
13 | "mismatched-arg-count", | ||
14 | message, | ||
15 | ctx.sema.diagnostics_display_range(d.call_expr.clone().map(|it| it.into())).range, | ||
16 | ) | ||
17 | } | ||
18 | |||
19 | #[cfg(test)] | ||
20 | mod tests { | ||
21 | use crate::diagnostics::tests::check_diagnostics; | ||
22 | |||
23 | #[test] | ||
24 | fn simple_free_fn_zero() { | ||
25 | check_diagnostics( | ||
26 | r#" | ||
27 | fn zero() {} | ||
28 | fn f() { zero(1); } | ||
29 | //^^^^^^^ expected 0 arguments, found 1 | ||
30 | "#, | ||
31 | ); | ||
32 | |||
33 | check_diagnostics( | ||
34 | r#" | ||
35 | fn zero() {} | ||
36 | fn f() { zero(); } | ||
37 | "#, | ||
38 | ); | ||
39 | } | ||
40 | |||
41 | #[test] | ||
42 | fn simple_free_fn_one() { | ||
43 | check_diagnostics( | ||
44 | r#" | ||
45 | fn one(arg: u8) {} | ||
46 | fn f() { one(); } | ||
47 | //^^^^^ expected 1 argument, found 0 | ||
48 | "#, | ||
49 | ); | ||
50 | |||
51 | check_diagnostics( | ||
52 | r#" | ||
53 | fn one(arg: u8) {} | ||
54 | fn f() { one(1); } | ||
55 | "#, | ||
56 | ); | ||
57 | } | ||
58 | |||
59 | #[test] | ||
60 | fn method_as_fn() { | ||
61 | check_diagnostics( | ||
62 | r#" | ||
63 | struct S; | ||
64 | impl S { fn method(&self) {} } | ||
65 | |||
66 | fn f() { | ||
67 | S::method(); | ||
68 | } //^^^^^^^^^^^ expected 1 argument, found 0 | ||
69 | "#, | ||
70 | ); | ||
71 | |||
72 | check_diagnostics( | ||
73 | r#" | ||
74 | struct S; | ||
75 | impl S { fn method(&self) {} } | ||
76 | |||
77 | fn f() { | ||
78 | S::method(&S); | ||
79 | S.method(); | ||
80 | } | ||
81 | "#, | ||
82 | ); | ||
83 | } | ||
84 | |||
85 | #[test] | ||
86 | fn method_with_arg() { | ||
87 | check_diagnostics( | ||
88 | r#" | ||
89 | struct S; | ||
90 | impl S { fn method(&self, arg: u8) {} } | ||
91 | |||
92 | fn f() { | ||
93 | S.method(); | ||
94 | } //^^^^^^^^^^ expected 1 argument, found 0 | ||
95 | "#, | ||
96 | ); | ||
97 | |||
98 | check_diagnostics( | ||
99 | r#" | ||
100 | struct S; | ||
101 | impl S { fn method(&self, arg: u8) {} } | ||
102 | |||
103 | fn f() { | ||
104 | S::method(&S, 0); | ||
105 | S.method(1); | ||
106 | } | ||
107 | "#, | ||
108 | ); | ||
109 | } | ||
110 | |||
111 | #[test] | ||
112 | fn method_unknown_receiver() { | ||
113 | // note: this is incorrect code, so there might be errors on this in the | ||
114 | // future, but we shouldn't emit an argument count diagnostic here | ||
115 | check_diagnostics( | ||
116 | r#" | ||
117 | trait Foo { fn method(&self, arg: usize) {} } | ||
118 | |||
119 | fn f() { | ||
120 | let x; | ||
121 | x.method(); | ||
122 | } | ||
123 | "#, | ||
124 | ); | ||
125 | } | ||
126 | |||
127 | #[test] | ||
128 | fn tuple_struct() { | ||
129 | check_diagnostics( | ||
130 | r#" | ||
131 | struct Tup(u8, u16); | ||
132 | fn f() { | ||
133 | Tup(0); | ||
134 | } //^^^^^^ expected 2 arguments, found 1 | ||
135 | "#, | ||
136 | ) | ||
137 | } | ||
138 | |||
139 | #[test] | ||
140 | fn enum_variant() { | ||
141 | check_diagnostics( | ||
142 | r#" | ||
143 | enum En { Variant(u8, u16), } | ||
144 | fn f() { | ||
145 | En::Variant(0); | ||
146 | } //^^^^^^^^^^^^^^ expected 2 arguments, found 1 | ||
147 | "#, | ||
148 | ) | ||
149 | } | ||
150 | |||
151 | #[test] | ||
152 | fn enum_variant_type_macro() { | ||
153 | check_diagnostics( | ||
154 | r#" | ||
155 | macro_rules! Type { | ||
156 | () => { u32 }; | ||
157 | } | ||
158 | enum Foo { | ||
159 | Bar(Type![]) | ||
160 | } | ||
161 | impl Foo { | ||
162 | fn new() { | ||
163 | Foo::Bar(0); | ||
164 | Foo::Bar(0, 1); | ||
165 | //^^^^^^^^^^^^^^ expected 1 argument, found 2 | ||
166 | Foo::Bar(); | ||
167 | //^^^^^^^^^^ expected 1 argument, found 0 | ||
168 | } | ||
169 | } | ||
170 | "#, | ||
171 | ); | ||
172 | } | ||
173 | |||
174 | #[test] | ||
175 | fn varargs() { | ||
176 | check_diagnostics( | ||
177 | r#" | ||
178 | extern "C" { | ||
179 | fn fixed(fixed: u8); | ||
180 | fn varargs(fixed: u8, ...); | ||
181 | fn varargs2(...); | ||
182 | } | ||
183 | |||
184 | fn f() { | ||
185 | unsafe { | ||
186 | fixed(0); | ||
187 | fixed(0, 1); | ||
188 | //^^^^^^^^^^^ expected 1 argument, found 2 | ||
189 | varargs(0); | ||
190 | varargs(0, 1); | ||
191 | varargs2(); | ||
192 | varargs2(0); | ||
193 | varargs2(0, 1); | ||
194 | } | ||
195 | } | ||
196 | "#, | ||
197 | ) | ||
198 | } | ||
199 | |||
200 | #[test] | ||
201 | fn arg_count_lambda() { | ||
202 | check_diagnostics( | ||
203 | r#" | ||
204 | fn main() { | ||
205 | let f = |()| (); | ||
206 | f(); | ||
207 | //^^^ expected 1 argument, found 0 | ||
208 | f(()); | ||
209 | f((), ()); | ||
210 | //^^^^^^^^^ expected 1 argument, found 2 | ||
211 | } | ||
212 | "#, | ||
213 | ) | ||
214 | } | ||
215 | |||
216 | #[test] | ||
217 | fn cfgd_out_call_arguments() { | ||
218 | check_diagnostics( | ||
219 | r#" | ||
220 | struct C(#[cfg(FALSE)] ()); | ||
221 | impl C { | ||
222 | fn new() -> Self { | ||
223 | Self( | ||
224 | #[cfg(FALSE)] | ||
225 | (), | ||
226 | ) | ||
227 | } | ||
228 | |||
229 | fn method(&self) {} | ||
230 | } | ||
231 | |||
232 | fn main() { | ||
233 | C::new().method(#[cfg(FALSE)] 0); | ||
234 | } | ||
235 | "#, | ||
236 | ); | ||
237 | } | ||
238 | |||
239 | #[test] | ||
240 | fn cfgd_out_fn_params() { | ||
241 | check_diagnostics( | ||
242 | r#" | ||
243 | fn foo(#[cfg(NEVER)] x: ()) {} | ||
244 | |||
245 | struct S; | ||
246 | |||
247 | impl S { | ||
248 | fn method(#[cfg(NEVER)] self) {} | ||
249 | fn method2(#[cfg(NEVER)] self, arg: u8) {} | ||
250 | fn method3(self, #[cfg(NEVER)] arg: u8) {} | ||
251 | } | ||
252 | |||
253 | extern "C" { | ||
254 | fn fixed(fixed: u8, #[cfg(NEVER)] ...); | ||
255 | fn varargs(#[cfg(not(NEVER))] ...); | ||
256 | } | ||
257 | |||
258 | fn main() { | ||
259 | foo(); | ||
260 | S::method(); | ||
261 | S::method2(0); | ||
262 | S::method3(S); | ||
263 | S.method3(); | ||
264 | unsafe { | ||
265 | fixed(0); | ||
266 | varargs(1, 2, 3); | ||
267 | } | ||
268 | } | ||
269 | "#, | ||
270 | ) | ||
271 | } | ||
272 | } | ||