use crate::{
Diagnostic, Reporter, Severity, Suggestion,
intelligence::{
cause_chain_from_sources, find_io_error_in_sources, io::suggestion as io_suggestion,
},
};
use std::error::Error;
pub trait DiagnosticMetadata {
fn diagnostic_severity(&self) -> Severity {
Severity::Error
}
fn diagnostic_code(&self) -> Option<String> {
None
}
fn diagnostic_help(&self) -> Option<String> {
None
}
fn diagnostic_notes(&self) -> Vec<String> {
Vec::new()
}
fn diagnostic_suggestions(&self) -> Vec<Suggestion> {
Vec::new()
}
}
pub trait DiagnosticErrorExt: Error + DiagnosticMetadata + 'static {
fn to_diagprint(&self, reporter: &Reporter) -> Diagnostic {
reporter.diagnostic_from_typed_error(self)
}
}
impl<T> DiagnosticErrorExt for T where T: Error + DiagnosticMetadata + 'static + ?Sized {}
impl Reporter {
pub fn diagnostic_from_typed_error<E>(&self, error: &E) -> Diagnostic
where
E: Error + DiagnosticMetadata + 'static + ?Sized,
{
let mut diagnostic = self.diagnostic(error.diagnostic_severity(), error.to_string());
if let Some(code) = error.diagnostic_code() {
diagnostic = diagnostic.code(code);
}
if let Some(help) = error.diagnostic_help() {
diagnostic = diagnostic.help(help);
}
for note in error.diagnostic_notes() {
diagnostic = diagnostic.note(note);
}
if let Some(cause) = cause_chain_from_sources(error) {
diagnostic = diagnostic.cause_chain(cause);
}
let mut suggestions = error.diagnostic_suggestions();
if let Some(io_error) = find_io_error_in_sources(error) {
let inferred = io_suggestion(io_error);
let duplicate = suggestions
.iter()
.any(|existing| existing.title == inferred.title);
if !duplicate {
suggestions.push(inferred);
}
}
diagnostic.suggestions(suggestions)
}
}