Skip to content

Add lint to detect unused Rust files in crate directory #544

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

Closed
wants to merge 1 commit into from
Closed
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
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ plugin = true
[dependencies]
unicode-normalization = "0.1"
semver = "0.2.1"
walkdir = "0.1"

[dev-dependencies]
compiletest_rs = "0.0.11"
Expand Down
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,7 @@ name
[unneeded_field_pattern](https://github.com/Manishearth/rust-clippy/wiki#unneeded_field_pattern) | warn | Struct fields are bound to a wildcard instead of using `..`
[unstable_as_mut_slice](https://github.com/Manishearth/rust-clippy/wiki#unstable_as_mut_slice) | warn | as_mut_slice is not stable and can be replaced by &mut v[..]see https://github.com/rust-lang/rust/issues/27729
[unstable_as_slice](https://github.com/Manishearth/rust-clippy/wiki#unstable_as_slice) | warn | as_slice is not stable and can be replaced by & v[..]see https://github.com/rust-lang/rust/issues/27729
[unused_files](https://github.com/Manishearth/rust-clippy/wiki#unused_files) | warn | unused Rust files in the crate root and sub-directories
[unused_collect](https://github.com/Manishearth/rust-clippy/wiki#unused_collect) | warn | `collect()`ing an iterator without using the result; this is usually better written as a for loop
[unused_lifetimes](https://github.com/Manishearth/rust-clippy/wiki#unused_lifetimes) | warn | unused lifetimes in function definitions
[used_underscore_binding](https://github.com/Manishearth/rust-clippy/wiki#used_underscore_binding) | warn | using a binding which is prefixed with an underscore
Expand Down
7 changes: 6 additions & 1 deletion src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,9 @@ extern crate unicode_normalization;
// for semver check in attrs.rs
extern crate semver;

// for walking directories in src/unused_files.rs
extern crate walkdir;

extern crate rustc_plugin;

use rustc_plugin::Registry;
Expand Down Expand Up @@ -77,6 +80,7 @@ pub mod misc_early;
pub mod array_indexing;
pub mod panic;
pub mod derive;
pub mod unused_files;

mod reexport {
pub use syntax::ast::{Name, NodeId};
Expand Down Expand Up @@ -140,7 +144,7 @@ pub fn plugin_registrar(reg: &mut Registry) {
reg.register_late_lint_pass(box panic::PanicPass);
reg.register_late_lint_pass(box strings::StringLitAsBytes);
reg.register_late_lint_pass(box derive::Derive);

reg.register_early_lint_pass(box unused_files::UnusedFilesPass);

reg.register_lint_group("clippy_pedantic", vec![
methods::OPTION_UNWRAP_USED,
Expand Down Expand Up @@ -243,6 +247,7 @@ pub fn plugin_registrar(reg: &mut Registry) {
types::TYPE_COMPLEXITY,
types::UNIT_CMP,
unicode::ZERO_WIDTH_SPACE,
unused_files::UNUSED_FILES,
zero_div_zero::ZERO_DIVIDED_BY_ZERO,
]);
}
65 changes: 65 additions & 0 deletions src/unused_files.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
extern crate syntax;

use rustc::lint::{EarlyLintPass, EarlyContext, LintContext, LintPass, LintArray};
use syntax::ast;

use std::collections::HashSet;
use std::path::Path;

use walkdir::WalkDir;

declare_lint!(
pub UNUSED_FILES,
Warn,
"warns about unused Rust files");

pub struct UnusedFilesPass;


impl LintPass for UnusedFilesPass {
fn get_lints(&self) -> LintArray {
lint_array!(UNUSED_FILES)
}
}

impl EarlyLintPass for UnusedFilesPass {
fn check_crate(&mut self, ctx: &EarlyContext, _: &ast::Crate) {
let cm = ctx.sess.codemap();

let mut visited: HashSet<String> = HashSet::new();
for file in cm.files.borrow().iter() {
let path = ctx.sess.working_dir.join(Path::new(&file.name));
visited.insert(path.to_str().unwrap().to_string());
}
if let Some(ref path) = ctx.sess.local_crate_source_file {
let mut dir = path.clone();
dir.pop();

let mut rs_files = HashSet::new();
for entry in WalkDir::new(dir) {
match entry {
Ok(entry) => {
let path = entry.path();
if let Some(ext) = path.extension() {
if ext == "rs" {
rs_files.insert(path.to_str().unwrap().to_string());
}
}
},
Err(e) => {
ctx.lint(UNUSED_FILES,
&format!("Error walking crate directory: {:?}", e));
}
}
}

let diff: HashSet<String> = rs_files.difference(&visited).cloned().collect();

if diff.len() > 0 {
let files: Vec<String> = diff.iter().map(|s| s.clone()).collect::<Vec<String>>();
ctx.lint(UNUSED_FILES,
&format!("Found {} unused files:\n{}\n", diff.len(), files.join("\n")));
}
}
}
}