1 //! This module contains `Diagnostic` and the types/functions it uses for deserialization.
2 
3 #[cfg(feature = "builder")]
4 use derive_builder::Builder;
5 use serde::{Deserialize, Serialize};
6 use std::fmt;
7 
8 /// The error code associated to this diagnostic.
9 #[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, Hash)]
10 #[cfg_attr(feature = "builder", derive(Builder))]
11 #[non_exhaustive]
12 #[cfg_attr(feature = "builder", builder(pattern = "owned", setter(into)))]
13 pub struct DiagnosticCode {
14     /// The code itself.
15     pub code: String,
16     /// An explanation for the code
17     pub explanation: Option<String>,
18 }
19 
20 /// A line of code associated with the Diagnostic
21 #[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, Hash)]
22 #[cfg_attr(feature = "builder", derive(Builder))]
23 #[non_exhaustive]
24 #[cfg_attr(feature = "builder", builder(pattern = "owned", setter(into)))]
25 pub struct DiagnosticSpanLine {
26     /// The line of code associated with the error
27     pub text: String,
28     /// Start of the section of the line to highlight. 1-based, character offset in self.text
29     pub highlight_start: usize,
30     /// End of the section of the line to highlight. 1-based, character offset in self.text
31     pub highlight_end: usize,
32 }
33 
34 /// Macro expansion information associated with a diagnostic.
35 #[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, Hash)]
36 #[cfg_attr(feature = "builder", derive(Builder))]
37 #[non_exhaustive]
38 #[cfg_attr(feature = "builder", builder(pattern = "owned", setter(into)))]
39 pub struct DiagnosticSpanMacroExpansion {
40     /// span where macro was applied to generate this code; note that
41     /// this may itself derive from a macro (if
42     /// `span.expansion.is_some()`)
43     pub span: DiagnosticSpan,
44 
45     /// name of macro that was applied (e.g., "foo!" or "#[derive(Eq)]")
46     pub macro_decl_name: String,
47 
48     /// span where macro was defined (if known)
49     pub def_site_span: Option<DiagnosticSpan>,
50 }
51 
52 /// A section of the source code associated with a Diagnostic
53 #[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, Hash)]
54 #[cfg_attr(feature = "builder", derive(Builder))]
55 #[non_exhaustive]
56 #[cfg_attr(feature = "builder", builder(pattern = "owned", setter(into)))]
57 pub struct DiagnosticSpan {
58     /// The file name or the macro name this diagnostic comes from.
59     pub file_name: String,
60     /// The byte offset in the file where this diagnostic starts from.
61     pub byte_start: u32,
62     /// The byte offset in the file where this diagnostic ends.
63     pub byte_end: u32,
64     /// 1-based. The line in the file.
65     pub line_start: usize,
66     /// 1-based. The line in the file.
67     pub line_end: usize,
68     /// 1-based, character offset.
69     pub column_start: usize,
70     /// 1-based, character offset.
71     pub column_end: usize,
72     /// Is this a "primary" span -- meaning the point, or one of the points,
73     /// where the error occurred?
74     ///
75     /// There are rare cases where multiple spans are marked as primary,
76     /// e.g. "immutable borrow occurs here" and "mutable borrow ends here" can
77     /// be two separate spans both "primary". Top (parent) messages should
78     /// always have at least one primary span, unless it has 0 spans. Child
79     /// messages may have 0 or more primary spans.
80     pub is_primary: bool,
81     /// Source text from the start of line_start to the end of line_end.
82     pub text: Vec<DiagnosticSpanLine>,
83     /// Label that should be placed at this location (if any)
84     pub label: Option<String>,
85     /// If we are suggesting a replacement, this will contain text
86     /// that should be sliced in atop this span.
87     pub suggested_replacement: Option<String>,
88     /// If the suggestion is approximate
89     pub suggestion_applicability: Option<Applicability>,
90     /// Macro invocations that created the code at this span, if any.
91     pub expansion: Option<Box<DiagnosticSpanMacroExpansion>>,
92 }
93 
94 /// Whether a suggestion can be safely applied.
95 #[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, Hash)]
96 #[non_exhaustive]
97 pub enum Applicability {
98     /// The suggested replacement can be applied automatically safely
99     MachineApplicable,
100     /// The suggested replacement has placeholders that will need to be manually
101     /// replaced.
102     HasPlaceholders,
103     /// The suggested replacement may be incorrect in some circumstances. Needs
104     /// human review.
105     MaybeIncorrect,
106     /// The suggested replacement will probably not work.
107     Unspecified,
108 }
109 
110 /// The diagnostic level
111 #[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq, Hash)]
112 #[non_exhaustive]
113 #[serde(rename_all = "lowercase")]
114 pub enum DiagnosticLevel {
115     /// Internal compiler error
116     #[serde(rename = "error: internal compiler error")]
117     Ice,
118     /// Error
119     Error,
120     /// Warning
121     Warning,
122     /// Failure note
123     #[serde(rename = "failure-note")]
124     FailureNote,
125     /// Note
126     Note,
127     /// Help
128     Help,
129 }
130 
131 /// A diagnostic message generated by rustc
132 #[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, Hash)]
133 #[cfg_attr(feature = "builder", derive(Builder))]
134 #[non_exhaustive]
135 #[cfg_attr(feature = "builder", builder(pattern = "owned", setter(into)))]
136 pub struct Diagnostic {
137     /// The error message of this diagnostic.
138     pub message: String,
139     /// The associated error code for this diagnostic
140     pub code: Option<DiagnosticCode>,
141     /// "error: internal compiler error", "error", "warning", "note", "help"
142     pub level: DiagnosticLevel,
143     /// A list of source code spans this diagnostic is associated with.
144     pub spans: Vec<DiagnosticSpan>,
145     /// Associated diagnostic messages.
146     pub children: Vec<Diagnostic>,
147     /// The message as rustc would render it
148     pub rendered: Option<String>,
149 }
150 
151 impl fmt::Display for Diagnostic {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result152     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
153         if let Some(ref rendered) = self.rendered {
154             f.write_str(rendered)?;
155         } else {
156             f.write_str("cargo didn't render this message")?;
157         }
158         Ok(())
159     }
160 }
161