Add --extern-loc
to augment unused crate dependency diagnostics
This allows a build system to indicate a location in its own dependency specification files (eg Cargo's `Cargo.toml`) which can be reported along side any unused crate dependency. This supports several types of location: - 'json' - provide some json-structured data, which is included in the json diagnostics in a `tool_metadata` field - 'raw' - emit the provided string into the output. This also appears as a json string in `tool_metadata`. If no `--extern-location` is explicitly provided then a default json entry of the form `"tool_metadata":{"name":<cratename>,"path":<cratepath>}` is emitted.
This commit is contained in:
parent
9778068cbc
commit
82ccb6582a
44 changed files with 512 additions and 47 deletions
|
@ -15,6 +15,8 @@ use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
|
|||
use rustc_target::abi::{Align, TargetDataLayout};
|
||||
use rustc_target::spec::{SplitDebuginfo, Target, TargetTriple};
|
||||
|
||||
use rustc_serialize::json;
|
||||
|
||||
use crate::parse::CrateConfig;
|
||||
use rustc_feature::UnstableFeatures;
|
||||
use rustc_span::edition::{Edition, DEFAULT_EDITION, EDITION_NAME_LIST};
|
||||
|
@ -408,6 +410,9 @@ impl OutputTypes {
|
|||
#[derive(Clone)]
|
||||
pub struct Externs(BTreeMap<String, ExternEntry>);
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct ExternDepSpecs(BTreeMap<String, ExternDepSpec>);
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct ExternEntry {
|
||||
pub location: ExternLocation,
|
||||
|
@ -439,6 +444,27 @@ pub enum ExternLocation {
|
|||
ExactPaths(BTreeSet<CanonicalizedPath>),
|
||||
}
|
||||
|
||||
/// Supplied source location of a dependency - for example in a build specification
|
||||
/// file like Cargo.toml. We support several syntaxes: if it makes sense to reference
|
||||
/// a file and line, then the build system can specify that. On the other hand, it may
|
||||
/// make more sense to have an arbitrary raw string.
|
||||
#[derive(Clone, PartialEq)]
|
||||
pub enum ExternDepSpec {
|
||||
/// Raw string
|
||||
Raw(String),
|
||||
/// Raw data in json format
|
||||
Json(json::Json),
|
||||
}
|
||||
|
||||
impl<'a> From<&'a ExternDepSpec> for rustc_lint_defs::ExternDepSpec {
|
||||
fn from(from: &'a ExternDepSpec) -> Self {
|
||||
match from {
|
||||
ExternDepSpec::Raw(s) => rustc_lint_defs::ExternDepSpec::Raw(s.clone()),
|
||||
ExternDepSpec::Json(json) => rustc_lint_defs::ExternDepSpec::Json(json.clone()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Externs {
|
||||
pub fn new(data: BTreeMap<String, ExternEntry>) -> Externs {
|
||||
Externs(data)
|
||||
|
@ -466,6 +492,25 @@ impl ExternEntry {
|
|||
}
|
||||
}
|
||||
|
||||
impl ExternDepSpecs {
|
||||
pub fn new(data: BTreeMap<String, ExternDepSpec>) -> ExternDepSpecs {
|
||||
ExternDepSpecs(data)
|
||||
}
|
||||
|
||||
pub fn get(&self, key: &str) -> Option<&ExternDepSpec> {
|
||||
self.0.get(key)
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for ExternDepSpec {
|
||||
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
match self {
|
||||
ExternDepSpec::Raw(raw) => fmt.write_str(raw),
|
||||
ExternDepSpec::Json(json) => json::as_json(json).fmt(fmt),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
|
||||
pub enum PrintRequest {
|
||||
FileNames,
|
||||
|
@ -679,6 +724,7 @@ impl Default for Options {
|
|||
cg: basic_codegen_options(),
|
||||
error_format: ErrorOutputType::default(),
|
||||
externs: Externs(BTreeMap::new()),
|
||||
extern_dep_specs: ExternDepSpecs(BTreeMap::new()),
|
||||
crate_name: None,
|
||||
alt_std_name: None,
|
||||
libs: Vec::new(),
|
||||
|
@ -1105,6 +1151,12 @@ pub fn rustc_optgroups() -> Vec<RustcOptGroup> {
|
|||
"Specify where an external rust library is located",
|
||||
"NAME[=PATH]",
|
||||
),
|
||||
opt::multi_s(
|
||||
"",
|
||||
"extern-location",
|
||||
"Location where an external crate dependency is specified",
|
||||
"NAME=LOCATION",
|
||||
),
|
||||
opt::opt_s("", "sysroot", "Override the system root", "PATH"),
|
||||
opt::multi("Z", "", "Set internal debugging options", "FLAG"),
|
||||
opt::opt_s(
|
||||
|
@ -1727,6 +1779,68 @@ pub fn parse_externs(
|
|||
Externs(externs)
|
||||
}
|
||||
|
||||
fn parse_extern_dep_specs(
|
||||
matches: &getopts::Matches,
|
||||
debugging_opts: &DebuggingOptions,
|
||||
error_format: ErrorOutputType,
|
||||
) -> ExternDepSpecs {
|
||||
let is_unstable_enabled = debugging_opts.unstable_options;
|
||||
let mut map = BTreeMap::new();
|
||||
|
||||
for arg in matches.opt_strs("extern-location") {
|
||||
if !is_unstable_enabled {
|
||||
early_error(
|
||||
error_format,
|
||||
"`--extern-location` option is unstable: set `-Z unstable-options`",
|
||||
);
|
||||
}
|
||||
|
||||
let mut parts = arg.splitn(2, '=');
|
||||
let name = parts.next().unwrap_or_else(|| {
|
||||
early_error(error_format, "`--extern-location` value must not be empty")
|
||||
});
|
||||
let loc = parts.next().unwrap_or_else(|| {
|
||||
early_error(
|
||||
error_format,
|
||||
&format!("`--extern-location`: specify location for extern crate `{}`", name),
|
||||
)
|
||||
});
|
||||
|
||||
let locparts: Vec<_> = loc.split(":").collect();
|
||||
let spec = match &locparts[..] {
|
||||
["raw", ..] => {
|
||||
// Don't want `:` split string
|
||||
let raw = loc.splitn(2, ':').nth(1).unwrap_or_else(|| {
|
||||
early_error(error_format, "`--extern-location`: missing `raw` location")
|
||||
});
|
||||
ExternDepSpec::Raw(raw.to_string())
|
||||
}
|
||||
["json", ..] => {
|
||||
// Don't want `:` split string
|
||||
let raw = loc.splitn(2, ':').nth(1).unwrap_or_else(|| {
|
||||
early_error(error_format, "`--extern-location`: missing `json` location")
|
||||
});
|
||||
let json = json::from_str(raw).unwrap_or_else(|_| {
|
||||
early_error(
|
||||
error_format,
|
||||
&format!("`--extern-location`: malformed json location `{}`", raw),
|
||||
)
|
||||
});
|
||||
ExternDepSpec::Json(json)
|
||||
}
|
||||
[bad, ..] => early_error(
|
||||
error_format,
|
||||
&format!("unknown location type `{}`: use `raw` or `json`", bad),
|
||||
),
|
||||
[] => early_error(error_format, "missing location specification"),
|
||||
};
|
||||
|
||||
map.insert(name.to_string(), spec);
|
||||
}
|
||||
|
||||
ExternDepSpecs::new(map)
|
||||
}
|
||||
|
||||
fn parse_remap_path_prefix(
|
||||
matches: &getopts::Matches,
|
||||
error_format: ErrorOutputType,
|
||||
|
@ -1888,6 +2002,7 @@ pub fn build_session_options(matches: &getopts::Matches) -> Options {
|
|||
}
|
||||
|
||||
let externs = parse_externs(matches, &debugging_opts, error_format);
|
||||
let extern_dep_specs = parse_extern_dep_specs(matches, &debugging_opts, error_format);
|
||||
|
||||
let crate_name = matches.opt_str("crate-name");
|
||||
|
||||
|
@ -1924,6 +2039,7 @@ pub fn build_session_options(matches: &getopts::Matches) -> Options {
|
|||
error_format,
|
||||
externs,
|
||||
unstable_features: UnstableFeatures::from_environment(crate_name.as_deref()),
|
||||
extern_dep_specs,
|
||||
crate_name,
|
||||
alt_std_name: None,
|
||||
libs,
|
||||
|
|
|
@ -112,6 +112,7 @@ top_level_options!(
|
|||
borrowck_mode: BorrowckMode [UNTRACKED],
|
||||
cg: CodegenOptions [TRACKED],
|
||||
externs: Externs [UNTRACKED],
|
||||
extern_dep_specs: ExternDepSpecs [UNTRACKED],
|
||||
crate_name: Option<String> [TRACKED],
|
||||
// An optional name to use as the crate for std during std injection,
|
||||
// written `extern crate name as std`. Defaults to `std`. Used by
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue