blob: 2bb8ada90277761d9f8fd7852dcd7e9b9b441e91 [file] [log] [blame]
//! Diagnostic reporting support for the codespan crate
use codespan::FileSpan;
#[cfg(feature = "serialization")]
use serde::{Deserialize, Serialize};
use std::cmp::Ordering;
/// A severity level for diagnostic messages.
///
/// These are ordered in the following way:
///
/// ```rust
/// use codespan_reporting::Severity;
///
/// assert!(Severity::Bug > Severity::Error);
/// assert!(Severity::Error > Severity::Warning);
/// assert!(Severity::Warning > Severity::Note);
/// assert!(Severity::Note > Severity::Help);
/// ```
#[derive(Copy, Clone, PartialEq, Hash, Debug)]
#[cfg_attr(feature = "memory_usage", derive(heapsize_derive::HeapSizeOf))]
#[cfg_attr(feature = "serialization", derive(Serialize, Deserialize))]
pub enum Severity {
/// An unexpected bug.
Bug,
/// An error.
Error,
/// A warning.
Warning,
/// A note.
Note,
/// A help message.
Help,
}
impl Severity {
/// We want bugs to be the maximum severity, errors next, etc...
fn to_cmp_int(self) -> u8 {
match self {
Severity::Bug => 5,
Severity::Error => 4,
Severity::Warning => 3,
Severity::Note => 2,
Severity::Help => 1,
}
}
}
impl PartialOrd for Severity {
fn partial_cmp(&self, other: &Severity) -> Option<Ordering> {
u8::partial_cmp(&self.to_cmp_int(), &other.to_cmp_int())
}
}
/// A label describing an underlined region of code associated with a diagnostic.
#[derive(Clone, Debug)]
#[cfg_attr(feature = "memory_usage", derive(heapsize_derive::HeapSizeOf))]
#[cfg_attr(feature = "serialization", derive(Serialize, Deserialize))]
pub struct Label {
/// The span we are going to include in the final snippet.
pub file_span: FileSpan,
/// A message to provide some additional information for the underlined
/// code. This could be a multi-line string.
pub message: String,
}
impl Label {
/// Create a new label.
pub fn new(file_span: FileSpan, message: impl Into<String>) -> Label {
Label {
file_span,
message: message.into(),
}
}
}
/// Represents a diagnostic message that can provide information like errors and
/// warnings to the user.
#[derive(Clone, Debug)]
#[cfg_attr(feature = "memory_usage", derive(heapsize_derive::HeapSizeOf))]
#[cfg_attr(feature = "serialization", derive(Serialize, Deserialize))]
pub struct Diagnostic {
/// The overall severity of the diagnostic
pub severity: Severity,
/// An optional code that identifies this diagnostic.
pub code: Option<String>,
/// The main message associated with this diagnostic.
pub message: String,
/// A label that describes the primary cause of this diagnostic.
pub primary_label: Label,
/// Secondary labels that provide additional context for the diagnostic.
pub secondary_labels: Vec<Label>,
}
impl Diagnostic {
/// Create a new diagnostic.
pub fn new(severity: Severity, message: impl Into<String>, primary_label: Label) -> Diagnostic {
Diagnostic {
severity,
code: None,
message: message.into(),
primary_label,
secondary_labels: Vec::new(),
}
}
/// Create a new diagnostic with a severity of `Severity::Bug`.
pub fn new_bug(message: impl Into<String>, primary_label: Label) -> Diagnostic {
Diagnostic::new(Severity::Bug, message, primary_label)
}
/// Create a new diagnostic with a severity of `Severity::Error`.
pub fn new_error(message: impl Into<String>, primary_label: Label) -> Diagnostic {
Diagnostic::new(Severity::Error, message, primary_label)
}
/// Create a new diagnostic with a severity of `Severity::Warning`.
pub fn new_warning(message: impl Into<String>, primary_label: Label) -> Diagnostic {
Diagnostic::new(Severity::Warning, message, primary_label)
}
/// Create a new diagnostic with a severity of `Severity::Note`.
pub fn new_note(message: impl Into<String>, primary_label: Label) -> Diagnostic {
Diagnostic::new(Severity::Note, message, primary_label)
}
/// Create a new diagnostic with a severity of `Severity::Help`.
pub fn new_help(message: impl Into<String>, primary_label: Label) -> Diagnostic {
Diagnostic::new(Severity::Help, message, primary_label)
}
/// Add an error code to the diagnostic.
pub fn with_code(mut self, code: impl Into<String>) -> Diagnostic {
self.code = Some(code.into());
self
}
/// Add some secondary labels to the diagnostic.
pub fn with_secondary_labels(mut self, labels: impl IntoIterator<Item = Label>) -> Diagnostic {
self.secondary_labels.extend(labels);
self
}
}