mirror of
https://github.com/rust-lang/rust-analyzer.git
synced 2025-09-30 05:45:12 +00:00
add record pat missing field diagnostic
This commit is contained in:
parent
176f7f6117
commit
e63315b8f1
7 changed files with 159 additions and 57 deletions
|
@ -9,7 +9,7 @@ use rustc_hash::FxHashSet;
|
|||
|
||||
use crate::{
|
||||
db::HirDatabase,
|
||||
diagnostics::{MissingFields, MissingMatchArms, MissingOkInTailExpr},
|
||||
diagnostics::{MissingFields, MissingMatchArms, MissingOkInTailExpr, MissingPatFields},
|
||||
utils::variant_data,
|
||||
ApplicationTy, InferenceResult, Ty, TypeCtor,
|
||||
_match::{is_useful, MatchCheckCtx, Matrix, PatStack, Usefulness},
|
||||
|
@ -49,39 +49,97 @@ impl<'a, 'b> ExprValidator<'a, 'b> {
|
|||
if let Some((variant_def, missed_fields, true)) =
|
||||
record_literal_missing_fields(db, &self.infer, id, expr)
|
||||
{
|
||||
// XXX: only look at source_map if we do have missing fields
|
||||
let (_, source_map) = db.body_with_source_map(self.func.into());
|
||||
|
||||
if let Ok(source_ptr) = source_map.expr_syntax(id) {
|
||||
if let Some(expr) = source_ptr.value.left() {
|
||||
let root = source_ptr.file_syntax(db.upcast());
|
||||
if let ast::Expr::RecordLit(record_lit) = expr.to_node(&root) {
|
||||
if let Some(field_list) = record_lit.record_field_list() {
|
||||
let variant_data = variant_data(db.upcast(), variant_def);
|
||||
let missed_fields = missed_fields
|
||||
.into_iter()
|
||||
.map(|idx| variant_data.fields()[idx].name.clone())
|
||||
.collect();
|
||||
self.sink.push(MissingFields {
|
||||
file: source_ptr.file_id,
|
||||
field_list: AstPtr::new(&field_list),
|
||||
missed_fields,
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
self.create_record_literal_missing_fields_diagnostic(
|
||||
id,
|
||||
db,
|
||||
variant_def,
|
||||
missed_fields,
|
||||
);
|
||||
}
|
||||
if let Expr::Match { expr, arms } = expr {
|
||||
self.validate_match(id, *expr, arms, db, self.infer.clone());
|
||||
}
|
||||
}
|
||||
for (id, pat) in body.pats.iter() {
|
||||
if let Some((variant_def, missed_fields, true)) =
|
||||
record_pattern_missing_fields(db, &self.infer, id, pat)
|
||||
{
|
||||
self.create_record_pattern_missing_fields_diagnostic(
|
||||
id,
|
||||
db,
|
||||
variant_def,
|
||||
missed_fields,
|
||||
);
|
||||
}
|
||||
}
|
||||
let body_expr = &body[body.body_expr];
|
||||
if let Expr::Block { tail: Some(t), .. } = body_expr {
|
||||
self.validate_results_in_tail_expr(body.body_expr, *t, db);
|
||||
}
|
||||
}
|
||||
|
||||
fn create_record_literal_missing_fields_diagnostic(
|
||||
&mut self,
|
||||
id: ExprId,
|
||||
db: &dyn HirDatabase,
|
||||
variant_def: VariantId,
|
||||
missed_fields: Vec<LocalStructFieldId>,
|
||||
) {
|
||||
// XXX: only look at source_map if we do have missing fields
|
||||
let (_, source_map) = db.body_with_source_map(self.func.into());
|
||||
|
||||
if let Ok(source_ptr) = source_map.expr_syntax(id) {
|
||||
if let Some(expr) = source_ptr.value.left() {
|
||||
let root = source_ptr.file_syntax(db.upcast());
|
||||
if let ast::Expr::RecordLit(record_lit) = expr.to_node(&root) {
|
||||
if let Some(field_list) = record_lit.record_field_list() {
|
||||
let variant_data = variant_data(db.upcast(), variant_def);
|
||||
let missed_fields = missed_fields
|
||||
.into_iter()
|
||||
.map(|idx| variant_data.fields()[idx].name.clone())
|
||||
.collect();
|
||||
self.sink.push(MissingFields {
|
||||
file: source_ptr.file_id,
|
||||
field_list: AstPtr::new(&field_list),
|
||||
missed_fields,
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn create_record_pattern_missing_fields_diagnostic(
|
||||
&mut self,
|
||||
id: PatId,
|
||||
db: &dyn HirDatabase,
|
||||
variant_def: VariantId,
|
||||
missed_fields: Vec<LocalStructFieldId>,
|
||||
) {
|
||||
// XXX: only look at source_map if we do have missing fields
|
||||
let (_, source_map) = db.body_with_source_map(self.func.into());
|
||||
|
||||
if let Ok(source_ptr) = source_map.pat_syntax(id) {
|
||||
if let Some(expr) = source_ptr.value.left() {
|
||||
let root = source_ptr.file_syntax(db.upcast());
|
||||
if let ast::Pat::RecordPat(record_pat) = expr.to_node(&root) {
|
||||
if let Some(field_list) = record_pat.record_field_pat_list() {
|
||||
let variant_data = variant_data(db.upcast(), variant_def);
|
||||
let missed_fields = missed_fields
|
||||
.into_iter()
|
||||
.map(|idx| variant_data.fields()[idx].name.clone())
|
||||
.collect();
|
||||
self.sink.push(MissingPatFields {
|
||||
file: source_ptr.file_id,
|
||||
field_list: AstPtr::new(&field_list),
|
||||
missed_fields,
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn validate_match(
|
||||
&mut self,
|
||||
id: ExprId,
|
||||
|
@ -232,9 +290,9 @@ pub fn record_pattern_missing_fields(
|
|||
infer: &InferenceResult,
|
||||
id: PatId,
|
||||
pat: &Pat,
|
||||
) -> Option<(VariantId, Vec<LocalStructFieldId>)> {
|
||||
let fields = match pat {
|
||||
Pat::Record { path: _, args } => args,
|
||||
) -> Option<(VariantId, Vec<LocalStructFieldId>, /*exhaustive*/ bool)> {
|
||||
let (fields, exhaustive) = match pat {
|
||||
Pat::Record { path: _, args, ellipsis } => (args, !ellipsis),
|
||||
_ => return None,
|
||||
};
|
||||
|
||||
|
@ -254,5 +312,5 @@ pub fn record_pattern_missing_fields(
|
|||
if missed_fields.is_empty() {
|
||||
return None;
|
||||
}
|
||||
Some((variant_def, missed_fields))
|
||||
Some((variant_def, missed_fields, exhaustive))
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue