internal: refactor mismatched args count diagnostic
This commit is contained in:
parent
bccf77f26c
commit
8d391ec981
@ -35,6 +35,7 @@ fn from(d: $diag) -> AnyDiagnostic {
|
||||
BreakOutsideOfLoop,
|
||||
InactiveCode,
|
||||
MacroError,
|
||||
MismatchedArgCount,
|
||||
MissingFields,
|
||||
MissingUnsafe,
|
||||
NoSuchField,
|
||||
@ -143,36 +144,13 @@ fn as_any(&self) -> &(dyn Any + Send + 'static) {
|
||||
}
|
||||
}
|
||||
|
||||
// Diagnostic: mismatched-arg-count
|
||||
//
|
||||
// This diagnostic is triggered if a function is invoked with an incorrect amount of arguments.
|
||||
#[derive(Debug)]
|
||||
pub struct MismatchedArgCount {
|
||||
pub file: HirFileId,
|
||||
pub call_expr: AstPtr<ast::Expr>,
|
||||
pub call_expr: InFile<AstPtr<ast::Expr>>,
|
||||
pub expected: usize,
|
||||
pub found: usize,
|
||||
}
|
||||
|
||||
impl Diagnostic for MismatchedArgCount {
|
||||
fn code(&self) -> DiagnosticCode {
|
||||
DiagnosticCode("mismatched-arg-count")
|
||||
}
|
||||
fn message(&self) -> String {
|
||||
let s = if self.expected == 1 { "" } else { "s" };
|
||||
format!("Expected {} argument{}, found {}", self.expected, s, self.found)
|
||||
}
|
||||
fn display_source(&self) -> InFile<SyntaxNodePtr> {
|
||||
InFile { file_id: self.file, value: self.call_expr.clone().into() }
|
||||
}
|
||||
fn as_any(&self) -> &(dyn Any + Send + 'static) {
|
||||
self
|
||||
}
|
||||
fn is_experimental(&self) -> bool {
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct RemoveThisSemicolon {
|
||||
pub file: HirFileId,
|
||||
|
@ -1176,12 +1176,9 @@ pub fn diagnostics(
|
||||
}
|
||||
BodyValidationDiagnostic::MismatchedArgCount { call_expr, expected, found } => {
|
||||
match source_map.expr_syntax(call_expr) {
|
||||
Ok(source_ptr) => sink.push(MismatchedArgCount {
|
||||
file: source_ptr.file_id,
|
||||
call_expr: source_ptr.value,
|
||||
expected,
|
||||
found,
|
||||
}),
|
||||
Ok(source_ptr) => acc.push(
|
||||
MismatchedArgCount { call_expr: source_ptr, expected, found }.into(),
|
||||
),
|
||||
Err(SyntheticSyntax) => (),
|
||||
}
|
||||
}
|
||||
|
@ -7,6 +7,7 @@
|
||||
mod break_outside_of_loop;
|
||||
mod inactive_code;
|
||||
mod macro_error;
|
||||
mod mismatched_arg_count;
|
||||
mod missing_fields;
|
||||
mod missing_unsafe;
|
||||
mod no_such_field;
|
||||
@ -224,6 +225,7 @@ pub(crate) fn diagnostics(
|
||||
AnyDiagnostic::MacroError(d) => macro_error::macro_error(&ctx, &d),
|
||||
AnyDiagnostic::MissingFields(d) => missing_fields::missing_fields(&ctx, &d),
|
||||
AnyDiagnostic::MissingUnsafe(d) => missing_unsafe::missing_unsafe(&ctx, &d),
|
||||
AnyDiagnostic::MismatchedArgCount(d) => mismatched_arg_count::mismatched_arg_count(&ctx, &d),
|
||||
AnyDiagnostic::NoSuchField(d) => no_such_field::no_such_field(&ctx, &d),
|
||||
AnyDiagnostic::UnimplementedBuiltinMacro(d) => unimplemented_builtin_macro::unimplemented_builtin_macro(&ctx, &d),
|
||||
AnyDiagnostic::UnresolvedExternCrate(d) => unresolved_extern_crate::unresolved_extern_crate(&ctx, &d),
|
||||
@ -836,256 +838,6 @@ fn x(a: S) {
|
||||
)
|
||||
}
|
||||
|
||||
#[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);
|
||||
}
|
||||
}
|
||||
"#,
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn missing_semicolon() {
|
||||
check_diagnostics(
|
||||
|
272
crates/ide/src/diagnostics/mismatched_arg_count.rs
Normal file
272
crates/ide/src/diagnostics/mismatched_arg_count.rs
Normal file
@ -0,0 +1,272 @@
|
||||
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);
|
||||
}
|
||||
}
|
||||
"#,
|
||||
)
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user