Refactor the diagnostics

This commit is contained in:
Kirill Bulatov 2020-08-09 01:59:26 +03:00
parent cfbbd91a88
commit 9963f43d51
6 changed files with 106 additions and 136 deletions

View file

@ -7,7 +7,7 @@
use std::cell::RefCell;
use hir::{
diagnostics::{AstDiagnostic, Diagnostic as _, DiagnosticSinkBuilder},
diagnostics::{Diagnostic as _, DiagnosticSinkBuilder},
HasSource, HirDisplay, Semantics, VariantDef,
};
use itertools::Itertools;
@ -63,10 +63,10 @@ pub(crate) fn diagnostics(
.into(),
);
res.borrow_mut().push(Diagnostic {
range: sema.diagnostics_range(d).range,
range: sema.diagnostics_presentation_range(d).range,
message: d.message(),
severity: Severity::Error,
fix: Some((fix, sema.diagnostics_fix_range(d).range)),
fix: Some((fix, sema.diagnostic_fix_source(d).syntax().text_range())),
})
})
.on::<hir::diagnostics::MissingFields, _>(|d| {
@ -78,56 +78,58 @@ pub(crate) fn diagnostics(
let fix = if d.missed_fields.iter().any(|it| it.as_tuple_index().is_some()) {
None
} else {
let mut field_list = d.ast(db);
for f in d.missed_fields.iter() {
let field = make::record_expr_field(
make::name_ref(&f.to_string()),
Some(make::expr_unit()),
);
field_list = field_list.append_field(&field);
}
let record_expr = sema.diagnostic_fix_source(d);
if let Some(old_field_list) = record_expr.record_expr_field_list() {
let mut new_field_list = old_field_list.clone();
for f in d.missed_fields.iter() {
let field = make::record_expr_field(
make::name_ref(&f.to_string()),
Some(make::expr_unit()),
);
new_field_list = new_field_list.append_field(&field);
}
let edit = {
let mut builder = TextEditBuilder::default();
algo::diff(&d.ast(db).syntax(), &field_list.syntax())
.into_text_edit(&mut builder);
builder.finish()
};
Some((
Fix::new("Fill struct fields", SourceFileEdit { file_id, edit }.into()),
sema.diagnostics_fix_range(d).range,
))
let edit = {
let mut builder = TextEditBuilder::default();
algo::diff(&old_field_list.syntax(), &new_field_list.syntax())
.into_text_edit(&mut builder);
builder.finish()
};
Some((
Fix::new("Fill struct fields", SourceFileEdit { file_id, edit }.into()),
sema.original_range(&old_field_list.syntax()).range,
))
} else {
None
}
};
res.borrow_mut().push(Diagnostic {
range: sema.diagnostics_range(d).range,
range: sema.diagnostics_presentation_range(d).range,
message: d.message(),
severity: Severity::Error,
fix,
})
})
.on::<hir::diagnostics::MissingOkInTailExpr, _>(|d| {
let node = d.ast(db);
let replacement = format!("Ok({})", node.syntax());
let edit = TextEdit::replace(node.syntax().text_range(), replacement);
let tail_expr = sema.diagnostic_fix_source(d);
let tail_expr_range = tail_expr.syntax().text_range();
let edit = TextEdit::replace(tail_expr_range, format!("Ok({})", tail_expr.syntax()));
let source_change = SourceFileEdit { file_id, edit }.into();
res.borrow_mut().push(Diagnostic {
range: sema.diagnostics_range(d).range,
range: sema.diagnostics_presentation_range(d).range,
message: d.message(),
severity: Severity::Error,
fix: Some((
Fix::new("Wrap with ok", source_change),
sema.diagnostics_fix_range(d).range,
)),
fix: Some((Fix::new("Wrap with ok", source_change), tail_expr_range)),
})
})
.on::<hir::diagnostics::NoSuchField, _>(|d| {
res.borrow_mut().push(Diagnostic {
range: sema.diagnostics_range(d).range,
range: sema.diagnostics_presentation_range(d).range,
message: d.message(),
severity: Severity::Error,
fix: missing_struct_field_fix(&sema, file_id, d)
.map(|fix| (fix, sema.diagnostics_fix_range(d).range)),
.map(|fix| (fix, sema.diagnostic_fix_source(d).syntax().text_range())),
})
})
// Only collect experimental diagnostics when they're enabled.
@ -136,7 +138,7 @@ pub(crate) fn diagnostics(
.build(|d| {
res.borrow_mut().push(Diagnostic {
message: d.message(),
range: sema.diagnostics_range(d).range,
range: sema.diagnostics_presentation_range(d).range,
severity: Severity::Error,
fix: None,
})
@ -154,9 +156,9 @@ fn missing_struct_field_fix(
usage_file_id: FileId,
d: &hir::diagnostics::NoSuchField,
) -> Option<Fix> {
let record_expr = sema.ast(d);
let record_expr_field = sema.diagnostic_fix_source(d);
let record_lit = ast::RecordExpr::cast(record_expr.syntax().parent()?.parent()?)?;
let record_lit = ast::RecordExpr::cast(record_expr_field.syntax().parent()?.parent()?)?;
let def_id = sema.resolve_variant(record_lit)?;
let module;
let def_file_id;
@ -184,12 +186,12 @@ fn missing_struct_field_fix(
};
let def_file_id = def_file_id.original_file(sema.db);
let new_field_type = sema.type_of_expr(&record_expr.expr()?)?;
let new_field_type = sema.type_of_expr(&record_expr_field.expr()?)?;
if new_field_type.is_unknown() {
return None;
}
let new_field = make::record_field(
record_expr.field_name()?,
record_expr_field.field_name()?,
make::ty(&new_field_type.display_source_code(sema.db, module.into()).ok()?),
);