use crate::diagnostics::{Diagnostic, DiagnosticsContext}; // Diagnostic: mismatched-arg-count // // This diagnostic is triggered if a function is invoked with an incorrect amount of arguments. pub(super) fn mismatched_arg_count( ctx: &DiagnosticsContext<'_>, d: &hir::MismatchedArgCount, ) -> Diagnostic { let s = if d.expected == 1 { "" } else { "s" }; let message = format!("expected {} argument{}, found {}", d.expected, s, d.found); Diagnostic::new( "mismatched-arg-count", message, ctx.sema.diagnostics_display_range(d.call_expr.clone().map(|it| it.into())).range, ) } #[cfg(test)] mod tests { use crate::diagnostics::tests::check_diagnostics; #[test] fn simple_free_fn_zero() { check_diagnostics( r#" fn zero() {} fn f() { zero(1); } //^^^^^^^ expected 0 arguments, found 1 "#, ); check_diagnostics( r#" fn zero() {} fn f() { zero(); } "#, ); } #[test] fn simple_free_fn_one() { check_diagnostics( r#" fn one(arg: u8) {} fn f() { one(); } //^^^^^ expected 1 argument, found 0 "#, ); check_diagnostics( r#" fn one(arg: u8) {} fn f() { one(1); } "#, ); } #[test] fn method_as_fn() { check_diagnostics( r#" struct S; impl S { fn method(&self) {} } fn f() { S::method(); } //^^^^^^^^^^^ expected 1 argument, found 0 "#, ); check_diagnostics( r#" struct S; impl S { fn method(&self) {} } fn f() { S::method(&S); S.method(); } "#, ); } #[test] fn method_with_arg() { check_diagnostics( r#" struct S; impl S { fn method(&self, arg: u8) {} } fn f() { S.method(); } //^^^^^^^^^^ expected 1 argument, found 0 "#, ); check_diagnostics( r#" struct S; impl S { fn method(&self, arg: u8) {} } fn f() { S::method(&S, 0); S.method(1); } "#, ); } #[test] fn method_unknown_receiver() { // note: this is incorrect code, so there might be errors on this in the // future, but we shouldn't emit an argument count diagnostic here check_diagnostics( r#" trait Foo { fn method(&self, arg: usize) {} } fn f() { let x; x.method(); } "#, ); } #[test] fn tuple_struct() { check_diagnostics( r#" struct Tup(u8, u16); fn f() { Tup(0); } //^^^^^^ expected 2 arguments, found 1 "#, ) } #[test] fn enum_variant() { check_diagnostics( r#" enum En { Variant(u8, u16), } fn f() { En::Variant(0); } //^^^^^^^^^^^^^^ expected 2 arguments, found 1 "#, ) } #[test] fn enum_variant_type_macro() { check_diagnostics( r#" macro_rules! Type { () => { u32 }; } enum Foo { Bar(Type![]) } impl Foo { fn new() { Foo::Bar(0); Foo::Bar(0, 1); //^^^^^^^^^^^^^^ expected 1 argument, found 2 Foo::Bar(); //^^^^^^^^^^ expected 1 argument, found 0 } } "#, ); } #[test] fn varargs() { check_diagnostics( r#" extern "C" { fn fixed(fixed: u8); fn varargs(fixed: u8, ...); fn varargs2(...); } fn f() { unsafe { fixed(0); fixed(0, 1); //^^^^^^^^^^^ expected 1 argument, found 2 varargs(0); varargs(0, 1); varargs2(); varargs2(0); varargs2(0, 1); } } "#, ) } #[test] fn arg_count_lambda() { check_diagnostics( r#" fn main() { let f = |()| (); f(); //^^^ expected 1 argument, found 0 f(()); f((), ()); //^^^^^^^^^ expected 1 argument, found 2 } "#, ) } #[test] fn cfgd_out_call_arguments() { check_diagnostics( r#" struct C(#[cfg(FALSE)] ()); impl C { fn new() -> Self { Self( #[cfg(FALSE)] (), ) } fn method(&self) {} } fn main() { C::new().method(#[cfg(FALSE)] 0); } "#, ); } #[test] fn cfgd_out_fn_params() { check_diagnostics( r#" fn foo(#[cfg(NEVER)] x: ()) {} struct S; impl S { fn method(#[cfg(NEVER)] self) {} fn method2(#[cfg(NEVER)] self, arg: u8) {} fn method3(self, #[cfg(NEVER)] arg: u8) {} } extern "C" { fn fixed(fixed: u8, #[cfg(NEVER)] ...); fn varargs(#[cfg(not(NEVER))] ...); } fn main() { foo(); S::method(); S::method2(0); S::method3(S); S.method3(); unsafe { fixed(0); varargs(1, 2, 3); } } "#, ) } }