1
Fork 0

Emit the lint level of the unused-crate-dependencies

Also, turn off the lint when the unused dependencies json flag
is specified so that cargo doesn't have to supress the lint
This commit is contained in:
est31 2020-08-10 01:57:35 +02:00
parent 13371b59ee
commit 3a62eb74db
6 changed files with 66 additions and 19 deletions

View file

@ -196,7 +196,7 @@ pub trait Emitter {
fn emit_future_breakage_report(&mut self, _diags: Vec<(FutureBreakage, Diagnostic)>) {} fn emit_future_breakage_report(&mut self, _diags: Vec<(FutureBreakage, Diagnostic)>) {}
/// Emit list of unused externs /// Emit list of unused externs
fn emit_unused_externs(&mut self, _unused_externs: &[&str]) {} fn emit_unused_externs(&mut self, _lint_level: &str, _unused_externs: &[&str]) {}
/// Checks if should show explanations about "rustc --explain" /// Checks if should show explanations about "rustc --explain"
fn should_show_explain(&self) -> bool { fn should_show_explain(&self) -> bool {

View file

@ -159,8 +159,8 @@ impl Emitter for JsonEmitter {
} }
} }
fn emit_unused_externs(&mut self, unused_externs: &[&str]) { fn emit_unused_externs(&mut self, lint_level: &str, unused_externs: &[&str]) {
let data = UnusedExterns { unused_extern_names: unused_externs }; let data = UnusedExterns { lint_level, unused_extern_names: unused_externs };
let result = if self.pretty { let result = if self.pretty {
writeln!(&mut self.dst, "{}", as_pretty_json(&data)) writeln!(&mut self.dst, "{}", as_pretty_json(&data))
} else { } else {
@ -336,9 +336,11 @@ struct FutureIncompatReport {
} }
#[derive(Encodable)] #[derive(Encodable)]
struct UnusedExterns<'a, 'b> { struct UnusedExterns<'a, 'b, 'c> {
/// The severity level of the unused dependencies lint
lint_level: &'a str,
/// List of unused externs by their names. /// List of unused externs by their names.
unused_extern_names: &'a [&'b str], unused_extern_names: &'b [&'c str],
} }
impl Diagnostic { impl Diagnostic {

View file

@ -767,8 +767,8 @@ impl Handler {
self.inner.borrow_mut().emitter.emit_future_breakage_report(diags) self.inner.borrow_mut().emitter.emit_future_breakage_report(diags)
} }
pub fn emit_unused_externs(&self, unused_externs: &[&str]) { pub fn emit_unused_externs(&self, lint_level: &str, unused_externs: &[&str]) {
self.inner.borrow_mut().emit_unused_externs(unused_externs) self.inner.borrow_mut().emit_unused_externs(lint_level, unused_externs)
} }
pub fn delay_as_bug(&self, diagnostic: Diagnostic) { pub fn delay_as_bug(&self, diagnostic: Diagnostic) {
@ -845,8 +845,8 @@ impl HandlerInner {
self.emitter.emit_artifact_notification(path, artifact_type); self.emitter.emit_artifact_notification(path, artifact_type);
} }
fn emit_unused_externs(&mut self, unused_externs: &[&str]) { fn emit_unused_externs(&mut self, lint_level: &str, unused_externs: &[&str]) {
self.emitter.emit_unused_externs(unused_externs); self.emitter.emit_unused_externs(lint_level, unused_externs);
} }
fn treat_err_as_bug(&self) -> bool { fn treat_err_as_bug(&self) -> bool {

View file

@ -17,6 +17,7 @@ use rustc_hir::definitions::Definitions;
use rustc_hir::Crate; use rustc_hir::Crate;
use rustc_index::vec::IndexVec; use rustc_index::vec::IndexVec;
use rustc_lint::LintStore; use rustc_lint::LintStore;
use rustc_metadata::creader::CStore;
use rustc_middle::arena::Arena; use rustc_middle::arena::Arena;
use rustc_middle::dep_graph::DepGraph; use rustc_middle::dep_graph::DepGraph;
use rustc_middle::middle; use rustc_middle::middle;
@ -836,6 +837,12 @@ fn analysis(tcx: TyCtxt<'_>, cnum: CrateNum) -> Result<()> {
}); });
sess.time("looking_for_derive_registrar", || proc_macro_decls::find(tcx)); sess.time("looking_for_derive_registrar", || proc_macro_decls::find(tcx));
let cstore = tcx
.cstore_as_any()
.downcast_ref::<CStore>()
.expect("`tcx.cstore` is not a `CStore`");
cstore.report_unused_deps(tcx);
}, },
{ {
par_iter(&tcx.hir().krate().modules).for_each(|(&module, _)| { par_iter(&tcx.hir().krate().modules).for_each(|(&module, _)| {

View file

@ -46,6 +46,9 @@ pub struct CStore {
/// This map is used to verify we get no hash conflicts between /// This map is used to verify we get no hash conflicts between
/// `StableCrateId` values. /// `StableCrateId` values.
stable_crate_ids: FxHashMap<StableCrateId, CrateNum>, stable_crate_ids: FxHashMap<StableCrateId, CrateNum>,
/// Unused externs of the crate
unused_externs: Vec<Symbol>,
} }
pub struct CrateLoader<'a> { pub struct CrateLoader<'a> {
@ -190,6 +193,21 @@ impl CStore {
crate fn has_global_allocator(&self) -> bool { crate fn has_global_allocator(&self) -> bool {
self.has_global_allocator self.has_global_allocator
} }
pub fn report_unused_deps(&self, tcx: TyCtxt<'_>) {
let level = tcx
.lint_level_at_node(lint::builtin::UNUSED_CRATE_DEPENDENCIES, rustc_hir::CRATE_HIR_ID)
.0;
if level != lint::Level::Allow && tcx.sess.opts.json_unused_externs {
let unused_externs =
self.unused_externs.iter().map(|ident| ident.to_ident_string()).collect::<Vec<_>>();
let unused_externs = unused_externs.iter().map(String::as_str).collect::<Vec<&str>>();
tcx.sess
.parse_sess
.span_diagnostic
.emit_unused_externs(level.as_str(), &unused_externs);
}
}
} }
impl<'a> CrateLoader<'a> { impl<'a> CrateLoader<'a> {
@ -217,6 +235,7 @@ impl<'a> CrateLoader<'a> {
allocator_kind: None, allocator_kind: None,
has_global_allocator: false, has_global_allocator: false,
stable_crate_ids, stable_crate_ids,
unused_externs: Vec::new(),
}, },
used_extern_options: Default::default(), used_extern_options: Default::default(),
} }
@ -893,18 +912,23 @@ impl<'a> CrateLoader<'a> {
fn report_unused_deps(&mut self, krate: &ast::Crate) { fn report_unused_deps(&mut self, krate: &ast::Crate) {
// Make a point span rather than covering the whole file // Make a point span rather than covering the whole file
let span = krate.span.shrink_to_lo(); let span = krate.span.shrink_to_lo();
let mut unused_externs = Vec::new();
// Complain about anything left over // Complain about anything left over
for (name, entry) in self.sess.opts.externs.iter() { for (name, entry) in self.sess.opts.externs.iter() {
if let ExternLocation::FoundInLibrarySearchDirectories = entry.location { if let ExternLocation::FoundInLibrarySearchDirectories = entry.location {
// Don't worry about pathless `--extern foo` sysroot references // Don't worry about pathless `--extern foo` sysroot references
continue; continue;
} }
if self.used_extern_options.contains(&Symbol::intern(name)) { let name_interned = Symbol::intern(name);
if self.used_extern_options.contains(&name_interned) {
continue; continue;
} }
// Got a real unused --extern // Got a real unused --extern
if self.sess.opts.json_unused_externs {
self.cstore.unused_externs.push(name_interned);
continue;
}
let diag = match self.sess.opts.extern_dep_specs.get(name) { let diag = match self.sess.opts.extern_dep_specs.get(name) {
Some(loc) => BuiltinLintDiagnostics::ExternDepSpec(name.clone(), loc.into()), Some(loc) => BuiltinLintDiagnostics::ExternDepSpec(name.clone(), loc.into()),
None => { None => {
@ -918,7 +942,6 @@ impl<'a> CrateLoader<'a> {
) )
} }
}; };
unused_externs.push(name as &str);
self.sess.parse_sess.buffer_lint_with_diagnostic( self.sess.parse_sess.buffer_lint_with_diagnostic(
lint::builtin::UNUSED_CRATE_DEPENDENCIES, lint::builtin::UNUSED_CRATE_DEPENDENCIES,
span, span,
@ -931,9 +954,6 @@ impl<'a> CrateLoader<'a> {
diag, diag,
); );
} }
if self.sess.opts.json_unused_externs {
self.sess.parse_sess.span_diagnostic.emit_unused_externs(&unused_externs);
}
} }
pub fn postprocess(&mut self, krate: &ast::Crate) { pub fn postprocess(&mut self, krate: &ast::Crate) {
@ -941,9 +961,9 @@ impl<'a> CrateLoader<'a> {
self.inject_allocator_crate(krate); self.inject_allocator_crate(krate);
self.inject_panic_runtime(krate); self.inject_panic_runtime(krate);
info!("{:?}", CrateDump(&self.cstore));
self.report_unused_deps(krate); self.report_unused_deps(krate);
info!("{:?}", CrateDump(&self.cstore));
} }
pub fn process_extern_crate( pub fn process_extern_crate(

View file

@ -188,8 +188,23 @@ crate fn run(options: Options) -> Result<(), ErrorReported> {
.map(|v| (*v).clone()) .map(|v| (*v).clone())
.collect::<Vec<String>>(); .collect::<Vec<String>>();
unused_extern_names.sort(); unused_extern_names.sort();
let unused_extern_json = // Take the most severe lint level
serde_json::to_string(&UnusedExterns { unused_extern_names }).unwrap(); let lint_level = unused_extern_reports
.iter()
.map(|uexts| uexts.lint_level.as_str())
.max_by_key(|v| match *v {
"warn" => 1,
"deny" => 2,
"forbid" => 3,
// The allow lint level is not expected,
// as if allow is specified, no message
// is to be emitted.
v => unreachable!("Invalid lint level '{}'", v),
})
.unwrap_or("warn")
.to_string();
let uext = UnusedExterns { lint_level, unused_extern_names };
let unused_extern_json = serde_json::to_string(&uext).unwrap();
eprintln!("{}", unused_extern_json); eprintln!("{}", unused_extern_json);
} }
} }
@ -265,6 +280,8 @@ impl DirState {
#[derive(serde::Serialize, serde::Deserialize)] #[derive(serde::Serialize, serde::Deserialize)]
struct UnusedExterns { struct UnusedExterns {
/// Lint level of the unused_crate_dependencies lint
lint_level: String,
/// List of unused externs by their names. /// List of unused externs by their names.
unused_extern_names: Vec<String>, unused_extern_names: Vec<String>,
} }
@ -317,6 +334,7 @@ fn run_test(
compiler.arg("--error-format=json"); compiler.arg("--error-format=json");
compiler.arg("--json").arg("unused-externs"); compiler.arg("--json").arg("unused-externs");
compiler.arg("-Z").arg("unstable-options"); compiler.arg("-Z").arg("unstable-options");
compiler.arg("-W").arg("unused_crate_dependencies");
} }
for lib_str in &options.lib_strs { for lib_str in &options.lib_strs {
compiler.arg("-L").arg(&lib_str); compiler.arg("-L").arg(&lib_str);