Skip to content

Emit JSON errors #30711

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 5 commits into from
Jan 15, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 5 additions & 4 deletions src/librustc/lint/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ use self::TargetLint::*;
use dep_graph::DepNode;
use middle::privacy::AccessLevels;
use middle::ty;
use session::{early_error, Session};
use session::{config, early_error, Session};
use lint::{Level, LevelSource, Lint, LintId, LintArray, LintPass};
use lint::{EarlyLintPass, EarlyLintPassObject, LateLintPass, LateLintPassObject};
use lint::{Default, CommandLine, Node, Allow, Warn, Deny, Forbid};
Expand All @@ -37,11 +37,12 @@ use util::nodemap::FnvHashMap;

use std::cell::RefCell;
use std::cmp;
use std::default::Default as StdDefault;
use std::mem;
use syntax::ast_util::{self, IdVisitingOperation};
use syntax::attr::{self, AttrMetaMethods};
use syntax::codemap::Span;
use syntax::errors::{self, DiagnosticBuilder};
use syntax::errors::DiagnosticBuilder;
use syntax::parse::token::InternedString;
use syntax::ast;
use syntax::attr::ThinAttributesExt;
Expand Down Expand Up @@ -168,7 +169,7 @@ impl LintStore {
match (sess, from_plugin) {
// We load builtin lints first, so a duplicate is a compiler bug.
// Use early_error when handling -W help with no crate.
(None, _) => early_error(errors::ColorConfig::Auto, &msg[..]),
(None, _) => early_error(config::ErrorOutputType::default(), &msg[..]),
(Some(sess), false) => sess.bug(&msg[..]),

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

// A duplicate name from a plugin is a user error.
Expand Down
142 changes: 88 additions & 54 deletions src/librustc/session/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@
pub use self::EntryFnType::*;
pub use self::CrateType::*;
pub use self::Passes::*;
pub use self::OptLevel::*;
pub use self::DebugInfoLevel::*;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this [breaking-change] be mentioned in the commit message?


use session::{early_error, early_warn, Session};
Expand Down Expand Up @@ -71,6 +70,18 @@ pub enum OutputType {
DepInfo,
}

#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum ErrorOutputType {
HumanReadable(ColorConfig),
Json,
}

impl Default for ErrorOutputType {
fn default() -> ErrorOutputType {
ErrorOutputType::HumanReadable(ColorConfig::Auto)
}
}

impl OutputType {
fn is_compatible_with_codegen_units_and_single_output_file(&self) -> bool {
match *self {
Expand Down Expand Up @@ -124,14 +135,14 @@ pub struct Options {
pub test: bool,
pub parse_only: bool,
pub no_trans: bool,
pub error_format: ErrorOutputType,
pub treat_err_as_bug: bool,
pub incremental_compilation: bool,
pub dump_dep_graph: bool,
pub no_analysis: bool,
pub debugging_opts: DebuggingOptions,
pub prints: Vec<PrintRequest>,
pub cg: CodegenOptions,
pub color: ColorConfig,
pub externs: HashMap<String, Vec<String>>,
pub crate_name: Option<String>,
/// An optional name to use as the crate for std during std injection,
Expand Down Expand Up @@ -221,7 +232,7 @@ pub fn basic_options() -> Options {
Options {
crate_types: Vec::new(),
gc: false,
optimize: No,
optimize: OptLevel::No,
debuginfo: NoDebugInfo,
lint_opts: Vec::new(),
lint_cap: None,
Expand All @@ -241,7 +252,7 @@ pub fn basic_options() -> Options {
debugging_opts: basic_debugging_options(),
prints: Vec::new(),
cg: basic_codegen_options(),
color: ColorConfig::Auto,
error_format: ErrorOutputType::default(),
externs: HashMap::new(),
crate_name: None,
alt_std_name: None,
Expand Down Expand Up @@ -308,7 +319,7 @@ macro_rules! options {
$struct_name { $($opt: $init),* }
}

pub fn $buildfn(matches: &getopts::Matches, color: ColorConfig) -> $struct_name
pub fn $buildfn(matches: &getopts::Matches, error_format: ErrorOutputType) -> $struct_name
{
let mut op = $defaultfn();
for option in matches.opt_strs($prefix) {
Expand All @@ -322,20 +333,20 @@ macro_rules! options {
if !setter(&mut op, value) {
match (value, opt_type_desc) {
(Some(..), None) => {
early_error(color, &format!("{} option `{}` takes no \
value", $outputname, key))
early_error(error_format, &format!("{} option `{}` takes no \
value", $outputname, key))
}
(None, Some(type_desc)) => {
early_error(color, &format!("{0} option `{1}` requires \
{2} ({3} {1}=<value>)",
$outputname, key,
type_desc, $prefix))
early_error(error_format, &format!("{0} option `{1}` requires \
{2} ({3} {1}=<value>)",
$outputname, key,
type_desc, $prefix))
}
(Some(value), Some(type_desc)) => {
early_error(color, &format!("incorrect value `{}` for {} \
option `{}` - {} was expected",
value, $outputname,
key, type_desc))
early_error(error_format, &format!("incorrect value `{}` for {} \
option `{}` - {} was expected",
value, $outputname,
key, type_desc))
}
(None, None) => unreachable!()
}
Expand All @@ -344,8 +355,8 @@ macro_rules! options {
break;
}
if !found {
early_error(color, &format!("unknown {} option: `{}`",
$outputname, key));
early_error(error_format, &format!("unknown {} option: `{}`",
$outputname, key));
}
}
return op;
Expand Down Expand Up @@ -863,6 +874,7 @@ pub fn rustc_optgroups() -> Vec<RustcOptGroup> {
"NAME=PATH"),
opt::opt("", "sysroot", "Override the system root", "PATH"),
opt::multi("Z", "", "Set internal debugging options", "FLAG"),
opt::opt_u("", "error-format", "How errors and other messages are produced", "human|json"),
opt::opt("", "color", "Configure coloring of output:
auto = colorize, if output goes to a tty (default);
always = always colorize output;
Expand Down Expand Up @@ -905,15 +917,37 @@ pub fn build_session_options(matches: &getopts::Matches) -> Options {
None => ColorConfig::Auto,

Some(arg) => {
early_error(ColorConfig::Auto, &format!("argument for --color must be auto, always \
or never (instead was `{}`)",
arg))
early_error(ErrorOutputType::default(), &format!("argument for --color must be auto, \
always or never (instead was `{}`)",
arg))
}
};

// We need the opts_present check because the driver will send us Matches
// with only stable options if no unstable options are used. Since error-format
// is unstable, it will not be present. We have to use opts_present not
// opt_present because the latter will panic.
let error_format = if matches.opts_present(&["error-format".to_owned()]) {
match matches.opt_str("error-format").as_ref().map(|s| &s[..]) {
Some("human") => ErrorOutputType::HumanReadable(color),
Some("json") => ErrorOutputType::Json,

None => ErrorOutputType::default(),

Some(arg) => {
early_error(ErrorOutputType::default(), &format!("argument for --error-format must \
be human or json (instead was \
`{}`)",
arg))
}
}
} else {
ErrorOutputType::default()
};

let unparsed_crate_types = matches.opt_strs("crate-type");
let crate_types = parse_crate_types_from_list(unparsed_crate_types)
.unwrap_or_else(|e| early_error(color, &e[..]));
.unwrap_or_else(|e| early_error(error_format, &e[..]));

let mut lint_opts = vec!();
let mut describe_lints = false;
Expand All @@ -930,11 +964,11 @@ pub fn build_session_options(matches: &getopts::Matches) -> Options {

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

let debugging_opts = build_debugging_options(matches, color);
let debugging_opts = build_debugging_options(matches, error_format);

let parse_only = debugging_opts.parse_only;
let no_trans = debugging_opts.no_trans;
Expand All @@ -960,7 +994,7 @@ pub fn build_session_options(matches: &getopts::Matches) -> Options {
"link" => OutputType::Exe,
"dep-info" => OutputType::DepInfo,
part => {
early_error(color, &format!("unknown emission type: `{}`",
early_error(error_format, &format!("unknown emission type: `{}`",
part))
}
};
Expand All @@ -973,7 +1007,7 @@ pub fn build_session_options(matches: &getopts::Matches) -> Options {
output_types.insert(OutputType::Exe, None);
}

let mut cg = build_codegen_options(matches, color);
let mut cg = build_codegen_options(matches, error_format);

// Issue #30063: if user requests llvm-related output to one
// particular path, disable codegen-units.
Expand All @@ -985,11 +1019,11 @@ pub fn build_session_options(matches: &getopts::Matches) -> Options {
}).collect();
if !incompatible.is_empty() {
for ot in &incompatible {
early_warn(color, &format!("--emit={} with -o incompatible with \
-C codegen-units=N for N > 1",
ot.shorthand()));
early_warn(error_format, &format!("--emit={} with -o incompatible with \
-C codegen-units=N for N > 1",
ot.shorthand()));
}
early_warn(color, "resetting to default -C codegen-units=1");
early_warn(error_format, "resetting to default -C codegen-units=1");
cg.codegen_units = 1;
}
}
Expand All @@ -1002,29 +1036,29 @@ pub fn build_session_options(matches: &getopts::Matches) -> Options {
let opt_level = {
if matches.opt_present("O") {
if cg.opt_level.is_some() {
early_error(color, "-O and -C opt-level both provided");
early_error(error_format, "-O and -C opt-level both provided");
}
Default
OptLevel::Default
} else {
match cg.opt_level {
None => No,
Some(0) => No,
Some(1) => Less,
Some(2) => Default,
Some(3) => Aggressive,
None => OptLevel::No,
Some(0) => OptLevel::No,
Some(1) => OptLevel::Less,
Some(2) => OptLevel::Default,
Some(3) => OptLevel::Aggressive,
Some(arg) => {
early_error(color, &format!("optimization level needs to be \
between 0-3 (instead was `{}`)",
arg));
early_error(error_format, &format!("optimization level needs to be \
between 0-3 (instead was `{}`)",
arg));
}
}
}
};
let debug_assertions = cg.debug_assertions.unwrap_or(opt_level == No);
let debug_assertions = cg.debug_assertions.unwrap_or(opt_level == OptLevel::No);
let gc = debugging_opts.gc;
let debuginfo = if matches.opt_present("g") {
if cg.debuginfo.is_some() {
early_error(color, "-g and -C debuginfo both provided");
early_error(error_format, "-g and -C debuginfo both provided");
}
FullDebugInfo
} else {
Expand All @@ -1033,16 +1067,16 @@ pub fn build_session_options(matches: &getopts::Matches) -> Options {
Some(1) => LimitedDebugInfo,
Some(2) => FullDebugInfo,
Some(arg) => {
early_error(color, &format!("debug info level needs to be between \
0-2 (instead was `{}`)",
arg));
early_error(error_format, &format!("debug info level needs to be between \
0-2 (instead was `{}`)",
arg));
}
}
};

let mut search_paths = SearchPaths::new();
for s in &matches.opt_strs("L") {
search_paths.add_path(&s[..], color);
search_paths.add_path(&s[..], error_format);
}

let libs = matches.opt_strs("l").into_iter().map(|s| {
Expand All @@ -1054,9 +1088,9 @@ pub fn build_session_options(matches: &getopts::Matches) -> Options {
(Some(name), "framework") => (name, cstore::NativeFramework),
(Some(name), "static") => (name, cstore::NativeStatic),
(_, s) => {
early_error(color, &format!("unknown library kind `{}`, expected \
one of dylib, framework, or static",
s));
early_error(error_format, &format!("unknown library kind `{}`, expected \
one of dylib, framework, or static",
s));
}
};
(name.to_string(), kind)
Expand All @@ -1071,26 +1105,26 @@ pub fn build_session_options(matches: &getopts::Matches) -> Options {
"file-names" => PrintRequest::FileNames,
"sysroot" => PrintRequest::Sysroot,
req => {
early_error(color, &format!("unknown print request `{}`", req))
early_error(error_format, &format!("unknown print request `{}`", req))
}
}
}).collect::<Vec<_>>();

if !cg.remark.is_empty() && debuginfo == NoDebugInfo {
early_warn(color, "-C remark will not show source locations without \
--debuginfo");
early_warn(error_format, "-C remark will not show source locations without \
--debuginfo");
}

let mut externs = HashMap::new();
for arg in &matches.opt_strs("extern") {
let mut parts = arg.splitn(2, '=');
let name = match parts.next() {
Some(s) => s,
None => early_error(color, "--extern value must not be empty"),
None => early_error(error_format, "--extern value must not be empty"),
};
let location = match parts.next() {
Some(s) => s,
None => early_error(color, "--extern value must be of the format `foo=bar`"),
None => early_error(error_format, "--extern value must be of the format `foo=bar`"),
};

externs.entry(name.to_string()).or_insert(vec![]).push(location.to_string());
Expand Down Expand Up @@ -1121,7 +1155,7 @@ pub fn build_session_options(matches: &getopts::Matches) -> Options {
debugging_opts: debugging_opts,
prints: prints,
cg: cg,
color: color,
error_format: error_format,
externs: externs,
crate_name: crate_name,
alt_std_name: None,
Expand Down
Loading