rust-analyzer/crates/ide/src/diagnostics/mismatched_arg_count.rs

273 lines
4.7 KiB
Rust
Raw Normal View History

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);
}
}
"#,
)
}
}