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 /// Prints out a message with a suggested edit of the code. If the suggestion is presented
233 /// inline it will only show the text message and not the text.
235 /// See `CodeSuggestion` for more information.
236 #[deprecated(note = "Use `span_suggestion_short_with_applicability`")]
237 pub fn span_suggestion_short(&mut self, sp: Span, msg: &str, suggestion: String) -> &mut Self {
238 self.suggestions.push(CodeSuggestion {
239 substitutions: vec![Substitution {
240 parts: vec![SubstitutionPart {
246 show_code_when_inline: false,
247 applicability: Applicability::Unspecified,
252 /// Prints out a message with a suggested edit of the code.
254 /// In case of short messages and a simple suggestion,
255 /// rustc displays it as a label like
257 /// "try adding parentheses: `(tup.0).1`"
261 /// * should not end in any punctuation (a `:` is added automatically)
262 /// * should not be a question
263 /// * should not contain any parts like "the following", "as shown"
264 /// * may look like "to do xyz, use" or "to do xyz, use abc"
265 /// * may contain a name of a function, variable or type, but not whole expressions
267 /// See `CodeSuggestion` for more information.
268 #[deprecated(note = "Use `span_suggestion_with_applicability`")]
269 pub fn span_suggestion(&mut self, sp: Span, msg: &str, suggestion: String) -> &mut Self {
270 self.suggestions.push(CodeSuggestion {
271 substitutions: vec![Substitution {
272 parts: vec![SubstitutionPart {
278 show_code_when_inline: true,
279 applicability: Applicability::Unspecified,
284 pub fn multipart_suggestion_with_applicability(
287 suggestion: Vec<(Span, String)>,
288 applicability: Applicability,
290 self.suggestions.push(CodeSuggestion {
291 substitutions: vec![Substitution {
294 .map(|(span, snippet)| SubstitutionPart { snippet, span })
298 show_code_when_inline: true,
304 #[deprecated(note = "Use `multipart_suggestion_with_applicability`")]
305 pub fn multipart_suggestion(
308 suggestion: Vec<(Span, String)>,
310 self.multipart_suggestion_with_applicability(
313 Applicability::Unspecified,
317 /// Prints out a message with multiple suggested edits of the code.
318 #[deprecated(note = "Use `span_suggestions_with_applicability`")]
319 pub fn span_suggestions(&mut self, sp: Span, msg: &str, suggestions: Vec<String>) -> &mut Self {
320 self.suggestions.push(CodeSuggestion {
321 substitutions: suggestions.into_iter().map(|snippet| Substitution {
322 parts: vec![SubstitutionPart {
328 show_code_when_inline: true,
329 applicability: Applicability::Unspecified,
334 /// This is a suggestion that may contain mistakes or fillers and should
335 /// be read and understood by a human.
336 pub fn span_suggestion_with_applicability(&mut self, sp: Span, msg: &str,
338 applicability: Applicability) -> &mut Self {
339 self.suggestions.push(CodeSuggestion {
340 substitutions: vec![Substitution {
341 parts: vec![SubstitutionPart {
347 show_code_when_inline: true,
353 pub fn span_suggestions_with_applicability(&mut self, sp: Span, msg: &str,
354 suggestions: impl Iterator<Item = String>, applicability: Applicability) -> &mut Self
356 self.suggestions.push(CodeSuggestion {
357 substitutions: suggestions.map(|snippet| Substitution {
358 parts: vec![SubstitutionPart {
364 show_code_when_inline: true,
370 pub fn span_suggestion_short_with_applicability(
371 &mut self, sp: Span, msg: &str, suggestion: String, applicability: Applicability
373 self.suggestions.push(CodeSuggestion {
374 substitutions: vec![Substitution {
375 parts: vec![SubstitutionPart {
381 show_code_when_inline: false,
382 applicability: applicability,
387 pub fn set_span<S: Into<MultiSpan>>(&mut self, sp: S) -> &mut Self {
388 self.span = sp.into();
392 pub fn code(&mut self, s: DiagnosticId) -> &mut Self {
397 pub fn get_code(&self) -> Option<DiagnosticId> {
401 pub fn message(&self) -> String {
402 self.message.iter().map(|i| i.0.as_str()).collect::<String>()
405 pub fn styled_message(&self) -> &Vec<(String, Style)> {
409 /// Used by a lint. Copies over all details *but* the "main
411 pub fn copy_details_not_message(&mut self, from: &Diagnostic) {
412 self.span = from.span.clone();
413 self.code = from.code.clone();
414 self.children.extend(from.children.iter().cloned())
417 /// Convenience function for internal use, clients should use one of the
418 /// public methods above.
419 pub fn sub(&mut self,
423 render_span: Option<MultiSpan>) {
424 let sub = SubDiagnostic {
426 message: vec![(message.to_owned(), Style::NoStyle)],
430 self.children.push(sub);
433 /// Convenience function for internal use, clients should use one of the
434 /// public methods above.
435 fn sub_with_highlights(&mut self,
437 message: Vec<(String, Style)>,
439 render_span: Option<MultiSpan>) {
440 let sub = SubDiagnostic {
446 self.children.push(sub);
451 pub fn message(&self) -> String {
452 self.message.iter().map(|i| i.0.as_str()).collect::<String>()
455 pub fn styled_message(&self) -> &Vec<(String, Style)> {