1 //! This module contains utilities for outputting metadata for diagnostic errors.
3 //! Each set of errors is mapped to a metadata file by a name, which is
4 //! currently always a crate name.
6 use std::collections::BTreeMap;
8 use std::fs::{remove_file, create_dir_all, File};
10 use std::path::PathBuf;
11 use std::error::Error;
12 use rustc_serialize::json::as_json;
14 use syntax_pos::{Span, FileName};
16 use crate::ext::base::ExtCtxt;
17 use crate::diagnostics::plugin::{ErrorMap, ErrorInfo};
19 /// JSON encodable/decodable version of `ErrorInfo`.
20 #[derive(PartialEq, RustcDecodable, RustcEncodable)]
21 pub struct ErrorMetadata {
22 pub description: Option<String>,
23 pub use_site: Option<ErrorLocation>
26 /// Mapping from error codes to metadata that can be (de)serialized.
27 pub type ErrorMetadataMap = BTreeMap<String, ErrorMetadata>;
29 /// JSON encodable error location type with filename and line number.
30 #[derive(PartialEq, RustcDecodable, RustcEncodable)]
31 pub struct ErrorLocation {
32 pub filename: FileName,
37 /// Creates an error location from a span.
38 pub fn from_span(ecx: &ExtCtxt<'_>, sp: Span) -> ErrorLocation {
39 let loc = ecx.source_map().lookup_char_pos(sp.lo());
41 filename: loc.file.name.clone(),
47 /// Gets the directory where metadata for a given `prefix` should be stored.
49 /// See `output_metadata`.
50 pub fn get_metadata_dir(prefix: &str) -> PathBuf {
51 env::var_os("RUSTC_ERROR_METADATA_DST")
53 .expect("env var `RUSTC_ERROR_METADATA_DST` isn't set")
57 /// Map `name` to a path in the given directory: <directory>/<name>.json
58 fn get_metadata_path(directory: PathBuf, name: &str) -> PathBuf {
59 directory.join(format!("{}.json", name))
62 /// Write metadata for the errors in `err_map` to disk, to a file corresponding to `prefix/name`.
64 /// For our current purposes the prefix is the target architecture and the name is a crate name.
65 /// If an error occurs steps will be taken to ensure that no file is created.
66 pub fn output_metadata(ecx: &ExtCtxt<'_>, prefix: &str, name: &str, err_map: &ErrorMap)
67 -> Result<(), Box<dyn Error>>
69 // Create the directory to place the file in.
70 let metadata_dir = get_metadata_dir(prefix);
71 create_dir_all(&metadata_dir)?;
73 // Open the metadata file.
74 let metadata_path = get_metadata_path(metadata_dir, name);
75 let mut metadata_file = File::create(&metadata_path)?;
77 // Construct a serializable map.
78 let json_map = err_map.iter().map(|(k, &ErrorInfo { description, use_site })| {
79 let key = k.as_str().to_string();
80 let value = ErrorMetadata {
81 description: description.map(|n| n.as_str().to_string()),
82 use_site: use_site.map(|sp| ErrorLocation::from_span(ecx, sp))
85 }).collect::<ErrorMetadataMap>();
87 // Write the data to the file, deleting it if the write fails.
88 let result = write!(&mut metadata_file, "{}", as_json(&json_map));
90 remove_file(&metadata_path)?;