pub(crate) mod silent_emitter;
use std::cell::RefCell;
use rustc_errors::{Diagnostic, TRACK_DIAGNOSTICS};
use rustc_hir::def_id::LocalDefId;
use rustc_span::Span;
thread_local! {
static BODY_DIAGNOSTICS: RefCell<Vec<DiagnosticInfo>> = RefCell::new(Vec::default());
static CURRENT_BODY: RefCell<Option<LocalDefId>> = RefCell::new(None);
}
#[derive(Copy, Clone, Debug, Eq, Hash, PartialEq)]
struct DiagnosticInfo {
primary_span: Span,
is_error: bool,
}
fn track_diagnostic(d: &mut Diagnostic, f: &mut dyn FnMut(&mut Diagnostic)) {
BODY_DIAGNOSTICS.with(|diagnostics| {
let mut diagnostics = diagnostics.borrow_mut();
let d = DiagnosticInfo {
primary_span: d.sort_span,
is_error: d.is_error(),
};
diagnostics.push(d);
});
(*f)(d);
}
pub fn initialize_error_tracking() {
log::debug!("Track diagnostics updated");
TRACK_DIAGNOSTICS.swap(&(track_diagnostic as _));
}
pub fn track_body_diagnostics(def_id: LocalDefId) {
CURRENT_BODY.with(|id| {
let mut id = id.borrow_mut();
let old_value = id.replace(def_id);
log::debug!("Replacing tracked body id {old_value:?} with {def_id:?}");
});
BODY_DIAGNOSTICS.with(|diagnostics| {
let mut diagnostics = diagnostics.borrow_mut();
diagnostics.clear();
});
}
pub fn errors_exist() -> bool {
BODY_DIAGNOSTICS.with(|diagnostics| !diagnostics.borrow().is_empty())
}
pub fn get_span_of_first_error(def_id: LocalDefId) -> Option<Span> {
CURRENT_BODY.with(|id| {
assert_eq!(def_id, id.borrow().unwrap());
});
BODY_DIAGNOSTICS.with(|diagnostics| {
let diagnostics = diagnostics.borrow();
log::debug!("Diagnostics {:?}", diagnostics);
diagnostics
.iter()
.filter_map(|d| d.is_error.then_some(d.primary_span))
.min_by_key(|s| s.lo())
})
}