use runestick::{SourceId, Span};
mod error;
mod warning;
pub use self::error::{Error, ErrorKind};
pub use self::warning::{Warning, WarningKind};
#[derive(Debug)]
pub enum Diagnostic {
Error(Error),
Warning(Warning),
}
#[derive(Debug, Clone, Copy)]
enum DiagnosticsMode {
All,
WithoutWarnings,
}
impl DiagnosticsMode {
fn warnings(self) -> bool {
matches!(self, Self::All)
}
}
#[derive(Debug)]
pub struct Diagnostics {
diagnostics: Vec<Diagnostic>,
mode: DiagnosticsMode,
last_error: Option<usize>,
last_warning: Option<usize>,
}
impl Diagnostics {
fn with_mode(mode: DiagnosticsMode) -> Self {
Self {
diagnostics: Vec::new(),
mode,
last_error: None,
last_warning: None,
}
}
pub fn without_warnings() -> Self {
Self::with_mode(DiagnosticsMode::WithoutWarnings)
}
pub fn new() -> Self {
Self::default()
}
pub fn is_empty(&self) -> bool {
self.diagnostics.is_empty()
}
pub fn has_error(&self) -> bool {
self.last_error.is_some()
}
pub fn has_warning(&self) -> bool {
self.last_warning.is_some()
}
pub fn diagnostics(&self) -> &[Diagnostic] {
&self.diagnostics
}
pub fn into_diagnostics(self) -> Vec<Diagnostic> {
self.diagnostics
}
pub(crate) fn internal(&mut self, source_id: SourceId, message: &'static str) {
self.error(source_id, ErrorKind::Internal(message));
}
pub fn not_used(&mut self, source_id: usize, span: Span, context: Option<Span>) {
self.warning(source_id, WarningKind::NotUsed { span, context });
}
pub fn let_pattern_might_panic(&mut self, source_id: usize, span: Span, context: Option<Span>) {
self.warning(
source_id,
WarningKind::LetPatternMightPanic { span, context },
);
}
pub fn template_without_expansions(
&mut self,
source_id: usize,
span: Span,
context: Option<Span>,
) {
self.warning(
source_id,
WarningKind::TemplateWithoutExpansions { span, context },
);
}
pub fn remove_tuple_call_parens(
&mut self,
source_id: usize,
span: Span,
variant: Span,
context: Option<Span>,
) {
self.warning(
source_id,
WarningKind::RemoveTupleCallParams {
span,
variant,
context,
},
);
}
pub fn uneccessary_semi_colon(&mut self, source_id: usize, span: Span) {
self.warning(source_id, WarningKind::UnecessarySemiColon { span });
}
pub fn warning<T>(&mut self, source_id: SourceId, kind: T)
where
WarningKind: From<T>,
{
if !self.mode.warnings() {
return;
}
let current = Some(self.diagnostics.len());
self.diagnostics.push(Diagnostic::Warning(Warning {
last: self.last_warning,
source_id,
kind: kind.into(),
}));
self.last_warning = current;
}
pub fn error<T>(&mut self, source_id: SourceId, kind: T)
where
ErrorKind: From<T>,
{
let current = Some(self.diagnostics.len());
self.diagnostics.push(Diagnostic::Error(Error {
last: self.last_error,
source_id,
kind: Box::new(kind.into()),
}));
self.last_error = current;
}
}
impl Default for Diagnostics {
fn default() -> Self {
Self::with_mode(DiagnosticsMode::All)
}
}