Skip to content

Commit

Permalink
Implement warning for unused dependencies.
Browse files Browse the repository at this point in the history
This will print a diagnostic for crates which are mentioned as `--extern`
arguments on the command line, but are never referenced from the source.

This diagnostic is controlled by `-Wunused-crate-dependencies` or
`#![warn(unused_crate_dependencies)]` and is "allow" by default.

There are cases where certain crates need to be linked in but are not
directly referenced - for example if they are providing symbols for C
linkage. In this case the warning can be suppressed with
`use needed_crate as _;`.

Thanks to @petrochenkov for simplified core.

Resolves issue rust-lang#57274
  • Loading branch information
jsgf committed May 26, 2020
1 parent f93bb2a commit ffa493a
Show file tree
Hide file tree
Showing 17 changed files with 188 additions and 0 deletions.
1 change: 1 addition & 0 deletions src/librustc_lint/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -276,6 +276,7 @@ fn register_builtins(store: &mut LintStore, no_interleave_lints: bool) {
UNUSED_ALLOCATION,
UNUSED_DOC_COMMENTS,
UNUSED_EXTERN_CRATES,
UNUSED_CRATE_DEPENDENCIES,
UNUSED_FEATURES,
UNUSED_LABELS,
UNUSED_PARENS,
Expand Down
29 changes: 29 additions & 0 deletions src/librustc_metadata/creader.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ use crate::rmeta::{CrateDep, CrateMetadata, CrateNumMap, CrateRoot, MetadataBlob

use rustc_ast::expand::allocator::{global_allocator_spans, AllocatorKind};
use rustc_ast::{ast, attr};
use rustc_data_structures::fx::FxHashSet;
use rustc_data_structures::svh::Svh;
use rustc_data_structures::sync::Lrc;
use rustc_errors::struct_span_err;
Expand All @@ -18,6 +19,7 @@ use rustc_middle::middle::cstore::{
};
use rustc_middle::ty::TyCtxt;
use rustc_session::config::{self, CrateType};
use rustc_session::lint;
use rustc_session::output::validate_crate_name;
use rustc_session::search_paths::PathKind;
use rustc_session::{CrateDisambiguator, Session};
Expand Down Expand Up @@ -49,6 +51,7 @@ pub struct CrateLoader<'a> {
local_crate_name: Symbol,
// Mutable output.
cstore: CStore,
used_extern_options: FxHashSet<Symbol>,
}

pub enum LoadedMacro {
Expand Down Expand Up @@ -205,6 +208,7 @@ impl<'a> CrateLoader<'a> {
allocator_kind: None,
has_global_allocator: false,
},
used_extern_options: Default::default(),
}
}

Expand Down Expand Up @@ -445,6 +449,9 @@ impl<'a> CrateLoader<'a> {
dep_kind: DepKind,
dep: Option<(&'b CratePaths, &'b CrateDep)>,
) -> CrateNum {
if dep.is_none() {
self.used_extern_options.insert(name);
}
self.maybe_resolve_crate(name, span, dep_kind, dep).unwrap_or_else(|err| err.report())
}

Expand Down Expand Up @@ -839,6 +846,26 @@ impl<'a> CrateLoader<'a> {
});
}

fn report_unused_deps(&mut self, krate: &ast::Crate) {
// Make a point span rather than covering the whole file
let span = krate.span.shrink_to_lo();
// Complain about anything left over
for (name, _) in self.sess.opts.externs.iter() {
if !self.used_extern_options.contains(&Symbol::intern(name)) {
self.sess.parse_sess.buffer_lint(
lint::builtin::UNUSED_CRATE_DEPENDENCIES,
span,
ast::CRATE_NODE_ID,
&format!(
"external crate `{}` unused in `{}`: remove the dependency or add `use {} as _;`",
name,
self.local_crate_name,
name),
);
}
}
}

pub fn postprocess(&mut self, krate: &ast::Crate) {
self.inject_profiler_runtime();
self.inject_allocator_crate(krate);
Expand All @@ -847,6 +874,8 @@ impl<'a> CrateLoader<'a> {
if log_enabled!(log::Level::Info) {
dump_crates(&self.cstore);
}

self.report_unused_deps(krate);
}

pub fn process_extern_crate(
Expand Down
7 changes: 7 additions & 0 deletions src/librustc_session/lint/builtin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,12 @@ declare_lint! {
"extern crates that are never used"
}

declare_lint! {
pub UNUSED_CRATE_DEPENDENCIES,
Allow,
"crate dependencies that are never used"
}

declare_lint! {
pub UNUSED_QUALIFICATIONS,
Allow,
Expand Down Expand Up @@ -523,6 +529,7 @@ declare_lint_pass! {
UNCONDITIONAL_PANIC,
UNUSED_IMPORTS,
UNUSED_EXTERN_CRATES,
UNUSED_CRATE_DEPENDENCIES,
UNUSED_QUALIFICATIONS,
UNKNOWN_LINTS,
UNUSED_VARIABLES,
Expand Down
1 change: 1 addition & 0 deletions src/test/ui/unused-crate-deps/auxiliary/bar.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
pub const BAR: &str = "bar";
5 changes: 5 additions & 0 deletions src/test/ui/unused-crate-deps/auxiliary/foo.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
// edition:2018
// aux-crate:bar=bar.rs

pub const FOO: &str = "foo";
pub use bar::BAR;
21 changes: 21 additions & 0 deletions src/test/ui/unused-crate-deps/libfib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
// Test warnings for a library crate

// check-pass
// aux-crate:bar=bar.rs
// compile-flags:--crate-type lib -Wunused-crate-dependencies

pub fn fib(n: u32) -> Vec<u32> {
//~^ WARNING external crate `bar` unused in
let mut prev = 0;
let mut cur = 1;
let mut v = vec![];

for _ in 0..n {
v.push(prev);
let n = prev + cur;
prev = cur;
cur = n;
}

v
}
10 changes: 10 additions & 0 deletions src/test/ui/unused-crate-deps/libfib.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
warning: external crate `bar` unused in `libfib`: remove the dependency or add `use bar as _;`
--> $DIR/libfib.rs:7:1
|
LL | pub fn fib(n: u32) -> Vec<u32> {
| ^
|
= note: requested on the command line with `-W unused-crate-dependencies`

warning: 1 warning emitted

11 changes: 11 additions & 0 deletions src/test/ui/unused-crate-deps/suppress.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
// Suppress by using crate

// edition:2018
// check-pass
// aux-crate:bar=bar.rs

#![warn(unused_crate_dependencies)]

use bar as _;

fn main() {}
13 changes: 13 additions & 0 deletions src/test/ui/unused-crate-deps/unused-aliases.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
// Warn about unused aliased for the crate

// edition:2018
// check-pass
// aux-crate:bar=bar.rs
// aux-crate:barbar=bar.rs

#![warn(unused_crate_dependencies)]
//~^ WARNING external crate `barbar` unused in

use bar as _;

fn main() {}
14 changes: 14 additions & 0 deletions src/test/ui/unused-crate-deps/unused-aliases.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
warning: external crate `barbar` unused in `unused_aliases`: remove the dependency or add `use barbar as _;`
--> $DIR/unused-aliases.rs:8:1
|
LL | #![warn(unused_crate_dependencies)]
| ^
|
note: the lint level is defined here
--> $DIR/unused-aliases.rs:8:9
|
LL | #![warn(unused_crate_dependencies)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^

warning: 1 warning emitted

13 changes: 13 additions & 0 deletions src/test/ui/unused-crate-deps/use_extern_crate_2015.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
// Suppress by using crate

// edition:2015
// check-pass
// aux-crate:bar=bar.rs

#![warn(unused_crate_dependencies)]

extern crate bar;

fn main() {
println!("bar {}", bar::BAR);
}
10 changes: 10 additions & 0 deletions src/test/ui/unused-crate-deps/warn-attr.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
// Check for unused crate dep, no path

// edition:2018
// check-pass
// aux-crate:bar=bar.rs

#![warn(unused_crate_dependencies)]
//~^ WARNING external crate `bar` unused in

fn main() {}
14 changes: 14 additions & 0 deletions src/test/ui/unused-crate-deps/warn-attr.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
warning: external crate `bar` unused in `warn_attr`: remove the dependency or add `use bar as _;`
--> $DIR/warn-attr.rs:7:1
|
LL | #![warn(unused_crate_dependencies)]
| ^
|
note: the lint level is defined here
--> $DIR/warn-attr.rs:7:9
|
LL | #![warn(unused_crate_dependencies)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^

warning: 1 warning emitted

10 changes: 10 additions & 0 deletions src/test/ui/unused-crate-deps/warn-cmdline-static.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
// Check for unused crate dep, no path

// edition:2018
// check-pass
// compile-flags: -Wunused-crate-dependencies
// aux-crate:bar=bar.rs
// no-prefer-dynamic

fn main() {}
//~^ WARNING external crate `bar` unused in
10 changes: 10 additions & 0 deletions src/test/ui/unused-crate-deps/warn-cmdline-static.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
warning: external crate `bar` unused in `warn_cmdline_static`: remove the dependency or add `use bar as _;`
--> $DIR/warn-cmdline-static.rs:9:1
|
LL | fn main() {}
| ^
|
= note: requested on the command line with `-W unused-crate-dependencies`

warning: 1 warning emitted

9 changes: 9 additions & 0 deletions src/test/ui/unused-crate-deps/warn-cmdline.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
// Check for unused crate dep, no path

// edition:2018
// check-pass
// compile-flags: -Wunused-crate-dependencies
// aux-crate:bar=bar.rs

fn main() {}
//~^ WARNING external crate `bar` unused in
10 changes: 10 additions & 0 deletions src/test/ui/unused-crate-deps/warn-cmdline.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
warning: external crate `bar` unused in `warn_cmdline`: remove the dependency or add `use bar as _;`
--> $DIR/warn-cmdline.rs:8:1
|
LL | fn main() {}
| ^
|
= note: requested on the command line with `-W unused-crate-dependencies`

warning: 1 warning emitted

0 comments on commit ffa493a

Please sign in to comment.