]>
Commit | Line | Data |
---|---|---|
9cc50fc6 SL |
1 | //! A JSON emitter for errors. |
2 | //! | |
3 | //! This works by converting errors to a simplified structural format (see the | |
3b2f2976 | 4 | //! structs at the start of the file) and then serializing them. These should |
9cc50fc6 SL |
5 | //! contain as much information about the error as possible. |
6 | //! | |
7 | //! The format of the JSON output should be considered *unstable*. For now the | |
8 | //! structs at the end of this file (Diagnostic*) specify the error format. | |
9 | ||
9fa01778 XL |
10 | // FIXME: spec the JSON output properly. |
11 | ||
dfeec247 | 12 | use rustc_span::source_map::{FilePathMapping, SourceMap}; |
9cc50fc6 | 13 | |
60c5eb7d | 14 | use crate::emitter::{Emitter, HumanReadableErrorType}; |
dfeec247 | 15 | use crate::registry::Registry; |
29967ef6 | 16 | use crate::DiagnosticId; |
6a06907d | 17 | use crate::ToolMetadata; |
dfeec247 | 18 | use crate::{CodeSuggestion, SubDiagnostic}; |
29967ef6 | 19 | use rustc_lint_defs::{Applicability, FutureBreakage}; |
9cc50fc6 | 20 | |
60c5eb7d | 21 | use rustc_data_structures::sync::Lrc; |
dfeec247 XL |
22 | use rustc_span::hygiene::ExpnData; |
23 | use rustc_span::{MultiSpan, Span, SpanLabel}; | |
9cc50fc6 | 24 | use std::io::{self, Write}; |
48663c56 | 25 | use std::path::Path; |
ff7c6d11 | 26 | use std::sync::{Arc, Mutex}; |
dfeec247 | 27 | use std::vec; |
9cc50fc6 | 28 | |
abe05a73 | 29 | use rustc_serialize::json::{as_json, as_pretty_json}; |
6a06907d | 30 | use rustc_serialize::{Encodable, Encoder}; |
9cc50fc6 | 31 | |
e74abb32 XL |
32 | #[cfg(test)] |
33 | mod tests; | |
34 | ||
9cc50fc6 | 35 | pub struct JsonEmitter { |
8faf50e0 | 36 | dst: Box<dyn Write + Send>, |
9cc50fc6 | 37 | registry: Option<Registry>, |
60c5eb7d | 38 | sm: Lrc<SourceMap>, |
abe05a73 | 39 | pretty: bool, |
0531ce1d | 40 | ui_testing: bool, |
48663c56 | 41 | json_rendered: HumanReadableErrorType, |
f035d41b | 42 | terminal_width: Option<usize>, |
74b04a01 | 43 | macro_backtrace: bool, |
9cc50fc6 SL |
44 | } |
45 | ||
46 | impl JsonEmitter { | |
48663c56 XL |
47 | pub fn stderr( |
48 | registry: Option<Registry>, | |
49 | source_map: Lrc<SourceMap>, | |
50 | pretty: bool, | |
51 | json_rendered: HumanReadableErrorType, | |
f035d41b | 52 | terminal_width: Option<usize>, |
74b04a01 | 53 | macro_backtrace: bool, |
48663c56 | 54 | ) -> JsonEmitter { |
c30ab7b3 | 55 | JsonEmitter { |
74b04a01 | 56 | dst: Box::new(io::BufWriter::new(io::stderr())), |
3b2f2976 | 57 | registry, |
a1dfa0c6 | 58 | sm: source_map, |
abe05a73 | 59 | pretty, |
0531ce1d | 60 | ui_testing: false, |
48663c56 | 61 | json_rendered, |
f035d41b | 62 | terminal_width, |
74b04a01 | 63 | macro_backtrace, |
c30ab7b3 SL |
64 | } |
65 | } | |
66 | ||
e1599b0c XL |
67 | pub fn basic( |
68 | pretty: bool, | |
69 | json_rendered: HumanReadableErrorType, | |
f035d41b | 70 | terminal_width: Option<usize>, |
74b04a01 | 71 | macro_backtrace: bool, |
e1599b0c | 72 | ) -> JsonEmitter { |
7cac9316 | 73 | let file_path_mapping = FilePathMapping::empty(); |
dfeec247 XL |
74 | JsonEmitter::stderr( |
75 | None, | |
76 | Lrc::new(SourceMap::new(file_path_mapping)), | |
77 | pretty, | |
78 | json_rendered, | |
f035d41b | 79 | terminal_width, |
74b04a01 | 80 | macro_backtrace, |
dfeec247 | 81 | ) |
9cc50fc6 SL |
82 | } |
83 | ||
48663c56 XL |
84 | pub fn new( |
85 | dst: Box<dyn Write + Send>, | |
86 | registry: Option<Registry>, | |
87 | source_map: Lrc<SourceMap>, | |
88 | pretty: bool, | |
89 | json_rendered: HumanReadableErrorType, | |
f035d41b | 90 | terminal_width: Option<usize>, |
74b04a01 | 91 | macro_backtrace: bool, |
48663c56 | 92 | ) -> JsonEmitter { |
9cc50fc6 | 93 | JsonEmitter { |
3b2f2976 XL |
94 | dst, |
95 | registry, | |
a1dfa0c6 | 96 | sm: source_map, |
abe05a73 | 97 | pretty, |
0531ce1d | 98 | ui_testing: false, |
48663c56 | 99 | json_rendered, |
f035d41b | 100 | terminal_width, |
74b04a01 | 101 | macro_backtrace, |
9cc50fc6 SL |
102 | } |
103 | } | |
0531ce1d XL |
104 | |
105 | pub fn ui_testing(self, ui_testing: bool) -> Self { | |
106 | Self { ui_testing, ..self } | |
107 | } | |
9cc50fc6 SL |
108 | } |
109 | ||
110 | impl Emitter for JsonEmitter { | |
60c5eb7d | 111 | fn emit_diagnostic(&mut self, diag: &crate::Diagnostic) { |
e74abb32 | 112 | let data = Diagnostic::from_errors_diagnostic(diag, self); |
abe05a73 XL |
113 | let result = if self.pretty { |
114 | writeln!(&mut self.dst, "{}", as_pretty_json(&data)) | |
115 | } else { | |
116 | writeln!(&mut self.dst, "{}", as_json(&data)) | |
74b04a01 XL |
117 | } |
118 | .and_then(|_| self.dst.flush()); | |
abe05a73 | 119 | if let Err(e) = result { |
9cc50fc6 SL |
120 | panic!("failed to print diagnostics: {:?}", e); |
121 | } | |
122 | } | |
48663c56 | 123 | |
dc9dc135 XL |
124 | fn emit_artifact_notification(&mut self, path: &Path, artifact_type: &str) { |
125 | let data = ArtifactNotification { artifact: path, emit: artifact_type }; | |
48663c56 XL |
126 | let result = if self.pretty { |
127 | writeln!(&mut self.dst, "{}", as_pretty_json(&data)) | |
128 | } else { | |
129 | writeln!(&mut self.dst, "{}", as_json(&data)) | |
74b04a01 XL |
130 | } |
131 | .and_then(|_| self.dst.flush()); | |
48663c56 XL |
132 | if let Err(e) = result { |
133 | panic!("failed to print notification: {:?}", e); | |
134 | } | |
135 | } | |
e74abb32 | 136 | |
29967ef6 XL |
137 | fn emit_future_breakage_report(&mut self, diags: Vec<(FutureBreakage, crate::Diagnostic)>) { |
138 | let data: Vec<FutureBreakageItem> = diags | |
139 | .into_iter() | |
140 | .map(|(breakage, mut diag)| { | |
141 | if diag.level == crate::Level::Allow { | |
142 | diag.level = crate::Level::Warning; | |
143 | } | |
144 | FutureBreakageItem { | |
145 | future_breakage_date: breakage.date, | |
146 | diagnostic: Diagnostic::from_errors_diagnostic(&diag, self), | |
147 | } | |
148 | }) | |
149 | .collect(); | |
150 | let report = FutureIncompatReport { future_incompat_report: data }; | |
151 | let result = if self.pretty { | |
152 | writeln!(&mut self.dst, "{}", as_pretty_json(&report)) | |
153 | } else { | |
154 | writeln!(&mut self.dst, "{}", as_json(&report)) | |
155 | } | |
156 | .and_then(|_| self.dst.flush()); | |
157 | if let Err(e) = result { | |
158 | panic!("failed to print future breakage report: {:?}", e); | |
159 | } | |
160 | } | |
161 | ||
60c5eb7d | 162 | fn source_map(&self) -> Option<&Lrc<SourceMap>> { |
e74abb32 XL |
163 | Some(&self.sm) |
164 | } | |
165 | ||
166 | fn should_show_explain(&self) -> bool { | |
29967ef6 | 167 | !matches!(self.json_rendered, HumanReadableErrorType::Short(_)) |
e74abb32 | 168 | } |
9cc50fc6 SL |
169 | } |
170 | ||
171 | // The following data types are provided just for serialisation. | |
172 | ||
6a06907d XL |
173 | // NOTE: this has a manual implementation of Encodable which needs to be updated in |
174 | // parallel. | |
32a655c1 | 175 | struct Diagnostic { |
9cc50fc6 | 176 | /// The primary error message. |
32a655c1 | 177 | message: String, |
9cc50fc6 SL |
178 | code: Option<DiagnosticCode>, |
179 | /// "error: internal compiler error", "error", "warning", "note", "help". | |
180 | level: &'static str, | |
7453a54e | 181 | spans: Vec<DiagnosticSpan>, |
a7813a04 | 182 | /// Associated diagnostic messages. |
32a655c1 | 183 | children: Vec<Diagnostic>, |
ff7c6d11 | 184 | /// The message as rustc would render it. |
a7813a04 | 185 | rendered: Option<String>, |
6a06907d XL |
186 | /// Extra tool metadata |
187 | tool_metadata: ToolMetadata, | |
188 | } | |
189 | ||
190 | macro_rules! encode_fields { | |
191 | ( | |
192 | $enc:expr, // encoder | |
193 | $idx:expr, // starting field index | |
194 | $struct:expr, // struct we're serializing | |
195 | $struct_name:ident, // struct name | |
196 | [ $($name:ident),+$(,)? ], // fields to encode | |
197 | [ $($ignore:ident),+$(,)? ] // fields we're skipping | |
198 | ) => { | |
199 | { | |
200 | // Pattern match to make sure all fields are accounted for | |
201 | let $struct_name { $($name,)+ $($ignore: _,)+ } = $struct; | |
202 | let mut idx = $idx; | |
203 | $( | |
204 | $enc.emit_struct_field( | |
205 | stringify!($name), | |
206 | idx, | |
207 | |enc| $name.encode(enc), | |
208 | )?; | |
209 | idx += 1; | |
210 | )+ | |
211 | idx | |
212 | } | |
213 | }; | |
214 | } | |
215 | ||
216 | // Special-case encoder to skip tool_metadata if not set | |
217 | impl<E: Encoder> Encodable<E> for Diagnostic { | |
218 | fn encode(&self, s: &mut E) -> Result<(), E::Error> { | |
219 | s.emit_struct("diagnostic", 7, |s| { | |
220 | let mut idx = 0; | |
221 | ||
222 | idx = encode_fields!( | |
223 | s, | |
224 | idx, | |
225 | self, | |
226 | Self, | |
227 | [message, code, level, spans, children, rendered], | |
228 | [tool_metadata] | |
229 | ); | |
230 | if self.tool_metadata.is_set() { | |
231 | idx = encode_fields!( | |
232 | s, | |
233 | idx, | |
234 | self, | |
235 | Self, | |
236 | [tool_metadata], | |
237 | [message, code, level, spans, children, rendered] | |
238 | ); | |
239 | } | |
240 | ||
241 | let _ = idx; | |
242 | Ok(()) | |
243 | }) | |
244 | } | |
9cc50fc6 SL |
245 | } |
246 | ||
3dfed10e | 247 | #[derive(Encodable)] |
9cc50fc6 SL |
248 | struct DiagnosticSpan { |
249 | file_name: String, | |
250 | byte_start: u32, | |
251 | byte_end: u32, | |
252 | /// 1-based. | |
253 | line_start: usize, | |
254 | line_end: usize, | |
255 | /// 1-based, character offset. | |
256 | column_start: usize, | |
257 | column_end: usize, | |
a7813a04 XL |
258 | /// Is this a "primary" span -- meaning the point, or one of the points, |
259 | /// where the error occurred? | |
260 | is_primary: bool, | |
54a0048b SL |
261 | /// Source text from the start of line_start to the end of line_end. |
262 | text: Vec<DiagnosticSpanLine>, | |
a7813a04 XL |
263 | /// Label that should be placed at this location (if any) |
264 | label: Option<String>, | |
265 | /// If we are suggesting a replacement, this will contain text | |
abe05a73 | 266 | /// that should be sliced in atop this span. |
a7813a04 | 267 | suggested_replacement: Option<String>, |
2c00a5a8 | 268 | /// If the suggestion is approximate |
83c7162d | 269 | suggestion_applicability: Option<Applicability>, |
a7813a04 XL |
270 | /// Macro invocations that created the code at this span, if any. |
271 | expansion: Option<Box<DiagnosticSpanMacroExpansion>>, | |
54a0048b SL |
272 | } |
273 | ||
3dfed10e | 274 | #[derive(Encodable)] |
54a0048b SL |
275 | struct DiagnosticSpanLine { |
276 | text: String, | |
a7813a04 | 277 | |
54a0048b SL |
278 | /// 1-based, character offset in self.text. |
279 | highlight_start: usize, | |
a7813a04 | 280 | |
54a0048b | 281 | highlight_end: usize, |
9cc50fc6 SL |
282 | } |
283 | ||
3dfed10e | 284 | #[derive(Encodable)] |
a7813a04 XL |
285 | struct DiagnosticSpanMacroExpansion { |
286 | /// span where macro was applied to generate this code; note that | |
287 | /// this may itself derive from a macro (if | |
288 | /// `span.expansion.is_some()`) | |
289 | span: DiagnosticSpan, | |
290 | ||
291 | /// name of macro that was applied (e.g., "foo!" or "#[derive(Eq)]") | |
292 | macro_decl_name: String, | |
293 | ||
294 | /// span where macro was defined (if known) | |
416331ca | 295 | def_site_span: DiagnosticSpan, |
a7813a04 XL |
296 | } |
297 | ||
3dfed10e | 298 | #[derive(Encodable)] |
9cc50fc6 SL |
299 | struct DiagnosticCode { |
300 | /// The code itself. | |
301 | code: String, | |
302 | /// An explanation for the code. | |
303 | explanation: Option<&'static str>, | |
304 | } | |
305 | ||
3dfed10e | 306 | #[derive(Encodable)] |
48663c56 XL |
307 | struct ArtifactNotification<'a> { |
308 | /// The path of the artifact. | |
309 | artifact: &'a Path, | |
dc9dc135 XL |
310 | /// What kind of artifact we're emitting. |
311 | emit: &'a str, | |
48663c56 XL |
312 | } |
313 | ||
29967ef6 XL |
314 | #[derive(Encodable)] |
315 | struct FutureBreakageItem { | |
316 | future_breakage_date: Option<&'static str>, | |
317 | diagnostic: Diagnostic, | |
318 | } | |
319 | ||
320 | #[derive(Encodable)] | |
321 | struct FutureIncompatReport { | |
322 | future_incompat_report: Vec<FutureBreakageItem>, | |
323 | } | |
324 | ||
32a655c1 | 325 | impl Diagnostic { |
dfeec247 XL |
326 | fn from_errors_diagnostic(diag: &crate::Diagnostic, je: &JsonEmitter) -> Diagnostic { |
327 | let sugg = diag.suggestions.iter().map(|sugg| Diagnostic { | |
328 | message: sugg.msg.clone(), | |
329 | code: None, | |
330 | level: "help", | |
331 | spans: DiagnosticSpan::from_suggestion(sugg, je), | |
332 | children: vec![], | |
333 | rendered: None, | |
6a06907d | 334 | tool_metadata: sugg.tool_metadata.clone(), |
7cac9316 | 335 | }); |
ff7c6d11 XL |
336 | |
337 | // generate regular command line output and store it in the json | |
338 | ||
339 | // A threadsafe buffer for writing. | |
340 | #[derive(Default, Clone)] | |
341 | struct BufWriter(Arc<Mutex<Vec<u8>>>); | |
342 | ||
343 | impl Write for BufWriter { | |
344 | fn write(&mut self, buf: &[u8]) -> io::Result<usize> { | |
345 | self.0.lock().unwrap().write(buf) | |
346 | } | |
347 | fn flush(&mut self) -> io::Result<()> { | |
348 | self.0.lock().unwrap().flush() | |
349 | } | |
350 | } | |
351 | let buf = BufWriter::default(); | |
352 | let output = buf.clone(); | |
dfeec247 | 353 | je.json_rendered |
f035d41b XL |
354 | .new_emitter( |
355 | Box::new(buf), | |
356 | Some(je.sm.clone()), | |
357 | false, | |
358 | je.terminal_width, | |
359 | je.macro_backtrace, | |
360 | ) | |
dfeec247 XL |
361 | .ui_testing(je.ui_testing) |
362 | .emit_diagnostic(diag); | |
ff7c6d11 XL |
363 | let output = Arc::try_unwrap(output.0).unwrap().into_inner().unwrap(); |
364 | let output = String::from_utf8(output).unwrap(); | |
365 | ||
9cc50fc6 | 366 | Diagnostic { |
e74abb32 XL |
367 | message: diag.message(), |
368 | code: DiagnosticCode::map_opt_string(diag.code.clone(), je), | |
369 | level: diag.level.to_str(), | |
370 | spans: DiagnosticSpan::from_multispan(&diag.span, je), | |
dfeec247 XL |
371 | children: diag |
372 | .children | |
373 | .iter() | |
374 | .map(|c| Diagnostic::from_sub_diagnostic(c, je)) | |
375 | .chain(sugg) | |
376 | .collect(), | |
ff7c6d11 | 377 | rendered: Some(output), |
6a06907d | 378 | tool_metadata: ToolMetadata::default(), |
9cc50fc6 SL |
379 | } |
380 | } | |
381 | ||
e74abb32 | 382 | fn from_sub_diagnostic(diag: &SubDiagnostic, je: &JsonEmitter) -> Diagnostic { |
9cc50fc6 | 383 | Diagnostic { |
e74abb32 | 384 | message: diag.message(), |
9cc50fc6 | 385 | code: None, |
e74abb32 | 386 | level: diag.level.to_str(), |
dfeec247 XL |
387 | spans: diag |
388 | .render_span | |
389 | .as_ref() | |
390 | .map(|sp| DiagnosticSpan::from_multispan(sp, je)) | |
391 | .unwrap_or_else(|| DiagnosticSpan::from_multispan(&diag.span, je)), | |
9cc50fc6 | 392 | children: vec![], |
7cac9316 | 393 | rendered: None, |
6a06907d | 394 | tool_metadata: ToolMetadata::default(), |
9cc50fc6 SL |
395 | } |
396 | } | |
397 | } | |
398 | ||
399 | impl DiagnosticSpan { | |
dfeec247 XL |
400 | fn from_span_label( |
401 | span: SpanLabel, | |
402 | suggestion: Option<(&String, Applicability)>, | |
403 | je: &JsonEmitter, | |
404 | ) -> DiagnosticSpan { | |
405 | Self::from_span_etc(span.span, span.is_primary, span.label, suggestion, je) | |
9cc50fc6 SL |
406 | } |
407 | ||
dfeec247 XL |
408 | fn from_span_etc( |
409 | span: Span, | |
410 | is_primary: bool, | |
411 | label: Option<String>, | |
412 | suggestion: Option<(&String, Applicability)>, | |
413 | je: &JsonEmitter, | |
414 | ) -> DiagnosticSpan { | |
a7813a04 XL |
415 | // obtain the full backtrace from the `macro_backtrace` |
416 | // helper; in some ways, it'd be better to expand the | |
417 | // backtrace ourselves, but the `macro_backtrace` helper makes | |
418 | // some decision, such as dropping some frames, and I don't | |
419 | // want to duplicate that logic here. | |
dfeec247 XL |
420 | let backtrace = span.macro_backtrace(); |
421 | DiagnosticSpan::from_span_full(span, is_primary, label, suggestion, backtrace, je) | |
a7813a04 XL |
422 | } |
423 | ||
dfeec247 XL |
424 | fn from_span_full( |
425 | span: Span, | |
426 | is_primary: bool, | |
427 | label: Option<String>, | |
428 | suggestion: Option<(&String, Applicability)>, | |
429 | mut backtrace: impl Iterator<Item = ExpnData>, | |
430 | je: &JsonEmitter, | |
431 | ) -> DiagnosticSpan { | |
a1dfa0c6 XL |
432 | let start = je.sm.lookup_char_pos(span.lo()); |
433 | let end = je.sm.lookup_char_pos(span.hi()); | |
a7813a04 | 434 | let backtrace_step = backtrace.next().map(|bt| { |
dfeec247 | 435 | let call_site = Self::from_span_full(bt.call_site, false, None, None, backtrace, je); |
416331ca | 436 | let def_site_span = |
dfeec247 | 437 | Self::from_span_full(bt.def_site, false, None, None, vec![].into_iter(), je); |
a7813a04 XL |
438 | Box::new(DiagnosticSpanMacroExpansion { |
439 | span: call_site, | |
dfeec247 | 440 | macro_decl_name: bt.kind.descr(), |
3b2f2976 | 441 | def_site_span, |
a7813a04 XL |
442 | }) |
443 | }); | |
2c00a5a8 | 444 | |
a7813a04 | 445 | DiagnosticSpan { |
ff7c6d11 | 446 | file_name: start.file.name.to_string(), |
e74abb32 XL |
447 | byte_start: start.file.original_relative_byte_pos(span.lo()).0, |
448 | byte_end: start.file.original_relative_byte_pos(span.hi()).0, | |
a7813a04 XL |
449 | line_start: start.line, |
450 | line_end: end.line, | |
451 | column_start: start.col.0 + 1, | |
452 | column_end: end.col.0 + 1, | |
3b2f2976 | 453 | is_primary, |
a7813a04 | 454 | text: DiagnosticSpanLine::from_span(span, je), |
2c00a5a8 | 455 | suggested_replacement: suggestion.map(|x| x.0.clone()), |
94b46f34 | 456 | suggestion_applicability: suggestion.map(|x| x.1), |
a7813a04 | 457 | expansion: backtrace_step, |
3b2f2976 | 458 | label, |
9cc50fc6 SL |
459 | } |
460 | } | |
9cc50fc6 | 461 | |
a7813a04 XL |
462 | fn from_multispan(msp: &MultiSpan, je: &JsonEmitter) -> Vec<DiagnosticSpan> { |
463 | msp.span_labels() | |
dfeec247 XL |
464 | .into_iter() |
465 | .map(|span_str| Self::from_span_label(span_str, None, je)) | |
466 | .collect() | |
a7813a04 XL |
467 | } |
468 | ||
dfeec247 XL |
469 | fn from_suggestion(suggestion: &CodeSuggestion, je: &JsonEmitter) -> Vec<DiagnosticSpan> { |
470 | suggestion | |
471 | .substitutions | |
472 | .iter() | |
473 | .flat_map(|substitution| { | |
474 | substitution.parts.iter().map(move |suggestion_inner| { | |
475 | let span_label = | |
476 | SpanLabel { span: suggestion_inner.span, is_primary: true, label: None }; | |
477 | DiagnosticSpan::from_span_label( | |
478 | span_label, | |
479 | Some((&suggestion_inner.snippet, suggestion.applicability)), | |
480 | je, | |
481 | ) | |
482 | }) | |
483 | }) | |
484 | .collect() | |
a7813a04 | 485 | } |
54a0048b SL |
486 | } |
487 | ||
488 | impl DiagnosticSpanLine { | |
dfeec247 | 489 | fn line_from_source_file( |
74b04a01 | 490 | sf: &rustc_span::SourceFile, |
dfeec247 XL |
491 | index: usize, |
492 | h_start: usize, | |
493 | h_end: usize, | |
494 | ) -> DiagnosticSpanLine { | |
54a0048b | 495 | DiagnosticSpanLine { |
74b04a01 | 496 | text: sf.get_line(index).map_or(String::new(), |l| l.into_owned()), |
54a0048b SL |
497 | highlight_start: h_start, |
498 | highlight_end: h_end, | |
499 | } | |
500 | } | |
501 | ||
9fa01778 | 502 | /// Creates a list of DiagnosticSpanLines from span - each line with any part |
54a0048b SL |
503 | /// of `span` gets a DiagnosticSpanLine, with the highlight indicating the |
504 | /// `span` within the line. | |
a7813a04 | 505 | fn from_span(span: Span, je: &JsonEmitter) -> Vec<DiagnosticSpanLine> { |
dfeec247 XL |
506 | je.sm |
507 | .span_to_lines(span) | |
48663c56 | 508 | .map(|lines| { |
ba9703b0 XL |
509 | // We can't get any lines if the source is unavailable. |
510 | if !je.sm.ensure_source_file_source_present(lines.file.clone()) { | |
511 | return vec![]; | |
512 | } | |
513 | ||
74b04a01 | 514 | let sf = &*lines.file; |
dfeec247 XL |
515 | lines |
516 | .lines | |
48663c56 | 517 | .iter() |
dfeec247 XL |
518 | .map(|line| { |
519 | DiagnosticSpanLine::line_from_source_file( | |
74b04a01 | 520 | sf, |
dfeec247 XL |
521 | line.line_index, |
522 | line.start_col.0 + 1, | |
523 | line.end_col.0 + 1, | |
524 | ) | |
525 | }) | |
526 | .collect() | |
527 | }) | |
528 | .unwrap_or_else(|_| vec![]) | |
54a0048b SL |
529 | } |
530 | } | |
531 | ||
9cc50fc6 | 532 | impl DiagnosticCode { |
abe05a73 | 533 | fn map_opt_string(s: Option<DiagnosticId>, je: &JsonEmitter) -> Option<DiagnosticCode> { |
9cc50fc6 | 534 | s.map(|s| { |
abe05a73 XL |
535 | let s = match s { |
536 | DiagnosticId::Error(s) => s, | |
29967ef6 | 537 | DiagnosticId::Lint { name, has_future_breakage: _ } => name, |
abe05a73 | 538 | }; |
74b04a01 XL |
539 | let je_result = |
540 | je.registry.as_ref().map(|registry| registry.try_find_description(&s)).unwrap(); | |
9cc50fc6 | 541 | |
74b04a01 | 542 | DiagnosticCode { code: s, explanation: je_result.unwrap_or(None) } |
9cc50fc6 SL |
543 | }) |
544 | } | |
545 | } |