7 use syntax_pos::{MultiSpan, Span};
11 #[derive(Clone, Debug, PartialEq, Hash, RustcEncodable, RustcDecodable)]
12 pub struct Diagnostic {
14 pub message: Vec<(String, Style)>,
15 pub code: Option<DiagnosticId>,
17 pub children: Vec<SubDiagnostic>,
18 pub suggestions: Vec<CodeSuggestion>,
21 #[derive(Clone, Debug, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)]
22 pub enum DiagnosticId {
27 /// For example a note attached to an error.
28 #[derive(Clone, Debug, PartialEq, Hash, RustcEncodable, RustcDecodable)]
29 pub struct SubDiagnostic {
31 pub message: Vec<(String, Style)>,
33 pub render_span: Option<MultiSpan>,
36 #[derive(PartialEq, Eq)]
37 pub struct DiagnosticStyledString(pub Vec<StringPart>);
39 impl DiagnosticStyledString {
40 pub fn new() -> DiagnosticStyledString {
41 DiagnosticStyledString(vec![])
43 pub fn push_normal<S: Into<String>>(&mut self, t: S) {
44 self.0.push(StringPart::Normal(t.into()));
46 pub fn push_highlighted<S: Into<String>>(&mut self, t: S) {
47 self.0.push(StringPart::Highlighted(t.into()));
49 pub fn normal<S: Into<String>>(t: S) -> DiagnosticStyledString {
50 DiagnosticStyledString(vec![StringPart::Normal(t.into())])
53 pub fn highlighted<S: Into<String>>(t: S) -> DiagnosticStyledString {
54 DiagnosticStyledString(vec![StringPart::Highlighted(t.into())])
57 pub fn content(&self) -> String {
58 self.0.iter().map(|x| x.content()).collect::<String>()
62 #[derive(PartialEq, Eq)]
69 pub fn content(&self) -> &str {
71 &StringPart::Normal(ref s) | & StringPart::Highlighted(ref s) => s
77 pub fn new(level: Level, message: &str) -> Self {
78 Diagnostic::new_with_code(level, None, message)
81 pub fn new_with_code(level: Level, code: Option<DiagnosticId>, message: &str) -> Self {
84 message: vec![(message.to_owned(), Style::NoStyle)],
86 span: MultiSpan::new(),
92 pub fn is_error(&self) -> bool {
98 Level::FailureNote => {
105 Level::Cancelled => {
111 /// Cancel the diagnostic (a structured diagnostic must either be emitted or
112 /// canceled or it will panic when dropped).
113 pub fn cancel(&mut self) {
114 self.level = Level::Cancelled;
117 pub fn cancelled(&self) -> bool {
118 self.level == Level::Cancelled
121 /// Add a span/label to be included in the resulting snippet.
122 /// This is pushed onto the `MultiSpan` that was created when the
123 /// diagnostic was first built. If you don't call this function at
124 /// all, and you just supplied a `Span` to create the diagnostic,
125 /// then the snippet will just include that `Span`, which is
126 /// called the primary span.
127 pub fn span_label<T: Into<String>>(&mut self, span: Span, label: T) -> &mut Self {
128 self.span.push_span_label(span, label.into());
132 pub fn replace_span_with(&mut self, after: Span) -> &mut Self {
133 let before = self.span.clone();
134 self.set_span(after);
135 for span_label in before.span_labels() {
136 if let Some(label) = span_label.label {
137 self.span_label(after, label);
143 pub fn note_expected_found(&mut self,
144 label: &dyn fmt::Display,
145 expected: DiagnosticStyledString,
146 found: DiagnosticStyledString)
149 self.note_expected_found_extra(label, expected, found, &"", &"")
152 pub fn note_expected_found_extra(&mut self,
153 label: &dyn fmt::Display,
154 expected: DiagnosticStyledString,
155 found: DiagnosticStyledString,
156 expected_extra: &dyn fmt::Display,
157 found_extra: &dyn fmt::Display)
160 let mut msg: Vec<_> = vec![(format!("expected {} `", label), Style::NoStyle)];
161 msg.extend(expected.0.iter()
163 StringPart::Normal(ref s) => (s.to_owned(), Style::NoStyle),
164 StringPart::Highlighted(ref s) => (s.to_owned(), Style::Highlight),
166 msg.push((format!("`{}\n", expected_extra), Style::NoStyle));
167 msg.push((format!(" found {} `", label), Style::NoStyle));
168 msg.extend(found.0.iter()
170 StringPart::Normal(ref s) => (s.to_owned(), Style::NoStyle),
171 StringPart::Highlighted(ref s) => (s.to_owned(), Style::Highlight),
173 msg.push((format!("`{}", found_extra), Style::NoStyle));
175 // For now, just attach these as notes
176 self.highlighted_note(msg);
180 pub fn note_trait_signature(&mut self, name: String, signature: String) -> &mut Self {
181 self.highlighted_note(vec![
182 (format!("`{}` from trait: `", name), Style::NoStyle),
183 (signature, Style::Highlight),
184 ("`".to_string(), Style::NoStyle)]);
188 pub fn note(&mut self, msg: &str) -> &mut Self {
189 self.sub(Level::Note, msg, MultiSpan::new(), None);
193 pub fn highlighted_note(&mut self, msg: Vec<(String, Style)>) -> &mut Self {
194 self.sub_with_highlights(Level::Note, msg, MultiSpan::new(), None);
198 pub fn span_note<S: Into<MultiSpan>>(&mut self,
202 self.sub(Level::Note, msg, sp.into(), None);
206 pub fn warn(&mut self, msg: &str) -> &mut Self {
207 self.sub(Level::Warning, msg, MultiSpan::new(), None);
211 pub fn span_warn<S: Into<MultiSpan>>(&mut self,
215 self.sub(Level::Warning, msg, sp.into(), None);
219 pub fn help(&mut self , msg: &str) -> &mut Self {
220 self.sub(Level::Help, msg, MultiSpan::new(), None);
224 pub fn span_help<S: Into<MultiSpan>>(&mut self,
228 self.sub(Level::Help, msg, sp.into(), None);
232 pub fn multipart_suggestion(
235 suggestion: Vec<(Span, String)>,
236 applicability: Applicability,
238 self.suggestions.push(CodeSuggestion {
239 substitutions: vec![Substitution {
242 .map(|(span, snippet)| SubstitutionPart { snippet, span })
246 show_code_when_inline: true,
252 /// Prints out a message with a suggested edit of the code.
254 /// In case of short messages and a simple suggestion, rustc displays it as a label:
257 /// try adding parentheses: `(tup.0).1`
262 /// * should not end in any punctuation (a `:` is added automatically)
263 /// * should not be a question (avoid language like "did you mean")
264 /// * should not contain any phrases like "the following", "as shown", etc.
265 /// * may look like "to do xyz, use" or "to do xyz, use abc"
266 /// * may contain a name of a function, variable, or type, but not whole expressions
268 /// See `CodeSuggestion` for more information.
269 pub fn span_suggestion(&mut self, sp: Span, msg: &str,
271 applicability: Applicability) -> &mut Self {
272 self.suggestions.push(CodeSuggestion {
273 substitutions: vec![Substitution {
274 parts: vec![SubstitutionPart {
280 show_code_when_inline: true,
286 /// Prints out a message with multiple suggested edits of the code.
287 pub fn span_suggestions(&mut self, sp: Span, msg: &str,
288 suggestions: impl Iterator<Item = String>, applicability: Applicability) -> &mut Self
290 self.suggestions.push(CodeSuggestion {
291 substitutions: suggestions.map(|snippet| Substitution {
292 parts: vec![SubstitutionPart {
298 show_code_when_inline: true,
304 /// Prints out a message with a suggested edit of the code. If the suggestion is presented
305 /// inline, it will only show the message and not the suggestion.
307 /// See `CodeSuggestion` for more information.
308 pub fn span_suggestion_short(
309 &mut self, sp: Span, msg: &str, suggestion: String, applicability: Applicability
311 self.suggestions.push(CodeSuggestion {
312 substitutions: vec![Substitution {
313 parts: vec![SubstitutionPart {
319 show_code_when_inline: false,
320 applicability: applicability,
325 pub fn set_span<S: Into<MultiSpan>>(&mut self, sp: S) -> &mut Self {
326 self.span = sp.into();
330 pub fn code(&mut self, s: DiagnosticId) -> &mut Self {
335 pub fn get_code(&self) -> Option<DiagnosticId> {
339 pub fn message(&self) -> String {
340 self.message.iter().map(|i| i.0.as_str()).collect::<String>()
343 pub fn styled_message(&self) -> &Vec<(String, Style)> {
347 /// Used by a lint. Copies over all details *but* the "main
349 pub fn copy_details_not_message(&mut self, from: &Diagnostic) {
350 self.span = from.span.clone();
351 self.code = from.code.clone();
352 self.children.extend(from.children.iter().cloned())
355 /// Convenience function for internal use, clients should use one of the
356 /// public methods above.
357 pub fn sub(&mut self,
361 render_span: Option<MultiSpan>) {
362 let sub = SubDiagnostic {
364 message: vec![(message.to_owned(), Style::NoStyle)],
368 self.children.push(sub);
371 /// Convenience function for internal use, clients should use one of the
372 /// public methods above.
373 fn sub_with_highlights(&mut self,
375 message: Vec<(String, Style)>,
377 render_span: Option<MultiSpan>) {
378 let sub = SubDiagnostic {
384 self.children.push(sub);
389 pub fn message(&self) -> String {
390 self.message.iter().map(|i| i.0.as_str()).collect::<String>()
393 pub fn styled_message(&self) -> &Vec<(String, Style)> {