mirror of
https://github.com/rust-lang/rust-analyzer.git
synced 2025-09-30 13:51:31 +00:00
Add argument count mismatch diagnostic
This commit is contained in:
parent
91005ecc27
commit
63ce2c7b5f
4 changed files with 103 additions and 6 deletions
|
@ -1,4 +1,6 @@
|
||||||
//! FIXME: write short doc here
|
//! FIXME: write short doc here
|
||||||
pub use hir_def::diagnostics::UnresolvedModule;
|
pub use hir_def::diagnostics::UnresolvedModule;
|
||||||
pub use hir_expand::diagnostics::{AstDiagnostic, Diagnostic, DiagnosticSink};
|
pub use hir_expand::diagnostics::{AstDiagnostic, Diagnostic, DiagnosticSink};
|
||||||
pub use hir_ty::diagnostics::{MissingFields, MissingMatchArms, MissingOkInTailExpr, NoSuchField};
|
pub use hir_ty::diagnostics::{
|
||||||
|
MismatchedArgCount, MissingFields, MissingMatchArms, MissingOkInTailExpr, NoSuchField,
|
||||||
|
};
|
||||||
|
|
|
@ -197,3 +197,32 @@ impl AstDiagnostic for MissingUnsafe {
|
||||||
ast::Expr::cast(node).unwrap()
|
ast::Expr::cast(node).unwrap()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct MismatchedArgCount {
|
||||||
|
pub file: HirFileId,
|
||||||
|
pub call_expr: AstPtr<ast::Expr>,
|
||||||
|
pub expected: usize,
|
||||||
|
pub found: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Diagnostic for MismatchedArgCount {
|
||||||
|
fn message(&self) -> String {
|
||||||
|
format!("Expected {} arguments, found {}", self.expected, self.found)
|
||||||
|
}
|
||||||
|
fn source(&self) -> InFile<SyntaxNodePtr> {
|
||||||
|
InFile { file_id: self.file, value: self.call_expr.clone().into() }
|
||||||
|
}
|
||||||
|
fn as_any(&self) -> &(dyn Any + Send + 'static) {
|
||||||
|
self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl AstDiagnostic for MismatchedArgCount {
|
||||||
|
type AST = ast::CallExpr;
|
||||||
|
fn ast(&self, db: &dyn AstDatabase) -> Self::AST {
|
||||||
|
let root = db.parse_or_expand(self.source().file_id).unwrap();
|
||||||
|
let node = self.source().value.to_node(&root);
|
||||||
|
ast::CallExpr::cast(node).unwrap()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -9,9 +9,11 @@ use rustc_hash::FxHashSet;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
db::HirDatabase,
|
db::HirDatabase,
|
||||||
diagnostics::{MissingFields, MissingMatchArms, MissingOkInTailExpr, MissingPatFields},
|
diagnostics::{
|
||||||
|
MismatchedArgCount, MissingFields, MissingMatchArms, MissingOkInTailExpr, MissingPatFields,
|
||||||
|
},
|
||||||
utils::variant_data,
|
utils::variant_data,
|
||||||
ApplicationTy, InferenceResult, Ty, TypeCtor,
|
ApplicationTy, CallableDef, InferenceResult, Ty, TypeCtor,
|
||||||
_match::{is_useful, MatchCheckCtx, Matrix, PatStack, Usefulness},
|
_match::{is_useful, MatchCheckCtx, Matrix, PatStack, Usefulness},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -24,7 +26,8 @@ pub use hir_def::{
|
||||||
ArithOp, Array, BinaryOp, BindingAnnotation, CmpOp, Expr, ExprId, Literal, LogicOp,
|
ArithOp, Array, BinaryOp, BindingAnnotation, CmpOp, Expr, ExprId, Literal, LogicOp,
|
||||||
MatchArm, Ordering, Pat, PatId, RecordFieldPat, RecordLitField, Statement, UnaryOp,
|
MatchArm, Ordering, Pat, PatId, RecordFieldPat, RecordLitField, Statement, UnaryOp,
|
||||||
},
|
},
|
||||||
LocalFieldId, VariantId,
|
src::HasSource,
|
||||||
|
LocalFieldId, Lookup, VariantId,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub struct ExprValidator<'a, 'b: 'a> {
|
pub struct ExprValidator<'a, 'b: 'a> {
|
||||||
|
@ -56,9 +59,16 @@ impl<'a, 'b> ExprValidator<'a, 'b> {
|
||||||
missed_fields,
|
missed_fields,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
if let Expr::Match { expr, arms } = expr {
|
|
||||||
|
match expr {
|
||||||
|
Expr::Match { expr, arms } => {
|
||||||
self.validate_match(id, *expr, arms, db, self.infer.clone());
|
self.validate_match(id, *expr, arms, db, self.infer.clone());
|
||||||
}
|
}
|
||||||
|
Expr::Call { .. } | Expr::MethodCall { .. } => {
|
||||||
|
self.validate_call(db, id, expr);
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
for (id, pat) in body.pats.iter() {
|
for (id, pat) in body.pats.iter() {
|
||||||
if let Some((variant_def, missed_fields, true)) =
|
if let Some((variant_def, missed_fields, true)) =
|
||||||
|
@ -138,6 +148,54 @@ impl<'a, 'b> ExprValidator<'a, 'b> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn validate_call(&mut self, db: &dyn HirDatabase, call_id: ExprId, expr: &Expr) -> Option<()> {
|
||||||
|
// Check that the number of arguments matches the number of parameters.
|
||||||
|
let (callee, args) = match expr {
|
||||||
|
Expr::Call { callee, args } => {
|
||||||
|
let callee = &self.infer.type_of_expr[*callee];
|
||||||
|
let (callable, _) = callee.as_callable()?;
|
||||||
|
let callee = match callable {
|
||||||
|
CallableDef::FunctionId(func) => func,
|
||||||
|
_ => return None,
|
||||||
|
};
|
||||||
|
|
||||||
|
(callee, args.clone())
|
||||||
|
}
|
||||||
|
Expr::MethodCall { receiver, args, .. } => {
|
||||||
|
let callee = self.infer.method_resolution(call_id)?;
|
||||||
|
let mut args = args.clone();
|
||||||
|
args.insert(0, *receiver);
|
||||||
|
(callee, args)
|
||||||
|
}
|
||||||
|
_ => return None,
|
||||||
|
};
|
||||||
|
|
||||||
|
let loc = callee.lookup(db.upcast());
|
||||||
|
let ast = loc.source(db.upcast());
|
||||||
|
let params = ast.value.param_list()?;
|
||||||
|
|
||||||
|
let mut param_count = params.params().count();
|
||||||
|
if params.self_param().is_some() {
|
||||||
|
param_count += 1;
|
||||||
|
}
|
||||||
|
let arg_count = args.len();
|
||||||
|
|
||||||
|
if arg_count != param_count {
|
||||||
|
let (_, source_map): (Arc<Body>, Arc<BodySourceMap>) =
|
||||||
|
db.body_with_source_map(self.func.into());
|
||||||
|
if let Ok(source_ptr) = source_map.expr_syntax(call_id) {
|
||||||
|
self.sink.push(MismatchedArgCount {
|
||||||
|
file: source_ptr.file_id,
|
||||||
|
call_expr: source_ptr.value,
|
||||||
|
expected: param_count,
|
||||||
|
found: arg_count,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
fn validate_match(
|
fn validate_match(
|
||||||
&mut self,
|
&mut self,
|
||||||
id: ExprId,
|
id: ExprId,
|
||||||
|
|
|
@ -127,6 +127,14 @@ pub(crate) fn diagnostics(db: &RootDatabase, file_id: FileId) -> Vec<Diagnostic>
|
||||||
severity: Severity::Error,
|
severity: Severity::Error,
|
||||||
fix: missing_struct_field_fix(&sema, file_id, d),
|
fix: missing_struct_field_fix(&sema, file_id, d),
|
||||||
})
|
})
|
||||||
|
})
|
||||||
|
.on::<hir::diagnostics::MismatchedArgCount, _>(|d| {
|
||||||
|
res.borrow_mut().push(Diagnostic {
|
||||||
|
range: sema.diagnostics_range(d).range,
|
||||||
|
message: d.message(),
|
||||||
|
severity: Severity::Error,
|
||||||
|
fix: None,
|
||||||
|
})
|
||||||
});
|
});
|
||||||
|
|
||||||
if let Some(m) = sema.to_module_def(file_id) {
|
if let Some(m) = sema.to_module_def(file_id) {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue