aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAleksey Kladov <[email protected]>2021-06-13 18:06:25 +0100
committerAleksey Kladov <[email protected]>2021-06-13 18:06:25 +0100
commit8d391ec981562785ec92ce3afe950972c523f925 (patch)
tree7729eb4ae1ef7a4cf0e0be42dfc2ef36c65cec1e
parentbccf77f26cd504de14f7d7d03f9f2a85d0fabb3d (diff)
internal: refactor mismatched args count diagnostic
-rw-r--r--crates/hir/src/diagnostics.rs26
-rw-r--r--crates/hir/src/lib.rs9
-rw-r--r--crates/ide/src/diagnostics.rs252
-rw-r--r--crates/ide/src/diagnostics/mismatched_arg_count.rs272
4 files changed, 279 insertions, 280 deletions
diff --git a/crates/hir/src/diagnostics.rs b/crates/hir/src/diagnostics.rs
index f7bf63215..f839616ce 100644
--- a/crates/hir/src/diagnostics.rs
+++ b/crates/hir/src/diagnostics.rs
@@ -35,6 +35,7 @@ diagnostics![
35 BreakOutsideOfLoop, 35 BreakOutsideOfLoop,
36 InactiveCode, 36 InactiveCode,
37 MacroError, 37 MacroError,
38 MismatchedArgCount,
38 MissingFields, 39 MissingFields,
39 MissingUnsafe, 40 MissingUnsafe,
40 NoSuchField, 41 NoSuchField,
@@ -143,36 +144,13 @@ impl Diagnostic for ReplaceFilterMapNextWithFindMap {
143 } 144 }
144} 145}
145 146
146// Diagnostic: mismatched-arg-count
147//
148// This diagnostic is triggered if a function is invoked with an incorrect amount of arguments.
149#[derive(Debug)] 147#[derive(Debug)]
150pub struct MismatchedArgCount { 148pub struct MismatchedArgCount {
151 pub file: HirFileId, 149 pub call_expr: InFile<AstPtr<ast::Expr>>,
152 pub call_expr: AstPtr<ast::Expr>,
153 pub expected: usize, 150 pub expected: usize,
154 pub found: usize, 151 pub found: usize,
155} 152}
156 153
157impl Diagnostic for MismatchedArgCount {
158 fn code(&self) -> DiagnosticCode {
159 DiagnosticCode("mismatched-arg-count")
160 }
161 fn message(&self) -> String {
162 let s = if self.expected == 1 { "" } else { "s" };
163 format!("Expected {} argument{}, found {}", self.expected, s, self.found)
164 }
165 fn display_source(&self) -> InFile<SyntaxNodePtr> {
166 InFile { file_id: self.file, value: self.call_expr.clone().into() }
167 }
168 fn as_any(&self) -> &(dyn Any + Send + 'static) {
169 self
170 }
171 fn is_experimental(&self) -> bool {
172 true
173 }
174}
175
176#[derive(Debug)] 154#[derive(Debug)]
177pub struct RemoveThisSemicolon { 155pub struct RemoveThisSemicolon {
178 pub file: HirFileId, 156 pub file: HirFileId,
diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs
index 16f862707..c1af5f097 100644
--- a/crates/hir/src/lib.rs
+++ b/crates/hir/src/lib.rs
@@ -1176,12 +1176,9 @@ impl Function {
1176 } 1176 }
1177 BodyValidationDiagnostic::MismatchedArgCount { call_expr, expected, found } => { 1177 BodyValidationDiagnostic::MismatchedArgCount { call_expr, expected, found } => {
1178 match source_map.expr_syntax(call_expr) { 1178 match source_map.expr_syntax(call_expr) {
1179 Ok(source_ptr) => sink.push(MismatchedArgCount { 1179 Ok(source_ptr) => acc.push(
1180 file: source_ptr.file_id, 1180 MismatchedArgCount { call_expr: source_ptr, expected, found }.into(),
1181 call_expr: source_ptr.value, 1181 ),
1182 expected,
1183 found,
1184 }),
1185 Err(SyntheticSyntax) => (), 1182 Err(SyntheticSyntax) => (),
1186 } 1183 }
1187 } 1184 }
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 @@
7mod break_outside_of_loop; 7mod break_outside_of_loop;
8mod inactive_code; 8mod inactive_code;
9mod macro_error; 9mod macro_error;
10mod mismatched_arg_count;
10mod missing_fields; 11mod missing_fields;
11mod missing_unsafe; 12mod missing_unsafe;
12mod no_such_field; 13mod 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#"
843fn zero() {}
844fn f() { zero(1); }
845 //^^^^^^^ Expected 0 arguments, found 1
846"#,
847 );
848
849 check_diagnostics(
850 r#"
851fn zero() {}
852fn f() { zero(); }
853"#,
854 );
855 }
856
857 #[test]
858 fn simple_free_fn_one() {
859 check_diagnostics(
860 r#"
861fn one(arg: u8) {}
862fn f() { one(); }
863 //^^^^^ Expected 1 argument, found 0
864"#,
865 );
866
867 check_diagnostics(
868 r#"
869fn one(arg: u8) {}
870fn f() { one(1); }
871"#,
872 );
873 }
874
875 #[test]
876 fn method_as_fn() {
877 check_diagnostics(
878 r#"
879struct S;
880impl S { fn method(&self) {} }
881
882fn f() {
883 S::method();
884} //^^^^^^^^^^^ Expected 1 argument, found 0
885"#,
886 );
887
888 check_diagnostics(
889 r#"
890struct S;
891impl S { fn method(&self) {} }
892
893fn 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#"
905struct S;
906impl 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#"
916struct S;
917impl S { fn method(&self, arg: u8) {} }
918
919fn 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#"
933trait Foo { fn method(&self, arg: usize) {} }
934
935fn f() {
936 let x;
937 x.method();
938}
939"#,
940 );
941 }
942
943 #[test]
944 fn tuple_struct() {
945 check_diagnostics(
946 r#"
947struct Tup(u8, u16);
948fn 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#"
959enum En { Variant(u8, u16), }
960fn 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#"
971macro_rules! Type {
972 () => { u32 };
973}
974enum Foo {
975 Bar(Type![])
976}
977impl 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#"
994extern "C" {
995 fn fixed(fixed: u8);
996 fn varargs(fixed: u8, ...);
997 fn varargs2(...);
998}
999
1000fn 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#"
1020fn 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#"
1036struct C(#[cfg(FALSE)] ());
1037impl C {
1038 fn new() -> Self {
1039 Self(
1040 #[cfg(FALSE)]
1041 (),
1042 )
1043 }
1044
1045 fn method(&self) {}
1046}
1047
1048fn 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#"
1059fn foo(#[cfg(NEVER)] x: ()) {}
1060
1061struct S;
1062
1063impl 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
1069extern "C" {
1070 fn fixed(fixed: u8, #[cfg(NEVER)] ...);
1071 fn varargs(#[cfg(not(NEVER))] ...);
1072}
1073
1074fn 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 @@
1use 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.
6pub(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)]
20mod tests {
21 use crate::diagnostics::tests::check_diagnostics;
22
23 #[test]
24 fn simple_free_fn_zero() {
25 check_diagnostics(
26 r#"
27fn zero() {}
28fn f() { zero(1); }
29 //^^^^^^^ expected 0 arguments, found 1
30"#,
31 );
32
33 check_diagnostics(
34 r#"
35fn zero() {}
36fn f() { zero(); }
37"#,
38 );
39 }
40
41 #[test]
42 fn simple_free_fn_one() {
43 check_diagnostics(
44 r#"
45fn one(arg: u8) {}
46fn f() { one(); }
47 //^^^^^ expected 1 argument, found 0
48"#,
49 );
50
51 check_diagnostics(
52 r#"
53fn one(arg: u8) {}
54fn f() { one(1); }
55"#,
56 );
57 }
58
59 #[test]
60 fn method_as_fn() {
61 check_diagnostics(
62 r#"
63struct S;
64impl S { fn method(&self) {} }
65
66fn f() {
67 S::method();
68} //^^^^^^^^^^^ expected 1 argument, found 0
69"#,
70 );
71
72 check_diagnostics(
73 r#"
74struct S;
75impl S { fn method(&self) {} }
76
77fn 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#"
89struct S;
90impl 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#"
100struct S;
101impl S { fn method(&self, arg: u8) {} }
102
103fn 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#"
117trait Foo { fn method(&self, arg: usize) {} }
118
119fn f() {
120 let x;
121 x.method();
122}
123"#,
124 );
125 }
126
127 #[test]
128 fn tuple_struct() {
129 check_diagnostics(
130 r#"
131struct Tup(u8, u16);
132fn 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#"
143enum En { Variant(u8, u16), }
144fn 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#"
155macro_rules! Type {
156 () => { u32 };
157}
158enum Foo {
159 Bar(Type![])
160}
161impl 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#"
178extern "C" {
179 fn fixed(fixed: u8);
180 fn varargs(fixed: u8, ...);
181 fn varargs2(...);
182}
183
184fn 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#"
204fn 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#"
220struct C(#[cfg(FALSE)] ());
221impl C {
222 fn new() -> Self {
223 Self(
224 #[cfg(FALSE)]
225 (),
226 )
227 }
228
229 fn method(&self) {}
230}
231
232fn 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#"
243fn foo(#[cfg(NEVER)] x: ()) {}
244
245struct S;
246
247impl 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
253extern "C" {
254 fn fixed(fixed: u8, #[cfg(NEVER)] ...);
255 fn varargs(#[cfg(not(NEVER))] ...);
256}
257
258fn 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}