1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
//! This module contains `Diagnostic` and the types/functions it uses for deserialization.

#[cfg(feature = "builder")]
use derive_builder::Builder;
use serde::{Deserialize, Serialize};
use std::fmt;

/// The error code associated to this diagnostic.
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "builder", derive(Builder))]
#[non_exhaustive]
#[cfg_attr(feature = "builder", builder(pattern = "owned", setter(into)))]
pub struct DiagnosticCode {
    /// The code itself.
    pub code: String,
    /// An explanation for the code
    pub explanation: Option<String>,
}

/// A line of code associated with the Diagnostic
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "builder", derive(Builder))]
#[non_exhaustive]
#[cfg_attr(feature = "builder", builder(pattern = "owned", setter(into)))]
pub struct DiagnosticSpanLine {
    /// The line of code associated with the error
    pub text: String,
    /// Start of the section of the line to highlight. 1-based, character offset in self.text
    pub highlight_start: usize,
    /// End of the section of the line to highlight. 1-based, character offset in self.text
    pub highlight_end: usize,
}

/// Macro expansion information associated with a diagnostic.
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "builder", derive(Builder))]
#[non_exhaustive]
#[cfg_attr(feature = "builder", builder(pattern = "owned", setter(into)))]
pub struct DiagnosticSpanMacroExpansion {
    /// span where macro was applied to generate this code; note that
    /// this may itself derive from a macro (if
    /// `span.expansion.is_some()`)
    pub span: DiagnosticSpan,

    /// name of macro that was applied (e.g., "foo!" or "#[derive(Eq)]")
    pub macro_decl_name: String,

    /// span where macro was defined (if known)
    pub def_site_span: Option<DiagnosticSpan>,
}

/// A section of the source code associated with a Diagnostic
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "builder", derive(Builder))]
#[non_exhaustive]
#[cfg_attr(feature = "builder", builder(pattern = "owned", setter(into)))]
pub struct DiagnosticSpan {
    /// The file name or the macro name this diagnostic comes from.
    pub file_name: String,
    /// The byte offset in the file where this diagnostic starts from.
    pub byte_start: u32,
    /// The byte offset in the file where this diagnostic ends.
    pub byte_end: u32,
    /// 1-based. The line in the file.
    pub line_start: usize,
    /// 1-based. The line in the file.
    pub line_end: usize,
    /// 1-based, character offset.
    pub column_start: usize,
    /// 1-based, character offset.
    pub column_end: usize,
    /// Is this a "primary" span -- meaning the point, or one of the points,
    /// where the error occurred?
    ///
    /// There are rare cases where multiple spans are marked as primary,
    /// e.g. "immutable borrow occurs here" and "mutable borrow ends here" can
    /// be two separate spans both "primary". Top (parent) messages should
    /// always have at least one primary span, unless it has 0 spans. Child
    /// messages may have 0 or more primary spans.
    pub is_primary: bool,
    /// Source text from the start of line_start to the end of line_end.
    pub text: Vec<DiagnosticSpanLine>,
    /// Label that should be placed at this location (if any)
    pub label: Option<String>,
    /// If we are suggesting a replacement, this will contain text
    /// that should be sliced in atop this span.
    pub suggested_replacement: Option<String>,
    /// If the suggestion is approximate
    pub suggestion_applicability: Option<Applicability>,
    /// Macro invocations that created the code at this span, if any.
    pub expansion: Option<Box<DiagnosticSpanMacroExpansion>>,
}

/// Whether a suggestion can be safely applied.
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, Hash)]
#[non_exhaustive]
pub enum Applicability {
    /// The suggested replacement can be applied automatically safely
    MachineApplicable,
    /// The suggested replacement has placeholders that will need to be manually
    /// replaced.
    HasPlaceholders,
    /// The suggested replacement may be incorrect in some circumstances. Needs
    /// human review.
    MaybeIncorrect,
    /// The suggested replacement will probably not work.
    Unspecified,
}

/// The diagnostic level
#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq, Hash)]
#[non_exhaustive]
#[serde(rename_all = "lowercase")]
pub enum DiagnosticLevel {
    /// Internal compiler error
    #[serde(rename = "error: internal compiler error")]
    Ice,
    /// Error
    Error,
    /// Warning
    Warning,
    /// Failure note
    #[serde(rename = "failure-note")]
    FailureNote,
    /// Note
    Note,
    /// Help
    Help,
}

/// A diagnostic message generated by rustc
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "builder", derive(Builder))]
#[non_exhaustive]
#[cfg_attr(feature = "builder", builder(pattern = "owned", setter(into)))]
pub struct Diagnostic {
    /// The error message of this diagnostic.
    pub message: String,
    /// The associated error code for this diagnostic
    pub code: Option<DiagnosticCode>,
    /// "error: internal compiler error", "error", "warning", "note", "help"
    pub level: DiagnosticLevel,
    /// A list of source code spans this diagnostic is associated with.
    pub spans: Vec<DiagnosticSpan>,
    /// Associated diagnostic messages.
    pub children: Vec<Diagnostic>,
    /// The message as rustc would render it
    pub rendered: Option<String>,
}

impl fmt::Display for Diagnostic {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        if let Some(ref rendered) = self.rendered {
            f.write_str(rendered)?;
        } else {
            f.write_str("cargo didn't render this message")?;
        }
        Ok(())
    }
}