kodept_macros/error/
report.rs

1use std::convert::Infallible;
2
3use codespan_reporting::diagnostic::{Diagnostic, Label};
4pub use codespan_reporting::diagnostic::Severity;
5
6use kodept_core::code_point::CodePoint;
7use kodept_core::file_relative::CodePath;
8
9#[derive(Debug)]
10pub struct ReportMessage {
11    pub severity: Severity,
12    pub code: String,
13    pub message: String,
14    pub additional_message: String,
15    pub notes: Vec<String>
16}
17
18#[derive(Debug)]
19pub struct Report {
20    diagnostic: Diagnostic<()>,
21}
22
23impl ReportMessage {
24    pub fn new<S: Into<String>>(severity: Severity, code: S, message: String) -> Self {
25        Self {
26            severity,
27            code: code.into(),
28            message,
29            additional_message: "here".to_string(),
30            notes: vec![]
31        }
32    }
33
34    #[must_use]
35    pub fn with_additional_message(self, additional_message: String) -> Self {
36        Self {
37            additional_message,
38            ..self
39        }
40    }
41    
42    pub fn with_notes(self, notes: Vec<String>) -> Self {
43        Self {
44            notes,
45            ..self
46        }
47    }
48}
49
50impl Report {
51    #[must_use]
52    pub const fn is_error(&self) -> bool {
53        matches!(self.diagnostic.severity, Severity::Error | Severity::Bug)
54    }
55
56    pub fn new<R: Into<ReportMessage>>(
57        _file: &CodePath,
58        points: Vec<CodePoint>,
59        message: R,
60    ) -> Self {
61        let msg = message.into();
62        let diagnostic = Diagnostic::new(msg.severity)
63            .with_code(msg.code)
64            .with_message(msg.message)
65            .with_notes(msg.notes);
66        let diagnostic = if let [p] = points.as_slice() {
67            diagnostic.with_labels(vec![Label::primary((), p.as_range())])
68        } else if let [p, s @ ..] = points.as_slice() {
69            let mut secondaries: Vec<_> = s
70                .iter()
71                .map(|it| Label::secondary((), it.as_range()))
72                .collect();
73            secondaries.insert(0, Label::primary((), p.as_range()));
74            diagnostic.with_labels(secondaries)
75        } else {
76            diagnostic
77        };
78        Self { diagnostic }
79    }
80
81    pub fn into_diagnostic(self) -> Diagnostic<()> {
82        self.diagnostic
83    }
84}
85
86impl From<Infallible> for ReportMessage {
87    fn from(_: Infallible) -> Self {
88        unreachable!()
89    }
90}