Auto merge of #4175 - yaahallo:master, r=oli-obk

Implement better help for clippy-driver

https://github.com/rust-lang/rust-clippy/issues/4173
This commit is contained in:
bors 2019-06-13 08:51:53 +00:00
commit bd39cea01c
4 changed files with 2349 additions and 4 deletions

View File

@ -87,9 +87,31 @@ fn print_lints() {
fn update_lints(update_mode: &UpdateMode) { fn update_lints(update_mode: &UpdateMode) {
let lint_list: Vec<Lint> = gather_all().collect(); let lint_list: Vec<Lint> = gather_all().collect();
let usable_lints: Vec<Lint> = Lint::usable_lints(lint_list.clone().into_iter()).collect(); let usable_lints: Vec<Lint> = Lint::usable_lints(lint_list.clone().into_iter()).collect();
let lint_count = usable_lints.len(); let lint_count = usable_lints.len();
let mut sorted_usable_lints = usable_lints.clone();
sorted_usable_lints.sort_by_key(|lint| lint.name.clone());
std::fs::write(
"../src/lintlist/mod.rs",
&format!(
"\
//! This file is managed by `util/dev update_lints`. Do not edit.
pub mod lint;
pub use lint::Level;
pub use lint::Lint;
pub use lint::LINT_LEVELS;
pub const ALL_LINTS: [Lint; {}] = {:#?};\n",
sorted_usable_lints.len(),
sorted_usable_lints
),
)
.expect("can write to file");
let mut file_change = replace_region_in_file( let mut file_change = replace_region_in_file(
"../README.md", "../README.md",
r#"\[There are \d+ lints included in this crate!\]\(https://rust-lang.github.io/rust-clippy/master/index.html\)"#, r#"\[There are \d+ lints included in this crate!\]\(https://rust-lang.github.io/rust-clippy/master/index.html\)"#,

View File

@ -15,6 +15,8 @@ use rustc_tools_util::*;
use std::path::Path; use std::path::Path;
use std::process::{exit, Command}; use std::process::{exit, Command};
mod lintlist;
/// If a command-line option matches `find_arg`, then apply the predicate `pred` on its value. If /// If a command-line option matches `find_arg`, then apply the predicate `pred` on its value. If
/// true, then return it. The parameter is assumed to be either `--arg=value` or `--arg value`. /// true, then return it. The parameter is assumed to be either `--arg=value` or `--arg value`.
fn arg_value<'a>( fn arg_value<'a>(
@ -108,6 +110,142 @@ impl rustc_driver::Callbacks for ClippyCallbacks {
} }
} }
#[allow(clippy::find_map, clippy::filter_map)]
fn describe_lints() {
use lintlist::*;
use std::collections::HashSet;
println!(
"
Available lint options:
-W <foo> Warn about <foo>
-A <foo> Allow <foo>
-D <foo> Deny <foo>
-F <foo> Forbid <foo> (deny <foo> and all attempts to override)
"
);
let lint_level = |lint: &Lint| {
LINT_LEVELS
.iter()
.find(|level_mapping| level_mapping.0 == lint.group)
.map(|(_, level)| match level {
Level::Allow => "allow",
Level::Warn => "warn",
Level::Deny => "deny",
})
.unwrap()
};
let mut lints: Vec<_> = ALL_LINTS.iter().collect();
// The sort doesn't case-fold but it's doubtful we care.
lints.sort_by_cached_key(|x: &&Lint| (lint_level(x), x.name));
let max_lint_name_len = lints
.iter()
.map(|lint| lint.name.len())
.map(|len| len + "clippy::".len())
.max()
.unwrap_or(0);
let padded = |x: &str| {
let mut s = " ".repeat(max_lint_name_len - x.chars().count());
s.push_str(x);
s
};
let scoped = |x: &str| format!("clippy::{}", x);
let lint_groups: HashSet<_> = lints.iter().map(|lint| lint.group).collect();
println!("Lint checks provided by clippy:\n");
println!(" {} {:7.7} meaning", padded("name"), "default");
println!(" {} {:7.7} -------", padded("----"), "-------");
let print_lints = |lints: &[&Lint]| {
for lint in lints {
let name = lint.name.replace("_", "-");
println!(
" {} {:7.7} {}",
padded(&scoped(&name)),
lint_level(lint),
lint.desc
);
}
println!("\n");
};
print_lints(&lints);
let max_group_name_len = std::cmp::max(
"clippy::all".len(),
lint_groups
.iter()
.map(|group| group.len())
.map(|len| len + "clippy::".len())
.max()
.unwrap_or(0),
);
let padded_group = |x: &str| {
let mut s = " ".repeat(max_group_name_len - x.chars().count());
s.push_str(x);
s
};
println!("Lint groups provided by clippy:\n");
println!(" {} sub-lints", padded_group("name"));
println!(" {} ---------", padded_group("----"));
println!(" {} the set of all clippy lints", padded_group("clippy::all"));
let print_lint_groups = || {
for group in lint_groups {
let name = group.to_lowercase().replace("_", "-");
let desc = lints
.iter()
.filter(|&lint| lint.group == group)
.map(|lint| lint.name)
.map(|name| name.replace("_", "-"))
.collect::<Vec<String>>()
.join(", ");
println!(" {} {}", padded_group(&scoped(&name)), desc);
}
println!("\n");
};
print_lint_groups();
}
fn display_help() {
println!(
"\
Checks a package to catch common mistakes and improve your Rust code.
Usage:
cargo clippy [options] [--] [<opts>...]
Common options:
-h, --help Print this message
-V, --version Print version info and exit
Other options are the same as `cargo check`.
To allow or deny a lint from the command line you can use `cargo clippy --`
with:
-W --warn OPT Set lint warnings
-A --allow OPT Set lint allowed
-D --deny OPT Set lint denied
-F --forbid OPT Set lint forbidden
You can use tool lints to allow or deny lints from your code, eg.:
#[allow(clippy::needless_lifetimes)]
"
);
}
pub fn main() { pub fn main() {
rustc_driver::init_rustc_env_logger(); rustc_driver::init_rustc_env_logger();
exit( exit(
@ -153,13 +291,34 @@ pub fn main() {
// Setting RUSTC_WRAPPER causes Cargo to pass 'rustc' as the first argument. // Setting RUSTC_WRAPPER causes Cargo to pass 'rustc' as the first argument.
// We're invoking the compiler programmatically, so we ignore this/ // We're invoking the compiler programmatically, so we ignore this/
if orig_args.len() <= 1 { let wrapper_mode = Path::new(&orig_args[1]).file_stem() == Some("rustc".as_ref());
std::process::exit(1);
} if wrapper_mode {
if Path::new(&orig_args[1]).file_stem() == Some("rustc".as_ref()) {
// we still want to be able to invoke it normally though // we still want to be able to invoke it normally though
orig_args.remove(1); orig_args.remove(1);
} }
if !wrapper_mode && std::env::args().any(|a| a == "--help" || a == "-h") {
display_help();
exit(0);
}
let should_describe_lints = || {
let args: Vec<_> = std::env::args().collect();
args.windows(2).any(|args| {
args[1] == "help"
&& match args[0].as_str() {
"-W" | "-A" | "-D" | "-F" => true,
_ => false,
}
})
};
if !wrapper_mode && should_describe_lints() {
describe_lints();
exit(0);
}
// this conditional check for the --sysroot flag is there so users can call // this conditional check for the --sysroot flag is there so users can call
// `clippy_driver` directly // `clippy_driver` directly
// without having to pass --sysroot or anything // without having to pass --sysroot or anything

27
src/lintlist/lint.rs Normal file
View File

@ -0,0 +1,27 @@
/// Lint data parsed from the Clippy source code.
#[derive(Clone, PartialEq, Debug)]
pub struct Lint {
pub name: &'static str,
pub group: &'static str,
pub desc: &'static str,
pub deprecation: Option<&'static str>,
pub module: &'static str,
}
#[derive(PartialOrd, PartialEq, Ord, Eq)]
pub enum Level {
Allow,
Warn,
Deny,
}
pub const LINT_LEVELS: [(&str, Level); 8] = [
("correctness", Level::Deny),
("style", Level::Warn),
("complexity", Level::Warn),
("perf", Level::Warn),
("restriction", Level::Allow),
("pedantic", Level::Allow),
("nursery", Level::Allow),
("cargo", Level::Allow),
];

2137
src/lintlist/mod.rs Normal file

File diff suppressed because it is too large Load Diff