]>
Commit | Line | Data |
---|---|---|
d9579d0f AL |
1 | // Copyright 2015 The Rust Project Developers. See the COPYRIGHT |
2 | // file at the top-level directory of this distribution and at | |
3 | // http://rust-lang.org/COPYRIGHT. | |
4 | // | |
5 | // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or | |
6 | // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license | |
7 | // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your | |
8 | // option. This file may not be copied, modified, or distributed | |
9 | // except according to those terms. | |
10 | ||
11 | //! This module contains utilities for outputting metadata for diagnostic errors. | |
12 | //! | |
13 | //! Each set of errors is mapped to a metadata file by a name, which is | |
14 | //! currently always a crate name. | |
15 | ||
16 | use std::collections::BTreeMap; | |
d9579d0f | 17 | use std::path::PathBuf; |
62682a34 SL |
18 | use std::fs::{remove_file, create_dir_all, File}; |
19 | use std::io::Write; | |
d9579d0f | 20 | use std::error::Error; |
62682a34 | 21 | use rustc_serialize::json::as_json; |
d9579d0f AL |
22 | |
23 | use codemap::Span; | |
24 | use ext::base::ExtCtxt; | |
25 | use diagnostics::plugin::{ErrorMap, ErrorInfo}; | |
26 | ||
d9579d0f | 27 | // Default metadata directory to use for extended error JSON. |
62682a34 | 28 | const ERROR_METADATA_PREFIX: &'static str = "tmp/extended-errors"; |
d9579d0f AL |
29 | |
30 | /// JSON encodable/decodable version of `ErrorInfo`. | |
31 | #[derive(PartialEq, RustcDecodable, RustcEncodable)] | |
32 | pub struct ErrorMetadata { | |
33 | pub description: Option<String>, | |
34 | pub use_site: Option<ErrorLocation> | |
35 | } | |
36 | ||
37 | /// Mapping from error codes to metadata that can be (de)serialized. | |
38 | pub type ErrorMetadataMap = BTreeMap<String, ErrorMetadata>; | |
39 | ||
40 | /// JSON encodable error location type with filename and line number. | |
41 | #[derive(PartialEq, RustcDecodable, RustcEncodable)] | |
42 | pub struct ErrorLocation { | |
43 | pub filename: String, | |
44 | pub line: usize | |
45 | } | |
46 | ||
47 | impl ErrorLocation { | |
48 | /// Create an error location from a span. | |
49 | pub fn from_span(ecx: &ExtCtxt, sp: Span) -> ErrorLocation { | |
50 | let loc = ecx.codemap().lookup_char_pos_adj(sp.lo); | |
51 | ErrorLocation { | |
52 | filename: loc.filename, | |
53 | line: loc.line | |
54 | } | |
55 | } | |
56 | } | |
57 | ||
62682a34 SL |
58 | /// Get the directory where metadata for a given `prefix` should be stored. |
59 | /// | |
60 | /// See `output_metadata`. | |
61 | pub fn get_metadata_dir(prefix: &str) -> PathBuf { | |
62 | PathBuf::from(ERROR_METADATA_PREFIX).join(prefix) | |
d9579d0f AL |
63 | } |
64 | ||
62682a34 SL |
65 | /// Map `name` to a path in the given directory: <directory>/<name>.json |
66 | fn get_metadata_path(directory: PathBuf, name: &str) -> PathBuf { | |
67 | directory.join(format!("{}.json", name)) | |
d9579d0f AL |
68 | } |
69 | ||
62682a34 SL |
70 | /// Write metadata for the errors in `err_map` to disk, to a file corresponding to `prefix/name`. |
71 | /// | |
72 | /// For our current purposes the prefix is the target architecture and the name is a crate name. | |
73 | /// If an error occurs steps will be taken to ensure that no file is created. | |
74 | pub fn output_metadata(ecx: &ExtCtxt, prefix: &str, name: &str, err_map: &ErrorMap) | |
d9579d0f AL |
75 | -> Result<(), Box<Error>> |
76 | { | |
62682a34 SL |
77 | // Create the directory to place the file in. |
78 | let metadata_dir = get_metadata_dir(prefix); | |
79 | try!(create_dir_all(&metadata_dir)); | |
d9579d0f | 80 | |
62682a34 SL |
81 | // Open the metadata file. |
82 | let metadata_path = get_metadata_path(metadata_dir, name); | |
83 | let mut metadata_file = try!(File::create(&metadata_path)); | |
d9579d0f AL |
84 | |
85 | // Construct a serializable map. | |
86 | let json_map = err_map.iter().map(|(k, &ErrorInfo { description, use_site })| { | |
87 | let key = k.as_str().to_string(); | |
88 | let value = ErrorMetadata { | |
89 | description: description.map(|n| n.as_str().to_string()), | |
90 | use_site: use_site.map(|sp| ErrorLocation::from_span(ecx, sp)) | |
91 | }; | |
92 | (key, value) | |
93 | }).collect::<ErrorMetadataMap>(); | |
94 | ||
62682a34 SL |
95 | // Write the data to the file, deleting it if the write fails. |
96 | let result = write!(&mut metadata_file, "{}", as_json(&json_map)); | |
97 | if result.is_err() { | |
98 | try!(remove_file(&metadata_path)); | |
99 | } | |
100 | Ok(try!(result)) | |
d9579d0f | 101 | } |