Skip to content

Commit d8869d3

Browse files
committed
Auto merge of #30711 - nrc:json-errs, r=huonw
The compiler can emit errors and warning in JSON format. This is a more easily machine readable form then the usual error output. Closes #10492, closes #14863.
2 parents 2fb0c5e + 82f8e5c commit d8869d3

File tree

21 files changed

+444
-129
lines changed

21 files changed

+444
-129
lines changed

src/librustc/lint/context.rs

+5-4
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ use self::TargetLint::*;
2828
use dep_graph::DepNode;
2929
use middle::privacy::AccessLevels;
3030
use middle::ty;
31-
use session::{early_error, Session};
31+
use session::{config, early_error, Session};
3232
use lint::{Level, LevelSource, Lint, LintId, LintArray, LintPass};
3333
use lint::{EarlyLintPass, EarlyLintPassObject, LateLintPass, LateLintPassObject};
3434
use lint::{Default, CommandLine, Node, Allow, Warn, Deny, Forbid};
@@ -37,11 +37,12 @@ use util::nodemap::FnvHashMap;
3737

3838
use std::cell::RefCell;
3939
use std::cmp;
40+
use std::default::Default as StdDefault;
4041
use std::mem;
4142
use syntax::ast_util::{self, IdVisitingOperation};
4243
use syntax::attr::{self, AttrMetaMethods};
4344
use syntax::codemap::Span;
44-
use syntax::errors::{self, DiagnosticBuilder};
45+
use syntax::errors::DiagnosticBuilder;
4546
use syntax::parse::token::InternedString;
4647
use syntax::ast;
4748
use syntax::attr::ThinAttributesExt;
@@ -168,7 +169,7 @@ impl LintStore {
168169
match (sess, from_plugin) {
169170
// We load builtin lints first, so a duplicate is a compiler bug.
170171
// Use early_error when handling -W help with no crate.
171-
(None, _) => early_error(errors::ColorConfig::Auto, &msg[..]),
172+
(None, _) => early_error(config::ErrorOutputType::default(), &msg[..]),
172173
(Some(sess), false) => sess.bug(&msg[..]),
173174

174175
// A duplicate name from a plugin is a user error.
@@ -192,7 +193,7 @@ impl LintStore {
192193
match (sess, from_plugin) {
193194
// We load builtin lints first, so a duplicate is a compiler bug.
194195
// Use early_error when handling -W help with no crate.
195-
(None, _) => early_error(errors::ColorConfig::Auto, &msg[..]),
196+
(None, _) => early_error(config::ErrorOutputType::default(), &msg[..]),
196197
(Some(sess), false) => sess.bug(&msg[..]),
197198

198199
// A duplicate name from a plugin is a user error.

src/librustc/session/config.rs

+88-54
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@
1414
pub use self::EntryFnType::*;
1515
pub use self::CrateType::*;
1616
pub use self::Passes::*;
17-
pub use self::OptLevel::*;
1817
pub use self::DebugInfoLevel::*;
1918

2019
use session::{early_error, early_warn, Session};
@@ -71,6 +70,18 @@ pub enum OutputType {
7170
DepInfo,
7271
}
7372

73+
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
74+
pub enum ErrorOutputType {
75+
HumanReadable(ColorConfig),
76+
Json,
77+
}
78+
79+
impl Default for ErrorOutputType {
80+
fn default() -> ErrorOutputType {
81+
ErrorOutputType::HumanReadable(ColorConfig::Auto)
82+
}
83+
}
84+
7485
impl OutputType {
7586
fn is_compatible_with_codegen_units_and_single_output_file(&self) -> bool {
7687
match *self {
@@ -124,14 +135,14 @@ pub struct Options {
124135
pub test: bool,
125136
pub parse_only: bool,
126137
pub no_trans: bool,
138+
pub error_format: ErrorOutputType,
127139
pub treat_err_as_bug: bool,
128140
pub incremental_compilation: bool,
129141
pub dump_dep_graph: bool,
130142
pub no_analysis: bool,
131143
pub debugging_opts: DebuggingOptions,
132144
pub prints: Vec<PrintRequest>,
133145
pub cg: CodegenOptions,
134-
pub color: ColorConfig,
135146
pub externs: HashMap<String, Vec<String>>,
136147
pub crate_name: Option<String>,
137148
/// An optional name to use as the crate for std during std injection,
@@ -221,7 +232,7 @@ pub fn basic_options() -> Options {
221232
Options {
222233
crate_types: Vec::new(),
223234
gc: false,
224-
optimize: No,
235+
optimize: OptLevel::No,
225236
debuginfo: NoDebugInfo,
226237
lint_opts: Vec::new(),
227238
lint_cap: None,
@@ -241,7 +252,7 @@ pub fn basic_options() -> Options {
241252
debugging_opts: basic_debugging_options(),
242253
prints: Vec::new(),
243254
cg: basic_codegen_options(),
244-
color: ColorConfig::Auto,
255+
error_format: ErrorOutputType::default(),
245256
externs: HashMap::new(),
246257
crate_name: None,
247258
alt_std_name: None,
@@ -308,7 +319,7 @@ macro_rules! options {
308319
$struct_name { $($opt: $init),* }
309320
}
310321

311-
pub fn $buildfn(matches: &getopts::Matches, color: ColorConfig) -> $struct_name
322+
pub fn $buildfn(matches: &getopts::Matches, error_format: ErrorOutputType) -> $struct_name
312323
{
313324
let mut op = $defaultfn();
314325
for option in matches.opt_strs($prefix) {
@@ -322,20 +333,20 @@ macro_rules! options {
322333
if !setter(&mut op, value) {
323334
match (value, opt_type_desc) {
324335
(Some(..), None) => {
325-
early_error(color, &format!("{} option `{}` takes no \
326-
value", $outputname, key))
336+
early_error(error_format, &format!("{} option `{}` takes no \
337+
value", $outputname, key))
327338
}
328339
(None, Some(type_desc)) => {
329-
early_error(color, &format!("{0} option `{1}` requires \
330-
{2} ({3} {1}=<value>)",
331-
$outputname, key,
332-
type_desc, $prefix))
340+
early_error(error_format, &format!("{0} option `{1}` requires \
341+
{2} ({3} {1}=<value>)",
342+
$outputname, key,
343+
type_desc, $prefix))
333344
}
334345
(Some(value), Some(type_desc)) => {
335-
early_error(color, &format!("incorrect value `{}` for {} \
336-
option `{}` - {} was expected",
337-
value, $outputname,
338-
key, type_desc))
346+
early_error(error_format, &format!("incorrect value `{}` for {} \
347+
option `{}` - {} was expected",
348+
value, $outputname,
349+
key, type_desc))
339350
}
340351
(None, None) => unreachable!()
341352
}
@@ -344,8 +355,8 @@ macro_rules! options {
344355
break;
345356
}
346357
if !found {
347-
early_error(color, &format!("unknown {} option: `{}`",
348-
$outputname, key));
358+
early_error(error_format, &format!("unknown {} option: `{}`",
359+
$outputname, key));
349360
}
350361
}
351362
return op;
@@ -861,6 +872,7 @@ pub fn rustc_optgroups() -> Vec<RustcOptGroup> {
861872
"NAME=PATH"),
862873
opt::opt("", "sysroot", "Override the system root", "PATH"),
863874
opt::multi("Z", "", "Set internal debugging options", "FLAG"),
875+
opt::opt_u("", "error-format", "How errors and other messages are produced", "human|json"),
864876
opt::opt("", "color", "Configure coloring of output:
865877
auto = colorize, if output goes to a tty (default);
866878
always = always colorize output;
@@ -903,15 +915,37 @@ pub fn build_session_options(matches: &getopts::Matches) -> Options {
903915
None => ColorConfig::Auto,
904916

905917
Some(arg) => {
906-
early_error(ColorConfig::Auto, &format!("argument for --color must be auto, always \
907-
or never (instead was `{}`)",
908-
arg))
918+
early_error(ErrorOutputType::default(), &format!("argument for --color must be auto, \
919+
always or never (instead was `{}`)",
920+
arg))
909921
}
910922
};
911923

924+
// We need the opts_present check because the driver will send us Matches
925+
// with only stable options if no unstable options are used. Since error-format
926+
// is unstable, it will not be present. We have to use opts_present not
927+
// opt_present because the latter will panic.
928+
let error_format = if matches.opts_present(&["error-format".to_owned()]) {
929+
match matches.opt_str("error-format").as_ref().map(|s| &s[..]) {
930+
Some("human") => ErrorOutputType::HumanReadable(color),
931+
Some("json") => ErrorOutputType::Json,
932+
933+
None => ErrorOutputType::default(),
934+
935+
Some(arg) => {
936+
early_error(ErrorOutputType::default(), &format!("argument for --error-format must \
937+
be human or json (instead was \
938+
`{}`)",
939+
arg))
940+
}
941+
}
942+
} else {
943+
ErrorOutputType::default()
944+
};
945+
912946
let unparsed_crate_types = matches.opt_strs("crate-type");
913947
let crate_types = parse_crate_types_from_list(unparsed_crate_types)
914-
.unwrap_or_else(|e| early_error(color, &e[..]));
948+
.unwrap_or_else(|e| early_error(error_format, &e[..]));
915949

916950
let mut lint_opts = vec!();
917951
let mut describe_lints = false;
@@ -928,11 +962,11 @@ pub fn build_session_options(matches: &getopts::Matches) -> Options {
928962

929963
let lint_cap = matches.opt_str("cap-lints").map(|cap| {
930964
lint::Level::from_str(&cap).unwrap_or_else(|| {
931-
early_error(color, &format!("unknown lint level: `{}`", cap))
965+
early_error(error_format, &format!("unknown lint level: `{}`", cap))
932966
})
933967
});
934968

935-
let debugging_opts = build_debugging_options(matches, color);
969+
let debugging_opts = build_debugging_options(matches, error_format);
936970

937971
let parse_only = debugging_opts.parse_only;
938972
let no_trans = debugging_opts.no_trans;
@@ -958,7 +992,7 @@ pub fn build_session_options(matches: &getopts::Matches) -> Options {
958992
"link" => OutputType::Exe,
959993
"dep-info" => OutputType::DepInfo,
960994
part => {
961-
early_error(color, &format!("unknown emission type: `{}`",
995+
early_error(error_format, &format!("unknown emission type: `{}`",
962996
part))
963997
}
964998
};
@@ -971,7 +1005,7 @@ pub fn build_session_options(matches: &getopts::Matches) -> Options {
9711005
output_types.insert(OutputType::Exe, None);
9721006
}
9731007

974-
let mut cg = build_codegen_options(matches, color);
1008+
let mut cg = build_codegen_options(matches, error_format);
9751009

9761010
// Issue #30063: if user requests llvm-related output to one
9771011
// particular path, disable codegen-units.
@@ -983,11 +1017,11 @@ pub fn build_session_options(matches: &getopts::Matches) -> Options {
9831017
}).collect();
9841018
if !incompatible.is_empty() {
9851019
for ot in &incompatible {
986-
early_warn(color, &format!("--emit={} with -o incompatible with \
987-
-C codegen-units=N for N > 1",
988-
ot.shorthand()));
1020+
early_warn(error_format, &format!("--emit={} with -o incompatible with \
1021+
-C codegen-units=N for N > 1",
1022+
ot.shorthand()));
9891023
}
990-
early_warn(color, "resetting to default -C codegen-units=1");
1024+
early_warn(error_format, "resetting to default -C codegen-units=1");
9911025
cg.codegen_units = 1;
9921026
}
9931027
}
@@ -1000,29 +1034,29 @@ pub fn build_session_options(matches: &getopts::Matches) -> Options {
10001034
let opt_level = {
10011035
if matches.opt_present("O") {
10021036
if cg.opt_level.is_some() {
1003-
early_error(color, "-O and -C opt-level both provided");
1037+
early_error(error_format, "-O and -C opt-level both provided");
10041038
}
1005-
Default
1039+
OptLevel::Default
10061040
} else {
10071041
match cg.opt_level {
1008-
None => No,
1009-
Some(0) => No,
1010-
Some(1) => Less,
1011-
Some(2) => Default,
1012-
Some(3) => Aggressive,
1042+
None => OptLevel::No,
1043+
Some(0) => OptLevel::No,
1044+
Some(1) => OptLevel::Less,
1045+
Some(2) => OptLevel::Default,
1046+
Some(3) => OptLevel::Aggressive,
10131047
Some(arg) => {
1014-
early_error(color, &format!("optimization level needs to be \
1015-
between 0-3 (instead was `{}`)",
1016-
arg));
1048+
early_error(error_format, &format!("optimization level needs to be \
1049+
between 0-3 (instead was `{}`)",
1050+
arg));
10171051
}
10181052
}
10191053
}
10201054
};
1021-
let debug_assertions = cg.debug_assertions.unwrap_or(opt_level == No);
1055+
let debug_assertions = cg.debug_assertions.unwrap_or(opt_level == OptLevel::No);
10221056
let gc = debugging_opts.gc;
10231057
let debuginfo = if matches.opt_present("g") {
10241058
if cg.debuginfo.is_some() {
1025-
early_error(color, "-g and -C debuginfo both provided");
1059+
early_error(error_format, "-g and -C debuginfo both provided");
10261060
}
10271061
FullDebugInfo
10281062
} else {
@@ -1031,16 +1065,16 @@ pub fn build_session_options(matches: &getopts::Matches) -> Options {
10311065
Some(1) => LimitedDebugInfo,
10321066
Some(2) => FullDebugInfo,
10331067
Some(arg) => {
1034-
early_error(color, &format!("debug info level needs to be between \
1035-
0-2 (instead was `{}`)",
1036-
arg));
1068+
early_error(error_format, &format!("debug info level needs to be between \
1069+
0-2 (instead was `{}`)",
1070+
arg));
10371071
}
10381072
}
10391073
};
10401074

10411075
let mut search_paths = SearchPaths::new();
10421076
for s in &matches.opt_strs("L") {
1043-
search_paths.add_path(&s[..], color);
1077+
search_paths.add_path(&s[..], error_format);
10441078
}
10451079

10461080
let libs = matches.opt_strs("l").into_iter().map(|s| {
@@ -1052,9 +1086,9 @@ pub fn build_session_options(matches: &getopts::Matches) -> Options {
10521086
(Some(name), "framework") => (name, cstore::NativeFramework),
10531087
(Some(name), "static") => (name, cstore::NativeStatic),
10541088
(_, s) => {
1055-
early_error(color, &format!("unknown library kind `{}`, expected \
1056-
one of dylib, framework, or static",
1057-
s));
1089+
early_error(error_format, &format!("unknown library kind `{}`, expected \
1090+
one of dylib, framework, or static",
1091+
s));
10581092
}
10591093
};
10601094
(name.to_string(), kind)
@@ -1069,26 +1103,26 @@ pub fn build_session_options(matches: &getopts::Matches) -> Options {
10691103
"file-names" => PrintRequest::FileNames,
10701104
"sysroot" => PrintRequest::Sysroot,
10711105
req => {
1072-
early_error(color, &format!("unknown print request `{}`", req))
1106+
early_error(error_format, &format!("unknown print request `{}`", req))
10731107
}
10741108
}
10751109
}).collect::<Vec<_>>();
10761110

10771111
if !cg.remark.is_empty() && debuginfo == NoDebugInfo {
1078-
early_warn(color, "-C remark will not show source locations without \
1079-
--debuginfo");
1112+
early_warn(error_format, "-C remark will not show source locations without \
1113+
--debuginfo");
10801114
}
10811115

10821116
let mut externs = HashMap::new();
10831117
for arg in &matches.opt_strs("extern") {
10841118
let mut parts = arg.splitn(2, '=');
10851119
let name = match parts.next() {
10861120
Some(s) => s,
1087-
None => early_error(color, "--extern value must not be empty"),
1121+
None => early_error(error_format, "--extern value must not be empty"),
10881122
};
10891123
let location = match parts.next() {
10901124
Some(s) => s,
1091-
None => early_error(color, "--extern value must be of the format `foo=bar`"),
1125+
None => early_error(error_format, "--extern value must be of the format `foo=bar`"),
10921126
};
10931127

10941128
externs.entry(name.to_string()).or_insert(vec![]).push(location.to_string());
@@ -1119,7 +1153,7 @@ pub fn build_session_options(matches: &getopts::Matches) -> Options {
11191153
debugging_opts: debugging_opts,
11201154
prints: prints,
11211155
cg: cg,
1122-
color: color,
1156+
error_format: error_format,
11231157
externs: externs,
11241158
crate_name: crate_name,
11251159
alt_std_name: None,

0 commit comments

Comments
 (0)